[メモ]初心者がコンテナを触ってみる - (4)Amazon EKSでクラスター作成

# はじめに
お疲れ様です。yuki_inkです。
初心者がコンテナを触ってみるシリーズ4回目です。

[前回](https://qiita.com/yuki_ink/items/481eaa22a910ad342434)の結びで「次回は満を持してDockerfileを触ってみようかなと思います」とか書いておきながら、諸般の事情により、数段飛ばしでEKSを触ってみたいと思います。
Dockerfileは後でやります！！
※最終的にはCodePipelineでDockerfileをビルドして、ECRに格納⇒EKS上でデプロイまでやりたい

# やったこと
「Introduction to Amazon EKS」のハンズオンをやってみました。

https://resources.awscloud.com/aws-summit-online-japan-2020-on-demand-self-paced-hands-on-85234/hol-06-aws-summit-online-2020-container-720p

>このハンズオンでは Amazon Elastic Kubernetes Service (Amazon EKS) と eksctl を使用して、マネージドな Kubernetes クラスターを実行します。サンプル Web アプリケーションをビルドして Kuberneres クラスターにデプロイし、kubectl コマンドによる Kubernetes の操作と、Amazon EKS 上でのアプリケーションの実行を体験していただきます。

ステップは下記の通り。
1. AWS Cloud9 環境の作成
2. クラスターの作成
3. クラスターの確認


本ハンズオンについては、クラメソ様の記事も参考にしました。

https://dev.classmethod.jp/articles/aws-summit-online-2020-hol-06/

# Cloud9 環境の作成
### Cloud9 環境の作成
Cloud9はクラウドベースの統合開発環境（IDE）。
k8sを操作するコマンドライン「cubectl」などを、Cloud9上から実行したい。

ハンズオンの指示に従ってCloud9環境を作成する。
こうして見ると、クラウドベースのIDEと言いつつ、実態はEC2で、Systems Manager（あるいはSSH）で接続して処理をさせていることがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/9fba4bbf-4622-c41f-d6af-5acd881d412b.png)

EC2の画面から、新規作成されたEC2が確認できる。
将来的にサーバレスで動かせるようにしてほしいなあ。。
この時点でEC2インスタンスには「AWSCloud9SSMAccessRole」がアタッチされている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/02b43717-596c-0fe8-1f03-f02daa28831c.png)

Cloud9の起動が完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/90390c22-470a-1734-6360-a4ed5ad32b49.png)

### IAM ロールの作成・割り当て
`AdministratorAccess`権限を持たせたIAMロールを作成し、先ほど作ったEC2にアタッチする。
公式のハンズオンで`AdministratorAccess`権限をIAMロールに持たせるのはちょっと意外。

IAMロールの設定が完了したら、Cloud9の画面に戻り、右上の歯車から AWS Settings > Credentials の「AWS managed temporary credentials」を無効化して、EC2に割り当てたIAMロールを利用するように設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/a0fdbbe6-5d8a-fba2-4c9d-02fb407db176.png)

### AWS CLI の初期設定
まずはクレデンシャルの削除。
>EC2 インスタンスに割り当てた IAM ロールが使用されることを確実にするため、クレデンシャルファイルを削除します。 ここまで手順通りに実行していればクレデンシャルファイルは存在していないはずですので、これは念のための作業です。

続いてAWS CLI のアップデートを行い、デフォルトリージョンの設定を行う。

# クラスターの作成

### eksctl と kubectl の導入
>この節では、Kubernetes クラスター自体の作成に使用する eksctl  コマンドと、作成した Kubernetes クラスターの操作に使用する kubectl コマンドをインストールします。

まずは eksctl コマンドをインストール。
```
$ curl -L "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 31.4M  100 31.4M    0     0  14.9M      0  0:00:02  0:00:02 --:--:-- 24.9M

$ sudo mv /tmp/eksctl /usr/local/bin

$ eksctl version
0.150.0-dev
```

