八、为什么要引入Secret¶
Secret对象类型主要用来保存敏感信息,例如密码、令牌和SSH Key,将这些信息放在Secret中比较安全和灵活。用户可以创建Secret并且引用到Pod中。
九、什么是Secret¶
Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在Pod规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。
由于创建 Secret 可以独立于使用它们的 Pod, 因此在创建、查看和编辑 Pod 的工作流程中暴露 Secret(及其数据)的风险较小。Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施, 例如避免将机密数据写入非易失性存储。
Secret 类似于ConfigMap但专门用于保存机密数据。
另外,目前Secret 是不支持备份和还原。
注意:默认情况下,Kubernetes Secret 未加密地存储在 API 服务器的底层数据存储(etcd)中。 任何拥有 API 访问权限的人都可以检索或修改 Secret,任何有权访问 etcd 的人也可以。 此外,任何有权限在命名空间中创建 Pod 的人都可以使用该访问权限读取该命名空间中的任何 Secret; 这包括间接访问,例如创建 Deployment 的能力。
十、Secret常用类型有哪些¶
Secret类型有很多,但是在实际使用时,用得最多的是通用型Opaque、镜像仓库Secret和HTTPS证书的Secret。
- Opaque:通用型Secret,默认类型。
- kubernetes.io/service-account-token:作用于ServiceAccount,包含一个令牌,用于标识API服务账户。Kubernetes 在 v1.22 版本之前都会自动创建用来访问 Kubernetes API 的凭据。 这一老的机制是基于创建可被挂载到运行中 Pod 内的令牌 Secret 来实现的。 在最近的版本中,包括 Kubernetes v1.27 中,API 凭据是直接通过 TokenRequest API 来获得的,这一凭据会使用投射卷挂载到 Pod 中。使用这种方式获得的令牌有确定的生命期,并且在挂载它们的 Pod 被删除时自动作废。你仍然可以手动创建服务账号令牌。例如,当你需要一个永远都不过期的令牌时。 不过,仍然建议使用 TokenRequest子资源来获得访问 API 服务器的令牌。 你可以使用
kubectl create token命令调用TokenRequestAPI 获得令牌。 - kubernetes.io/dockercfg:Kubernetes下载私有仓库镜像使用的Secret,和宿主机的~/.dockercfg一致,新版本的Kubernetes(1.8+)使用kubernetes.io/dockerconfigjson替代kubernetes.io/dockercfg。
- kubernetes.io/dockerconfigjson:下载私有仓库镜像使用的Secret,和宿主机的/root/.docker/config.json一致,宿主机登录后即可产生该文件。
- kubernetes.io/basic-auth:用于使用基本认证(账号、密码)的Secret,可以使用Opaque取代。
- kubernetes.io/ssh-auth:用于存储SSH密钥的Secret
- kubernetes.io/tls:用于存储HTTPS域名证书文件的Secret,可以被Ingress使用
- bootstrap.kubernetes.io/token:一种简单的bearer token,用于创建新集群或将新节点添加到现有集群,在集群安装时可用于自动颁发集群的证书。
10.1 Docker镜像仓库Secret¶
当部署一个应用时,如果使用的是公开的镜像,就可以不用添加认证信息,直接拉取镜像到宿主机。但是当在拉取私有镜像库中的镜像时,可能需要认证后才可以拉取,此时可以使用imagePullSecret字段将包含Docker镜像注册表密码的Secret传递给Kubelet,然后即可拉取私有镜像。
1.创建一个包含镜像仓库账户信息的Secret,创建的Secret类型为docker-registry
$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
上面参数说明如下:
- docker-registry:指定Secret的类型
- myregistrykey:Secret的名称
- DOCKER_REGISTRY_SERVER:镜像仓库地址
- DOCKER_USER:镜像仓库用户名,需要有拉取镜像的权限
- DOCKER_PASSWORD:镜像仓库密码
- DOCKER_EMAIL:邮箱信息,可以为空
如果需要访问多个Registry,则可以为每个镜像仓库创建一个Secret,在Pods拉取镜像时,Kubelet会合并imagePullSecrets到.docker/config.json,注意Secret和ConfigMap一样需要和Pod在同一个命名空间中。
2.编写Yaml文件
$ vim dp-cm.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dp-cm
name: dp-cm
spec:
replicas: 1
selector:
matchLabels:
app: dp-cm
template:
metadata:
labels:
app: dp-cm
spec:
imagePullSecrets:
- name: myregistrykey
containers:
- image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2
name: nginx
volumeMounts:
- name: redisconf
mountPath: /etc/config
volumes:
- name: redisconf
configMap:
name: redis-conf
items:
- key: redis.conf
path: redis.conf.bak
defaultMode: 0666
3.创建Pod
$ kubectl create -f dp-cm.yaml
4.查看pod状态
[root@k8s-master01 conf]# kubectl get po
NAME READY STATUS RESTARTS AGE
cluster-test-79b978867f-4x2lw 1/1 Running 99 (20m ago) 52d
dp-cm-5c4ddb6777-9nkwh 1/1 Running 0 1s
5.现在演示一下,不设置Secret能不能拉取私有镜像仓库中的镜像

