24
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pleasanterをk3s+Rancher+Longhorn+CNPGで構築してみる 〜絶対に落ちない社内システムを目指して〜

Last updated at Posted at 2025-12-18

はじめまして、インプリムさんのPleasanter Loungeで開催されているNakano Tech Loungeのイベントの運営メンバーをしています、もちもちずきんと申します。

私は普段はSIerと事業会社でバックエンド開発やサーバー構築を行っているインフラ・バックエンドエンジニアです。Linuxユーザーグループである、東海道らぐFediverse Linux Users GroupopenSUSE ユーザー会などのコミュニティ活動への参加を趣味としており、多数出没しています。

今回は所属としては全くのインプリムさんの部外者でありながら、このアドベントカレンダーの執筆にお誘いをいただいたので、Pleasanterをk3sで構築してみようと思います。

はじめに

今回のこの記事ではインプリムさんの公式ドキュメントにも記載がなく、調べてみたところ前例もあまりない、PleasanterをKubernetesで動かしてみるという部分が趣旨になります。

おことわりとして、この記事に書いてある内容は

  • 非公式の人間が書いています
  • 実験的な内容を含むため、実用的・セキュリティ的にそのまま運用を推奨できるものではありません
  • プロダクトの各名称及びバージョンは2025年12月19日現在のものを使用しています

ということを承知の上で読んでいただけると幸いです。

また、本記事で紹介する構成は、EKS や GKEいわゆるマネージドKubernetesサービスを使用した「クラウド前提の Kubernetes 運用」ではありません。すべてのノード、ストレージ、ネットワークを自前で管理する フルオンプレミス環境 を前提に、「社内システムとして止まりにくい構成」を検証します。

概要

kubernetes(k3s)を使用してHAなPleasanter環境を構築する

用意するものは以下です

  • VM:4台(クラスタ用3台+Rancher用1台)
  • Tailscaleアカウント

今回の構成

今回の登場人物です。ざっくりの構成とそれぞれ出てくる名前について説明します。

また、これはもしかしたら賛非が分かれるかもしれませんが、今回はつかえるものは使える限りhelmを使用して構築を行います。helmとはKubernetes用のパッケージマネージャで複雑なKubernetesの設定の管理を容易にします。

インフラ・ミドルウエア層

OS:openSUSE Leap Micro 6.2

OSは今回openSUSE Leap Micro 6.2を使用します。openSUSE Leap Microは高信頼性を謳う軽量Linuxディストリビューションです。

スナップショットでのOS管理などを特徴としており、今回のようなコンテナや仮想化の環境などに最適とされます。

Kubernetesディストリ:K3s

Kubernetesのディストリビューションは複数ありますが、今回は私の好みでRancher Labs によって開発され、現在は SUSE 傘下でメンテナンスされているK3sを使用したいと思います。

軽量なKubernetes。インストールが簡単で、メモリ使用量は半分、100MB未満のバイナリにすべてが収まります。

とあり、Go言語で実装されており、軽量かつ単一バイナリで動作することが売りです。

分散ブロックストレージ:Longhorn

今回永続ボリュームとして使用する分散ブロックストレージの実装はLonghornを使用します。エンタープライズ版は最近名前が変わりました。そっちはSUSE Storageと呼ばれているみたいです。

Webコンソール:Rancher

今回はお手軽構築の道具として、SUSEが開発しているRancherをk3sクラスタおよびlonghorn分散ストレージの管理用WebコンソールとしてRancherを使用します。

VPN・接続窓口:Tailscale

今回、VM間接続とクライアント⇔サービス間接続をTailscaleで接続・ルーティングします。TailscaleはWireGuardをベースにしたP2P型のVPNサービスです。クライアントはOSSで公開されていることなどが特徴的です。

アプリケーション層

Ingress:Traefik

TraefikはTraefik Labsによって開発されている、クラウドネイティブ環境向けに設計されたGoで実装されたリバースプロキシ・ロードバランサです。k3sにはデフォルトでIngress ControllerにTraefikが採用されています。今回はそれを使用します。

アプリケーション:implem/pleasanter:1.4.23.3

皆さんご存知、今回の主役、Pleasanterは株式会社インプリムさんがOSSで開発しているノーコード・ローコードツールです。

業種業界を問わず数多くの導入実績、140社以上の全国に広がるパートナーネットワーク、充実した学習コンテンツと安心のサポート体制。プリザンターが、あなたの企業のDXを成功に導きます。

