EKS を触って何となく仕組みを理解する

# eksctl のインストール

https://github.com/weaveworks/eksctl/blob/main/README.md#installation

ドキュメントを参考に各環境に応じた　eksctl　をインストールします。

eksctl がインストールされたことを確認します。

```
eksctl version
``` 

# kubectl のインストール

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/install-kubectl.html

ドキュメントを参考に各環境に応じた　kubectl　をインストールします。

kubectl がインストールされたことを確認します。

```
kubectl version --short --client
```

# 各ツールのインストール

https://catalog.us-east-1.prod.workshops.aws/workshops/f5abb693-2d87-43b5-a439-77454f28e2e7/ja-JP/020-create-cluster/30-configure-useful-tools

必要に応じて、Kubernetes の利用の際によく使われるいくつかの便利なツールの導入と、コマンド補完の設定をします。

# クラスター

https://eksctl.io/usage/creating-and-managing-clusters/

次の通り、クラスターを作成するための　cluster.yaml ファイルを準備します。

※コストを抑えるために小さいノードを使用しています。
 また、既存の VPC に作成することも可能です、上記ドキュメントを参考にするか、記事の後半をご確認ください。

```cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-cluster
  region: ap-northeast-1
  version: "1.25"

nodeGroups:
  - name: eks-ng
    instanceType: t3.small
    desiredCapacity: 1 
```

次のコマンドを実行する事でクラスターが作成されます。

```
eksctl create cluster -f cluster.yaml
```

動いているノードを確認。

```
$ kubectl get node
NAME                                                STATUS   ROLES    AGE     VERSION
ip-192-168-92-235.ap-northeast-1.compute.internal   Ready    <none>   2m40s   v1.25.7-eks-a59e1f0
```

EC2 の料金が課金されるので利用しない場合は次のコマンドで、ノードを削除できます。

```
$ eksctl delete nodegroup -f cluster.yaml --approve
```

# Pod

https://kubernetes.io/ja/docs/concepts/workloads/pods/

nginx コンテナを起動する nginx.yaml ファイルを作成します。

```nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx:latest
    name: nginx
  restartPolicy: Always
```

kubectl apply　で　pod をデプロイします。

```
$ kubectl apply -f nginx.yaml 
pod/nginx created
```

実際に、pod が起動したことを確認します。

```
$ kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          89s
```

# NodePort

https://kubernetes.io/ja/docs/concepts/services-networking/service/#nodeport

nginx。yaml ファイルに　Service を追加します。

```nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  # selector に合わせることで そのリソースと紐づく
  labels:
    app: nginx
spec:
  containers:
  - image: nginx:latest
    name: nginx
  restartPolicy: Always


apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  # labels に合わせることで そのリソースと紐づく
  selector:
    app: nginx
  type: NodePort
```

kubectl apply　で　service をデプロイします。

```
$ kubectl apply -f nginx.yaml 
service/nginx created
```

NodePort が起動したことを確認します。

```
$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.100.0.1       <none>        443/TCP        7h43m
nginx        NodePort    10.100.178.212   <none>        80:31142/TCP   7s
```

以下コマンドで node の詳細な情報を確認し、X.X.X.X:31142 にアクセスする事で　nginx の画面が表示されるということになります。（セキュリティグループでポート解放する必要有り）

```
$ kubectl get node -o wide
NAME                                                STATUS   ROLES    AGE     VERSION               INTERNAL-IP      EXTERNAL-IP     OS-IMAGE         KERNEL-VERSION                  CONTAINER-RUNTIME
ip-192-168-42-127.ap-northeast-1.compute.internal   Ready    <none>   7h39m   v1.25.7-eks-a59e1f0   192.168.42.127   X.X.X.X   Amazon Linux 2   5.10.178-162.673.amzn2.x86_64   containerd://1.6.19
```

# AWS Load Balancer Controller

https://eksctl.io/usage/iam-policies/

ノードにIAMポリシーを追加した cluster.yaml ファイルを準備する。

```cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-cluster
  region: ap-northeast-1
  version: "1.25"

nodeGroups:
  - name: eks-ng
    instanceType: t3.small
    desiredCapacity: 1
    # AWS Load Balancer Controller を動かすための IAMポリシーを設定します。
    iam: 
      withAddonPolicies: 
        awsLoadBalancerController: true
```

