「开源摘星计划」镜像拉取凭证,k8s是如何拉取Harbor中的私有镜像的?

1,880 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

本文已参与「开源摘星计划」,欢迎正在阅读的你加入。
活动链接:github.com/weopenproje…
【文章来源】:《Harbor进阶实战》公众号

前言


  作为企业级的私有镜像仓库,Harbor提供了公有项目(Projects)和私有项目两种不同类型的仓库。公有项目中的镜像,任何的用户都可以直接拉取,而私有项目中的镜像,为保证镜像的安全性,仅拥有对应权限的用户才可以进行拉取,从而需要进行登录验证。

  那么,在kubernetes部署应用的业务环境中,每次拉取镜像都需要我们登录Harbor吗?如果如此,那便太不符合需求了吧。

  我们可以利用k8s的Secret资源对象,将Harbor用户的登录信息制作成密钥,在Pod创建资源时引用对应的Secret即可实现。

  本篇文章以docker为k8s的容器运行时为例进行相关操作,containerd为容器运行时的配置将在后续文章进行分享!

环境说明


  • Harbor version: 2.5.3
  • kubernetes version: 1.20.15
  • docker version: 19.03.8
  • 操作系统: CentOS 7.8
  • harbor服务地址: https://192.168.2.250:443

1、docker配置

kubernetes的节点若想从Harbor中拉取镜像,都需要在docker的配置文件中通过insecure-registries参数指定Harbor的服务地址。参考示例:

$ cat  /etc/docker/daemon.json 
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "insecure-registries": ["192.168.2.250:443"],
  "storage-driver": "overlay2",
  "log-driver": "json-file",
   "live-restore": true,
  "log-opts": {
    "max-size": "500m",
    "max-file": "2" 
  }
}
$ systemctl  daemon-reload  #重新加载配置
$ systemctl restart docker  #重启docker使配置生效

注意
每台运行Pod的kubernetes节点都需要进行该配置!

2、登录Harbor

  在命令行登录Harbor,登录成功后会在当前用户下生成.docker/config.json文件,该文件含登录密钥,制作Secret时会根据该密钥

$ docker  login  192.168.2.250:443
Username: admin  #输入登录用户
Password:   #输入用户密码
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  #出现该提示则表示登录成功!

如果报错请检查dockers的配置是否正常!


3、查看docker登录密钥数据

当docker login登录成功后,相信细心的你早已发现在~/.docker目录下多了个config.json文件。

注意
每台运行Pod的kubernetes节点都需要进行该操作!未进行该操作的节点无法拉取到私有镜像。

$ ls  -la ~/.docker/config.json 
-rw------- 1 root root 155 8月  17 23:48 /root/.docker/config.json
$ cat ~/.docker/config.json
{
	"auths": {
		"192.168.2.250:443": {
			"auth": "YWRtaW46SGFyYm9yMTIzNDU="
		}
	},
	"HttpHeaders": {
		"User-Agent": "Docker-Client/19.03.8 (linux)"
	}
}

4、对密钥进行加密

  用BASE64编码dockercfg内容。

$ cat ~/.docker/config.json  | base64 -w 0
ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjIuMjUwOjQ0MyI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy44IChsaW51eCkiCgl9Cn0=

-w 0 表示生成秘钥不转行,默认转行不是正确的格式会出错!

5、创建secrest资源对象

  在kubernetes集群的master节点进行该操作。

1)编写资源清单文件

$ cat <<EOF >  harbor-image-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: harbor-pull
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjIuMjUwOjQ0MyI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOS4wMy44IChsaW51eCkiCgl9Cn0=
EOF

注意:
.dockerconfigjson的值为前面执行命令cat ~/.docker/config.json | base64 -w 0获取到的值,需要填写自己生成的字符串!
Secret资源对象是命名空间级别的资源对象,可通过namespace参数将该secret创建在指定的命名空间。

2)创建Secret资源

根据刚才编写的yaml资源清单文件创建Secret资源对象。

$ kubectl apply -f harbor-image-secret.yaml 
secret/harbor-pull created

3)查看验证

$ kubectl get secrets 
NAME                  TYPE                                DATA     AGE
default-token-xmdv2   kubernetes.io/service-account-token   3      25d
harbor-pull           kubernetes.io/dockerconfigjson        1      2m11


6、Pod中指定镜像拉取凭证参数

  下面基于Deployment控制器部署nginx服务,从Harbor的私有项目jenkins-demo中拉取私有镜像。
通过spec.imagePullSecrets参数指定刚才创建的secrets名称(可多个),该参数与containers参数同级别。

$ cat <<EOF > nginx-test.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-test
  namespace: default
spec:
  replicas: 1
  selector: 
    matchLabels: 
      app: nginx
  template: 
    metadata: 
      labels:
        app: nginx
    spec:
      imagePullSecrets:
      - name: harbor-pull
      containers:
      - name: nginx
        image: 192.168.2.250:443/jenkins-demo/nginx:1.23.1-alpine
        imagePullPolicy: IfNotPresent
        ports: 
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: default
spec: 
  type: NodePort
  selector: 
    app: nginx
  ports: 
  - name: web
    port: 80
    protocol: TCP
    targetPort: 80
EOF
$ kubectl apply   -f nginx-test.yaml  #创建nginx服务
  • 验证Pod是否被成功创建
$ kubectl get pod
NAME                          READY   STATUS    RESTARTS   AGE
nginx-test-56b4465749-xpwqk   1/1     Running   0          3m54s
$ kubectl get  svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        26d
nginx        NodePort    10.107.180.109   <none>        80:42509/TCP   8m36s

可以发现镜像拉取成功,服务也创建成功!