LoginSignup
4
2

More than 3 years have passed since last update.

[EKS] Cronjob経由でpodからAWSリソースへのアクセスとkubectlを実行したい

Last updated at Posted at 2021-03-14

はじめに

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
---

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2