ノードをデプロイする。

```
$ eksctl create nodegroup -f cluster.yaml
```

Pod をデプロイする。

```
$ kubectl apply -f nginx.yaml 
pod/nginx created
```

次のページを参考に AWS Load Balancer Controller をインストールする。

https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.5/deploy/installation/#add-controller-to-cluster

AWS Load Balancer Controller が作成されたことを確認する。

```
$ kubectl get pods -n kube-system
NAME                                            READY   STATUS    RESTARTS   AGE
aws-load-balancer-controller-7b66fb998b-twkgf   1/1     Running   0          20m
```

ALB をデプロイするための　Ingress　を作成します。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/alb-ingress.html

```nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
  annotations:
    # AWS Load Balancer Controller の設定内容を記述する
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
spec:
  rules:
  - http:
      paths:
      - backend:
          service:
            name: nginx
            port:
              number: 80
        path: /
        pathType: Prefix
```

kubectl apply で　Ingress　をデプロイします。

```
$ kubectl apply -f nginx-ingress.yaml
ingress.networking.k8s.io/nginx created
```

次のコマンドでALBのDNS名を確認し、curl やブラウザなどでアクセスできることを確認します。

```
aws elbv2 describe-load-balancers --query 'LoadBalancers[].DNSName[]'
```

# ヘルスチェック

https://kubernetes.io/ja/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

次の通り nginx.yaml ファイルを作成します。

```nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - image: nginx:latest
    name: nginx
    # Pod が正常に起動しているか確認する。
    livenessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      timeoutSeconds: 1
      periodSeconds: 10
      failureThreshold: 3
    # Pod がサービスインする準備ができているかを確認する。
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      timeoutSeconds: 1
      periodSeconds: 10
      failureThreshold: 3
  restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort
```

kubectl apply　で　pod をデプロイします。

```
$ kubectl apply -f nginx.yaml
```

kubectl describe で Pod の詳細設定を確認します。 

```
$ kubectl describe pods nginx
    Liveness:       http-get http://:80/ delay=5s timeout=1s period=10s #success=1 #failure=3
    Readiness:      http-get http://:80/ delay=5s timeout=1s period=10s #success=1 #failure=3
```

動作確認をするために、別タブで -w オプションで、Pod の状態を確認します。

```
$ kubectl get pods -w
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          7m33s
```

kubectl exec　で、Pod の中に入り、擬似的に、Pod を終了させます。

```
$ kubectl exec nginx -it /bin/sh
# rm /usr/share/nginx/html/index.html
```

別のタブで開いていた、Pod　の状態を確認すると新しい　Pod が起動したことが確認できます。

```
$ kubectl get pods -w
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          7m33s
nginx   0/1     Running   0          8m
nginx   0/1     Running   1 (2s ago)   8m3s
nginx   1/1     Running   1 (9s ago)   8m10s
```

# Deployment

https://kubernetes.io/ja/docs/concepts/workloads/controllers/deployment/

次の通り nginx.yaml ファイルを作成します。

```nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  # nginx という　Deployment　が作成されます。
  name: nginx
spec:
  # 1 つのレプリカ　Pod　を作成します。
  replicas: 1
  selector:
    # Deployment が管理する Pod のラベルを定義。
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 3
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort
```

kubectl apply　で　デプロイします。

```
$ kubectl apply -f nginx.yaml
```

Deployment と　Pod の状態を確認します。

```
$ kubectl get deployment
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           81s

$ kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
nginx-84fdd6fdbd-lqzj5   1/1     Running   0          60s
```

# HPA

下記のページを参考に、metrics-server をインストールします。

https://github.com/kubernetes-sigs/metrics-server

kubectl top コマンドで、ノードの CPU や　memory の状態が見れることを確認します。

```
$ kubectl top node
NAME                                                CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
ip-192-168-37-209.ap-northeast-1.compute.internal   45m          2%     635Mi           43%  
```

次の通り nginx.yaml ファイルを作成します。

```nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 3
        # 1 コア　の　1/10 の値を要求する。
        resources:
          requests:
            cpu: 100m
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort
```

Pod　レプリカ数を　1　から　10　の間に維持する　HPA を作成します。

```
$ kubectl autoscale deployment nginx --cpu-percent 50 --min 1 --max 10
horizontalpodautoscaler.autoscaling/nginx autoscaled
```

