Amazon EKSのPrivate ClusterでContainer Insightsを動かす(インターネット接続不可環境)

この記事はBeeX Advent Calendar 2020の12/4の記事です。

直接インターネット接続不可の環境に構築したEKSのPrivate ClusterでContainer Insightsを動かそうとしたら、ハマりどころが多かったので残しておきます。

前提

Private Cluster作成後、必要なVPC Endpointが作成されていることが前提となります。VPC Endpointは以下に記載があります。

docs.aws.amazon.com

方針

当然、AWSの公式ドキュメントにもContainer Insightsの設定方法の記載はあります。ただ、Private Clusterには対応していなかったので、手順に調整が必要になります。

手順を一つ一つ説明するのも膨大なので、こちらのクイックスタートを調整する形にしたいと思います。

Amazon EKS および Kubernetes の Container Insights のクイックスタートセットアップ - Amazon CloudWatch

クイックスタートは本当にクイックで以下のワンライナー実行でデプロイ終わりです。(Private Clusterでは動きません)

curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluentd-quickstart.yaml | sed "s/{{cluster_name}}/cluster-name/;s/{{region_name}}/cluster-region/" | kubectl apply -f -

内部的には以下のファイルをダウンロードして一部置換して kubectl apply しています。これを書いている時点では Gitタグが 1.2.4 が最新なので、このファイルの中身を修正してPrivate Clusterで動くContainer Insightsの定義に変更していこうと思います。

https://github.com/aws-samples/amazon-cloudwatch-container-insights/blob/k8s/1.2.4/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluentd-quickstart.yaml

Container Insights設定事前作業

Service AccountとIAM Role作成

こちらの記事に記載したスクリプトを利用して作成します。

Amazon EKSのService Accountをawscliやkubectl使ったスクリプトで作成する - YOMON8.NET

CLUSTER_NAME=my-cluster 
SA_NAMESPACE=amazon-cloudwatch
SA_NAME=cloudwatch-agent
/bin/bash ./create_service_account.sh ${CLUSTER_NAME} ${SA_NAMESPACE} ${SA_NAME}

このために作ったスクリプトでないので、最後にnamespace無いとエラー出ますが無視します。

Error from server (NotFound): error when creating "STDIN": namespaces "amazon-cloudwatch" not found

IAM RoleにCloudWatch送信用ポリシーをアタッチ

上記のスクリプトでは eks-role-my-cluster-amazon-cloudwatch-cloudwatch-agent というロールが作成されたので、ここに CloudWatchAgentServerPolicy のポリシーをアタッチします。

QuickStartダウンロード

まずは方針でも書いた通りQuickStartのManufestをダウンロードして、これを調整していきます。

curl -o my-cwagent-fluentd.yaml https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/k8s/1.2.4/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluentd-quickstart.yaml

Dockerイメージ整理

Docker Hubも使えない状態を想定しますので、ECRに必要なイメージを入れておきます。

必要なイメージは先程ダウンロードしたyamlファイルから抽出できます。

$ cat my-cwagent-fluentd.yaml | grep image:
          image: amazon/cloudwatch-agent:1.247346.0b249609
          image: busybox
          image: busybox
          image: fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-cloudwatch-1.0

ということで以下のようにEKSから接続できないDockerHubからECRに移動してきます。

説明の簡素化のためにECRの方はlatestタグ使ってますが、適宜変更してください。

DockerHub mv ECR
amazon/cloudwatch-agent:1.247346.0b249609 {ECR}/cw-insight/busybox:latest
busybox{ECR} {ECR}/cw-insight/cloudwatch-agent:latest
fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-cloudwatch-1.0 {ECR}/cw-insight/fluentd-kubernetes-daemonset:latest

ECR側にRepositoryを作っておきます。

f:id:yomon8:20201201225127p:plain

Dockerイメージ移動

