使用 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的更新及应用部署过程中对私用镜像的获取。

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 的认证信息复制到 ~/.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 使用的证书格式如下,可根据自己环境使用方式做调整

[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. 创建 k8s cronjob

cronjob需要在每个用到的 namespace 下都创建一个,同名不同 namespace即可,yaml中添加了注释,复制使用时记得把注释删掉

[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 \  # 创建新的 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 小时刷新一次,测试时可调整,参考 linux crontab
  successfulJobsHistoryLimit: 3
  suspend: false

k8s master 上创建 cronjob

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

查看创建结果,一切正常

[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

# 到了设定的时间后 cronjob 会拉起一个 pod 执行命令,更新 token,执行完后是 completed 状态
[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 查看执行状态
[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. 在需要创建的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 中执行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` # 看看是否可以创建一个存储库
              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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容