K8s環境で本家のチュートリアルに従ってRabbitMQをデプロイしてみた


はじめに

Helmを利用してRabbitMQを稼動させていましたが、いろいろ問題が発生して、別クラスターを構築したタイミングで本家のドキュメントに従ってRabbitMQをK8s環境で稼動させてみました。

その際のメモを残します。

参考文書

環境

K8sクラスターは以下のような環境です。

  • Hardware: TX1320 M4 (富士通製 Xeon E-2234)
    • 8GB Memory (DDR4-21300 ECC)
    • 4TB HDD (/dev/sda)
    • 500GB SSD (/dev/sdb)
  • K8s: v1.19.7 (Kubespray v2.15.0で構築)
    • MetalLB v0.9.5 (Kubesprayのaddons.ymlで構成)
    • Rook/Ceph v1.5.5

方針

今回はRabbitMQ Operatorを使用します。これはK8sのバージョンがv1.17以上、Dockerイメージが3.8.8以上という条件があって、以前構築したクラスターでは利用できないものでした。

本番に移行させることを目的に、テスト環境を構築したので、この手順を試してみることにします。

作業メモ

あらかじめRabbitMQ Cluster Operatorを導入しておきます。

$ sudo kubectl apply -f https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml

ここからの作業は参考文書に掲載したUsing RabbitMQ Cluster Kubernetes Operatorに従っていきます。

CRDsについて

Custom Resources (CRDs)を確認するよう指示があります。

$ sudo kubectl get crd/rabbitmqclusters.rabbitmq.com    
NAME                            CREATED AT
rabbitmqclusters.rabbitmq.com   2021-01-26T05:59:59Z

確認するだけであればこれで十分ですが、どのようなCRDsが定義されているかは-o yamlなどの冗長出力によって確認することができます。

$ sudo kubectl get crd/rabbitmqclusters.rabbitmq.com -o yaml

長々と出力されますが定義されているリソースは、"RabbitmqCluster"だけのようです。

RabbitMQインスタンスの実行

書いてあるとおり、definition.yamlファイルを準備して適用します。

一連の作業ログ
$ cat > 01.definition.yaml
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: definition

$ sudo kubectl -n rabbitmq-system apply -f 01.definition.yaml
rabbitmqcluster.rabbitmq.com/definition created

$ sudo kubectl -n rabbitmq-system get all
NAME                                             READY   STATUS    RESTARTS   AGE
pod/definition-server-0                          0/1     Pending   0          2s
pod/rabbitmq-cluster-operator-7bbbb8d559-884lc   1/1     Running   0          3h40m

NAME                       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)              AGE
service/definition         ClusterIP   10.233.7.222   <none>        5672/TCP,15672/TCP   2s
service/definition-nodes   ClusterIP   None           <none>        4369/TCP,25672/TCP   2s

NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/rabbitmq-cluster-operator   1/1     1            1           3h40m

NAME                                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/rabbitmq-cluster-operator-7bbbb8d559   1         1         1       3h40m

NAME                                 READY   AGE
statefulset.apps/definition-server   0/1     2s

Podは現時点ではPendingのままです。原因についてはdescribeで確認します。

Pendingとなっている理由をPodから確認する
$ sudo kubectl -n rabbitmq-system describe pod definition-server-0 
...
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  22h   default-scheduler  0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims.

PVCを確認すると、次のようになっていました。

PVCの状態を確認する
$ sudo kubectl -n rabbitmq-system get pvc
NAME                              STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistence-definition-server-0   Pending                                                     10m

Pending状態の解消

PVはRook/Cephで構成しているために、PVC定義にstorageClassName: rook-ceph-blockを指定することが必要です。
RabbitMQのドキュメントにstorageClassNameを指定する方法が掲載されているので、これを参照し、01.definition.yamlを編集し、再度適用します。

ファイルを更新し、再度適用する
$ cat 01.definition.yaml
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: definition
spec:
  persistence:
    storageClassName: rook-ceph-block
    storage: 20Gi

$ sudo kubectl -n rabbitmq-system delete -f 01.definition.yaml
$ sudo kubectl -n rabbitmq-system apply -f 01.definition.yaml

これで無事にサービスが起動するところまでは確認できました。

PVCとPodがRunningになっている事を確認する
$ sudo kubectl -n rabbitmq-system get all
NAME                                             READY   STATUS    RESTARTS   AGE
pod/definition-server-0                          0/1     Running   0          27s
pod/rabbitmq-cluster-operator-7bbbb8d559-884lc   1/1     Running   0          26h

NAME                       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)              AGE
service/definition         ClusterIP   10.233.49.46   <none>        5672/TCP,15672/TCP   27s
service/definition-nodes   ClusterIP   None           <none>        4369/TCP,25672/TCP   27s

NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/rabbitmq-cluster-operator   1/1     1            1           26h

NAME                                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/rabbitmq-cluster-operator-7bbbb8d559   1         1         1       26h

NAME                                 READY   AGE
statefulset.apps/definition-server   0/1     27s

$ sudo kubectl -n rabbitmq-system get pvc
NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES  STORAGECLASS      AGE
persistence-definition-server-0   Bound    pvc-5cf12c25-aeb0-45f5-9ce6-b9825ec0946d   20Gi       RWO           rook-ceph-block   40s

LoadBalancerの有効化

このままだとサービスにWebブラウザからアクセスすることが難しいので、LoadBalancerを有効にします。