今回は執筆時点で最新バージョンの1.4.23.3のdockerhubのイメージを使用します。

データベース:CloudNativePG 1.27.0 / PostgreSQL 16

CloudNative PGはPostgreSQLをKubernetes環境で動かす、オペレーターです。プライマリ・スタンバイでの運用、ストリーミングレプリケーション、自動フェイルオーバーなど、高可用性運用に対応しています。今回はCloudNative PGのバージョンを1.27.0を使用し、動かすPostgreSQLのバージョンは16を使用します。

1. k3s用VMの準備

(今回は私の自宅にあるサーバー環境でProxmox上でVMを作成しています)

今回は3台のVMで冗長化構成を組んで動かします。この手順は3台全てに行います。

1-1. openSUSE Leap Micro 6.2のインストール

image-20251216210040771.png

https://get.opensuse.org/ja/leapmicro/6.2/ からご自身のマシンのCPUアーキテクチャにあったイメージやISOでインストールを行います。今回は「自己インストール型イメージ」でインストールをおこない

ちなみに今回はメインのアプリケーションであるPleasanterのコンテナイメージがAMD64かARM64で配布されているのでこの構成で使用できるCPUアーキテクチャは実質この二択になります。

1-2. OSのインストール

image-20251217104509331.png

起動するとディスクのデータを全て消してインストールを始めていいか聞かれます。<Yes>でいきましょう。そしたらインストールが行われます。インストールが完了したら、再起動がかかり、rootパスワードやタイムゾーンなど、初期セットアップに必要な情報を求められます。それぞれの環境に合わせて回答していきましょう。

image-20251217104743814.png

hostnameを見分けやすいようにユニークなものをつけておきましょう。今回はpleasanter-k3s-nにしてあります。

echo pleasanter-k3s-1 > /etc/hostname

のような形で設定します。

1-3. Tailscaleのインストール

今回ノード間接続に使用するTailscaleのインストールを行います。UbuntuやFedoraなどのディストリであれば

curl -fsSL https://tailscale.com/install.sh | sh

を実行するだけでインストールできるのですが、Leap Microはサポート対象外なので手動でインストールする必要があります。基本的には公式のガイドに沿っていればいいです。

今回は/usr/local/binにインストールを行います。

まず、Tailscaleのバイナリを取得するためのwgetコマンドをインストール・再起動します。

transactional-update pkg install wget
reboot

先程インストールしたwgetコマンドでTailscaleのバイナリを取得します。その時にマシンのアーキテクチャに合った最新バージョンを公式サイトから取得してください。

wget https://pkgs.tailscale.com/unstable/tailscale_1.93.56_amd64.tgz

tgzで圧縮されているので解凍し、ディレクトリに入ります。

tar xvf tailscale_1.93.56_amd64.tgz
cd tailscale_1.93.56_amd64

installコマンドでディレクトリにあるTailscaleのバイナリを/usr/local/binにインストールします。

install -m 0755 ./tailscale  /usr/local/bin/tailscale
install -m 0755 ./tailscaled /usr/local/bin/tailscaled

また、このディレクトリの中にはsystemdの定義ファイルも入っていますので、それを/etc/systemd/systemに移動します。