上記で整理した通り移動してきます。この作業はDockerHubに接続可能な端末で実施する必要があります。

ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
AWS_REGION=ap-northeast-1
ECR_REPO_BASE=${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com

SRC=amazon/cloudwatch-agent:1.247346.0b249609
TGT=${ECR_REPO_BASE}/cw-insight/cloudwatch-agent:latest
docker pull ${SRC} && docker tag ${SRC} ${TGT} && docker push ${TGT}

SRC=fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-cloudwatch-1.0
TGT=${ECR_REPO_BASE}/cw-insight/fluentd-kubernetes-daemonset
docker pull ${SRC} && docker tag ${SRC} ${TGT} && docker push ${TGT}

SRC=busybox
TGT=${ECR_REPO_BASE}/cw-insight/busybox
docker pull ${SRC} && docker tag ${SRC} ${TGT} && docker push ${TGT}

Container Insights用マニュフェスト作成

Cluster名とRegionを設定

まずはQuickstartの手順にもある、クラスタ名とリージョン名を置換します。

CLUSTER_NAME=my-cluster
AWS_REGION=ap-northeast-1
sed -i.org "s/{{cluster_name}}/${CLUSTER_NAME}/;s/{{region_name}}/${AWS_REGION}/" my-cwagent-fluentd.yaml 

その他の変更点整理

その他と言いながらこの項目がこの記事の一番重要ポイントになります。

ServiceAccountの変更点

Service Accountに先程作成したロールを紐付けます。

 apiVersion: v1
 kind: ServiceAccount
 metadata:
   name: cloudwatch-agent
   namespace: amazon-cloudwatch
+  annotations:
+    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/eks-role-my-cluster-amazon-cloudwatch-cloudwatch-agent
Podの変更点

大きく分けて二つの変更点があります。一つはイメージの取得元をECRに変更すること。もう一つはstsのendpointをVPC Endpointに向けるための以下の設定です。

AWS_STS_REGIONAL_ENDPOINTS=regional

この設定が無いとインターネットにstsのエンドポイントを見に行こうとして以下のようなタイムアウトのメッセージになります。

caused by: RequestError: send request failed
caused by: Post "https://sts.amazonaws.com/": dial tcp 54.239.21.217:443: i/o timeout

この辺りが参考になります。

docs.aws.amazon.com

その他の実際の変更箇所

以下、変更箇所を見ていきます。

Busybox

Busyboxはイメージの宛先を変更します。

       initContainers:
         - name: copy-fluentd-config
-          image: busybox
+          image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/cw-insight/busybox
           command: ['sh', '-c', 'cp /config-volume/..data/* /fluentd/etc']
           volumeMounts:
             - name: config-volume
               mountPath: /config-volume
             - name: fluentdconf
               mountPath: /fluentd/etc
         - name: update-log-driver
-          image: busybox
+          image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/cw-insight/busybox
           command: ['sh','-c','']
cloudwatch-agent

cloudwatch-agentはイメージをECRから取得する変更と、AWS_STS_REGIONAL_ENDPOINTSの設定を行います。

 apiVersion: apps/v1
 kind: DaemonSet
 metadata:
   name: cloudwatch-agent
   namespace: amazon-cloudwatch
 spec:
   selector:
     matchLabels:
       name: cloudwatch-agent
   template:
     metadata:
       labels:
         name: cloudwatch-agent
     spec:
       containers:
         - name: cloudwatch-agent
-          image: amazon/cloudwatch-agent:1.247346.0b249609
+          image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/cw-insight/cloudwatch-agent:latest
           #ports:
           #  - containerPort: 8125
           #    hostPort: 8125
           #    protocol: UDP
           resources:
             limits:
               cpu:  200m
               memory: 200Mi
             requests:
               cpu: 200m
               memory: 200Mi
           # Please don't change below envs
           env:
+            - name: AWS_STS_REGIONAL_ENDPOINTS
+              value: regional
             - name: HOST_IP
               valueFrom:
                 fieldRef:
                   fieldPath: status.hostIP
fluentd-cloudwatch

fluentd-cloudwatchもイメージをECRから取得する変更と、AWS_STS_REGIONAL_ENDPOINTSの設定を行います。

         - name: fluentd-cloudwatch
-          image: fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-cloudwatch-1.0
+          image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/cw-insight/fluentd-kubernetes-daemonset
           env:
+            - name: AWS_STS_REGIONAL_ENDPOINTS
+              value: regional
             - name: AWS_REGION
               valueFrom:
                 configMapKeyRef:
                   name: cluster-info
                   key: logs.region

デプロイ

後はマニュフェストファイルをApplyするだけです。ここまでの手順が合っていれば、ここはあっさりいくはずです。

$ kubectl apply -f my-cwagent-fluentd.yaml 
namespace/amazon-cloudwatch created
serviceaccount/cloudwatch-agent created
clusterrole.rbac.authorization.k8s.io/cloudwatch-agent-role created
clusterrolebinding.rbac.authorization.k8s.io/cloudwatch-agent-role-binding created
configmap/cwagentconfig created
daemonset.apps/cloudwatch-agent created
configmap/cluster-info created
serviceaccount/fluentd created
clusterrole.rbac.authorization.k8s.io/fluentd-role created
clusterrolebinding.rbac.authorization.k8s.io/fluentd-role-binding created
configmap/fluentd-config created
daemonset.apps/fluentd-cloudwatch created

DaemonSetなので2Pod/NodeのPodが立ち上がります。

$ kubectl get po -n amazon-cloudwatch
NAME                       READY   STATUS    RESTARTS   AGE
cloudwatch-agent-bj7fw     1/1     Running   0          46s
cloudwatch-agent-ph74f     1/1     Running   0          46s
fluentd-cloudwatch-qlb86   1/1     Running   0          46s
fluentd-cloudwatch-vwkqr   1/1     Running   0          46s

Container Insightsの画面を見ると、情報取得できてそうです。

f:id:yomon8:20201201232827p:plain

f:id:yomon8:20201201233032p:plain

追記)ログが取得できない