6.登录镜像仓库把本地镜像重新打tag并上传
$ docker login --username=xxxxx registry.cn-hangzhou.aliyuncs.com
$ docker tag registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2 registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test
$ docker push registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test
7.修改dp-cm.yaml
把下面两行去除掉
imagePullSecrets:
- name: myregistrykey
替换镜像地址为
registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test
修改后为
$ vim dp-cm.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dp-cm
name: dp-cm
spec:
replicas: 1
selector:
matchLabels:
app: dp-cm
template:
metadata:
labels:
app: dp-cm
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test
name: nginx
volumeMounts:
- name: redisconf
mountPath: /etc/config
volumes:
- name: redisconf
configMap:
name: redis-conf
items:
- key: redis.conf
path: redis.conf.bak
defaultMode: 0666
8.重新启动Pod
$ kubectl delete -f dp-cm.yaml ; kubectl create -f dp-cm.yaml
9.查看pod状态,此时由Running变为ImagePullBackOff。发现不设置Secret是不能拉取私有镜像仓库中的镜像
[root@k8s-master01 conf]# kubectl get po
NAME READY STATUS RESTARTS AGE
dp-cm-6bdc9b8b59-j5lzn 0/1 ImagePullBackOff 0 3s
[root@k8s-master01 conf]# kubectl describe po dp-cm-6bdc9b8b59-j5lzn
...
...
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 14s default-scheduler Successfully assigned default/dp-cm-6bdc9b8b59-j5lzn to k8s-master03
Normal BackOff 12s (x2 over 13s) kubelet Back-off pulling image "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test"
Warning Failed 12s (x2 over 13s) kubelet Error: ImagePullBackOff
Normal Pulling 1s (x2 over 13s) kubelet Pulling image "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test"
Warning Failed 1s (x2 over 13s) kubelet Failed to pull image "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test": rpc error: code = Unknown desc = failed to pull and unpack image "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test": failed to resolve reference "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
Warning Failed 1s (x2 over 13s) kubelet Error: ErrImagePull
10.2 HTTPS证书类型的Secret¶
生产环境中,应用服务一般都是使用HTTPS协议发布的,可以起到加密通信的作用。在传统架构中,域名证书一般在集群入口的代理服务器上进行管理,比如Nginx,而在Kubernetes中,一般服务都是通过Ingress发布的,此时可以将域名证书保存在TLS类型的Secret上,之后Ingress即可绑定该证书。
1.创建HTTPS的证书文件,假设域名为zq.com(生产环境中的证书为购买的受信任的证书,自签名证书不受浏览器信任)
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=zq.com"
上面参数说明:
req:该命令用于生成证书签名请求(CSR),也可以用于生成自签名证书-x509:该选项告诉 OpenSSL 生成自签名证书而不是 CSR。-nodes:该选项指定私钥不应使用密码短语进行加密。-days 365:该选项指定证书有效期为多少天-newkey rsa:2048:该选项告诉 OpenSSL 生成一个新的 RSA 密钥对,密钥长度为 2048 位。-keyout tls.key:该选项指定将保存私钥的文件名-out tls.crt:该选项指定将保存证书的文件名-subj "/CN=zq.com":该选项指定证书的主题,其中包括通用名称(CN)属性。在本例中,CN 设置为 "zq.com"
2.根据生成的tls.key和tls.crt创建Secret
$ kubectl -n default create secret tls nginx-test-tls --key=tls.key --cert=tls.crt
3.验证
[root@k8s-master01 conf]# kubectl get secret
NAME TYPE DATA AGE
nginx-test-tls kubernetes.io/tls 2 12s
4.创建一个Ingress将证书绑定到指定的域名上
$ vim nginx-http-zq.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx-https-zq
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: https-test.com
http:
paths:
- backend:
serviceName: nginx-svc
servicePort: 80
tls:
- secretName: nginx-test-tls
说明:一个Ingress可以绑定多个TLS类型的Secret,同一个Secret也可以被多个Ingress使用。