$ cat 01.definition.yaml 
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: definition
spec:
  persistence:
    storageClassName: rook-ceph-block
    storage: 20Gi
  service:
    type: LoadBalancer


$ sudo kubectl -n rabbitmq-system apply -f 01.definition.yaml 
rabbitmqcluster.rabbitmq.com/definition configured

$ sudo kubectl -n rabbitmq-system get svc
NAME               TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)                          AGE
definition         LoadBalancer   10.233.49.46   192.168.1.110  5672:30104/TCP,15672:30706/TCP   59m
definition-nodes   ClusterIP      None           <none>         4369/TCP,25672/TCP               59m

ドキュメントを眺める限りはLBにIPを割り当てるための設定(loadBalancerIP)がないようだと思って初稿を書いたのですが、spec.override.service が定義可能だと分かって次のような設定を試しました。

02.definition.yaml
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: definition
spec:
  replicas: 3
  persistence:
    storageClassName: rook-ceph-block
    storage: 20Gi
  service:
    type: LoadBalancer
  override:
    service:
      spec:
        loadBalancerIP: 192.168.1.139

この設定を適用すると、EXTERNAL-IPが指定した値になります。

EXTERNAL-IPを指定するもう一つの方法

このセクションは初稿でLoadBalancerにExternal-IPを割り当てる唯一の方法として記述したものです。オンプレミスであれば直接IPを指定する前述の方法が楽だと思いますが、環境に応じて使い分けてください。

annotationsに項目を追加することはできるので、address-poolを指定する方法で通常とは違うip-rangeを指定することはできそうです。

address-poolから割り当てられると、再構築したタイミングで変更されてしまう可能性があります。
サービス用のIPアドレスは固定したいので、loadBalancerIPを指定する以外の方法を検討します。

あらかじめmetallbの設定で、割り当てたいIPを別のpoolとして定義しておきます。
下記の例では元々設定していたip-rangeの最後の1つ(192.168.1.139)を"rabbitmq-pool"として別に定義しました。

今回のk8sクラスターではmetallbはkubesprayのaddons.ymlから設定しているので、あらかじめkubesprayからaddress-poolを追加しています。

metallbe-systemの設定を確認
$ sudo kubectl -n metallb-system get cm -o yaml
apiVersion: v1
items:
- apiVersion: v1
  data:
    config: |
      address-pools:
      - name: loadbalanced
        protocol: layer2
        addresses:
        - 192.168.1.110-192.168.1.138
      - name: rabbitmq-pool
        protocol: layer2
        addresses:
        - 192.168.1.139-192.168.1.139
        auto-assign: False
  kind: ConfigMap
...

この"rabbitmq-pool"をannotationsで指定するよう01.definition.yamlファイルを編集し、適用します。

自動で割り当てられたIPを192.168.1.139に変更する様子
$ cat 01.definition.yaml 
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: definition
spec:
  persistence:
    storageClassName: rook-ceph-block
    storage: 20Gi
  service:
    type: LoadBalancer
    annotations:
      metallb.universe.tf/address-pool: rabbitmq-pool

$ sudo kubectl -n rabbitmq-system apply -f 01.definition.yaml 
rabbitmqcluster.rabbitmq.com/definition configured

設定が反映されると、1つしかIPが定義されていないrabbitmq-poolからEXTERNAL-IPが割り当てられた事を確認します。

EXTERNAL-IPが切り替わった事を確認
$ sudo kubectl -n rabbitmq-system get svc
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                          AGE
definition         LoadBalancer   10.233.18.226   192.168.1.139  15672:31925/TCP,5672:30675/TCP   14h
definition-nodes   ClusterIP      None            <none>         4369/TCP,25672/TCP               36h

直接loadBalancerIPが割り当てられると良いのですが、これでも同じような事ができたので、しばらく使ってみます。

Web UIにログインするためのID,Passwordの確認

自動的にランダムな文字列が割り当てられているので、ログインに必要なID, Passwordをドキュメントに書かれているように確認します。

手元では次のようなMakefileのタスクを設定しています。

管理者IDを確認するためのMakefileタスク
show-adminuser:
        (i=`sudo kubectl -n rabbitmq-system get secret definition-default-user -o jsonpath="{.data.username}" 
| base64 --decode | tee /dev/null` ; echo user: $$i)
        (i=`sudo kubectl -n rabbitmq-system get secret definition-default-user -o jsonpath="{.data.password}" 
| base64 --decode | tee /dev/null` ; echo pass: $$i)

Replica数の変更

デフォルトではPodが1つのRabbitMQクラスターとなっているので、複数のPodを実行します。

replicaの指定を追加
$ cat 01.definition.yaml 
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: definition
spec:
  replicas: 3
  persistence:
    storageClassName: rook-ceph-block
    storage: 20Gi
  service:
    type: LoadBalancer
    annotations:
      metallb.universe.tf/address-pool: rabbitmq-pool

これを適用し、コンソールからNodeが増加したことを確認します。

さいごに

Operatorによる制御はかなり自然で、今後はHelmからRabbitMQをデプロイすることはないと思います。

MetalLBではloadBalancerIPによる制御を許可すると、(管理下の)任意のIPアドレスがアサインできてしまうので管理面からはあらかじめ準備しているaddress-poolからEXTERNAL-IPを割り当てる方が実際の場面では便利なのかなと感じています。

更新した記事では、spec.override.service によるloadBalancerIPを使用する方法も確認しました。両方確認しましたが、address-poolを利用する方法もそれなりに便利だと利用してみて思っているところなので、環境に応じて適切なものを選択していこうと思います。

以上