続いて kubectl コマンドをインストール。
導入するコマンドのバージョンに注意が必要とのこと。
>kubectl コマンドは EKS クラスターの Kubernetes バージョンに合わせたバージョンを使用します。各バージョンのダウンロード URL は以下のリンク先を確認して下さい。
　 [kubectl のインストール](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/install-kubectl.html)
このハンズオンでは Kubernetes のバージョンは 1.24 を使用しますので、同じバージョンの kubectl コマンドをインストールします。

```
$ sudo curl -L -o /usr/local/bin/kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.24.9/2023-01-11/bin/linux/amd64/kubectl
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 43.6M  100 43.6M    0     0  9146k      0  0:00:04  0:00:04 --:--:--  9.9M

$ sudo chmod +x /usr/local/bin/kubectl

$ kubectl version --short --client
Flag --short has been deprecated, and will be removed in the future. The --short output will become the default.
Client Version: v1.24.9-eks-49d8fe8
Kustomize Version: v4.5.4
```

### クラスターの作成
`eksctl create cluster`コマンドでクラスターを作る。
```
$ eksctl create cluster   --name=ekshandson   --version 1.24   --nodes=3 --managed   --region ${AWS_REGION} --zones ${AWS_REGION}a,${AWS_REGION}c
2023-07-25 07:02:47 [ℹ]  eksctl version 0.150.0-dev
2023-07-25 07:02:47 [ℹ]  using region ap-northeast-1
2023-07-25 07:02:47 [ℹ]  subnets for ap-northeast-1a - public:192.168.0.0/19 private:192.168.64.0/19
2023-07-25 07:02:47 [ℹ]  subnets for ap-northeast-1c - public:192.168.32.0/19 private:192.168.96.0/19
2023-07-25 07:02:47 [ℹ]  nodegroup "ng-042cd4a7" will use "" [AmazonLinux2/1.24]
2023-07-25 07:02:47 [ℹ]  using Kubernetes version 1.24
2023-07-25 07:02:47 [ℹ]  creating EKS cluster "ekshandson" in "ap-northeast-1" region with managed nodes
2023-07-25 07:02:47 [ℹ]  will create 2 separate CloudFormation stacks for cluster itself and the initial managed nodegroup
2023-07-25 07:02:47 [ℹ]  if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=ap-northeast-1 --cluster=ekshandson'
2023-07-25 07:02:47 [ℹ]  Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster "ekshandson" in "ap-northeast-1"
2023-07-25 07:02:47 [ℹ]  CloudWatch logging will not be enabled for cluster "ekshandson" in "ap-northeast-1"
2023-07-25 07:02:47 [ℹ]  you can enable it with 'eksctl utils update-cluster-logging --enable-types={SPECIFY-YOUR-LOG-TYPES-HERE (e.g. all)} --region=ap-northeast-1 --cluster=ekshandson'
2023-07-25 07:02:47 [ℹ]  
2 sequential tasks: { create cluster control plane "ekshandson", 
    2 sequential sub-tasks: { 
        wait for control plane to become ready,
        create managed nodegroup "ng-042cd4a7",
    } 
}
2023-07-25 07:02:47 [ℹ]  building cluster stack "eksctl-ekshandson-cluster"
2023-07-25 07:02:47 [ℹ]  deploying stack "eksctl-ekshandson-cluster"
2023-07-25 07:03:17 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:03:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:04:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:05:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:06:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:07:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:08:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:09:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:10:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:11:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-cluster"
2023-07-25 07:13:49 [ℹ]  building managed nodegroup stack "eksctl-ekshandson-nodegroup-ng-042cd4a7"
2023-07-25 07:13:49 [ℹ]  deploying stack "eksctl-ekshandson-nodegroup-ng-042cd4a7"
2023-07-25 07:13:49 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-nodegroup-ng-042cd4a7"
2023-07-25 07:14:19 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-nodegroup-ng-042cd4a7"
2023-07-25 07:15:03 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-nodegroup-ng-042cd4a7"
2023-07-25 07:16:47 [ℹ]  waiting for CloudFormation stack "eksctl-ekshandson-nodegroup-ng-042cd4a7"
2023-07-25 07:16:47 [ℹ]  waiting for the control plane to become ready
2023-07-25 07:16:49 [✔]  saved kubeconfig as "/home/ec2-user/.kube/config"
2023-07-25 07:16:49 [ℹ]  no tasks
2023-07-25 07:16:49 [✔]  all EKS cluster resources for "ekshandson" have been created
2023-07-25 07:16:49 [ℹ]  nodegroup "ng-042cd4a7" has 3 node(s)
2023-07-25 07:16:49 [ℹ]  node "ip-192-168-52-233.ap-northeast-1.compute.internal" is ready
2023-07-25 07:16:49 [ℹ]  node "ip-192-168-53-185.ap-northeast-1.compute.internal" is ready
2023-07-25 07:16:49 [ℹ]  node "ip-192-168-8-90.ap-northeast-1.compute.internal" is ready
2023-07-25 07:16:49 [ℹ]  waiting for at least 3 node(s) to become ready in "ng-042cd4a7"
2023-07-25 07:16:49 [ℹ]  nodegroup "ng-042cd4a7" has 3 node(s)
2023-07-25 07:16:49 [ℹ]  node "ip-192-168-52-233.ap-northeast-1.compute.internal" is ready
2023-07-25 07:16:49 [ℹ]  node "ip-192-168-53-185.ap-northeast-1.compute.internal" is ready
2023-07-25 07:16:49 [ℹ]  node "ip-192-168-8-90.ap-northeast-1.compute.internal" is ready
2023-07-25 07:16:51 [ℹ]  kubectl command should work with "/home/ec2-user/.kube/config", try 'kubectl get nodes'
2023-07-25 07:16:51 [✔]  EKS cluster "ekshandson" in "ap-northeast-1" region is ready
```

