#夏日挑战赛# k8s节点如何从Harbor中拉取私有镜像? 原创
[本文正在参加星光计划3.0–夏日挑战赛]
活动链接:https://ost.51cto.com/posts/13641#comment
前言
Harbor因为kubernetes而兴起,作为镜像存储仓库,那要如何才能使用呢?本篇文章分析kubernetes集群中,Pod中容器的镜像是如何从Harbor中拉取镜像的,看到这篇文章,相比你对kubernetes多多少少都有了解吧!
1、Pod中拉取Harbor中镜像的两种情况
k8s集群在部署pod过程中,有以下两种情况来拉取镜像:
1.1、拉取Harbor中的公有镜像
公有镜像,即供任何人都可以访问使用的镜像,如library公有项目下的镜像。pod部署到的主机(宿主机)的网络能跟Harbor服务器能通就行,不需要做特殊的配置。
1.2、拉取Harbor中的私有镜像
在Harbor的生成使用环境中,因为有很多不同的系统使用Harbor来存储、拉取镜像,为防止各个系统间造成影响,harbor管理员会为每个系统创建一个项目(project)和一个用户(user),然后将项目设置为私有项目,并且该项目对用户授权。
该系统在部署Pod的时候,要拉取分配的私有项目中的私有镜像时,还能直接拉取吗?在kubernetes中,可以通过Secrets资源对象(认证)来配置镜像拉取凭证,然后在imagePullSecrets字段(参数)指定对应的拉取凭证来拉取私有镜像。
# 2、主机配置
Pod在拉取Harbor中的镜像是通过节点主机的容器运行时(CRI)来拉取的,本处以docker为例。需要对docker做些配置。
kubernetes集群中的每个节点都需要配置,至少要保证使用该镜像的Pod所在的节点都配置。
2.1、修改docker配置文件并重启服务
- 修改配置:
[root@sc-node1 ~]# vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://registry.docker.cn.com"],
"insecure-registries": ["192.168.2.250:443"] # 此处添加Harbor仓库地址(安全加密端口)
}
2.1、修改docker配置文件并重启服务
• 修改配置:
[root@sc-node1 ~]# vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://registry.docker.cn.com"],
"insecure-registries": ["192.168.2.250:443"] # 此处添加Harbor仓库地址(安全加密端口)
}
• 重新加载配置
[root@sc-node1 ~]# systemctl daemon-reload
重新启动docker服务
[root@sc-node1 ~]# systemctl restart docker
Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.
2.2 节点主机命令行登录Harbor
本处以test-1私有项目、用户lidabai/Lidabai123为演示。
1)命令行登录harbor
[root@sc-node1 ~]# docker login https://192.168.2.250:443 -u lidabai -p Lidabai123
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
如果登录报错,需要检查docker的配置及网络与Harbor是否正常。
注:
Pod所在节点主机均需要登录成功!登录成功后,会在当前用户下生成 .docker/config.json 文件,该文件记录了相关的登录信息,后面会基于该文件来制作镜像拉取凭证。
[root@sc-node1 ~]# pwd
/root
[root@sc-node1 ~]# ls -la .docker/
总用量 4
drwx------ 2 root root 25 4月 4 11:07 .
dr-xr-x---. 4 root root 178 4月 4 11:07 ..
-rw------- 1 root root 155 4月 4 11:07 config.json # 该文件记录了相关的登录信息
2)查看登录的密钥数据
[root@sc-node1 ~]# cat ~/.docker/config.json
{
"auths": {
"192.168.2.250:443": {
"auth": "bGlkYWJhaTpMaWRhYmFpMTIz"
}
},
"HttpHeaders": {
"User-Agent": "Docker-Client/19.03.8 (linux)"
}
}[root@sc-node1 ~]#
3) 对密钥进行加密
用BASE64编码dockercfg内容,注意一下要用到编码后的子串。
[root@sc-node1 ~]# cat ~/.docker/config.json | base64 -w 0
ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjIuMjUwOjQ0MyI6IHsKCQkJImF1dGgiOiAiYkdsa1lXSmhhVHBNYVdSaFltRnBNVEl6IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy44IChsaW51eCkiCgl9Cn0=[root@sc-node1 ~]#
-w 0 表示生成秘钥不转行,默认转行不是正确的格式会出错!
3、创建Secret资源对象
在kubernetes集群管理节点操作!
3.1 编写资源清单文件
[root@sc-master1 ~]# vim harbor-image-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: harbor-pull-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjIuMjUwOjQ0MyI6IHsKCQkJImF1dGgiOiAiYkdsa1lXSmhhVHBNYVdSaFltRnBNVEl6IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy44IChsaW51eCkiCgl9Cn0=
3.2 更新资源清单文件
[root@sc-master1 ~]# kubectl apply -f harbor-image-secret.yaml
secret/harbor-pull-secret created
[root@sc-master1 ~]# kubectl get secret
NAME TYPE DATA AGE
default-token-qkbdw kubernetes.io/service-account-token 3 9d
harbor-pull-secret kubernetes.io/dockerconfigjson 1 13s # 是这个!!!
扩展:命令行创建secret
# kubectl create secret docker-registry image-secret \
--docker-server=https://192.168.2.250:443 \
--docker-username=lidabai --docker-password=lidabai123
4、容器中指定镜像拉取凭证
Secret制作的镜像拉取凭证制作好后,就可以在创建Pod时使用了。
本处以拉取test-1私有项目下的192.168.2.250:443/test-1/traefik:2.6.2私有镜像为例,lidabai用户以“开发者”的角色拥有对test-1项目的镜像上传、拉取权限。
4.1 环境说明
4.2 编写测试资源清单文件
[root@sc-master1 ~]# vim traefik.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: 192.168.2.250:443/test-1/traefik:2.6.2
imagePullPolicy: IfNotPresent
imagePullSecrets: # 镜像拉取凭证
- name: harbor-pull-secret # 镜像拉取凭证的名称,填入刚才创建的secret名称!!!
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
4.3、更新资源清单文件
[root@sc-master1 ~]# kubectl apply -f traefik.yaml
deployment.apps/traefik created
4.4、查看资源部署状态(验证)
[root@sc-master1 ~]# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
traefik-599b969746-5xc6r 1/1 Running 0 56s 10.244.119.243 sc-node1 <none> <none>
traefik-599b969746-9pw72 0/1 ErrImagePull 0 56s 10.244.242.136 sc-node2 <none> <none>
可以看到,有个Pod创建失败了,因为镜像拉取失败!
4.4、故障分析
我的kubernetes集群是1master,2node节点,2个pod副本分别调度到两个node节点,之前在主机登录docker的时候,master和node1均有操作,但node2没有登录到harbor,从而没有生成~/.docker/config.json文件。
[root@sc-master1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
sc-master1 Ready control-plane,master 9d v1.20.6
sc-node1 Ready <none> 9d v1.20.6
sc-node2 Ready <none> 15h v1.20.6
[root@sc-node2 ~]# pwd
/root
[root@sc-node2 ~]# ls -la
总用量 110552
dr-xr-x---. 3 root root 191 4月 3 20:12 .
dr-xr-xr-x. 17 root root 224 2月 8 17:05 ..
-rw-------. 1 root root 1216 2月 8 17:06 anaconda-ks.cfg
-rw-------. 1 root root 3047 4月 4 11:16 .bash_history
-rw-r--r--. 1 root root 18 12月 29 2013 .bash_logout
-rw-r--r--. 1 root root 176 12月 29 2013 .bash_profile
-rw-r--r--. 1 root root 176 12月 29 2013 .bashrc
-rw-r--r--. 1 root root 100 12月 29 2013 .cshrc
-rw-r--r-- 1 root root 113171272 8月 30 2021 docker-ce-rpm.tar.gz
drwxr----- 3 root root 19 2月 18 18:01 .pki
-rw-r--r--. 1 root root 129 12月 29 2013 .tcshrc
-rw------- 1 root root 1712 3月 16 09:42 .viminfo
解决: node2节点在命令行登录harbor!
[root@sc-node2 ~]# docker login https://192.168.2.250:443 -u lidabai -p Lidabai123
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Error response from daemon: Get https://192.168.2.250:443/v2/: x509: cannot validate certificate for 192.168.2.250 because it doesn't contain any IP SANs
[root@sc-node2 ~]# vim /etc/docker/daemon.json
[root@sc-node2 ~]# systemctl daemon-reload
[root@sc-node2 ~]# systemctl restart docker
[root@sc-node2 ~]# docker login https://192.168.2.250:443 -u lidabai -p Lidabai123
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
[root@sc-node2 ~]# ls -la
drwx------ 2 root root 25 4月 4 12:07 .docker
再次查看Pod状态:
[root@sc-master1 ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
traefik-599b969746-5xc6r 1/1 Running 0 13m 10.244.119.243 sc-node1 <none> <none>
traefik-599b969746-9pw72 0/1 ImagePullBackOff 0 13m 10.244.242.140 sc-node2 <none> <none>
[root@sc-master1 ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
traefik-599b969746-5xc6r 1/1 Running 0 16m 10.244.119.243 sc-node1 <none> <none>
traefik-599b969746-9pw72 1/1 Running 0 16m 10.244.242.140 sc-node2 <none> <none>
可以看到,node2上的pod也拉取到Harbor私有仓库的镜像了。
感谢分享。学习!
感谢分享。
这三个节点都需要安装docker,不太合适。
只有harbor所在节点需要有harbor, 其他节点使用containerd拉取镜像。