cp ./systemd/* /etc/systemd/system

stateファイルについてもディレクトリを作って配置します

mkdir /var/lib/tailscale
cp tailscaled.state /var/lib/tailscale/

また/etc/defaultにtailscaleのenvを配置します。お好みのエディタで/etc/default/tailscaledに以下の内容を書いてください。

FLAGS=""
PORT="41641"

デフォルトのsystemd設定ファイルはバイナリのパスが異なるので、編集する必要があります。お好みのエディタで/etc/systemd/system/tailscaled.serviceを編集しましょう。以下のようにすると動くはずです。

- ExecStart=/usr/sbin/tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock --port=${PORT} $FLAGS
- ExecStopPost=/usr/sbin/tailscaled --cleanup
+ ExecStart=/usr/local/bin/tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock --port=${PORT} $FLAGS
+ ExecStopPost=/usr/local/bin/tailscaled --cleanup

そうしたら、デーモンのリロードをかけることで設定が読み込まれ、起動することができるようになるはずです。

systemctl daemon-reload
systemctl start tailscaled.service

そうしたら、tailscaleを起動・接続します。

tailscale up

ログイン用のURLが出てくるのでそこにアクセスし、認証を行うとTailscaleに接続されます

To authenticate, visit:

	https://login.tailscale.com/a/xxxxxxxxxxxxx

Screenshot From 2025-12-17 11-18-39.png

1.4. k3sのインストール

k3sのインストールを行っていきます。こちらは公式のインストールスクリプトが使用できるのでそれを実行します。また、起動します。

1-4-1. 1台目

まずシングルノードとしてクラスタを構築します。今回ノード間接続はtailscaleにお任せするので、tailscaleのIPアドレスを確認しておきます。

ip a

2台目以降の接続用トークンを作っておきます。

openssl rand -hex 32

などでランダムな文字列を生成するのが良いでしょう。

tailscale0のIPアドレスが今回は100.70.242.62だったので、これを--tls-sanに書きます。Tailscaleでの接続の場合これを書かないと証明書のCAエラーが出てしまうので注意しましょう。

curl -sfL https://get.k3s.io | K3S_TOKEN={さっき作ったトークン} sh -s --tls-san 100.70.242.62 --cluster-init 
systemctl enable --now  k3s

起動しているか確認してみましょう

# k3s kubectl get no
NAME                    STATUS   ROLES                  AGE   VERSION
localhost.localdomain   Ready    control-plane,master   7s    v1.33.6+k3s1

2つめ以降のノードで必要なトークンを控えておきます

cat /var/lib/rancher/k3s/server/node-token

1-4-2. 2台目以降

https://docs.k3s.io/datastore/ha-embedded#existing-single-node-clusters に従ってインストールスクリプトを使用して同様にインストールを行います。今回は3台ともコントロールプレーンとしての役割をもたせます。

--tls-sanには自分のマシンのTailscaleのIPアドレスを入れます。

curl -sfL https://get.k3s.io | K3S_TOKEN={1台目で控えたトークン} sh -s - server --server https://{1台目のIP}:6443 --tls-san {tailscale0のIP}

1-4-3. クラスタの確認

3台のうちのどれか一つでkubectl get noコマンドで確認を行うと、マルチノードのクラスタになっていることがわかります。

kubectl get no
NAME               STATUS   ROLES                       AGE     VERSION
pleasanter-k3s-1   Ready    control-plane,etcd,master   30m     v1.33.6+k3s1
pleasanter-k3s-2   Ready    control-plane,etcd,master   3m14s   v1.33.6+k3s1
pleasanter-k3s-3   Ready    control-plane,etcd,master   11s     v1.33.6+k3s1

1-5. Longhornストレージの構築の準備

Longhornはopen-iscsiiscsidが必要なため、インストールを行っておきます。

transactional-update pkg install open-iscsi nfs-client
reboot
systemctl enable --now iscsid

2. Rancher用VMの準備

Rancher用のVM準備に関しても1-1から1-3までは同じです。それぞれ実行してください。

2-1. Dockerのインストール

今回はRancherは簡単にDockerで実行します。transactional-updateでdockerをインストールします。

transactional-update pkg install docker
reboot
systemctl enable --now docker 

2-2. Ranckerの起動

Rancherをdockerでインストール・起動します

docker run -d --restart=unless-stopped -p 80:80 -p 443:443 --privileged rancher/rancher

初期パスワードはログに出ているので確認しておきます

docker logs {コンテナID} 2>&1 | grep "Bootstrap Password:"

https://{IPアドレス} にアクセスすると、Rancherのページが表示されます。確認しておいた初期パスワードでログインし、パスワードを変更したら、Rancherのセットアップ完了です。

image-20251217230027049.png

2-3. k3sクラスタをRancherに登録する

セットアップしたk3sクラスタをRancherに追加します。ちなみにデフォルトで表示されているのは、Rancherのノードに自動で作られたシングルノードクラスタです。

真ん中辺りにある「Import Existing」ボタンから追加します。

image-20251218000303126.png

今回はオンプレなのでGenericを選択します

image-20251218000349241.png

色々設定項目がありますが、今回はCluster Nameのみ設定します。今回は「pleasantertest」にしました

image-20251218000445415.png

Createボタンを押すと、接続用のkubectlコマンドが表示されるので、コピーして3つのうちのどこかで実行します。実行が成功すると、クラスタが追加され、リソースの監視などができるようになります。

image-20251218003251697.png

3. CloudNative PGによるPostgreSQLクラスタの構築

下準備は整いました。次にCloudNative PGをhelmを使用して構築します。

3-1. Rancherからリポジトリをロード

登録したクラスタを選択して、Apps>RepositoriesのCreateを押します。

image-20251218003751270.png

リポジトリの追加画面で任意の名前とURLを入力します。今回は普通に名前をcnpgのものとlonghornのものを入れます。

CNPGのURL : https://cloudnative-pg.github.io/charts

LonghornのURL:https://charts.longhorn.io

image-20251218003831991.png

正常に追加できると以下のようにActive表示になります。

image-20251218004018606.png

3-2. Longhornのインストールとストレージの構築

同じ画面のままメニューをChartsに切り替えます。検索フォームに「longhorn」と入力すると、ヒットします。longhornをクリックします。

image-20251218154448568.png

Install this versionからインストールを行います。

image-20251218155947894.png

今回はデフォルト設定でそのままインストールします。

image-20251218160033153.png

インストールが進む様子をログで確認しながらコーヒーでも飲みましょう。

インストールが完了すると、左のタブにLonghornが追加されているはずです。OverviewからLonghornをクリックするとLonghornのWeb管理画面にジャンプすることができます。

image-20251218160359423.png

上のメニューのVolumeを選択し、CreateVolumeを選択します。

かっこいいダッシュボードが表示されたら作業完了です。

image-20251218160553331.png

3-3. CloudNativePGのクラスタ構築

3-3-1. CloudNativePG Operatorのインストール

同じ画面のままメニューをChartsに切り替えます。検索フォームに「cloudnative pg」と入力すると、ヒットします。cloudnative-pgをクリックします。

image-20251218004120828.png

問題なさそうであればInstall this versionをクリックします。

image-20251218004259415.png

そうすると、NamespaceとNameを聞かれます。今回はNamespaceはdefaultのまま、Nameは空にしました。

また、コントロールも冗長化したいので最後のステップのyaml変更画面でreplicaCountを3に変更します。

image-20251218163221987.png

Installを行うとオペレータがインストールされます。

3-3-2. CloudNativePG Clusterのインストール

同じ画面のままメニューをChartsに切り替えます。検索フォームに「cloudnative pg」と入力すると、ヒットします。clusterをクリックします。

image-20251218180953615.png

Install this versionを押すと、NamespaceとNameを聞かれます。今回はNamespaceはdefaultのまま、Nameは空にしました。

また、コントロールも冗長化したいので最後のステップのyaml変更画面でstorage.storageClassを先程入れたlonghornに変更します。

image-20251218180925316.png

ここでサーバー側でk8sのpodが作成されているか見てみましょう。

pleasanter-k3s-1:/home/yoheizuho # kubectl get po
NAME                                                READY   STATUS    RESTARTS   AGE
cloudnative-pg-0-1766048663-86857dbbc9-7msqb        1/1     Running   0          25m
cloudnative-pg-0-1766048663-86857dbbc9-dh2rr        1/1     Running   0          25m
cloudnative-pg-0-1766048663-86857dbbc9-r4fwh        1/1     Running   0          25m
cluster-0-1766049839-1                              1/1     Running   0          5m55s
cluster-0-1766049839-2                              1/1     Running   0          5m2s
cluster-0-1766049839-3                              1/1     Running   0          4m25s
csi-attacher-b5547c89c-5jrzr                        1/1     Running   0          25m
csi-attacher-b5547c89c-fcx2l                        1/1     Running   0          25m
csi-attacher-b5547c89c-ndbkn                        1/1     Running   0          25m
csi-provisioner-6d9fbbd668-c9ld5                    1/1     Running   0          25m
csi-provisioner-6d9fbbd668-pknjq                    1/1     Running   0          25m
csi-provisioner-6d9fbbd668-wmbng                    1/1     Running   0          25m
csi-resizer-588c678f58-d99gb                        1/1     Running   0          25m
csi-resizer-588c678f58-f7wgs                        1/1     Running   0          25m
csi-resizer-588c678f58-sbwzw                        1/1     Running   0          25m
csi-snapshotter-589f996dc-6szwp                     1/1     Running   0          25m
csi-snapshotter-589f996dc-mlw7g                     1/1     Running   0          25m
csi-snapshotter-589f996dc-vwv4b                     1/1     Running   0          25m
engine-image-ei-3154f3aa-6jc2p                      1/1     Running   0          26m
engine-image-ei-3154f3aa-pqvqx                      1/1     Running   0          26m
engine-image-ei-3154f3aa-t78p5                      1/1     Running   0          26m
instance-manager-38e4191462ab524cde79ff02ff1ab2a9   1/1     Running   0          26m
instance-manager-4977adb0b5c6229ebc590735b86ba78f   1/1     Running   0          26m
instance-manager-f4a600b4d74a706f48cb8fca0985b0ee   1/1     Running   0          26m
longhorn-csi-plugin-gzt9z                           3/3     Running   0          25m
longhorn-csi-plugin-ktq5h                           3/3     Running   0          25m
longhorn-csi-plugin-n8mdj                           3/3     Running   0          25m
longhorn-driver-deployer-567c4b678b-hc88k           1/1     Running   0          27m
longhorn-manager-gxlqc                              2/2     Running   0          27m
longhorn-manager-nr5zq                              2/2     Running   0          27m
longhorn-manager-t8pxh                              2/2     Running   0          27m
longhorn-ui-7974b7c999-hvlqk                        1/1     Running   0          27m
longhorn-ui-7974b7c999-xcx8s                        1/1     Running   0          27m

3-3-3. データベースの設定

PostgreSQLのオーナーユーザーのパスワードを変更します。Rancherのクラスタ管理画面からService Discovery > Servicesで構築したCloudNativePGのRW(ReadWrite)サービス(今回はmastodon-cnpg-cluster-rw )をクリックします。そうするとPodsにRWのPodが表示されているので、Nameをクリックします。Podの管理画面右上のからExecuteShellをクリックするとターミナルがブラウザ上に展開されます。

パスワードは適宜適切なものを使用してください。

postgres@cluster-0-1766049839-1:/$ psql
psql (16.11 (Debian 16.11-1.pgdg11+1))
Type "help" for help.

postgres=# ALTER ROLE postgres with password 'super_strong_pass';
ALTER ROLE
postgres=# quit;

4. Pleasanterのクラスタ構築

最後に皆さんお待ちかねPleasanterを構築します。以下のyamlファイルをサーバー上に作成します。今回は名前をpleasanter.yamlにしました。データベースのパスワードやホスト名は環境によって異なるので適宜変更してください。この設定では3つのレプリカを作ります。

データベースのRWのホスト名はRancherのServiceDiscovery > Servicesのなかから確認できます。自動で作られているならcluster-0-1766049839-rwのような名前です。

traefikで用いるホスト名も環境によって変更が必要です。今回はpleasanter.example.comになっています。

apiVersion: v1
kind: Secret
metadata:
  name: pleasanter-db-secret
  namespace: default
type: Opaque
stringData:
  Implem_Pleasanter_Rds_PostgreSQL_SaConnectionString: "Host=cluster-0-1766049839-rw;Port=5432;Database=postgres;uid=postgres;pwd={上で設定したパスワード};"
  Implem_Pleasanter_Rds_PostgreSQL_OwnerConnectionString: "Host=cluster-0-1766049839-rw;Port=5432;Database=#ServiceName#;uid=#ServiceName#_Owner;pwd={任意のパスワード};"
  Implem_Pleasanter_Rds_PostgreSQL_UserConnectionString: "Host=cluster-0-1766049839-rw;Port=5432;Database=#ServiceName#;uid=#ServiceName#_User;pwd={任意のパスワード};"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: pleasanter-config
  namespace: default
data:
  PORT: "8080"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pleasanter
  namespace: default
spec:
  replicas: 3
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: pleasanter
  template:
    metadata:
      labels:
        app: pleasanter
    spec:
      containers:
        - name: pleasanter
          image: implem/pleasanter:1.4.23.3
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
          env:
            - name: Implem.Pleasanter_Rds_PostgreSQL_SaConnectionString
              valueFrom:
                secretKeyRef:
                  name: pleasanter-db-secret
                  key: Implem_Pleasanter_Rds_PostgreSQL_SaConnectionString
            - name: Implem.Pleasanter_Rds_PostgreSQL_OwnerConnectionString
              valueFrom:
                secretKeyRef:
                  name: pleasanter-db-secret
                  key: Implem_Pleasanter_Rds_PostgreSQL_OwnerConnectionString
            - name: Implem.Pleasanter_Rds_PostgreSQL_UserConnectionString
              valueFrom:
                secretKeyRef:
                  name: pleasanter-db-secret
                  key: Implem_Pleasanter_Rds_PostgreSQL_UserConnectionString
          readinessProbe:
            tcpSocket:
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5
            timeoutSeconds: 2
            failureThreshold: 6
          livenessProbe:
            tcpSocket:
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 2
            failureThreshold: 6
          resources:
            requests:
              cpu: 100m
              memory: 256Mi
            limits:
              cpu: "2"
              memory: 2Gi
---
apiVersion: v1
kind: Service
metadata:
  name: pleasanter
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: pleasanter
  ports:
    - name: http
      port: 8080
      targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: pleasanter
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: pleasanter.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: pleasanter
                port:
                  number: 8080

kubectl applyと行きたいところですがCodeDefinerの実行を行います。ここのタイムゾーンなどの設定項目に関しては公式のDockerでのインストール手順と同じなので参照してください。

kubectl -n default run codedefiner-once --rm -it \
  --image=implem/pleasanter:codedefiner \
  --restart=Never \
  --env=Implem.Pleasanter_Rds_PostgreSQL_SaConnectionString="Host=cluster-0-1766049839-rw;Port=5432;Database=postgres;uid=postgres;pwd={上で設定したパスワード};" \
  --env=Implem.Pleasanter_Rds_PostgreSQL_OwnerConnectionString="Host=cluster-0-1766049839-rw;Port=5432;Database=#ServiceName#;uid=#ServiceName#_Owner;pwd={任意のパスワード};" \
  --env=Implem.Pleasanter_Rds_PostgreSQL_UserConnectionString="Host=cluster-0-1766049839-rw;Port=5432;Database=#ServiceName#;uid=#ServiceName#_User;pwd={任意のパスワード};" \
  -- _rds /l ja /z Asia/Tokyo

途中で

Type "y" (yes) if the license is correct, otherwise type "n" (no).

と聞かれるのでyを入力します。そうするとログが流れてCodeDefinerが走るはずです。

ホストでkubectlコマンドを用いてpodを起動させます。

kubectl apply -f pleasanter.yaml

kubectl get poで起動したpodを取得してみましょう。namespaceをpleasanterで作成したので指定しています。

pleasanter-k3s-1:/home/yoheizuho # kubectl get po
NAME                                                READY   STATUS    RESTARTS   AGE
cloudnative-pg-0-1766048663-86857dbbc9-7msqb        1/1     Running   0          116m
cloudnative-pg-0-1766048663-86857dbbc9-dh2rr        1/1     Running   0          116m
cloudnative-pg-0-1766048663-86857dbbc9-r4fwh        1/1     Running   0          116m
cluster-0-1766049839-1                              1/1     Running   0          97m
cluster-0-1766049839-2                              1/1     Running   0          96m
cluster-0-1766049839-3                              1/1     Running   0          95m
csi-attacher-b5547c89c-5jrzr                        1/1     Running   0          117m
csi-attacher-b5547c89c-fcx2l                        1/1     Running   0          117m
csi-attacher-b5547c89c-ndbkn                        1/1     Running   0          117m
csi-provisioner-6d9fbbd668-c9ld5                    1/1     Running   0          117m
csi-provisioner-6d9fbbd668-pknjq                    1/1     Running   0          117m
csi-provisioner-6d9fbbd668-wmbng                    1/1     Running   0          117m
csi-resizer-588c678f58-d99gb                        1/1     Running   0          117m
csi-resizer-588c678f58-f7wgs                        1/1     Running   0          117m
csi-resizer-588c678f58-sbwzw                        1/1     Running   0          117m
csi-snapshotter-589f996dc-6szwp                     1/1     Running   0          117m
csi-snapshotter-589f996dc-mlw7g                     1/1     Running   0          117m
csi-snapshotter-589f996dc-vwv4b                     1/1     Running   0          117m
engine-image-ei-3154f3aa-6jc2p                      1/1     Running   0          118m
engine-image-ei-3154f3aa-pqvqx                      1/1     Running   0          118m
engine-image-ei-3154f3aa-t78p5                      1/1     Running   0          118m
instance-manager-38e4191462ab524cde79ff02ff1ab2a9   1/1     Running   0          117m
instance-manager-4977adb0b5c6229ebc590735b86ba78f   1/1     Running   0          117m
instance-manager-f4a600b4d74a706f48cb8fca0985b0ee   1/1     Running   0          117m
longhorn-csi-plugin-gzt9z                           3/3     Running   0          117m
longhorn-csi-plugin-ktq5h                           3/3     Running   0          117m
longhorn-csi-plugin-n8mdj                           3/3     Running   0          117m
longhorn-driver-deployer-567c4b678b-hc88k           1/1     Running   0          118m
longhorn-manager-gxlqc                              2/2     Running   0          118m
longhorn-manager-nr5zq                              2/2     Running   0          118m
longhorn-manager-t8pxh                              2/2     Running   0          118m
longhorn-ui-7974b7c999-hvlqk                        1/1     Running   0          118m
longhorn-ui-7974b7c999-xcx8s                        1/1     Running   0          118m
pleasanter-6f6b4c769d-2pcvd                         1/1     Running   0          5m4s
pleasanter-6f6b4c769d-8b6zt                         1/1     Running   0          5m17s
pleasanter-6f6b4c769d-r2jv5                         1/1     Running   0          4m52s

また、traefikで待ち受けがされているか確認してみましょう。

pleasanter-k3s-1:/home/yoheizuho # kubectl get ingress
NAME         CLASS     HOSTS                    ADDRESS                                     PORTS   AGE
pleasanter   traefik   pleasanter.example.com   192.168.0.111,192.168.0.119,192.168.0.222   80      50m

pleasanter.example.comのホスト名で80ポートで公開されていることがわかります。(なぜかマシンのローカルIPになってしまっていますが💦)

5. ルーティングの設定

サーバーIPのAレコードでDNSラウンドロビンを行うのがいいですが、今回は公開していないので、/etc/hostsで運用します。

Cloudflaredを使うなどの方法もあります。

6. ブラウザで確認

これで構築の全ての工程が終わりました。設定したホスト名でブラウザでアクセスしてみましょう。

image-20251218201522692.png

ログイン画面が表示されました🎉やったー成功です!!(実はめっちゃ失敗しながらここまできたのでめっちゃ嬉しい)

「ログインID: Administrator」、「初期パスワード: pleasanter」を入力します。 デフォルトのパスワードの変更が求められると思いますが、それを入力すると…

image-20251218201722025.png

きましたね…長かった…(ここまで4日かかっている)

このあとのフェイルオーバーテストのためにも、なにかプロジェクトを作ってみましょう

image-20251218201952718.png

image-20251218202014463.png

ちゃんと作成されましたね。

7. フェイルオーバーのテスト

今回のテーマである冗長化、本当に効いているのかテストしてみましょう。

ServiceDiscoveryを見ると、RW=プライマリはcluster-0-1766049839-1というpodが担っており、ノードはpleasanter-k3s-2で動いているようです。

image-20251218202141511.png

ということでpleasanter-k3s-2を落としてみます。

pleasanter-k3s-2:/home/yoheizuho # poweroff

少し待っているとpleasanter-k3s-3 にあるcluster-0-1766049839-2がRWに昇格しました。

image-20251218202937990.png

マシンの性能不足だと思われますが、数分ダウンタイムが出てしまいましたが、無事参照が可能になりました。

image-20251218203733211.png

それでは電源を落としたpleasanter-k3s-2を再度起こしてみましょう。

pleasanter-k3s-2:/home/yoheizuho # kubectl get no
NAME               STATUS   ROLES                       AGE    VERSION
pleasanter-k3s-1   Ready    control-plane,etcd,master   163m   v1.33.6+k3s1
pleasanter-k3s-2   Ready    control-plane,etcd,master   162m   v1.33.6+k3s1
pleasanter-k3s-3   Ready    control-plane,etcd,master   163m   v1.33.6+k3s1

確認すると、k3sのクラスタには復帰しているようです。

image-20251218204729873.png

障害時はここから復旧作業をもろもろ行っていく形になるでしょう。

まとめ

Pleasanterの環境をk3s+Longhorn+CNPGで冗長化をして、自動フェイルオーバーを行う構成で落ちない社内システムを作ってみようという趣旨で書かせてもらいました。

実際の結果はフェイルオーバーはして動いたものの、ダウンタイムが数分発生してしまう結果になりました。

HDDのサーバーに複数VMを作って実験をしたのでそのディスクIOとメモリ、CPUのスペック不足が影響していると思われます。

自分がお世話になっているサービスを前例があまりない構成で構築してみるのは結構楽しかったです。なにかに応用できれば良いな。閲覧くださり、ありがとうございました。

24
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?