はじめに
Kubernetesの Cronjob経由のPodでkubectlコマンドを実行したり、AWSリソースへアクセスする方法についてのメモです。
やりたいことは以下の通りです。
- 定期的にkubectlコマンドを実行し、結果をAWSのcloudwatchのカスタムメトリクスへ送信する
ポイントは以下の5点です
- aws cliとkubectlを実行できるコンテナイメージの作成
- awsリソースを操作する権限
- kubectlリソースを操作する権限
- cloud watchへカスタムメトリクスの送信
- cron jobの実行
aws cliとkubectlを実行できるコンテナイメージの作成
aws cliはamazonに公式のイメージがあります。
https://hub.docker.com/r/amazon/aws-cli
これにkubectlを追加するのが良さそうです。
FROM amazon/aws-cli:latest
RUN yum update -y \
&& curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" \
&& chmod +x kubectl \
&& mv kubectl /usr/local/bin/
ENTRYPOINT [""]
kubectlだけ実行したい人はalpineにkubectlを追加した方がイメージが軽くなると思います。
※最初にこの方法で進めてたら、aws cliはalpineをサポート対象に含まれていないのと、
動かすにはpythonやらglibcやらと結局イメージ膨れそうなので、amazonの公式イメージにしました。
FROM alpine
RUN apk add --no-cache --virtual=build wget \
&& wget https://storage.googleapis.com/kubernetes-release/release/v1.20.0/bin/linux/amd64/kubectl \
&& mv kubectl /usr/local/bin/ \
&& chmod +x /usr/local/bin/ \
&& apk del build
各イメージサイズはこんな感じです。
# docker images | sort master
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest 28f6e2705743 2 weeks ago 5.61MB
alpine-with-kubectl latest 0f52e434f905 6 minutes ago 45.9MB
amazon/aws-cli latest 19790bab4269 4 days ago 298MB
aws-cli-with-kubectl latest f7b960da07f6 3 hours ago 534MB
ECRへpushしておく
# aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com
Login Succeeded
# docker build -t xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/nodestatus-check:latest .
# docker push xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/nodestatus-check
awsリソースを操作する権限
これはNodeに付与するIAMRoleで制御できました。
kubectl/EKSリソースを操作する権限
そのまま試したらNGでした。
defaultのservice accountが使われるようで、そのアカウントに権限がないみたいです。
kubectl run -it aws-cli-test --image=amazon/aws-cli:latest --command '/bin/bash'
bash-4.2#
bash-4.2# curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" \
> && chmod +x kubectl \
> && mv kubectl /usr/local/bin/
bash-4.2# kubectl get node
Error from server (Forbidden): nodes is forbidden: User "system:serviceaccount:default:default" cannot list resource "nodes" in API group "" at the cluster scope
新たにservice accountを作成して、rbacのcluster role bindingに追加してあげる
# kubectl create sa aws-cli
serviceaccount/aws-cli created
# kubectl edit clusterrolebinding -n kube-system cluster-admin
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
~~
- kind: ServiceAccount
name: aws-cli
namespace: default
そうすると見えるようになる。
ただ、 軽く調べたらOpenID Connect (OIDC) ID を使うのが正攻法みたいです。
# kubectl run -it aws-cli-test --image=amazon/aws-cli:latest --command '/bin/bash' --serviceaccount=aws-cli
If you don't see a command prompt, try pressing enter.
bash-4.2#
bash-4.2# kubectl get node
NAME STATUS ROLES AGE VERSION
ip-10-0-2-99.ap-northeast-1.compute.internal Ready <none> 18d v1.17.12-eks-7684af
ip-10-0-3-144.ap-northeast-1.compute.internal Ready <none> 18d v1.17.12-eks-7684af
bash-4.2# kubectl get pod | grep aws-cli
aws-cli-test 1/1 Running 0 2m25s
cloud watchへカスタムメトリクスの送信
aws cliが使えれば送れます。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudwatch-custom-metrics/
因みにやりたかったことは、NodeのステータスがたまにNotReadyになってて、何か気づく術が欲しかったのが発端です。
AWSへ問い合わせたら、prometheus入れて kube-state-metrics 入れたらメトリクス取れるよ。と言われましたが、途中で断念しました。
nodestatus=$(kubectl get node | grep Ready | wc -l)
aws cloudwatch put-metric-data --metric-name notready_count --dimensions ClusterName=eks-cluster --namespace "ContainerInsights" --value $nodestatus
cron jobの実行
config mapで実行したいscriptを書いて、cronjob側で読み込みます。
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: nodecheck
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
serviceAccountName: aws-cli
containers:
- name: nodecheck
image: xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/nodestatus-check:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh"]
args: ["/root/entrypoint.sh"]
volumeMounts:
- name: entrypoint
mountPath: /root
restartPolicy: OnFailure
volumes:
- name: entrypoint
configMap:
name: node-status-check
---
apiVersion: v1
kind: ConfigMap
metadata:
name: node-status-check
data:
entrypoint.sh: |-
#!/bin/sh
nodestatus=$(kubectl get node | grep Ready | wc -l)
aws cloudwatch put-metric-data --metric-name Eks_node_notready_count --dimensions ClusterName=eks-cluster --namespace "ContainerInsights" --value $nodestatus
---