HPA　の状態を確認します。

```
$ kubectl get hpa
NAME    REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
nginx   Deployment/nginx   1%/50%    1         10        1          21m
```

apache-bench コンテナで負荷をかけ、Pod がスケールするか確認します。

```
$ kubectl run apache-bench -i --tty --rm --image httpd -- /bin/sh 
If you don't see a command prompt, try pressing enter.
while true;
> do ab -n 10 -c 10 http://nginx.default.svc.cluster.local/ > /dev/null;
> done
```

Pod または　HPA の動作を確認します。

```
$ kubectl get pod -w
NAME                     READY   STATUS    RESTARTS   AGE
apache-bench             1/1     Running   0          3m47s
nginx-6c85484665-t9n4g   1/1     Running   0          14m
nginx-6c85484665-xb5jv   0/1     Pending   0          0s
nginx-6c85484665-xb5jv   0/1     Pending   0          0s

$ kubectl get hpa -w
NAME    REFERENCE          TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
nginx   Deployment/nginx   150%/50%   1         10        4          34m
nginx   Deployment/nginx   162%/50%   1         10        4          34m
nginx   Deployment/nginx   163%/50%   1         10        4          35m
```

# Cluster Autoscaler

次の通り、1〜3 までスケールする、cluster.yaml　を作成します。

```cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-cluster
  region: ap-northeast-1
  version: "1.22"

nodeGroups:
  - name: eks-ng
    instanceType: t3.small
    desiredCapacity: 1
    # 最小１/最大のノード数を指定。
    minSize: 1
    maxSize: 3
    iam:
      withAddonPolicies:
        awsLoadBalancerController: true
        # AutoScaler を利用できるように設定を追加。
        autoScaler: true
```

次のページにある通り、cluster-autoscaler.yaml を準備します。

https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

```cluster-autoscaler-autodiscover.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
  name: cluster-autoscaler
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["events", "endpoints"]
    verbs: ["create", "patch"]
  - apiGroups: [""]
    resources: ["pods/eviction"]
    verbs: ["create"]
  - apiGroups: [""]
    resources: ["pods/status"]
    verbs: ["update"]
  - apiGroups: [""]
    resources: ["endpoints"]
    resourceNames: ["cluster-autoscaler"]
    verbs: ["get", "update"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["watch", "list", "get", "update"]
  - apiGroups: [""]
    resources:
      - "pods"
      - "services"
      - "replicationcontrollers"
      - "persistentvolumeclaims"
      - "persistentvolumes"
    verbs: ["watch", "list", "get"]
  - apiGroups: ["extensions"]
    resources: ["replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["policy"]
    resources: ["poddisruptionbudgets"]
    verbs: ["watch", "list"]
  - apiGroups: ["apps"]
    resources: ["statefulsets", "replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses", "csinodes"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["batch", "extensions"]
    resources: ["jobs"]
    verbs: ["get", "list", "watch", "patch"]
  - apiGroups: ["coordination.k8s.io"]
    resources: ["leases"]
    verbs: ["create"]
  - apiGroups: ["coordination.k8s.io"]
    resourceNames: ["cluster-autoscaler"]
    resources: ["leases"]
    verbs: ["get", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["create","list","watch"]
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"]
    verbs: ["delete", "get", "update", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    app: cluster-autoscaler
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cluster-autoscaler
  template:
    metadata:
      labels:
        app: cluster-autoscaler
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '8085'
    spec:
      serviceAccountName: cluster-autoscaler
      containers:
        # kubernetes のバージョンに合わせる。
        - image: k8s.gcr.io/autoscaling/cluster-autoscaler:v1.25.6
          name: cluster-autoscaler
          resources:
            limits:
              cpu: 100m
              memory: 600Mi
            requests:
              cpu: 100m
              memory: 600Mi
          command:
            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --expander=least-waste
            # 環境のクラスター名前に変更。
            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/eks-cluster
          volumeMounts:
            - name: ssl-certs
              mountPath: /etc/ssl/certs/ca-certificates.crt #/etc/ssl/certs/ca-bundle.crt for Amazon Linux Worker Nodes
              readOnly: true
          imagePullPolicy: "Always"
      volumes:
        - name: ssl-certs
          hostPath:
            path: "/etc/ssl/certs/ca-bundle.crt"
```

