Red Hat OpenShift on IBM Cloud(ROKS)上でMySQLを動かしてみる

## はじめに

IBM CloudのOpenShiftクラスター上でMySQLを動かしてみたので、そのメモ。

永続ボリュームとしてICOS(IBM Cloud Object Storage)を使用しますので、その辺りを中心とした手順を整理してみました。

## 前提

+ IBM Cloudアカウント（残念ながらライトアカウントでは実施できません）
+ VPC環境（サブネットに東京1、東京2を含む）
+ ICOSインスタンス（バケット作成は不要）
+ ibmcloud CLI、ocコマンドが導入済みのPCあるいは仮想サーバー

## ROKSクラスター作成

GUIから最小構成で作成します。

| 項目 | 設定内容 |
|:-|:-|
|セットアップの選択|手動セットアップ|
|インフラストラクチャー|VPC|
|仮想プライベート・クラウド|クラスターを作成するVPC|
|クラウド・オブジェクト・ストレージ|作成済みのICOSインスタンス|
|リソース・グループ|任意|
|ワーカー・ゾーン|東京1、東京2にチェック|
|ワーカー・プールのフレーバー|4vCPU、16GBメモリ|
|ゾーンあたりのワーカー・ノード|1|
|クラスター名|任意|

クラスターの作成が完了したら、画面右上の「OpenShift Web コンソール」をクリックし、その先の画面右上にある「ログインコマンドのコピー」をクリックし、oc loginで始まるコマンドを入手し、作業環境で実行します。

また、以下を実行してibmcloud CLIを利用出来るようにします。

```
# ibmcloud login -r jp-tok -g [ROKSクラスターを作成したリソースグループ名] --sso
# ibmcloud ks cluster config --cluster [ROKSクラスター名]
``` 

## IBM Cloud Object Storage plug-in導入

ICOSを永続ボリュームとして使用するために必要なものを入れていきます。まず以下のサイトから、環境にあったHelm CLIを導入します。

https://github.com/helm/helm/releases

そして、以下のサイトにある通りにセットアップします。

https://cloud.ibm.com/docs/containers?topic=containers-helm#install_v3

```
# helm repo add iks-charts https://private.icr.io/helm/iks-charts
# helm repo add ibm-charts https://raw.githubusercontent.com/IBM/charts/master/repo/stable
# helm repo add ibm-community https://raw.githubusercontent.com/IBM/charts/master/repo/community
# helm repo add entitled https://raw.githubusercontent.com/IBM/charts/master/repo/entitled
# helm repo add ibm-helm https://raw.githubusercontent.com/IBM/charts/master/repo/ibm-helm
# helm repo update 
```

続けて、以下のサイトにある通りにICOSプラグインを導入します。

https://cloud.ibm.com/docs/containers?topic=containers-storage_cos_install

```
# helm fetch --untar ibm-helm/ibm-object-storage-plugin
# helm plugin install ./ibm-object-storage-plugin/helm-ibmc
# chmod 755 /root/.local/share/helm/plugins/helm-ibmc/ibmc.sh
# helm ibmc install ibm-object-storage-plugin ibm-helm/ibm-object-storage-plugin --set license=true
```

## ICOSバケット作成

以下のバケットを作成します（uniqnameの部分は、IBM Cloud全体で重複しないようユニークなものにします）

+ uniqname-redmine-mysql-data

「バケットのカスタマイズ」から、以下の設定で作成します。

| 項目 | 設定内容 |
|:-|:-|
| 回復力  | Regional  |
| ロケーション  | jp-tok  |
| ストレージ・クラス | Smart Tier |

そして、バケットを作成したICOSインスタンスに資格情報を以下のように、役割：ライター、「HMAC資格情報を含める」をONにして作成します。（資格とサービスID名は任意の分かりやすい名前で）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/1634aa00-5b7a-2a46-9e67-f4e23d18f0a5.png)

作成された資格情報の内容について、以下3つの値を確認します。

```
  "apikey": "***************",
  "cos_hmac_keys": {
    "access_key_id": "*****************",
    "secret_access_key": "*******************"
  },
```

## ネームスペース作成

ROKS上に新たにネームスペースを作成します。（なぜredmineなのかは次の記事で）

```
# oc new-project redmine
```

## Secret作成

先に確認したICOSのアクセスキー、シークレットアクセスキー、APIキーのそれぞれをbase64エンコードします。

```
~ $ echo -n "*************" | base64
[base64エンコードされた文字列]
```

これら3つの文字列を使用してSecret作成用のymlファイルを作成します。

```yaml:secret-icos.yml
apiVersion: v1
kind: Secret
metadata: 
 name: keys-icos
type: ibm/ibmc-s3fs
data:
 access-key: [base64エンコードしたアクセスキー]
 secret-key: [base64エンコードしたシークレットアクセスキー]
 res-conf-apikey: [base64エンコードしたAPIキー]
```

同じようにして、MySQLのデータベース接続に使用するユーザーIDとパスワードのSecret作成用のymlファイルを作成します。

```yaml:secret-mysql.yml
apiVersion: v1
kind: Secret
metadata:
  name: env-mysql
type: Opaque
data:
  mysql-user: [base64エンコードしたユーザーID]
  mysql-password: [base64エンコードしたパスワード]
```

Secretを作成します。

```
# oc apply -f secret-mysql.yml,secret-icos.yml -n redmine
secret/env-mysql created
secret/keys-icos created
```

## ConfigMap作成

データベース名を設定するためのConfigMapを作成します。以下のymlファイルを作成します。

```yaml:cm-mysql.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-mysql
type: Opaque
data:
  mysql-database: redmine
```

ConfigMapを作成します。