コマンド実行後に気づいたが、裏でCloudFormationが動いており、クラスター以外にも、VPCやInternet GW、NAT GW、ElasticIPなどが作成されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/6ecff8a4-369c-a9fa-afac-a8e8923b5d5b.png)

ノードグループは別スタックで作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/5e62bf3f-69cb-e4ee-54e5-0eee4c7b6425.png)

`eks create cluster`コマンドで作成されるものは、以下の記事が参考になった。
https://dev.classmethod.jp/articles/getting-started-amazon-eks-with-eksctl/#toc-5

※余談※
実務でEKSを利用するときは、あらかじめ用意したNWにクラスターを作成したいとか、パブリックサブネットなんて絶対に作りたくない、という要件もありそうだなと思いつつ。。
参考になりそうなリンクだけ貼っておく。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/network_reqs.html

https://qiita.com/dulao5/items/a91d1495300f1bf84878

https://repost.aws/ja/knowledge-center/eks-cluster-node-group-private-network


### 便利なツールと設定
>クラスターが作成されるのを待つ間、Kubernetes の利用の際によく使われるいくつかの便利なツールの導入と、コマンド補完の設定をしておきましょう。

ということで、別Terminalで便利ツールの導入や設定の追加を行う。
```
# jq, bash-completionインストール
$ sudo yum -y install jq bash-completion

# dockerのコマンド補完設定
$ sudo curl -L -o /etc/bash_completion.d/docker https://raw.githubusercontent.com/docker/cli/master/contrib/completion/bash/docker

# docker-compose導入/補完設定
$ sudo curl -L -o /usr/local/bin/docker-compose "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)"
$ sudo chmod +x /usr/local/bin/docker-compose
$ sudo curl -L -o /etc/bash_completion.d/docker-compose https://raw.githubusercontent.com/docker/compose/1.26.2/contrib/completion/bash/docker-compose

# kubectlとeksctlのコマンド補完設定
$ kubectl completion bash > kubectl_completion
$ sudo mv kubectl_completion /etc/bash_completion.d/kubectl
$ eksctl completion bash > eksctl_completion
$ sudo mv eksctl_completion /etc/bash_completion.d/eksctl

# "k"=kubectlのエイリアス設定
$ cat <<"EOT" >> ${HOME}/.bashrc
 
alias k="kubectl"
complete -o default -F __start_kubectl k
EOT

# kube-ps1導入
$ git clone https://github.com/jonmosco/kube-ps1.git ~/.kube-ps1
$ cat <<"EOT" >> ~/.bashrc

source ~/.kube-ps1/kube-ps1.sh
function get_cluster_short() {
  echo "$1" | cut -d . -f1
}
KUBE_PS1_CLUSTER_FUNCTION=get_cluster_short
KUBE_PS1_SUFFIX=') '
PS1='$(kube_ps1)'$PS1
EOT

# kubectx / kubens導入
$ git clone https://github.com/ahmetb/kubectx.git ~/.kubectx
$ sudo ln -sf ~/.kubectx/completion/kubens.bash /etc/bash_completion.d/kubens
$ sudo ln -sf ~/.kubectx/completion/kubectx.bash /etc/bash_completion.d/kubectx
$ cat <<"EOT" >> ~/.bashrc

export PATH=~/.kubectx:$PATH
EOT

# stern導入
$ sudo curl -L -o /usr/local/bin/stern https://github.com/wercker/stern/releases/download/1.11.0/stern_linux_amd64
$ sudo chmod +x /usr/local/bin/stern

# 設定の読み込み
$ . ~/.bashrc
$ . /etc/profile.d/bash_completion.sh
$ . /etc/bash_completion.d/kubectl
$ . /etc/bash_completion.d/eksctl
```


