順を追ってkubernetes上でWordPressを展開する

順を追ってkubernetes上でWordPressを展開してみます。

# 動作環境
kubernetesクラスタは[Docker Desktop for Mac](https://hub.docker.com/editions/community/docker-ce-desktop-mac)を利用して、Macのローカル環境で動かしています。kubernetesのバージョンは1.18.6、ノードはmasterのみです。

```shell
$ kubectl get nodes
NAME             STATUS   ROLES    AGE   VERSION
docker-desktop   Ready    master   57d   v1.18.6
```
# コンポーネントの構成
今回展開する構成は下記の通りです。

![Components.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165095/2b6073d4-d796-d666-35c8-719d0f512dad.png)

アイコン: https://github.com/kubernetes/community/tree/master/icons


# WordPressの展開
Manifestファイルを作成しながら、リソースを展開していきます。
Manifestファイル作成の過程で、[CKA](https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/)や[CKAD](https://training.linuxfoundation.org/certification/certified-kubernetes-application-developer-ckad/)の試験テクニックとしてよく使う`kubectl`コマンドの`--dry-run=client`オプションを使って雛形を生成しながらリソースを展開していきます。

## DBユーザのパスワード用のSecret
DBユーザのパスワードをSecretリソースで展開します。
下記のコマンドでManifestファイルを生成します。パスワードは必要に応じて変更してください。

```shell
$ kubectl create secret generic wordpress --from-literal=db-password=wordpress-password --dry-run=client -o yaml > wp-secret.yaml
```

下記のようなManifestファイル(`wp-secret.yaml`)が生成されます。

```yaml
apiVersion: v1
data:
  db-password: d29yZHByZXNzLXBhc3N3b3Jk
kind: Secret
metadata:
  creationTimestamp: null
  name: wordpress
```

このままでも問題ありませんが、不要な部分を削除して下記のように整形しておきます。

```yaml
apiVersion: v1
data:
  db-password: d29yZHByZXNzLXBhc3N3b3Jk
kind: Secret
metadata:
  name: wordpress
```
## DB用のPersistent Volume Claim
DB(MySQL)のPodにマウントするVolumeを作成するため、Persistent Volume Claimを作成します。Persistent Volume Claimは`kubectl`からManifestの雛形を作成できないので、[ドキュメント](https://v1-18.docs.kubernetes.io/docs/concepts/storage/persistent-volumes/)を参考にManifestファイル(`mysql-pvc.yaml`)を作成します。容量は適宜変更してください。

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
```
なお、Docker Desktop for Macのkubernetes環境の場合、Dynamic Volume Provisioningにより、Persistent Volumeは自動的に作成されます。

## MySQLのDeployment
WordPressのDBとしてMySQLコンテナを展開します。
Deploymentを利用してPodを展開することにします。

まず`kubectl`でManifestファイルの雛形を作成します。

```shell
$ kubectl create deployment mysql --image=mysql --dry-run=client -o yaml > mysql-deployment.yaml
```

下記のようなManifestファイルの雛形(`mysql-deployment.yaml`)が作成されます。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: mysql
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql
        name: mysql
        resources: {}
status: {}
```
次に不要な部分を削除し、MySQLコンテナの起動に必要な環境変数を設定します。環境変数のうち、`MYSQL_PASSWORD`は、先ほど作成したSecretリソースから読み込むようにします。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: mysql
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - image: mysql
          name: mysql
          env:
            - name: MYSQL_RANDOM_ROOT_PASSWORD
              value: "yes"
            - name: MYSQL_DATABASE
              value: wordpress
            - name: MYSQL_USER
              value: wordpress
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: wordpress
                  key: db-password
```
ここでは、`root`ユーザではなく、`wordpress`という専用のDBユーザを利用するように設定しています。

次にDBのデータの永続化のために、先ほど作成したPersistent Volume ClaimをマウントするようにManifestファイルを変更します。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: mysql
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - image: mysql
          name: mysql
          env:
            - name: MYSQL_RANDOM_ROOT_PASSWORD
              value: "yes"
            - name: MYSQL_DATABASE
              value: wordpress
            - name: MYSQL_USER
              value: wordpress
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: wordpress
                  key: db-password
          volumeMounts:
            - mountPath: /var/lib/mysql
              name: mysql-volume
      volumes:
        - name: mysql-volume
          persistentVolumeClaim:
            claimName: mysql-pvc
```
## MySQL用のService
先ほど展開したMySQLのDeployment(Pod)にkubernetesクラスタ内から直接アクセスすることも可能ですが、Serviceを経由してアクセスするように設定します。

ServiceのManifestファイルの雛形を作成するために、一度これまで作成してきたManifestファイルからリソースを作成します。

```shell
$ ls
mysql-deployment.yaml	mysql-pvc.yaml		wp-secret.yaml
$ kubectl apply -f .
deployment.apps/mysql created
persistentvolumeclaim/mysql-pvc created
secret/wordpress created
```
次にMySQLのDeploymentを公開するためのServiceのManifestファイルの雛形を作成します。

```shell
$ kubectl expose deployment mysql --name=mysql-service --port=3306 --dry-run=client -o yaml > mysql-service.yaml
```
下記のようなManifestファイルの雛形(`mysql-service.yaml`)が作成されます。

```yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: mysql
  name: mysql-service
spec:
  ports:
  - port: 3306
    protocol: TCP
    targetPort: 3306
  selector:
    app: mysql
status:
  loadBalancer: {}
```

不要な部分を削除して下記のように整形しておきます。

```yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: mysql
  name: mysql-service
spec:
  ports:
    - port: 3306
      protocol: TCP
      targetPort: 3306
  selector:
    app: mysql
```

上記のServiceを展開しておきます。

```shell
$ kubectl apply -f mysql-service.yaml
service/mysql-service created
```
ここまででDBの展開が完了しました。
## WordPressのDeployment
WordPressのコンテナを展開します。
DBと同じくDeploymentを利用してPodを展開します。

まず`kubectl`を利用して、Manifestファイルの雛形を作成します。

```shell
$ kubectl create deployment wordpress --image=wordpress --dry-run=client -o yaml > wp-deployment.yaml
```
下記のようなManifestファイルの雛形(`wp-deployment.yaml`)が作成されます。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: wordpress
  name: wordpress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: wordpress
    spec:
      containers:
      - image: wordpress
        name: wordpress
        resources: {}
status: {}
```

不要な部分を削除しつつ、WordPressの実行に必要な環境変数を設定します。
MySQLのDeploymentと同じくDBのパスワード(`WORDPRESS_DB_PASSWORD`)はSecretから読み込みます。またWordPressのホスト名(`WORDPRESS_DB_HOST`)は、先ほど作成したMYSQLのService名(`mysql-service`)を指定します。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: wordpress
  name: wordpress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
        - image: wordpress
          name: wordpress
          env:
            - name: WORDPRESS_DB_HOST
              value: mysql-service
            - name: WORDPRESS_DB_USER
              value: wordpress
            - name: WORDPRESS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: wordpress
                  key: db-password
            - name: WORDPRESS_DB_NAME
              value: wordpress
```
ここまで作成したら、WordPressのDeploymentを展開します。

```shell
$ kubectl apply -f wp-deployment.yaml 
deployment.apps/wordpress created
```

## WordPress用のService
最後に作成したWordPressのDeploymentをServiceとして公開します。
`kubectl`コマンドでServiceのManifestファイルの雛形を作成します。

```shell
$ kubectl expose deployment wordpress --port=80 --dry-run=client -o yaml > wp-service.yaml
```
下記のようなManifestファイルの雛形(`wp-service.yaml`)が作成されます。

```shell
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: wordpress
  name: wordpress
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: wordpress
status:
  loadBalancer: {}
```
不要な部分を削除してManifestファイルを整形します。

```yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: wordpress
  name: wordpress-service
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: wordpress
```
作成したManifestファイルでServiceを展開します。

```shell
$ kubectl apply -f wp-service.yaml 
service/wordpress-service created
```

## 作成されたリソースの確認
ここまでの手順でWordPressの展開が完了しました。
作成されたリソースを確認しておきます。

```shell
$ kubectl get deployments,pods,services,secrets
NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql       1/1     1            1           43m
deployment.apps/wordpress   1/1     1            1           13m

NAME                             READY   STATUS    RESTARTS   AGE
pod/mysql-76d48947b-88dz7        1/1     Running   0          43m
pod/wordpress-666b48f5bd-vncmh   1/1     Running   0          13m

NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/kubernetes          ClusterIP   10.96.0.1       <none>        443/TCP    57d
service/mysql-service       ClusterIP   10.97.95.189    <none>        3306/TCP   29m
service/wordpress-service   ClusterIP   10.111.138.76   <none>        80/TCP     2m23s

NAME                         TYPE                                  DATA   AGE
secret/default-token-4tvq2   kubernetes.io/service-account-token   3      57d
secret/wordpress             Opaque                                1      43m
```

# WordPressへのアクセス
最後に展開されたWordPressへアクセスしてみます。
ここでは`kubectl`の`port-forward`サブコマンドにてポートフォワードをしてアクセスします。ローカルのポートは必要に応じて変更してください。ここでは`8080`ポートを利用します。

```shell
$ kubectl port-forward service/wordpress-service 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
```
ブラウザから`http://localhost:8080`へアクセスして、WordPress画面が表示されたアクセス成功です。
![Screen Shot 2020-10-10 at 23.41.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165095/439e339a-cdef-a96a-8cdb-6d8d648b0714.png)
また言語選択をして、サイトタイトル入力画面に遷移したら、DBへのアクセスも成功しています。
![Screen Shot 2020-10-10 at 23.45.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165095/bbc5a554-d904-88ce-e63f-153420becd60.png)

以上でkubernetes上へのWordPressの展開は完了です。

# Clean up
展開したリソースが不要になったら、削除しておきます。

```shell
$ ls               
mysql-deployment.yaml	mysql-service.yaml	wp-secret.yaml
mysql-pvc.yaml		wp-deployment.yaml	wp-service.yaml
$ kubectl delete -f .
deployment.apps "mysql" deleted
persistentvolumeclaim "mysql-pvc" deleted
service "mysql-service" deleted
deployment.apps "wordpress" deleted
secret "wordpress" deleted
service "wordpress-service" deleted
```