```
# oc apply -f cm-mysql.yml -n redmine
configmap/env-mysql created
```

## PVC作成

PVC作成用のymlファイルを作成します。

```yaml:pvc-mysql-data.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-data
  annotations:
    ibm.io/auto-create-bucket: "false"
    ibm.io/auto-delete-bucket: "false"
    ibm.io/bucket: "uniqname-redmine-mysql-data"
    ibm.io/secret-name: "keys-icos"
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: ibmc-s3fs-flex-regional
```

PVCを作成します

```
# oc apply -f pvc-mysql-data.yml -n redmine
persistentvolumeclaim/mysql-data created
```

正常に作成できたか確認します。

```
# oc get pvc -n redmine
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS              AGE
mysql-data   Bound    pvc-92ee9e83-daba-44f7-85a3-607fa19effc0   1Gi        RWO            ibmc-s3fs-flex-regional   19s
```

上記でSTATUSがBoundでない場合は、シークレットキーが間違っているなどの可能性があるので、`oc describe pvc pvc-mysql-data -n redmine` で確認します。

例えば、ネームスペースを間違えてPVCを作成しようとすると、必要なSecretが無いので `secrets "keys-icos" not found` となります。

```
# oc describe pvc pvc-mysql-data
Name:          pvc-mysql-data
Namespace:     default
StorageClass:  ibmc-s3fs-flex-regional
Status:        Pending
Volume:        
Labels:        <none>
Annotations:   ibm.io/auto-create-bucket: true
               ibm.io/auto-delete-bucket: false
               ibm.io/bucket: hirokuda-mysql-data
               ibm.io/secret-name: keys-icos
               volume.beta.kubernetes.io/storage-provisioner: ibm.io/ibmc-s3fs
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      
Access Modes:  
VolumeMode:    Filesystem
Mounted By:    <none>
Events:
  Type     Reason                Age                        From                                                                                                   Message
  ----     ------                ----                       ----                                                                                                   -------
  Normal   Provisioning          <invalid> (x7 over 2m4s)   ibm.io/ibmc-s3fs_ibmcloud-object-storage-plugin-85cf59576f-7c87f_20c4e165-609b-4339-a869-f50bd4b279eb  External provisioner is provisioning volume for claim "default/pvc-mysql-data"
  Normal   ExternalProvisioning  <invalid> (x11 over 2m4s)  persistentvolume-controller                                                                            waiting for a volume to be created, either by external provisioner "ibm.io/ibmc-s3fs" or manually created by system administrator
  Warning  ProvisioningFailed    <invalid> (x7 over 2m4s)   ibm.io/ibmc-s3fs_ibmcloud-object-storage-plugin-85cf59576f-7c87f_20c4e165-609b-4339-a869-f50bd4b279eb  failed to provision volume with StorageClass "ibmc-s3fs-flex-regional": pvc-mysql-data:ca870cnt02k09ufjlmfg:cannot validate annotations: cannot retrieve secret: secrets "keys-icos" not found
```

## MySQLデプロイ

MySQLをデプロイするためのymlファイルを作成します。

```yaml:dm-mysql.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  replicas: 1
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - args:
        - --character-set-server
        - utf8mb4
        - --collation-server
        - utf8mb4_unicode_ci
        env:
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: env-mysql
              key: mysql-user
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: env-mysql
              key: mysql-password
        - name: MYSQL_DATABASE
          valueFrom:
            configMapKeyRef:
              name: env-mysql
              key: mysql-database
        - name: MYSQL_RANDOM_ROOT_PASSWORD
          value: "1"
        image: mysql:5.7
        imagePullPolicy: IfNotPresent
        name: mysql
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: mysql-data
      volumes:
      - name: mysql-data
        persistentVolumeClaim:
          claimName: mysql-data
```

MySQLをデプロイします。

```
# oc apply -n redmine -f dm-mysql.yml 
deployment.apps/mysql created
```

正常に起動してくるのを確認します。

```
# oc get pod -n redmine
NAME                     READY   STATUS    RESTARTS   AGE
mysql-7cfdb5ff76-pmbvh   1/1     Running   0          4s
```

## Service作成

MySQLをクラスター内で参照するためのServiceを作成します。以下のymlファイルを作成します。

```yaml:svc-mysql.yml 
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
    protocol: TCP
    targetPort: 3306
  selector:
    app: mysql
  sessionAffinity: None
  type: ClusterIP
```

Serviceを作成します。

```
# oc apply -f svc-mysql.yml -n redmine
service/mysql created
```

## Pod動作確認

起動したPodに対し、作業環境上にあるmysqlコマンドからの接続を試します。(RHELサーバーにMariaDBをインストールして実施しています)

まずPodのポートをローカルにポートフォワードします。

```
# oc port-forward pod/mysql-7cfdb5ff76-pmbvh 3306:3306 -n redmine
Forwarding from 127.0.0.1:3306 -> 3306
```

別のウィンドウで、mysqlコマンドで接続してみます。

```
[root@vs-hirokuda-tok2 redmine]# mysql -h 127.0.0.1 -u redmine -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.38 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> 
```

なお、`-h 127.0.0.1` か `--protocol=tcp` のいずれかを指定しないと失敗しますのでご注意ください。

https://qiita.com/hirokuda/items/70b06a5f4735480435d3

## Service動作確認

Service経由の接続も同様、以下のようにServiceのポートをローカルにポートフォワードして確認します。（結果は同様なので割愛）

```
# oc port-forward svc/mysql  3306:3306 -n redmine
Forwarding from 127.0.0.1:3306 -> 3306
```

## To be continued.

このMySQLを使用するアプリをデプロイし、インターネットに公開するまでを次の記事でまとめたいと思います。