一个计算机技术爱好者与学习者

0%

好好学K8S:K8S配置使用imagePullSecrets

1. 前言

《Harbor入门篇》一文中,我们已经安装配置好了Harbor。
本文中,我们来学习一下怎样在K8S中配置使用imagePullSecrets,从Harbor或者其他私有镜像仓库拉取镜像。

参考文档:

2. 创建imagePullSecrets

创建一个docker-registry类型的secret,名字为harbor-secret

1
2
3
4
kubectl create secret docker-registry harbor-secret \
--docker-server=harbor.voidking.com \
--docker-username=admin \
--docker-password=Harbor12345

3. 使用imagePullSecrets

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Pod
metadata:
name: testpod
spec:
containers:
- name: busybox
image: harbor.voidking.com/voidking/busybox:1.31
command:
- sleep
- "3600"
imagePullSecrets:
- name: harbor-secret

4. 给pod添加默认imagePullSecrets

上面的配置,已经可以正常从harbor镜像仓库拉取镜像了。
但是,每个pod都需要指定一下imagePullSecrets,也是比较麻烦。
这里我们可以在命名空间默认sa中添加imagePullSecrets,这样我们就不用在pod中指定imagePullSecrets了,创建pod时会自动注入。

1
2
3
kubectl patch serviceaccount default \
-p "{\"imagePullSecrets\": [{\"name\": \"docker-secret\"}]}" \
-n <your-namespace>

5. 全局配置imagePullSecrets

如果新增了namespace,那么这个namespace就需要单独添加一次imagePullSecrets,而且这个namespace的sa也需要添加imagePullSecrets。

这里可以使用imagepullsecret-patcher来简化我们的工作,参考文档:

1、获取 dockerconfigjson

1
2
3
4
5
6
# kubectl get secret harbor-secret -oyaml
kubectl create secret docker-registry harbor-secret \
--docker-server=harbor.voidking.com \
--docker-username=admin \
--docker-password=Harbor12345 \
--dry-run=client -oyaml

获取到 dockerconfigjson ,填入到下一步的 deployment.yaml 文件中。

2、准备资源清单

  • namespace.yaml,定义namespace
  • rbac.yaml,定义sa权限
  • deployment,定义imagepullsecret-patcher服务

namespace.yaml 内容如下:

1
2
3
4
apiVersion: v1
kind: Namespace
metadata:
name: imagepullsecret-patcher

rbac.yaml 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
apiVersion: v1
kind: ServiceAccount
metadata:
name: imagepullsecret-patcher
namespace: imagepullsecret-patcher
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
k8s-app: imagepullsecret-patcher
name: imagepullsecret-patcher
rules:
- apiGroups:
- ""
resources:
- secrets
- serviceaccounts
verbs:
- list
- patch
- create
- get
- delete
- apiGroups:
- ""
resources:
- namespaces
verbs:
- list
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: imagepullsecret-patcher
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: imagepullsecret-patcher
subjects:
- kind: ServiceAccount
name: imagepullsecret-patcher
namespace: imagepullsecret-patcher

deployment.yaml 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
apiVersion: v1
kind: Secret
type: kubernetes.io/dockerconfigjson
metadata:
name: image-pull-secret-src
namespace: imagepullsecret-patcher
data:
.dockerconfigjson: eyJhdXRocyI6eyJoYXJib3Iudm9pZGtpbmcuY29tIjp7InVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IkhhcmJvcjEyMzQ1IiwiYXV0aCI6IllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSJ9fX0=
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: imagepullsecret-patcher
namespace: imagepullsecret-patcher
labels:
name: imagepullsecret-patcher
spec:
replicas: 1
selector:
matchLabels:
name: imagepullsecret-patcher
template:
metadata:
labels:
name: imagepullsecret-patcher
spec:
automountServiceAccountToken: true
serviceAccountName: imagepullsecret-patcher
containers:
- name: imagepullsecret-patcher
image: "quay.io/titansoft/imagepullsecret-patcher:v0.14"
env:
- name: CONFIG_FORCE
value: "true"
- name: CONFIG_DEBUG
value: "false"
- name: CONFIG_ALLSERVICEACCOUNT
value: "true"
- name: CONFIG_DOCKERCONFIGJSONPATH
value: "/app/secrets/.dockerconfigjson"
- name: CONFIG_SECRETNAME
value: "harbor-secret"
volumeMounts:
- name: src-dockerconfigjson
mountPath: "/app/secrets"
readOnly: true
resources:
requests:
cpu: 0.1
memory: 15Mi
limits:
cpu: 0.2
memory: 30Mi
volumes:
- name: src-dockerconfigjson
secret:
secretName: image-pull-secret-src