AWSからダウンロードしてきたマニュフェストのfluentd-kubernetes-daemonsetのバージョン( fluent/fluentd-kubernetes-daemonset:v1.7.3-debian-cloudwatch-1.0 ) だとサービスアカウントの認証に対応してないようです。

新しいイメージを落としてくると動きます。

hub.docker.com

以下のイメージで動作確認しました。

fluent/fluentd-kubernetes-daemonset:v1.11.5-debian-cloudwatch-1.0

CloudWatch Logsで以下のように、Performance以外のログも表示されるようになります。

f:id:yomon8:20210306012431p:plain

Container Insightsからは以下のようにアイテム選ぶと「ログを表示」がクリックできるようになります。クリックするとCloudWatch Logs Insightsに飛びます。

f:id:yomon8:20210306012659p:plain

掃除

もし削除したくなったら、 kubectl delete 使えば一気に関連項目を削除可能です。

$ kubectl delete -f my-cwagent-fluentd.yaml 
namespace "amazon-cloudwatch" deleted
serviceaccount "cloudwatch-agent" deleted
clusterrole.rbac.authorization.k8s.io "cloudwatch-agent-role" deleted
clusterrolebinding.rbac.authorization.k8s.io "cloudwatch-agent-role-binding" deleted
configmap "cwagentconfig" deleted
daemonset.apps "cloudwatch-agent" deleted
configmap "cluster-info" deleted
serviceaccount "fluentd" deleted
clusterrole.rbac.authorization.k8s.io "fluentd-role" deleted
clusterrolebinding.rbac.authorization.k8s.io "fluentd-role-binding" deleted
configmap "fluentd-config" deleted
daemonset.apps "fluentd-cloudwatch" deleted

最後に

ちょうど昨日のAWS re:Invent 2020でEKSの管理画面が拡張されました。Container Insightsほどでは無いですが、PodやNodeの状態が見られるようになりました。

Amazon EKS Console Now Includes Kubernetes Resources to Simplify Cluster Management

IAMにRBACマッピングすれば、Private Clusterでも使えることが確認できました。今までは管理画面を使うことほとんど無かったですが、ちょっと中身見るような時にはこちらも使えそうです。

f:id:yomon8:20201202085233p:plain