VMware Tanzu RabbitMQ on Kubernetes 4.2のHelm Chartをリロケートしてインストールするメモ

Warning

Work in Progress

https://techdocs.broadcom.com/us/en/vmware-tanzu/data-solutions/tanzu-rabbitmq-on-kubernetes/4-2/tanzu-rabbitmq-kubernetes/installation-using-helm.html

cert-managerがインストール済みの状態を前提とします。

Helm Chartのリロケート

https://support.broadcom.com にログインして、"My Downloads"ページにアクセスし、"Registry Tokens"ボタンをクリック。

image

"Generate Registry Token"ボタンをクリックして、"Submit"ボタンをクリック。

image

生成されたトークンの"Copy Token"ボタンをクリックし、トークンをクリップボードにコピーします。

image

export BROADCOM_USERNAME=your-email-address@example.com
export BROADCOM_TOKEN=eyJ2ZXIiO.....
docker login rabbitmq-helmoci.packages.broadcom.com -u ${BROADCOM_USERNAME} -p ${BROADCOM_TOKEN}
docker login rabbitmq-operator.packages.broadcom.com -u ${BROADCOM_USERNAME} -p ${BROADCOM_TOKEN}
docker login rabbitmq.packages.broadcom.com -u ${BROADCOM_USERNAME} -p ${BROADCOM_TOKEN}

"Login Succeeded"と出力されればOKです。

Helmプラグインである"Distribution Tooling for Helm"を使います。

次のコマンドでインストールできます。

helm plugin install https://github.com/vmware-labs/distribution-tooling-for-helm

VMware Tanzu RabbitMQ on Kubernetesのダウンロードページにアクセスし、最新のバージョン(ここでは4.2.3)を確認します。

helm dt wrap oci://rabbitmq-helmoci.packages.broadcom.com/tanzu-rabbitmq-operators --version 4.2.3

次のように出力されればOKです。認証エラーになる場合は、docker loginが漏れています。

image

export REGISTRY_HOST=registry.example.com
export REGISTRY_USERNAME=changeme
export REGISTRY_PASSWORD=changeme

docker login ${REGISTRY_HOST} -u ${REGISTRY_USERNAME} -p ${REGISTRY_PASSWORD}
helm dt unwrap tanzu-rabbitmq-operators-4.2.3.wrap.tgz ${REGISTRY_HOST}/tanzu-rabbitmq --yes

image

$ helm show values oci://${REGISTRY_HOST}/tanzu-rabbitmq/tanzu-rabbitmq-operators | grep 'registry:' -A 1
Pulled: registry.example.com/tanzu-rabbitmq/tanzu-rabbitmq-operators:4.2.3
Digest: sha256:2faca9c439fe447f995285270c940c5a0930391bf7345bcc14872ae30f0d3b7b
  registry: registry.example.com
  repository: tanzu-rabbitmq/vmware-tanzu-rabbitmq
--
  registry: registry.example.com
  repository: tanzu-rabbitmq/default-user-credential-updater
--
    registry: registry.example.com
    repository: tanzu-rabbitmq/cluster-operator
--
    registry: registry.example.com
    repository: tanzu-rabbitmq/messaging-topology-operator
--
    registry: registry.example.com
    repository: tanzu-rabbitmq/audit-logger
kubectl create namespace rabbitmq-system

kubectl create secret docker-registry -n rabbitmq-system tanzu-rabbitmq-registry-creds \
  --docker-server ${REGISTRY_HOST} \
  --docker-username ${REGISTRY_USERNAME} \
  --docker-password ${REGISTRY_PASSWORD}

RabbitMQ Opeartorのインストール

helm upgrade tanzu-rabbitmq oci://${REGISTRY_HOST}/tanzu-rabbitmq/tanzu-rabbitmq-operators -n rabbitmq-system --version 4.2.3 --install --wait
$ helm list -n rabbitmq-system
NAME          	NAMESPACE      	REVISION	UPDATED                             	STATUS  	CHART                         	APP VERSION
tanzu-rabbitmq	rabbitmq-system	1       	2026-02-10 12:55:23.896299 +0900 JST	deployed	tanzu-rabbitmq-operators-4.2.3	4.2.3 
$ kubectl get pod -n rabbitmq-system       
NAME                                           READY   STATUS    RESTARTS   AGE
messaging-topology-operator-7cdd799697-n97t7   1/1     Running   0          60s
rabbitmq-cluster-operator-6fdfbf966f-8mmtg     1/1     Running   0          60s
$ kubectl api-resources --api-group=rabbitmq.com        
NAME                 SHORTNAMES   APIVERSION              NAMESPACED   KIND
bindings                          rabbitmq.com/v1beta1    true         Binding
exchanges                         rabbitmq.com/v1beta1    true         Exchange
federations                       rabbitmq.com/v1beta1    true         Federation
operatorpolicies                  rabbitmq.com/v1beta1    true         OperatorPolicy
permissions                       rabbitmq.com/v1beta1    true         Permission
policies                          rabbitmq.com/v1beta1    true         Policy
queues                            rabbitmq.com/v1beta1    true         Queue
rabbitmqclusters     rmq          rabbitmq.com/v1beta1    true         RabbitmqCluster
schemareplications                rabbitmq.com/v1beta1    true         SchemaReplication
shovels                           rabbitmq.com/v1beta1    true         Shovel
superstreams                      rabbitmq.com/v1alpha1   true         SuperStream
topicpermissions                  rabbitmq.com/v1beta1    true         TopicPermission
users                             rabbitmq.com/v1beta1    true         User
vhosts                            rabbitmq.com/v1beta1    true         Vhost

