【初心者】Amazon EKSを使ってみる #2（WordPressのデプロイ）

# 目的
- 以前、[「【初心者】Amazon EKSを使ってみる　（環境構築～サンプルアプリ起動まで）」](https://qiita.com/mksamba/items/666c0d666fbb2e052d19)という記事を書いたが、k8sの理解のため、もう少し各種機能を使ってみる。

# やったこと
- kubernetes.io のチュートリアル[「例: Persistent Volumeを使用したWordpressとMySQLをデプロイする」](https://kubernetes.io/ja/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/)を参考にして、wordpress/mysqlのpodをデプロイし、httpsでインターネットからWordPressサイトにアクセスできるようにする。

- 主な技術要素
    - eksctl (eks環境のデプロイ)
    - StorageClass (Volumeの作成)
    - ACM連携 (https接続)

# 構成図

![eksctl10構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/202d6d67-1ebd-b8dd-aaba-cdd1ccd84882.png)




# 作業手順
## 1.eksctlによる環境構築
- [前の記事](https://qiita.com/mksamba/items/666c0d666fbb2e052d19)ではマネコンからステップバイステップで環境作成したが、面倒なので今回はeksctlで作成する。eksctlのコマンドで、VPC(Subnet、IGWなど含む)、eksのcluster(コントロールプレーン)、nodegroup(Worker Nodeのセット)を一気に作成する。
- 公式サイト[「eksctl の開始方法」](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/getting-started-eksctl.html)に従い作業する。
- 事前準備として、作業用のEC2インスタンス(Amazon Linux 2)にaws cli(v2)、kubectl、eksctl をインストールする。

```
[ec2-user@ip-172-16-0-29 ~]$ aws --version
aws-cli/2.0.61 Python/3.7.3 Linux/4.14.193-149.317.amzn2.x86_64 exe/x86_64.amzn.2
[ec2-user@ip-172-16-0-29 ~]$ kubectl version --client
Client Version: version.Info{Major:"1", Minor:"18+", GitVersion:"v1.18.8-eks-7c9bda", GitCommit:"7c9bda52c425d0d56d7b93f1377a826b4132c05c", GitTreeState:"clean", BuildDate:"2020-08-28T23:07:29Z", GoVersion:"go1.13.15", Compiler:"gc", Platform:"linux/amd64"}
[ec2-user@ip-172-16-0-29 ~]$ eksctl version
0.30.0
```

- eksctlコマンドを実行して環境を構築する。実行したeksctlコマンドのパラメータは以下の通り。

```
eksctl create cluster \
--name mksamba-eks-cluster \
--version 1.18 \
--region ap-northeast-1 \
--nodegroup-name mksamba-eks-nodes \
--nodes 3 \
--nodes-min 1 \
--nodes-max 3 \
--with-oidc \
--ssh-access \
--ssh-public-key "key-pair" \
--managed \
--node-type t3.medium \
--node-volume-size=80 \
--vpc-nat-mode Disable \
```

- eksctlではあまり細かいパラメータの指定ができず、上記のコマンドにより、構成図のVPC(Public Subnet *3、Private Subnet *3)が作成され、CIDRも既定のもの(192.168.0.0/16を分割)になる。ノード(EC2インスタンス *3)は Public Subnetの中に作成される。
- デフォルト設定だとNat Gatewayが作成されるが、今回の検証ではPublic Subnetのみ使用するためNat Gatewayが不要なため、「--vpc-nat-mode Disable」でNat Gatewayを作成しないようにしている。
- 無事3ノード作成されたことを確認する。

```
[ec2-user@ip-172-16-0-29 ~]$ kubectl get nodes
NAME                                                STATUS   ROLES    AGE   VERSION
ip-192-168-16-195.ap-northeast-1.compute.internal   Ready    <none>   11m   v1.18.9-eks-d1db3c
ip-192-168-40-42.ap-northeast-1.compute.internal    Ready    <none>   11m   v1.18.9-eks-d1db3c
ip-192-168-83-21.ap-northeast-1.compute.internal    Ready    <none>   11m   v1.18.9-eks-d1db3c
```
- ノードへのsshを許可するようにしたため、インターネット(0.0.0.0/0)からssh可能になっている。Security Groupの内容を変更して、適切なSrcIPのみにアクセスを制限する。

## 2.Volumeの作成
- wordpress/mysqlのコンテナで使用するVolumeを作成する。
- EKSにて最初からStorageClassが定義されており、EBSをVolumeとして使用することができる。

```
[ec2-user@ip-172-16-0-29 ~]$ kubectl get sc
NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  21m
```

- kubernetes.io チュートリアルからそのままコピペし、wordpressコンテナ用、mysqlコンテナ用のpvcを作成するyamlを準備する。

```wordpress-pv-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
```
``` mysql-pv-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
```
- pvcを作成しステータスを確認する。

```
[ec2-user@ip-172-16-0-29 myyaml]$ kubectl apply -f wordpress-pv-claim.yaml
persistentvolumeclaim/wp-pv-claim created
[ec2-user@ip-172-16-0-29 myyaml]$ kubectl apply -f mysql-pv-claim.yaml
persistentvolumeclaim/mysql-pv-claim created
[ec2-user@ip-172-16-0-29 myyaml]$ kubectl get pvc
NAME             STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pv-claim   Pending                                      gp2            44s
wp-pv-claim      Pending                                      gp2            52s
```

## 3. podの作成
- kubernetes.io チュートリアルからほぼそのままコピペして、mysql、wordpressのpodを作成するyamlを準備する。(単純化のため、Secretを使わず環境変数の値をそのまま埋め込んでいる。)
 
``` mysql-deployment.yaml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
```
``` wordpress-deployment.yaml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          value: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim
```
- deploymentを作成し、deployment, pod, pvcの状況を確認する。

```
[ec2-user@ip-172-16-0-29 qiita]$ kubectl apply -f mysql-deployment.yaml
deployment.apps/wordpress-mysql created
[ec2-user@ip-172-16-0-29 qiita]$ kubectl apply -f wordpress-deployment.yaml
deployment.apps/wordpress created
[ec2-user@ip-172-16-0-29 qiita]$ kubectl get deployment
NAME              READY   UP-TO-DATE   AVAILABLE   AGE
wordpress         1/1     1            1           32s
wordpress-mysql   1/1     1            1           11m
[ec2-user@ip-172-16-0-29 qiita]$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
wordpress-6c76bb8768-jjhsn        1/1     Running   0          39s
wordpress-mysql-65bb879f6-kmxj2   1/1     Running   0          12m
[ec2-user@ip-172-16-0-29 qiita]$ kubectl get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pv-claim   Bound    pvc-60ef7f20-8074-466f-a6e5-7c81ce2ba562   20Gi       RWO            gp2            21m
wp-pv-claim      Bound    pvc-34f766a2-dc2d-4bc6-9f59-71e05e016679   20Gi       RWO            gp2            21m
```
- EBSの画面でも、volumeが自動生成されて、 in use になっていることが確認できる。


![eksctl02b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/9fefb4b6-d28e-e77a-df6e-2b5dd87ddea5.png)



## 4.Serviceの作成
- kubernetes.io チュートリアルからほぼそのままコピペして、mysql、wordpressのServiceを作成するyamlを準備する。Service TypeをmysqlはClusterIP、wordpressはLoadbalancerとしている。（mysql用のServiceがHeadlessだったため、普通のClusterIPに変更）

``` mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
```
``` wordpress-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
```

- Service を作成し、状況を確認する。wordpressのほうは「Type: LoadBalancer」としたため、CLBが自動作成される。

```
[ec2-user@ip-172-16-0-29 qiita]$ kubectl apply -f mysql-service.yaml
service/wordpress-mysql created
[ec2-user@ip-172-16-0-29 qiita]$ kubectl apply -f wordpress-service.yaml
service/wordpress created
[ec2-user@ip-172-16-0-29 qiita]$ kubectl get svc
NAME              TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT(S)        AGE
kubernetes        ClusterIP      10.100.0.1       <none>                                                                         443/TCP        114m
wordpress         LoadBalancer   10.100.187.185   12345678901234567890123456789012-1234567890.ap-northeast-1.elb.amazonaws.com   80:31070/TCP   68s
wordpress-mysql   ClusterIP      10.100.251.124   <none>
```
- ブラウザでCLBのURLにhttpでアクセスし、WordPressの初期画面が表示されることを確認する。

![eksctl03a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/226e52c9-9607-c1e1-da1a-27d08abbfe66.png)


- CLBが生成されていることを確認する。(インターネットからの80/tcpアクセスを、3つのノードの31070/tcp(NodePort)に転送するよう自動的に設定される)

![eksctl04b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/32b6135d-e2c6-d131-9da4-0618d1293d5e.png)


- Serviceはこの後httpsで作り直すのでいったん消しておく。

## 5.https化

- 公式サイト[「ACM で Amazon EKS ワークロードの HTTPS トラフィックを終了する方法を教えてください。」](https://aws.amazon.com/jp/premiumsupport/knowledge-center/terminate-https-traffic-eks-acm/) を参考に作業を行う。
- ACMで証明書を取得する。ここでは仮にFQDNを「eks.mksambaaws.com」とする。証明書を取得したらARNをメモする。
- hpttsでServiceを作成するyamlを作成する。その中でパラメータとして証明書のARNを記載する。

``` wordpress-service-https.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "証明書のARN"
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
spec:
  ports:
  - name: http
    port: 80
  - name: https
    port: 443
    targetPort: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
```

- Serviceを作成し状況を確認する。

```
[ec2-user@ip-172-16-0-29 qiita]$ kubectl apply -f wordpress-service-https.yaml
service/wordpress created
[ec2-user@ip-172-16-0-29 qiita]$ kubectl get svc
NAME              TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)                      AGE
kubernetes        ClusterIP      10.100.0.1       <none>                                                                        443/TCP                      9h
wordpress         LoadBalancer   10.100.173.16    12345678901234567890123456789012-1234567890.ap-northeast-1.elb.amazonaws.com   80:30765/TCP,443:31041/TCP   22s
wordpress-mysql   ClusterIP      10.100.251.124   <none>                                                                        3306/TCP                     7h18m
```

- CLBが作成され、httpsを受け付けていること、また証明書のARNが設定されていることを確認する。

![eksctl09a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/44fd4a6b-327c-b66c-129d-89dc92a83805.png)


- Route 53でAレコードを登録する。「eks.mksambaaws.com」のAレコードとして、作成したCLBを指定する。

![eksctl05a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/94837f9e-5794-c449-cacd-dfa14b87d212.png)

- 登録したFQDNにhttpsでにアクセスして、WordPressの初期画面が表示されることを確認する。

![eksctl08a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189302/8ccdb1f2-ff0e-dd78-fa65-fd41541acec1.png)


# 所感
- 少しだけk8sぽい感じになったので、引き続き勉強したい。