1. Before
aws ecr
使用都需要credentials
认证,才可以pull/push
镜像,即使通过docker login -u AWS -p
的方式登陆https:// .dkr.ecr. .amazonaws.com.cn ecr
,获得的token
认证也只有12h
的有效期,对于CICD
的要求来说无疑是一大障碍,因此下文采用k8s cronjob/ secrets
的方式来保持token
的更新及应用部署过程中对私用镜像的获取。
2. 制作一个具有awscli
和 kubectl
的 docker image
此处Dockerfile
中使用的 base image
为centos7
,想用小些的镜像可自行下载,alpine
即可
[root@aws-172-20-20-101 aws-kubectl]# cat Dockerfile
FROM centos:centos7
MAINTAINER xx.xx
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="[email protected]" # 注册的邮箱
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 官方说明
- Error response from daemon: Get https://xxxx.dkr.ecr.xxxxx.amazonaws.com.n/v2/amazon-k8s-cni/manifests/v1.3.2: no basic auth credentials
如果觉得官方说明没 niao 用,按下面步骤测试一下,确认生成的 secret 是正确的
- 在 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 确认生成的认证是否正确,
auth
是username
和password
的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":"[email protected]","auth":"QVdTOmV5SndZxxxxxEo5"}}}
若生成的认证 token 无误,依然有
no basic auth credentials
报错,使用amazon-ecr-credential-helper
工具可解决问题,纤细参考 how to use amazon-ecr-credential-helper