EKSのチュートリアルをやりながらKubernetesを感覚で学ぶ

## やりたいこと

Aamazon EKSをチュートリアルをやりながら、どうせならKubernetesについても感覚で学んでいこうと思います。

参考文献：https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/getting-started.html

## 前提

* 作業はmacosで行います。
* EKSは対応リージョンが限られています。
    * 詳細はURLをご確認ください。
        * https://aws.amazon.com/jp/about-aws/global-infrastructure/regional-product-services/

## IAMロールの作成

EKSでは自身でELBを作成するため、IAMのロールを作成する必要があります。

* https://console.aws.amazon.com/iam/ にログイン
* `[Create role] > [AWS service] > [EKS]`でIAMを作成

## VPCの作成

* https://console.aws.amazon.com/cloudformation にログイン
* CFn(CloudFormation)の管理画面で、以下のURLのyamlを使いstackを作成
    * https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2018-11-07/amazon-eks-vpc-sample.yaml
        * 上記のYamlでは以下のリソースを作成しています。AWSからインターネット接続する基礎部分となります。
            * VPC
            * InternetGateway
            * RouteTable
            * Subnet
            * SecurityGroup

※ 今回はCFnで作成しましたが、勉強のためにYamlを見ながら手で作成するのもありだと思います。

## `kubectl`のインストール

### `kubectl`について

Kubectlはawscliのようなもので、kubernetesのApiをcliで管理できるコマンドです。
awscliをお使いの方はご存知かもしれませんが、cliではほとんど全ての操作が可能です。
そのため、本番環境へEKSを採用する際はkubectlを実施できる環境を安全に保つ必要があります。
例として、「kubectlを実行できる専用のEC2インスタンスを用意する」などの施策が必要となります。

### インストール方法

* kubectlのバイナリファイルをローカルPCにダウンロードします
    * ローカルPC(macos)で以下のコマンドを実行
    * 最後のコマンドで `Client Version: v.XXX` が表示されればOK

```bash

curl -o kubectl https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-06-05/bin/darwin/amd64/kubectl	
chmod +x ./kubectl
cp ./kubectl /usr/local/bin/kubectl
kubectl version --short --client
```

## `aws-iam-authenticator`のインストール

### `aws-iam-authenticator`について

kubectlはKubernetesのApiをcliで使うために作られています。
ですので、EKSへ接続には、別途、IAMでの認証が必要になります。
IAMでの認証をするために、今回は `aws-iam-authenticator`を使用します。

### インストール方法

* `aws-iam-authenticator`のバイナリファイルをローカルPCにダウンロードします
    * ローカルPC(macos)で以下のコマンドを実行
    * 最後のコマンドでコマンドのhelpが表示されればOK

```bash

curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/darwin/amd64/aws-iam-authenticator
chmod +x ./aws-iam-authenticator
mv ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
aws-iam-authenticator help
```

* windows, Linux用のバイナリ
    * Linux: https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/linux/amd64/aws-iam-authenticator
    * Windows: https://amazon-eks.s3-us-west-2.amazonaws.com/1.10.3/2018-07-26/bin/windows/amd64/aws-iam-authenticator.exe


## EKSクラスタの作成

### EKSクラスタについて

EKSでKubernetesを動かすには、IAMやVPCの設定が必要です。
EKSクラスタを作成すると、以下のリソースがKubernetesに紐付けられます。

* EKSクラスタに紐づくもの
    * IAM Role
    * VPC
    * Subnets
    * Security groups
    
EKSクラスタを作成後、kubectlを使ってクラスタ上にコンテナを配置していくことになります。

## EKSクラスタをコンソールで作成

* https://console.aws.amazon.com/eks/home#/clusters にログイン
* `[Create cluster]` を押してクラスタを作成
    * EKS用に作成した IAM Role, VPC, Subnets, Security groups を設定
* `Status` を確認し、EKSクラスタが作成されるまで待つ