RabbitMQ Clusterの作成

kubectl create ns demo
kubectl create secret docker-registry -n demo tanzu-rabbitmq-registry-creds \
  --docker-server ${REGISTRY_HOST} \
  --docker-username ${REGISTRY_USERNAME} \
  --docker-password ${REGISTRY_PASSWORD}
cat <<EOF > rabbitmq.yaml
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: demo-rabbitmq
  namespace: demo
spec:
  imagePullSecrets:
  - name: tanzu-rabbitmq-registry-creds
  service:
    type: LoadBalancer
  replicas: 3
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app.kubernetes.io/name
              operator: In
              values:
              - demo-rabbitmq
          topologyKey: kubernetes.io/hostname
EOF

kubectl apply -f rabbitmq.yaml

作成されたリソースを確認します。

$ kubectl get pod,sts,rabbitmq,secret,svc -n demo -owide
NAME                         READY   STATUS    RESTARTS   AGE   IP            NODE             NOMINATED NODE   READINESS GATES
pod/demo-rabbitmq-server-0   1/1     Running   0          70s   10.42.1.122   192.168.11.51    <none>           <none>
pod/demo-rabbitmq-server-1   1/1     Running   0          70s   10.42.2.107   192.168.11.52    <none>           <none>
pod/demo-rabbitmq-server-2   1/1     Running   0          70s   10.42.0.82    192.168.11.150   <none>           <none>

NAME                                    READY   AGE   CONTAINERS   IMAGES
statefulset.apps/demo-rabbitmq-server   3/3     70s   rabbitmq     registry.example.com/tanzu-rabbitmq/vmware-tanzu-rabbitmq:4.2.3

NAME                                         ALLREPLICASREADY   RECONCILESUCCESS   AGE
rabbitmqcluster.rabbitmq.com/demo-rabbitmq   True               Unknown            71s

NAME                                   TYPE                             DATA   AGE
secret/demo-rabbitmq-default-user      Opaque                           8      70s
secret/demo-rabbitmq-erlang-cookie     Opaque                           1      71s
secret/regsecret                       kubernetes.io/dockerconfigjson   1      48d
secret/tanzu-rabbitmq-registry-creds   kubernetes.io/dockerconfigjson   1      6h16m

NAME                          TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                                          AGE   SELECTOR
service/demo-rabbitmq         LoadBalancer   10.43.200.24   192.168.11.241   15692:31148/TCP,5672:31198/TCP,15672:32614/TCP   71s   app.kubernetes.io/name=demo-rabbitmq
service/demo-rabbitmq-nodes   ClusterIP      None           <none>           4369/TCP,25672/TCP                               71s   app.kubernetes.io/name=demo-rabbitmq

http://192.168.11.241:15672 で管理コンソールにアクセスできます。

ユーザー名とパスワードは次のコマンドで確認できます。

$ kubectl get secret -n demo demo-rabbitmq-default-user -ojson | jq '.data | map_values(@base64d)'
{
  "default_user.conf": "default_user = default_user_UgZFbsYLfl9KZEyJnvM\ndefault_pass = wtlfnLKYTWLu4u4y31_vUDOfnrTuUfaI\n",
  "host": "demo-rabbitmq.demo.svc",
  "password": "wtlfnLKYTWLu4u4y31_vUDOfnrTuUfaI",
  "port": "5672",
  "provider": "rabbitmq",
  "type": "rabbitmq",
  "username": "default_user_UgZFbsYLfl9KZEyJnvM"
}

image

Tip

Management Consoleへのアクセスをsticky sessionにしたい場合。Ingress ControllerにTraefikを使う場合は、rabbitmq.yamlを以下のように修正する

apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: demo-rabbitmq
  namespace: demo
spec:
  imagePullSecrets:
  - name: tanzu-rabbitmq-registry-creds
  service:
    type: LoadBalancer
    annotations:
      #! 追加   
      traefik.ingress.kubernetes.io/service.sticky.cookie: "true"
      traefik.ingress.kubernetes.io/service.sticky.cookie.name: X-Traefik-Session-Affinity
  replicas: 3
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app.kubernetes.io/name
              operator: In
              values:
              - demo-rabbitmq
          topologyKey: kubernetes.io/hostname

そして次のようなIngressを作成する。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-rabbitmq-management
  namespace: demo
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  rules:
  - host: demo-rabbitmq-management.lan.ik.am
    http:
      paths:
      - backend:
          service:
            name: demo-rabbitmq
            port:
              name: management
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - demo-rabbitmq-management.lan.ik.am
    secretName: demo-rabbitmq-management-tls

受信アプリのデプロイ

cat <<EOF > demo-rabbitmq-receiver.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-rabbitmq-receiver
  labels:
    app: demo-rabbitmq-receiver
    app.kubernetes.io/part-of: demo-rabbitmq-receiver
spec:
  replicas: 2
  selector:
    matchLabels:
      app: demo-rabbitmq-receiver
  template:
    metadata:
      annotations:
        prometheus.io/path: /actuator/prometheus
        prometheus.io/port: "8081"
        prometheus.io/scrape: "true"
      labels:
        app: demo-rabbitmq-receiver
        app.kubernetes.io/part-of: demo-rabbitmq-receiver
    spec:
      containers:
      - name: workload
        image: ghcr.io/making/demo-rabbitmq-receiver:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: user-port
          protocol: TCP
        resources:
          limits:
            cpu: "1"
            memory: 1Gi
          requests:
            cpu: "1"
            memory: 1Gi
        env:
        - name: JAVA_TOOL_OPTIONS
          value: -Duser.country=JP -Duser.language=ja -Duser.timezone=Asia/Tokyo -Dfile.encoding=UTF-8 -Dmanagement.endpoint.health.probes.add-additional-paths=true -Dmanagement.endpoint.health.show-details=always -Dmanagement.endpoints.web.base-path=/actuator -Dmanagement.endpoints.web.exposure.include="*" -Dmanagement.health.probes.enabled=true -Dmanagement.server.port=8081 -Dserver.port=8080
        - name: SERVICE_BINDING_ROOT
          value: /bindings
        volumeMounts:
        - name: rabbitmq
          mountPath: /bindings/rabbitmq
          readOnly: true
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /livez
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8080
            scheme: HTTP
        startupProbe:
          httpGet:
            path: /readyz
            port: 8080
            scheme: HTTP
          failureThreshold: 20
          periodSeconds: 5
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          runAsNonRoot: true
          runAsUser: 1002
          seccompProfile:
            type: RuntimeDefault
      volumes:
      - name: rabbitmq
        secret:
          secretName: demo-rabbitmq-default-user
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchLabels:
                  app: demo-rabbitmq-receiver
              topologyKey: kubernetes.io/hostname
            weight: 1
EOF
kubectl apply -f demo-rabbitmq-receiver.yaml -n demo

送信アプリのデプロイ

cat <<EOF > demo-rabbitmq-sender.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-rabbitmq-sender
  labels:
    app: demo-rabbitmq-sender
    app.kubernetes.io/part-of: demo-rabbitmq-sender
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-rabbitmq-sender
  template:
    metadata:
      annotations:
        prometheus.io/path: /actuator/prometheus
        prometheus.io/port: "8081"
        prometheus.io/scrape: "true"
      labels:
        app: demo-rabbitmq-sender
        app.kubernetes.io/part-of: demo-rabbitmq-sender
    spec:
      containers:
      - name: workload
        image: ghcr.io/making/demo-rabbitmq-sender:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: user-port
          protocol: TCP
        resources:
          limits:
            cpu: "1"
            memory: 1Gi
          requests:
            cpu: "1"
            memory: 1Gi
        env:
        - name: JAVA_TOOL_OPTIONS
          value: -Duser.country=JP -Duser.language=ja -Duser.timezone=Asia/Tokyo -Dfile.encoding=UTF-8 -Dmanagement.endpoint.health.probes.add-additional-paths=true -Dmanagement.endpoint.health.show-details=always -Dmanagement.endpoints.web.base-path=/actuator -Dmanagement.endpoints.web.exposure.include="*" -Dmanagement.health.probes.enabled=true -Dmanagement.server.port=8081 -Dserver.port=8080
        - name: SERVICE_BINDING_ROOT
          value: /bindings
        volumeMounts:
        - name: rabbitmq
          mountPath: /bindings/rabbitmq
          readOnly: true
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /livez
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8080
            scheme: HTTP
        startupProbe:
          httpGet:
            path: /readyz
            port: 8080
            scheme: HTTP
          failureThreshold: 20
          periodSeconds: 5
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          runAsNonRoot: true
          runAsUser: 1002
          seccompProfile:
            type: RuntimeDefault
      volumes:
      - name: rabbitmq
        secret:
          secretName: demo-rabbitmq-default-user
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchLabels:
                  app: demo-rabbitmq-sender
              topologyKey: kubernetes.io/hostname
            weight: 1
EOF
kubectl apply -f demo-rabbitmq-sender.yaml -n demo

image

image