kubectl apply　で　　cluster-autoscaler　をデプロイします。

```
$ kubectl apply -f cluster-autoscaler-autodiscover.yaml
```

cluster-autoscaler　が作成されたことを確認します。

```
$ kubectl get pods -n kube-system
NAME                                            READY   STATUS             RESTARTS   AGE
cluster-autoscaler-7c44b7fc58-7pllg             0/1     ImagePullBackOff   0          106s
```

kubectl apply　で　Pod をデプロイしておく。

```
$ kubectl apply -f nginx.yaml
```

Podレプリカを、10 にスケールさせてクラスターがスケールするか確認してみます。

```
$　kubectl scale deployment --replicas 10 nginx
deployment.apps/nginx scaled
```

クラスターがスケールしていることを確認します。

```
$ kubectl get node
NAME                                                STATUS   ROLES    AGE   VERSION
ip-192-168-35-58.ap-northeast-1.compute.internal    Ready    <none>   30m   v1.25.7-eks-0a21954
ip-192-168-77-129.ap-northeast-1.compute.internal   Ready    <none>   32s   v1.25.7-eks-0a21954
```

# ConfigMap

https://kubernetes.io/ja/docs/concepts/configuration/configmap/

.env ファイルに環境変数を作成する。

```.env
ENV=dev
```

configmap を作成する。

```
$ kubectl create configmap eks-cluster --from-env-file=.env
configmap/eks-cluster created
```

作成された configmap を確認する。

```
$ kubectl describe configmap eks-cluster
Name:         eks-cluster
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
ENV:
----
dev
```

nginx.yaml　では次の通り、環境変数を読み込むように設定する。

```nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        # 環境変数を設定する。
        envFrom:
          - configMapRef:
              name: eks-cluster
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 3
        resources:
          requests:
            cpu: 100m
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort
```

nginx.yaml をデプロイする。

```
$ kubectl apply -f nginx.yaml
```

Pod名を確認する。

```
$ kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
nginx-c97746c48-785dz   1/1     Running   0          18s
```

Pod に　exec　でコンテナの中に入り、環境変数を確認する。

```
$ kubectl exec -it nginx-c97746c48-785dz env
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=nginx-c97746c48-785dz
TERM=xterm
ENV=dev
```

なお、envファイルを編集した場合は、Pod を再起動する必要がある。

```
$ kubectl rollout restart deployment/nginx
```

Pod名を確認する。

```
$ kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
nginx-b9d6884ff-qrgbr   1/1     Running   0          32s
```

Pod に　exec　でコンテナの中に入り、環境変数が変更されているか確認する。

```
$ kubectl exec -it nginx-b9d6884ff-qrgbr env
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=nginx-b9d6884ff-qrgbr
TERM=xterm
ENV=stg
```

# Secret

https://kubernetes.io/ja/docs/concepts/configuration/secret/

secret情報を作成する。ここでは、DB の　USER と　PASS を作成してみます。

```
$ kubectl create secret generic eks-cluster --from-literal=DB_USER=root --from-literal=DB_PASS=pass
secret/eks-cluster created
```

secret情報を確認する。

```
$ kubectl describe secret eks-cluster
DB_PASS:  4 bytes
DB_USER:  4 bytes
```

secret 情報は以下のコマンドで確認できます。

```
$ kubectl get secret eks-cluster -o yaml
apiVersion: v1
data:
  DB_PASS: cGFzcw==
  DB_USER: cm9vdA==
kind: Secret
metadata:
  creationTimestamp: "2023-05-21T05:53:26Z"
  name: eks-cluster
  namespace: default
  resourceVersion: "576461"
  uid: afc2cee0-7e84-4fdc-9985-04d79993ddf3
type: Opaque
```

base64 にデコードする事で、Secret の実際の　value を確認できます。

```
$ echo 'cGFzcw==' | base64 --decode 
pass
```

nginx.yaml ファイルには、configMap と同じように、secret に記載します。

```nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        # 環境変数を設定する。
        envFrom:
          - configMapRef:
              name: eks-cluster
          - secretRef:
              name: eks-cluster
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 3
        resources:
          requests:
            cpu: 100m
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: NodePort
```

kubectl apply　で　デプロイします。

```
$ kubectl apply -f nginx.yaml
deployment.apps/nginx configured
service/nginx unchanged
```

