使用 k8s cronjob 自動更新 aws ecr credentiails 認證

1. Before

aws ecr 使用都需要 credentials認證,才可以 pull/push鏡像,即使通過 docker login -u AWS -p <password> https://<aws_account_id>.dkr.ecr.<region>.amazonaws.com.cn 的方式登陸 ecr,獲得的token認證也只有 12h的有效期,對于CICD的要求來說無疑是一大障礙,因此下文采用 k8s cronjob/ secrets 的方式來保持token的更新及應(yīng)用部署過程中對私用鏡像的獲取。

2. 制作一個具有awsclikubectldocker image

此處Dockerfile 中使用的 base imagecentos7 ,想用小些的鏡像可自行下載,alpine 即可

[root@aws-172-20-20-101 aws-kubectl]# cat Dockerfile 
FROM centos:centos7
MAINTAINER xx.xx <xx.xx@xx.cn>

WORKDIR /opt/cronjob
RUN yum install -y awscli 
RUN mkdir ~/.aws &&\
      mkdir ./pki
# 若想使用 docker login 功能,則需安裝 docker-cli,docker-cli rpm 包需要提前下載好
#    mkdir ./pki &&\
#    mkdir ./docker
#COPY docker-ce-cli-18.09.5-3.el7.x86_64.rpm  ./docker/
#RUN  rpm -i ./docker/docker-ce-cli-18.09.5-3.el7.x86_64.rpm 
#COPY credentials config   ~/.aws/ # 將 aws 的認證信息復(fù)制到 ~/.aws/ 目錄下
COPY ca.crt admin.crt admin.key admin.kubeconfig ./pki/ # kubectl 訪問 k8s 集群需要用到的證書,build 鏡像前將證書都放在上下文同一路徑下
COPY kubectl /usr/local/bin
ENV PATH=/root/.local/bin:/usr/local/bin:$PATH
ENV KUBECONFIG=/opt/cronjob/pki/admin.kubeconfig

這里 kubectl 使用的證書格式如下,可根據(jù)自己環(huán)境使用方式做調(diào)整

[root@aws-172-20-20-101 aws-kubectl]# cat admin.kubeconfig 
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /opt/cronjob/pki/ca.crt
    server: https://xxxxx.com.cn:443
  name: default-cluster
contexts:
- context:
    cluster: default-cluster
    user: default-user
  name: default-context
current-context: default-context
kind: Config
preferences: {}
users:
- name: default-user
  user:
    client-certificate: /opt/cronjob/pki/admin.crt
    client-key: /opt/cronjob/pki/admin.key

build 鏡像,并 push 到遠端倉庫,鏡像名稱 tag 自己定義

[root@aws-172-20-20-101 aws-kubectl]# docker build -t xxx.dkr.ecr.xxx.amazonaws.com.cn/k8s-mirror:aws-kubectl-1.7 .

3. 創(chuàng)建 k8s cronjob

cronjob需要在每個用到的 namespace 下都創(chuàng)建一個,同名不同 namespace即可,yaml中添加了注釋,復(fù)制使用時記得把注釋刪掉

[root@aws-172-20-20-28 aws-kubectl]# cat aws-kubectl-centos.yaml 
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  annotations:
  name: ecr-cred-helper
#  namespace: kube-system
spec:
  concurrencyPolicy: Allow
  failedJobsHistoryLimit: 1
  jobTemplate:
    metadata:
      creationTimestamp: null
    spec:
      template:
        metadata:
          creationTimestamp: null
        spec:
          containers:
          - command:
            - /bin/sh
            - -c
            - |-
              ACCOUNT=$your_aws_account_id
              REGION=$your_aws_region
              SECRET_NAME=${REGION}-ecr-registry # secret name,可自定義
              TOKEN=`aws ecr get-login --region ${REGION} --registry-ids ${ACCOUNT} | cut -d ' ' -f6` # 通過 awscli 命令行實時獲取能訪問 aws ecr 的 password
              echo `aws sts get-caller-identity` # 查看獲取的認證信息是否正確,上線使用時可刪此行
              echo `aws --version`  # 查看 awscli 的版本號
              echo "ENV variables setup done."
              /usr/local/bin/kubectl delete secret --ignore-not-found $SECRET_NAME # 刪除舊的 secret
              /usr/local/bin/kubectl create secret docker-registry $SECRET_NAME \  # 創(chuàng)建新的 secret
              --docker-server=xxxx.dkr.ecr.xxxx.amazonaws.com.cn \ # aws ecr server
              --docker-username=AWS \
              --docker-password="${TOKEN}" \
              --docker-email="xx.xxx@xxxx.cn" # 注冊的郵箱
              echo "Secret created by name. $SECRET_NAME"
              /usr/local/bin/kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "$SECRET_NAME"}]}'  # 將 secret patch 到 default token 中
              echo "All done."
            env:
            - name: AWS_DEFAULT_REGION
              value: xxxxx   # aws 的 region name
            - name: AWS_SECRET_ACCESS_KEY
              value: 8nOxxxxxxxxjnpf5fZlV0MxxxxxxXs+  # access_key
            - name: AWS_ACCESS_KEY_ID
              value: AxxxxxxGK22xxxxx  # access_id
            - name: KUBERNETES_SERVICE_HOST
              value: xxxxxx.com.cn  # apiserver 訪問入口
            - name: KUBERNETES_SERVICE_PORT
              value: "443"
            image: xxxxx.dkr.ecr.xxxxx.amazonaws.com.cn/k8s-mirror:aws-kubectl-1.7 # 剛才編譯好的鏡像
            imagePullPolicy: IfNotPresent
            name: ecr-cred-helper
            resources: {}
            securityContext:
              capabilities: {}
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          nodeSelector:
            node-role.kubernetes.io/master: "true"
          tolerations:
          - key: "node-role.kubernetes.io/master"
            value:
          dnsPolicy: Default
          hostNetwork: true
          restartPolicy: Never
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
  schedule: "* */6 * * *" # 表示每 6 小時刷新一次,測試時可調(diào)整,參考 linux crontab
  successfulJobsHistoryLimit: 3
  suspend: false