其中dockerconfigjson改成上一步中获取到的dockerconfigjson,CONFIG_SECRETNAME变量的value改成期望的secret名称。

3、安装imagepullsecret-patcher

1
2
3
kubectl apply -f namespace.yaml
kubectl apply -f rbac.yaml
kubectl apply -f deployment.yaml

4、查看安装

1
2
3
kubectl get all -n imagepullsecret-patcher
kubectl get sa -n imagepullsecret-patcher
kubectl get sa default -n imagepullsecret-patcher -oyaml

可以发现,harbor-secret 已经注入到了sa中。

6. 修改imagePullSecrets

有时候,我们需要修改imagePullSecrets,比如修改用户名和密码。这时可以直接修改 image-pull-secret-src 这个secret,修改完成后,imagepullsecret-patcher会自动完成所有namespace下的 harbor-secret 的修改。

1
kubectl edit secret image-pull-secret-src -n imagepullsecret-patcher

7. 删除imagePullSecrets

有时候,我们需要替换imagePullSecrets,比如imagePullSecrets名称发生了变更。这时就需要删除原本的imagePullSecrets。

单个sa删除imagePullSecrets方法:

1
2
INDEX=$(kubectl get sa default -n imagepullsecret-patcher -o json | jq '.imagePullSecrets | map(.name == "harbor-secret") | index(true)')
kubectl patch sa default --type=json -p="[{'op': 'remove', 'path': '/imagePullSecrets/$INDEX'}]" -n imagepullsecret-patcher

批量sa删除imagePullSecrets方法:

1
2
3
4
5
6
7
#!/bin/bash
kubectl get ns | awk '{print $1}' | grep -v "NAME" > namespace.txt

for namespace in `cat namespace.txt`;do
INDEX=$(kubectl get sa default -n $namespace -o json | jq '.imagePullSecrets | map(.name == "harbor-secret") | index(true)')
kubectl patch sa default --type=json -p="[{'op': 'remove', 'path': '/imagePullSecrets/$INDEX'}]" -n $namespace
done

8. 添加多个imagePullSecrets

问:如果有多个镜像仓库需要配置imagePullSecrets,该怎么处理?
答:可以把多个imagePullSecrets写入到同一个dockerconfigjson。

8.1. dockerconfigjson解析

dockerconfigjson是一个base64加密的字符串,执行

1
echo "eyJhdXRocyI6eyJoYXJib3Iudm9pZGtpbmcuY29tIjp7InVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IkhhcmJvcjEyMzQ1IiwiYXV0aCI6IllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSJ9fX0=" | base64 -d

结果为:

1
{"auths":{"harbor.voidking.com":{"username":"admin","password":"Harbor12345","auth":"YWRtaW46SGFyYm9yMTIzNDU="}}}

实际上,它的结构和docker login后产生的$HOME/.docker/config.json完全一致。

其中,auth的value也是base64加密的字符串,执行

1
echo "YWRtaW46SGFyYm9yMTIzNDU=" | base64 -d

结果为:

1
admin:Harbor12345

8.2. dockerconfigjson拼接

知道了dockerconfigjson的结构,那么我们可以知道,如果有多个imagePullSecrets,我们可以自己拼接一个dockerconfigjson明文字符串,然后进行base64加密。

dockerconfigjson1 内容为:

1
{"auths":{"harbor.voidking.com":{"username":"admin","password":"Harbor12345","auth":"YWRtaW46SGFyYm9yMTIzNDU="}}}

dockerconfigjson2 内容为:

1
2
3
4
5
6
7
8
9
{
"auths": {
"harbor1.voidking.com": {
"username": "haojin",
"password": "haojin123",
"auth": "aGFvamluOmhhb2ppbjEyMwo="
}
}
}

那么 dockerconfigjson1 和 dockerconfigjson2 可以拼接成一个明文dockerconfigjson:

1
jq -n 'reduce inputs as $i ({}; . * $i)' dockerconfigjson1 dockerconfigjson2 | jq -c

然后通过base64加密,就是我们需要的加密后的dockerconfigjson。

1
jq -n 'reduce inputs as $i ({}; . * $i)' dockerconfigjson1 dockerconfigjson2 | jq -c | base64 | tr -d '\n'

参考文档: