ICPでRabbitMQを稼働してみる(1/2)

## Summary
### やったこと

* **[ローカル端末にインストールした IBM Cloud Private (以下ICP)](https://qiita.com/yurak/items/d56575635bca0061155d)上で、RabbitMQ を稼働させます。(1/2)**
* **Kubernetes から RabbitMQ の管理画面を見れるようにします。(1/2)**
* Liberty アプリケーションから MQ Put、MQ Get します。(2/2)

### やっていないこと
* RabbitMQ についての説明はしていません。
* Liberty アプリケーションの詳細な説明はしていません。

## RabbitMQを稼働
### Pureイメージを使用した起動
[公式イメージ](https://hub.docker.com/_/rabbitmq)を使用します。
今後、管理画面を使用できるように、`<バージョン名>-management`のバージョンを使用します。
また、デフォルトの VHOST 、ユーザー、パスワードを指定します。

| # | Key | Value |
|:-:|:-:|:-:|
| VHOST | RABBITMQ_DEFAULT_VHOST | vhost1 |
| ユーザー | RABBITMQ_DEFAULT_USER | rabbitmq |
| パスワード | RABBITMQ_DEFAULT_PASS | rabbitmq |

```sh
$ docker run --rm -d --hostname rabbitmq --name rabbitmq -e RABBITMQ_DEFAULT_VHOST=vhost1 -e RABBITMQ_DEFAULT_USER=rabbitmq -e RABBITMQ_DEFAULT_PASS=rabbitmq rabbitmq:3.7.7-management
```

### 起動時に読み込む定義の作成
`docker exec`で アプリユーザー、Exchange、Queue、Bingdings を作成します。

```sh
$ docker exec rabbitmq rabbitmqctl add_user ossapl ossapl
Adding user "ossapl" ...
$ docker exec rabbitmq rabbitmqctl set_permissions -p vhost1 ossapl ".*" ".*" ".*"
Setting permissions for user "ossapl" in vhost "vhost1" ...
$ docker exec rabbitmq rabbitmqadmin -u rabbitmq -p rabbitmq -V vhost1 declare exchange name=exchange1 type=direct
exchange declared
$ docker exec rabbitmq rabbitmqadmin -u rabbitmq -p rabbitmq -V vhost1 declare queue name=queue1 auto_delete=false durable=true
queue declared
$ docker exec rabbitmq rabbitmqadmin -u rabbitmq -p rabbitmq -V vhost1 declare binding source=exchange1 destination=queue1
binding declared
```
`custom_definitions.json`を作成し、`docker cp`でローカルに持ってきます。

```
$ docker exec rabbitmq rabbitmqadmin -u rabbitmq -p rabbitmq export custom_definitions.json
Exported definitions for localhost to "custom_definitions.json"
$ docker cp rabbitmq:custom_definitions.json .
```

```custom_definitions.json
{
	"rabbit_version": "3.7.7",
	"users": [
		{
			"name": "ossapl",
			"password_hash": "rFTe2HD9vOb8zFdG83KlokhakaK4OLFKIC2POssvvZUaL6+f",
			"hashing_algorithm": "rabbit_password_hashing_sha256",
			"tags": ""
		},
		{
			"name": "rabbitmq",
			"password_hash": "8JLE1YW/TKIqh7LmzxcFTfGwRqt8xpr7AHa9kxezPBCbGOc6",
			"hashing_algorithm": "rabbit_password_hashing_sha256",
			"tags": "administrator"
		}
	],
	"vhosts": [
		{
			"name": "vhost1"
		}
	],
	"permissions": [
		{
			"user": "rabbitmq",
			"vhost": "vhost1",
			"configure": ".*",
			"write": ".*",
			"read": ".*"
		},
		{
			"user": "ossapl",
			"vhost": "vhost1",
			"configure": ".*",
			"write": ".*",
			"read": ".*"
		}
	],
	"topic_permissions": [],
	"parameters": [],
	"global_parameters": [],
	"policies": [],
	"queues": [
		{
			"name": "queue1",
			"vhost": "vhost1",
			"durable": true,
			"auto_delete": false,
			"arguments": {}
		}
	],
	"exchanges": [
		{
			"name": "exchange1",
			"vhost": "vhost1",
			"type": "direct",
			"durable": true,
			"auto_delete": false,
			"internal": false,
			"arguments": {}
		}
	],
	"bindings": [
		{
			"source": "exchange1",
			"vhost": "vhost1",
			"destination": "queue1",
			"destination_type": "queue",
			"routing_key": "",
			"arguments": {}
		}
	]
}
```

定義が作成できたら、コンテナを停止します。

```sh
$ docker stop rabbitmq
```

### Dockerfileの作成
RabbitMQの`Dockerfile` を作成します。
`custom_definitions.json`をコピーし、起動時に読み込むよう定義を追記します。

```Dockerfile
FROM rabbitmq:3.7.7-management
COPY custom_definitions.json /etc/rabbitmq/
RUN printf 'management.load_definitions = /etc/rabbitmq/custom_definitions.json\n' >> /etc/rabbitmq/rabbitmq.conf
```

### ビルド、タグの作成、イメージのプッシュ
`Dockerfile`を用いてビルド、タグを作成し、ICPのプライベートDocker Registry へプッシュします。

```sh
$ docker build . -t mycluster.icp:8500/default/docker_hub_id/rabbitmq:v0.0.1
$ docker push mycluster.icp:8500/default/docker_hub_id/rabbitmq:v0.0.1
```
ICPの管理画面から確認できます。
<img width="1663" alt="スクリーンショット 2019-04-20 21.28.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232123/5f96495a-54fd-48cf-e288-fc2c77f29be6.png">


### Secretの作成
ここから、Kubernetes へリソースを定義していきます。
RabbitMQ のデフォルトパスワードを変更していますので Secret を作成します。
パスワードを Base64 でエンコードします。

```sh
$ echo -n "rabbitmq" | base64
cmFiYml0bXE=
```
Secretを作成します。

```rabbitmq-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: rabbitmq-secret
type: Opaque
data:
  rabbitmq-default-pass: cmFiYml0bXE=
```
### ConfigMapの作成
デフォルトの VHOST とユーザーを定義した ConfigMap を作成します。

```rabbitmq-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: rabbitmq-config
data:
  rabbitmq-default-vhost: "vhost1"
  rabbitmq-default-user: "rabbitmq"
```

### Deploymentの作成
使用するイメージは、先ほどICPのプライベート Docer Registryにプッシュしたものを指定します。
RabbitMQ で使用するポートはいくつかあります。
今回はデフォルトの`5672`と、管理画面用の`15672`を開けます。

```rabbitmq-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rabbitmq
spec:
  selector:
    matchLabels:
      app: rabbitmq
  replicas: 1
  template:
    metadata:
      labels:
        app: rabbitmq
	spec:
      containers:
      - name: rabbitmq
        image: mycluster.icp:8500/default/docker_hub_id/rabbitmq:v0.0.1
        imagePullPolicy: Always
        ports:
        - containerPort: 5672
        - containerPort: 15672
        env:
        - name: RABBITMQ_DEFAULT_VHOST
          valueFrom:
            configMapKeyRef:
              name: rabbitmq-config
              key: rabbitmq-default-vhost
        - name: RABBITMQ_DEFAULT_USER
          valueFrom:
            configMapKeyRef:
              name: rabbitmq-config
              key: rabbitmq-default-user
        - name: RABBITMQ_DEFAULT_PASS
          valueFrom:
            secretKeyRef:
              name: rabbitmq-secret
              key: rabbitmq-default-pass
```

### Serviceの作成
Service を作成します。
複数のポートを定義する場合は、それぞれに`name`を指定する必要があります。

```rabbitmq-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: rabbitmq
spec:
  type: ClusterIP
  selector:
    app: rabbitmq
  ports:
  - name: amqp
    protocol: TCP
    port: 5672
  - name: mgmt
    protocol: TCP
    port: 15672
```

### Ingressの作成
管理画面用です。

```rabbitmq-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: rabbitmq
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host:
    http:
      paths:
      - path: /rabbitmq/
        backend:
          serviceName: rabbitmq
          servicePort: 15672
```

### ICP上でRabbitMQを稼働
`kubectl apply`をします。
作成したファイルを再帰的にアプライします。

```sh
$ find . -name "*.yaml"|xargs -I {} kubectl apply -f {}
deployment.apps/rabbitmq created
secret/rabbitmq-secret created
ingress.extensions/rabbitmq created
service/rabbitmq created
configmap/rabbitmq-config created
```

管理画面が表示されました。
<img width="1219" alt="スクリーンショット 2019-04-20 22.13.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232123/164f737b-3a8f-b73b-3300-1e7f4d4ee403.png">

[ICPでRabbitMQを稼働してみる(2/2)](https://qiita.com/yurak/items/42d61b601e547b3fedfa) へ続きます。

## 参考
https://hub.docker.com/_/rabbitmq
https://www.rabbitmq.com/networking.html
https://qiita.com/ptiringo/items/c554fa66f0d985394fed
https://qiita.com/MahoTakara/items/e0aa723b02d04e1accd2
https://qiita.com/hana_shin/items/c674ccdf0aecdcb91747
https://qiita.com/tototoshi/items/83c5897bb4890a328067