# クラスターの確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/0347f494-01df-68fa-cbc8-96f61accc5d0.png)
え、ENI経由で通信するなら、IGWとかいらんかったやん!!??と思ったが、
ワーカーノード⇒コントロールプレーンへの通信があるんですね。。
これもVPCエンドポイント経由でできそうだけど。。
それはまた今度やりたい。

まずは`eksctl get cluster`コマンドでクラスターの存在を確認する。
`kubectl cluster-info`コマンドでクラスターの情報を確認する。

### ノードの確認
`kubectl get node`コマンドでワーカーノードを確認。
```
$ kubectl get node
NAME                                                STATUS   ROLES    AGE   VERSION
ip-192-168-52-233.ap-northeast-1.compute.internal   Ready    <none>   58m   v1.24.15-eks-a5565ad
ip-192-168-53-185.ap-northeast-1.compute.internal   Ready    <none>   58m   v1.24.15-eks-a5565ad
ip-192-168-8-90.ap-northeast-1.compute.internal     Ready    <none>   58m   v1.24.15-eks-a5565ad
```
ノードグループに紐づくAutoScalingグループの配下にいるインスタンスがリストされる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/4d19b82a-86a7-5197-93de-2d2466717023.png)

### Namespace の確認
>Kubernetes では、Namespace を使うことで Pod や Service といった Kubernetes リソースをグルーピングすることができます。
アプリケーション毎、プロジェクト毎、チーム毎、環境毎といった単位で Namepspace を分けて使用することで Kubernetes クラスターを効率的に使用することができます。

`kubectl get namespace`コマンドで Namespace を確認。
```
$ kubectl get namespace
NAME              STATUS   AGE
default           Active   70m
kube-node-lease   Active   70m
kube-public       Active   70m
kube-system       Active   70m
```
>default はその名の通りデフォルトの Namespace です。kube-system は Kubernetes のシステムコンポーネントが稼働する Namespace です。

`kubectl get pod`コマンドで Namespace で稼働している Pod を確認する。
`-n`オプションで明示的に Namespace を指定することもできるが、`kubens kube-system`コマンドでデフォルトの Namespace を kube-system に変更しておけば、その手間もなくなる。

:::note info
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/bf94ed6a-480c-67fd-487f-ea93065f33a1.png)
便利ツールとして導入した kube-ps1  が現在 kubectl コマンドがどの Namespace をデフォルトとしているかをプロンプトに表示してくれる。
※ハンズオン資料から抜粋
:::