k8s master 上創(chuàng)建 cronjob

[root@aws-172-20-20-28 aws-kubectl]# kubectl create -f aws-kubectl-centos.yaml 

查看創(chuàng)建結(jié)果,一切正常

[root@aws-172-20-20-28 aws-kubectl]# kubectl get cronjob
# 這里使用的是測試時間,每2分鐘刷新一次
NAME              SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
ecr-cred-helper   */2 * * * *   False     0        76s             3h39m

# 到了設(shè)定的時間后 cronjob 會拉起一個 pod 執(zhí)行命令,更新 token,執(zhí)行完后是 completed 狀態(tài)
[root@aws-172-20-20-28 aws-kubectl]# kubectl get pods 
NAME                               READY   STATUS             RESTARTS   AGE
ecr-cred-helper-1561107840-wlqjl   0/1     Completed          0          5m16s
ecr-cred-helper-1561107960-x6dql   0/1     Completed          0          3m16s
ecr-cred-helper-1561108080-gr6kt   0/1     Completed          0          75s

# 可通過 kubectl logs $pod-name 查看執(zhí)行狀態(tài)
[root@aws-172-20-20-28 aws-kubectl]# kubectl logs ecr-cred-helper-1561108080-gr6kt
{ "Account": "xxxx", "UserId": "xxxxxxxx", "Arn": "arn:aws-cn:iam::xxxxxx:user/xxxxxx" }
aws-cli/1.14.28 Python/2.7.5 Linux/4.4.180-2.el7.elrepo.x86_64 botocore/1.8.35

ENV variables setup done.
secret "xxxxxxx-ecr-registry" deleted
secret/xxxxxxx-ecr-registry created
Secret created by name. xxxxxx-ecr-registry
serviceaccount/default patched 
All done.

4. 在需要創(chuàng)建的statefulset/ deployment/ daemonset/ pod 中使用 imagePullSecrets

成功的話,在沒有docker login的宿主機上可以直接拉取 aws ecr上的私有鏡像

[root@aws-172-20-20-28 aws-kubectl]# cat test.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: image-test
spec:
  containers:
    - name: image-test-container
      image: xxxx.dkr.ecr.cn-xxx-1.amazonaws.com.cn/k8s-mirror:nginx-1.0
  imagePullSecrets:
    - name: xxxx-ecr-registry

[root@aws-172-20-20-28 aws-kubectl]#  kubectl create -f test.yaml

彩蛋

如果有如下報錯,請參考 aws 官方說明

  • 在 cronjob 的 yaml 中執(zhí)行sh命令那里加入幾個命令,將獲取的信息輸出,通過kubectl logs $pod-name 查看
 containers:
          - command:
            - /bin/sh
            - -c
            - |-
              ACCOUNT=xxxxx
              REGION=xxxx
              SECRET_NAME=${REGION}-ecr-registry
              TOKEN=`aws ecr get-login --region cn-xxxxx-1 --registry-ids xxxxx | cut -d ' ' -f6`
              echo `aws ecr create-repository --repository-name aws-kubectl` # 看看是否可以創(chuàng)建一個存儲庫
              echo `aws sts get-caller-identity`
              echo `aws --version`
              echo "${TOKEN}" # 將獲取的 passwd 輸出,查看是否正確
              echo "ENV variables setup done."

通過查看更新的 secret 確認生成的認證是否正確, authusernamepassword的base64編碼

[root@aws-172-20-20-28 aws-kubectl]# kubectl get secret $your_secret_name --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
{"auths":{"xxxxx.dkr.ecr.cn-xxxxx-1.amazonaws.com.cn":{"username":"AWS","password":"xxxxxxx","email":"xxxxx@xxxxx.cn","auth":"QVdTOmV5SndZxxxxxEo5"}}}

若生成的認證 token 無誤,依然有no basic auth credentials報錯,使用 amazon-ecr-credential-helper工具可解決問題,纖細參考 how to use amazon-ecr-credential-helper

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容