Pod名を確認する。

```
$ kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
nginx-c98f99b4c-ppg5x   1/1     Running   0          13s
```

Pod に　exec　でコンテナの中に入り、環境変数が設定されているか確認する。

```
$ kubectl exec -it nginx-c98f99b4c-ppg5x env
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=nginx-c98f99b4c-ppg5x
TERM=xterm
ENV=stg
DB_PASS=pass
DB_USER=root
```

# CloudWatch Container Insights

cluster.yaml　を　cloudWatch の権限を追加したものに編集。

```cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-cluster
  region: ap-northeast-1
  version: "1.24"

nodeGroups:
  - name: eks-ng
    instanceType: t3.small
    desiredCapacity: 1
    minSize: 1
    maxSize: 3
    iam:
      withAddonPolicies:
        awsLoadBalancerController: true
        autoScaler: true
        # cloudWatch の権限を追加。
        cloudwatch: true
```

次のページの通り、Container Insights をデプロイする。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-quickstart.html

後は、CloudWatch から Container Insights　でメトリクス、ロググループなどを確認してみましょう。

なお、ロググループには次のようなロググループが作成されるようです。

`
/aws/containerinsights/eks-cluster/application
/aws/containerinsights/eks-cluster/dataplane
/aws/containerinsights/eks-cluster/host
/aws/containerinsights/eks-cluster/performance
`

# アプリケーションのデプロイ

自身で作成したアプリケーションをデプロイしてみたいと思います。

まず、必要な環境を準備します。

```
$ node -v
v16.20.0

$ mkdir nodejs && cd nodejs

$ npm init -y

$ npm install express --save
```

サンプルアプリケーションの準備。

```app.js
const express = require('express');
const app = express();

app.get('/', (req, res) => res.send('Hello World!'));
app.listen(3000, () => console.log('Example app listening on port 3000'));
```

ローカルで動作確認。

```
$ node app.js

$ curl http://localhost:3000
```

Dockerfile を作成。

```Dockerfile:Dockerfile
FROM node:14-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "node", "app.js" ]
```

コンテナの準備と動作確認。

```
$ docker build -t node-web-app:latest

$ docker images
REPOSITORY     TAG         IMAGE ID       CREATED              SIZE
node-web-app   latest      df7248480cfc   About a minute ago   122MB

$ docker run -d -p 3000:3000 node-web-app:latest
f28581312123a0e95c0fac891c4b0fb1fcad4f2ff876394e104314af3a68218a

$ curl http://localhost:3000
Hello World!
```

コンテナイメージの作成、ログイン、push。

```
$ docker build -t XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/node-web-app:1.0 .

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com 

$ aws ecr create-repository --repository-name node-web-app --region ap-northeast-1

$ docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/node-web-app:1.0
```

node-web-app.yaml を次の通り用意。

```node-web-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: node-web-app
  name: node-web-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-web-app
  strategy: {}
  template:
    metadata:
      labels:
        app: node-web-app
    spec:
      containers:
        #ECRにpushしたイメージを指定。
      - image: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/node-web-app:1.0
        name: node-web-app
        resources: {}
```

apply　し、pod　の起動を確認。

```kubectl
$ kubectl apply -f node-web-app.yaml
deployment.apps/node-web-app created

$ kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
node-web-app-5fdc988f58-4ljj2   1/1     Running   0          2m38s
```

# ユーザー管理

EKS のリソースを作成したIAMユーザーやIAMロールには、Kubernetess上の管理者権限が付与されます。他のIAMユーザーやIAMロールにKubernetessの権限を与えるには、別途操作が必要です。

現状を確認してみます。

```
$ eksctl get iamidentitymapping --cluster eks-cluster
ARN                                                                                             USERNAME                                GROUPS                                  ACCOUNT
arn:aws:iam::XXXXXXXXXXXX:role/eksctl-eks-cluster-nodegroup-eks-NodeInstanceRole-XXXXXXXXXXXX  system:node:{{EC2PrivateDNSName}}       system:bootstrappers,system:nodes
```

現在は、cloudshell から、eks-user　で操作。

```json
$ aws sts get-caller-identity 
{
    "Account": "XXXXXXXXXXXX", 
    "UserId": "XXXXXXXXXXXX", 
    "Arn": "arn:aws:iam::XXXXXXXXXXXX:user/eks-user"
}
```