この状態で`kubectl get pod`コマンドを実行すると、kube-system で稼働しているPodが確認できる。
※せっかくなので"k"エイリアスを使ってみる
```
$ k get pod
NAME                       READY   STATUS    RESTARTS   AGE
aws-node-f2fjd             1/1     Running   0          67m
aws-node-hhr56             1/1     Running   0          67m
aws-node-zjtzg             1/1     Running   0          67m
coredns-5fc8d4cdcf-qgdhm   1/1     Running   0          73m
coredns-5fc8d4cdcf-w49zw   1/1     Running   0          73m
kube-proxy-jswfl           1/1     Running   0          67m
kube-proxy-kv894           1/1     Running   0          67m
kube-proxy-nvkgk           1/1     Running   0          67m
```

>aws-node は Pod にネットワーク機能を提供する Amazon VPC CNI Plugin for Kubernetes  です
coredns  は Kubernetes クラスター内の名前解決を提供する DNS サーバーです
kube-proxy  は Kubernetes Service の機能を提供する Kubernetes のコンポーネントです

`-A`オプションで全ての Namespace を対象として情報を取得。
```
$ kubectl get pod -A
NAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE
kube-system   aws-node-f2fjd             1/1     Running   0          79m
kube-system   aws-node-hhr56             1/1     Running   0          79m
kube-system   aws-node-zjtzg             1/1     Running   0          79m
kube-system   coredns-5fc8d4cdcf-qgdhm   1/1     Running   0          85m
kube-system   coredns-5fc8d4cdcf-w49zw   1/1     Running   0          85m
kube-system   kube-proxy-jswfl           1/1     Running   0          79m
kube-system   kube-proxy-kv894           1/1     Running   0          79m
kube-system   kube-proxy-nvkgk           1/1     Running   0          79m
```
現在は kube-system 以外の Namespace で稼働している Pod はいない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731275/758bd29c-e58f-a72b-7e6b-212ad1cb12ad.png)

`-o wide`オプションでより詳細な情報を取得。
```
NAME                       READY   STATUS    RESTARTS   AGE   IP               NODE                                                NOMINATED NODE   READINESS GATES
aws-node-f2fjd             1/1     Running   0          84m   192.168.8.90     ip-192-168-8-90.ap-northeast-1.compute.internal     <none>           <none>
aws-node-hhr56             1/1     Running   0          84m   192.168.52.233   ip-192-168-52-233.ap-northeast-1.compute.internal   <none>           <none>
aws-node-zjtzg             1/1     Running   0          84m   192.168.53.185   ip-192-168-53-185.ap-northeast-1.compute.internal   <none>           <none>
coredns-5fc8d4cdcf-qgdhm   1/1     Running   0          89m   192.168.3.250    ip-192-168-8-90.ap-northeast-1.compute.internal     <none>           <none>
coredns-5fc8d4cdcf-w49zw   1/1     Running   0          89m   192.168.17.111   ip-192-168-8-90.ap-northeast-1.compute.internal     <none>           <none>
kube-proxy-jswfl           1/1     Running   0          84m   192.168.8.90     ip-192-168-8-90.ap-northeast-1.compute.internal     <none>           <none>
kube-proxy-kv894           1/1     Running   0          84m   192.168.53.185   ip-192-168-53-185.ap-northeast-1.compute.internal   <none>           <none>
kube-proxy-nvkgk           1/1     Running   0          84m   192.168.52.233   ip-192-168-52-233.ap-northeast-1.compute.internal   <none>           <none>
```
PodごとにIPが振られていることを発見。
k8sのネットワークについては後で詳しく勉強したい。

https://zenn.dev/taisho6339/books/fc6facfb640d242dc7ec/viewer/9187c6

# 終わりに
k8sの知識が全くない状態でハンズオンをやってみました。
ネットワーク構成はどうなっているのか / どこで設定しているのかといった点や、具体的にコンテナをデプロイするためにはどうすればいいのかといったところは、これから勉強していきたいと思います。