![スクリーンショット 2019-02-05 11.53.42.png](https://qiita-image-store.s3.amazonaws.com/0/259386/2ca02382-6bd6-7410-38cc-18c2f65f8f9a.png)
![スクリーンショット 2019-02-05 12.01.23.png](https://qiita-image-store.s3.amazonaws.com/0/259386/d50dbf6c-75f3-e822-575f-6676380d59a3.png)


## configファイルの作成

### configファイルについて

kubectlの設定ファイルです。
ここにEKSクラスタやその他の設定を記述してきます。

### 作成方法

以下のコマンドを実行します。
configファイル名は任意の名前で作成します。
`~/.kube/cofig`で作成するとKubernetesの設定ファイルを上書きすることになります。
例えば、`Docker Desktop for Mac`でKubernetesを使っている場合、configファイルは`~/.kube/cofig`に作成されます。

```bash

mkdir -p ~/.kube
touch ~/.kube/config-eks
```

`.kube/config-eks`に以下を記述します。

```yaml

apiVersion: v1
clusters:
- cluster:
    server: <endpoint-url>
    certificate-authority-data: <base64-encoded-ca-cert>
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: aws
  name: aws
current-context: aws
kind: Config
preferences: {}
users:
- name: aws
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      command: aws-iam-authenticator
      args:
        - "token"
        - "-i"
        - "<cluster-name>"
        # - "-r"
        # - "<role-arn>"
      # env:
        # - name: AWS_PROFILE
        #   value: "<aws-profile>"
```

* 以下の値は置き換えが必要になります。
    * `<endpoint-url>`
        * EKSコンソールで`Cluster ARN`をコピーして置き換え
    * `<base64-encoded-ca-cert>`
        * EKSコンソールで`Certificate authority`をコピーして置き換え
    * `<cluster-name>`
        * EKSコンソールで`Cluster`を確認し、クラスタ名に置き換えます
    * (オプション) `<role-arn>`
        * aws-iam-authenticatorで使うデフォルトのRoleを変更する場合に設定します
        * 使用する場合はコメントアウトを外して使います
    * (オプション) `<aws-profile>`
        * aws-iam-authenticatorでAWS Profileを使用する場合に設定します
        * 使用する場合はコメントアウトを外して使います

### 設定ファイルをkubectlへ反映させる

作成したconfigファイルをKUBECONFIGに設定します。

* 設定方法は２つあります
    * 1. 環境変数として設定する
    * 2. エイリアスとして設定する
    * 3. `kubectl config`で切り替える

#### 環境変数として設定する場合

```bash

echo 'export KUBECONFIG=$KUBECONFIG:~/.kube/config-eks' >> ~/.bash_profile
source ~/.bash_profile
kubectl config view
```

この場合、kubectlを実行するたびに、`~/.kube/config-eks`が必ず読まれます。

#### エイリアスとして設定する

```bash

echo 'alias eksctl="KUBECONFIG=$KUBECONFIG:~/.kube/config-eks kubectl"' >> ~/.bash_profile
source ~/.bash_profile
eksctl config view
# eksctlと違うconfigが設定されていることを確認
kubectl config view
```

エイリアスとして設定すると、`Docker Desktop for Mac`との棲み分けができて便利です。

※ 上記まで、読み飛ばす方もいるはずなので、今後、cliの名前は`kubectlに統一`しています。

#### `kubectl config`で切り替える

`~/.kube/config`に複数環境を設定しておいて、必要に応じてkubectlで切り替える方法もあります。
例えば以下のように、2つの設定を記述しておきます。

```bash
apiVersion: v1
clusters:
- cluster:
    server: <endpoint-url>
    certificate-authority-data: <base64-encoded-ca-cert>
  name: docker-for-desktop-cluster
## ↓追加
- cluster:
    server: <endpoint-url>
    certificate-authority-data: <base64-encoded-ca-cert>
  name: kubernetes
contexts:
## ↓追加
- context:
    cluster: kubernetes
    user: aws
  name: aws
- context:
    cluster: docker-for-desktop-cluster
    user: docker-for-desktop
  name: docker-for-desktop
## ↓現在、設定されているクラスタ
current-context: aws
kind: Config
preferences: {}
users:
## ↓追加
- name: aws
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      command: aws-iam-authenticator
      args:
        - "token"
        - "-i"
        - "<cluster-name>"
        # - "-r"
        # - "<role-arn>"
      # env:
        # - name: AWS_PROFILE
        #   value: "<aws-profile>"
- name: docker-for-desktop
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
```

`kubectl config view`でNAMEとCLUSTERが増えたことを確認

```bash
→ kubectl config get-contexts
CURRENT   NAME                 CLUSTER                      AUTHINFO             NAMESPACE
*         aws                  kubernetes                   aws                  
          docker-for-desktop   docker-for-desktop-cluster   docker-for-desktop 
```

NAMEで指定して切り替え

```
→ kubectl config use-context docker-for-desktop
Switched to context "docker-for-desktop".
```

切り替えが成功したかを確認

```
→ kubectl config get-contexts
CURRENT   NAME                 CLUSTER                      AUTHINFO             NAMESPACE
          aws                  kubernetes                   aws                  
*         docker-for-desktop   docker-for-desktop-cluster   docker-for-desktop
```

## EKSにワーカーノードを作成する

### ワーカーノードについて

Kubernetesには`node`という概念があります。AWSで言うとEC2インスタンスに当たります。
EKSでコンテナを動かすには`node`(EC2インスタンス)の作成が必要となります。
後述しますが、`node`上にはランダムにコンテナが配置されるようになります。

### ワーカーノードの作成

* https://console.aws.amazon.com/cloudformation にログイン
* CFn(CloudFormation)の管理画面で、以下のURLのyamlを使いstackを作成
    * https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2018-11-07/amazon-eks-nodegroup.yaml
        * AMI IDを入力するところがありますが、ここには下記URLに記述されているものを使います
            * https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/eks-optimized-ami.html
        * `amazon-eks-nodegroup.yaml`では以下のリソースを作成しています。
            * IAM (EC2用のIAM Roleなど)
            * SecurityGroup (EC2用のセキュリティグループ)
            * AutoScalingGroup (オートスケール)
            * LaunchConfiguration (EC2インスタンスの起動)
        * いままでEKSのリソースを作成してきましたが、今回はEC2用のリソースを作成しています。

CFnへの設定項目

```
Stack name: CFnのスタック名（任意の値でOK）
ClusterName: EKSクラスタ名（名前を一致させる必要がある）
ClusterControlPlaneSecurityGroup: EKSクラスタに設定したSecurityGroup
NodeGroupName: nodeグループ名（任意の値でOK）
NodeAutoScalingGroupMinSize: ワーカーノードがスケールアウトする際のnode数の最小値（任意の値でOK）
NodeAutoScalingGroupDesiredCapacity: スタック作成時のnode数（任意の値でOK）
NodeAutoScalingGroupMaxSize: ワーカーノードがスケールアウトする際のnode数の最大値（任意の値でOK）
NodeInstanceType: ワーカーノードのインスタンスタイプ （任意の値でOK）
NodeImageId: ワーカーノードのAMI ID
（参照：https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/eks-optimized-ami.html）
NodeVolumeSize: ワーカーノードに割り当てるVolumeの大きさ
KeyName: EC2インスタンスへのssh key
```

### ワーカーノードとEKSクラスタを紐付ける

`aws-auth ConfigMap`を使って、IAMのユーザとロールをKubernetes内のユーザやロールに紐付けます。

```bash

curl -O https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2018-11-07/aws-auth-cm.yaml
```

* aws-auth-cm.yamlの`<ARN of instance role>`はEC2インスタンス用に作成したRoleのARNに置き換えます。

```yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
    - rolearn: <ARN of instance role>
      username: system:node:{{EC2PrivateDNSName}}
      groups:
        - system:bootstrappers
        - system:nodes
```

* kubectlでKubernetesに適用
    * `configmap "aws-auth" created`が出力されればOK

```bash

kubectl apply -f aws-auth-cm.yaml
```

* 適用できているか、nodeを確認
    * `XXXX.compute.internal`というのが作られていればOK
        * 注意：STATUSがReadyにならないとコンテナは配置できない

```bash

kubectl get node
```

* ちなみにEC2のコンソールからもnodeが確認できます

## サンプルアプリケーションを作成

nodeの準備ができたので、コンテナを配置してインターネット経由でアクセスできるようにします。

### Redisクラスタ作成のサンプル

Kubernetesには`replicationcontroller`,`service`などのリソースが存在します。
とりあえずコンテナをデプロイして行きます。

```bash

kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-master-controller.json
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-master-service.json
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-slave-controller.json
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/redis-slave-service.json
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/guestbook-controller.json
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/v1.10.3/examples/guestbook-go/guestbook-service.json
```

* Webページの確認
    * `TYPE`がLoadBalancerの`EXTERNAL-IP`をコピーして`<EXTERNAL-IP>:3000`をブラウザで開きます。
    * ブラウザで`Guestbook`を確認できればOKです。

```bash

kubectl get services -o wide
```

![スクリーンショット 2019-02-05 15.58.52.png](https://qiita-image-store.s3.amazonaws.com/0/259386/d118d2a3-9f87-e2ab-c6eb-6c95fcae8a92.png)


以上で一旦、EKS上でコンテナを動かすことが可能になりました。


## podとnodeとserviceとreplicationcontrollerの確認

* `kubectl get`を使えは大抵の値はとってこれます。
    * また、一度に複数の値をとってくることも可能です
        * 以下、例に `pod, node, service(svc), replicationcontroller(rc)` の値を一緒に取ってきています。

```bash

kubectl get pod,node,svc,rc
```

上記のコマンドの結果からも、どのnodeにどのpodを配置するかは意識しなくていいことがわかります。

## Redisクラスタの削除

先程、作成した`service`と`replicationcontroller`を全て消していきます。

```bash

kubectl delete service --all
kubectl delete replicationcontroller --all
```


## Nodeの削除

nodeはCFnで作成したので、CFnのコンソール画面で消します。


## EKSクラスタの削除

EKSのコンソール画面からEKSクラスタも削除します。


## 所感

多少の設定項目はありますが、 設定さえしてしまえば通常のKubernetesと同じように使えるのがいいです。
また、ロードバランサやNodeは従来のAWSリソースを使えるので、AWSユーザにはわかりやすいと思います。
ローカルPCでは `Docker Desktop for Mac` を使いつつ、AWSにはEKSでデプロイするというは開発環境としても使いやすいと思います。