在Kubernetes(k8s)里如何拉取私有Docker镜像?

1. 故事背景

如果你存下以下情况或者需求,满足一个就可以往下读

  • No.1

在Kubernetes(k8s)里拉取私有Docker镜像


  • No.2

当你查看pod基本情况(类似kubectl get pods),出现ErrImagePull,类似如下:

> kubectl get pods -n=foo
NAME                              READY     STATUS         RESTARTS   AGE
bar-production-7fbf67d957-96fdg   0/1       ErrImagePull   0          12s

当你查看pod描述(类似kubectl describe pods),Events部分出现Failed to pull image "your-domain/foo/bar:latest": rpc error: code = Unknown desc = repository your-domain/foo/bar not found: does not exist or no pull access,意思没办法pull, 类似如下:

> kubectl describe pods -n foo
...
...以下节选..
...
...
Events:
Type     Reason          Age   From                              Message
----     ------          ----  ----                              -------
Normal   Scheduled       21s   default-scheduler                 Successfully assigned foo/bar-production-7fbf67d957-96fdg to izbp12teyx4eiu85kj
      yd5uz
Normal   Pulling         10s   kubelet, izbp12teyx4eiu85kjyd5uz  pulling image "your-domain/foo/bar:latest"
Warning  Failed          10s   kubelet, izbp12teyx4eiu85kjyd5uz  Failed to pull image "your-domain/foo/bar:latest": 
rpc error: code = Unknown desc = repository your-domain/foo/bar not found: does not exist or no pull access
Warning  Failed          10s   kubelet, izbp12teyx4eiu85kjyd5uz  Error: ErrImagePull
Normal   SandboxChanged  9s    kubelet, izbp12teyx4eiu85kjyd5uz  Pod sandbox changed, it will be killed and re-created.

可以不看的废话

我已经登录了docker私有镜像仓库,为什么pull不了,我在宿主机上使用命令docker pull尝试是否可以成功,结果是成功的。

于是乎,我把pod删掉,再重新运行,结果pod运行起来了。

这个现象非常奇怪,我查看了pod描述的Events块,其中一条日志写着这个镜像已经存在,无需pull。难道是因为这样,所以运行成功了?

于是乎,我把pod和镜像都删了,重新运行pod,结果是跑不起来的,依旧是因为无法pull的原因。

那看来,要在k8s里pull其他docker镜像仓库,是有讲究的,国际惯例Google一番。

2. 提前准备

  • 本次试验是在CentOS 7.4 64位系统,root用户下进行
  • Kubernetes(k8s)集群
  • 部署容器名称bar,namespacefoo

3. 解决方案

3.1 登录docker私有镜像仓库

如果已登录,可忽略

> sudo docker login --username=${YOUR-USERNAME} ${YOUR-DOCKER-HUB-URL}
# 密码你才知道啦
# 实例
> sudo docker login --username=foo registry.cn-hangzhou.aliyuncs.com

当你成功后,登录信息会被记录在文件~/.docker/config.json

3.2 编写secret描述文件

# 每次都是读取最新的
---
apiVersion: v1
data:
  .dockerconfigjson: {base64 -w 0 ~/.docker/config.json}
kind: Secret
metadata:
  name: docker-register-secret
  namespace: foo
type: kubernetes.io/dockerconfigjson

# 用上面的base64命令加密,静态编辑
---
apiVersion: v1
data:
  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS12cGMuY24taGFuZ3pob3UuYWxpeXVuY3MuY29tIjogewoJCQkiYXV0aCI6ICJZV1poYm5ScFkyRnlPbUZtZEdNeE16RTBRWE5rWmlFeU16UT0iCgkJfQoJfQp9
kind: Secret
metadata:
 name: docker-register-secret
 namespace: foo
type: kubernetes.io/dockerconfigjson

3.3 创建secret

> kubectl apply -f ${YOUR-SECRET-PATH}

3.4 修改pod描述文件

以下摘自pod描述文件的部分,增加节点imagePullSecrets,放在spec节点下,与containers同级

spec:
  containers:
  - name: pod-name
  image: registry.cn-hangzhou.aliyuncs.com/foo/bar:latest
  imagePullSecrets:
  - name: docker-register-secret

3.5 创建pod

kubectl apply -f ${YOUR-POD-PATH}

3.6 结果

> kubectl get pods -n=foo
NAME                              READY     STATUS    RESTARTS   AGE
bar-production-575c56b5bf-nwcd2   1/1       Running   0          12s

那应该是成功滴,如果不成功,可留言交流交流