別に、cloud９ を起動し、eks-role を別途用意。

```json
$ aws sts get-caller-identity                                                                                                                                                        
{
    "Account": "XXXXXXXXXXXX", 
    "UserId": "AXXXXXXXXXXXX:i-0XXXXXXXXXXX", 
    "Arn": "arn:aws:sts::XXXXXXXXXXXX:assumed-role/eks-role/i-0XXXXXXXXXX"
}
```

ID マッピングを作成。

```
$ eksctl create iamidentitymapping --cluster eks-cluster --arn arn:aws:iam::XXXXXXXXXXXX:role/eks-role --group system:masters --username eks-admin
```

設定できたか確認。

```
$ eksctl get iamidentitymapping --cluster eks-cluster
ARN                                                                                             USERNAME                                GROUPS                                  ACCOUNT
arn:aws:iam::XXXXXXXXXXXX:role/eksctl-eks-cluster-nodegrou-NodeInstanceRole-XXXXXXXXXXXX system:node:{{EC2PrivateDNSName}}       system:bootstrappers,system:nodes
arn:aws:iam::XXXXXXXXXXXX:role/ekshandson-admin                                                 eks-admin                               system:masters
```

context を作成。

```
$ aws eks update-kubeconfig --region ap-northeast-1 --name eks-cluster
Added new context arn:aws:eks:ap-northeast-1:XXXXXXXXXXXX:cluster/eks-cluster to /home/ec2-user/.kube/config
```

cloud9 の　eks-role から操作可能なことを確認。

```
$ kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6c85484665-qsxkn   1/1     Running   0          63s
```

なお、次のようなエラーが表示された場合は、aws-cli のバージョンが古いため、ドキュメントを参考にaws-cli をアップデートしましょう。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

```
$ kubectl get pods
error: exec plugin: invalid apiVersion "client.authentication.k8s.io/v1alpha1"
```

```
$ aws --version
aws-cli/2.11.26 Python/3.11.3 Linux/4.14.314-238.539.amzn2.x86_64 exe/x86_64.amzn.2 prompt/off
```

# 既存のVPCに構築する

既存の VPC にタグづけをしておきましょう。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/network-load-balancing.html

- プライベートサブネット：kubernetes.io/role/elb=1
- パブリックサブネット：kubernetes.io/role/internal-elb=1

cluster.yaml　は次の通り作成しておきます。

```cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-cluster
  region: ap-northeast-1
  version: "1.25"

# vpc と　サブネットIDを指定。 
vpc:
  id: "vpc-XXX"
  subnets:
    private:
      eks-private-1:
        id: "subnet-XXX"
      eks-private-2:
        id: "subnet-XXX"
    public:
      eks-public-1:
        id: "subnet-XXX"
      eks-public-2:
        id: "subnet-XXX"

nodeGroups:
  - name: eks-ng
    instanceType: t3.small
    desiredCapacity: 1
    # プライベートサブネットに作成するように指定。
    privateNetworking: true
    minSize: 1
    maxSize: 3
    iam:
      withAddonPolicies:
        awsLoadBalancerController: true
        autoScaler: true
        cloudWatch: true
```

クラスターを作成します。 

```
$ eksctl create cluster -f cluster.yaml
```

# EKSのアップデート

PDB(PodDisruptionBudget)　 
アップデートなどで意図的にノードを終了させる際に、最低限起動しておくべきPodの数を保証できる機能を作成しておきます。次の設定では最低限 1 は保証するということになります。

```pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: nginx
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: nginx
```

pdb をデプロイ。

```
$ kubectl apply -f pdb.yaml
```

作成されている事を確認。

```
$ kubectl get poddisruptionbudget.policy
NAME    MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
nginx   1               N/A               1                     2m21s
```

現在の Version を確認。

```
$ kubectl version --short
Flag --short has been deprecated, and will be removed in the future. The --short output will become the default.
Client Version: v1.26.4-eks-0a21954
Kustomize Version: v4.5.7
Server Version: v1.25.10-eks-c12679a
```

各アップデート。

```
$ eksctl upgrade cluster --name eks-cluster --approve

$ eksctl utils update-aws-node --name eks-cluster --approve

$ eksctl utils update-coredns --name eks-cluster --approve

$ eksctl utils update-kube-proxy --name eks-cluster --approve
```