Secret概述
Secret解决了密码、token、秘钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。Secret可以以Volume或者环境变量的方式使用。
用户可以创建 secret,同时系统也创建了一些 secret。
要使用 secret,pod 需要引用 secret。Pod 可以用两种方式使用 secret:作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里,或者当 kubelet 为 pod 拉取镜像时使用。
Secret类型
- Service Account:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的 /run/secrets/kubernetes.io/serviceaccount 目录中。
- Opaque:base64编码格式的Secret,用来存储密码、秘钥等。
- kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。
Service Account
通过kube-proxy查看[root@k8s-master01 ~]# kubectl get pod -A | grep "kube-proxy"
kube-system kube-proxy-5jt9d 1/1 Running 6 22d
kube-system kube-proxy-r4dx5 1/1 Running 6 22d
[root@k8s-master01 ~]# kubectl exec -it -n kube-system kube-proxy-5jt9d -- /bin/sh
# ls -l /run/secrets/kubernetes.io/serviceaccount
total 0
lrwxrwxrwx 1 root root 13 Apr 27 12:55 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Apr 27 12:55 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Apr 27 12:55 token -> ..data/token
Opaque Secret
创建secret
手动加密,基于base64加密
yaml文件[root@k8s-master01 ~]# echo "admin" | base64 YWRtaW4K [root@k8s-master01 ~]# echo -n '1f2d1e2e67df' | base64 MWYyZDFlMmU2N2Rm
或者通过如下命令行创建【secret名称故意设置不一样,以方便查看对比】,生成secret后会自动加密,而非明文存储。[root@k8s-master01 secret]# pwd /root/k8s_practice/secret [root@k8s-master01 secret]# cat secret.yaml apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: YWRtaW4K password: MWYyZDFlMmU2N2Rm
生成secret,并查看状态 ```shell [root@k8s-master01 secret]# kubectl apply -f secret.yaml secret/mysecret createdkubectl create secret generic db-user-pass --from-literal=username=admin --from-literal=password=1f2d1e2e67df
[root@k8s-master01 secret]# kubectl get secret ### 查看默认名称空间的secret简要信息 NAME TYPE DATA AGE db-user-pass Opaque 2 53s default-token-k2f44 kubernetes.io/service-account-token 3 22d mysecret Opaque 2 21s
[root@k8s-master01 secret]# kubectl get secret mysecret -o yaml ### 查看mysecret详细信息 apiVersion: v1 data: password: MWYyZDFlMmU2N2Rm username: YWRtaW4K kind: Secret metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {“apiVersion”:”v1”,”data”:{“password”:”MWYyZDFlMmU2N2Rm”,”username”:”YWRtaW4K”},”kind”:”Secret”,”metadata”:{“annotations”:{},”name”:”mysecret”,”namespace”:”default”},”type”:”Opaque”} creationTimestamp: “2021-04-27T23:49:37Z” name: mysecret namespace: default resourceVersion: “149397” selfLink: /api/v1/namespaces/default/secrets/mysecret uid: 70cfe6e0-6347-4efd-9333-5f896d14e6b8 type: Opaque
[root@k8s-master01 secret]# kubectl describe secret mysecret ### 查看描述信息
Name: mysecret
Namespace: default
Labels:
Type: Opaque
Data
password: 12 bytes username: 6 bytes
<a name="csEBW"></a>
## 将Secret挂载到Volume中
yaml文件
```shell
[root@k8s-master01 secret]# pwd
/root/k8s_practice/secret
[root@k8s-master01 secret]# cat pod_secret_volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret-volume
spec:
containers:
- name: myapp
image: registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
volumeMounts:
- name: secret-volume
mountPath: /etc/secret
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: mysecret
启动pod并查看状态
[root@k8s-master01 secret]# kubectl apply -f pod_secret_volume.yaml
pod/pod-secret-volume created
[root@k8s-master01 secret]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-example-5sjhf 1/1 Running 0 10h 192.168.85.244 k8s-node01 <none> <none>
frontend-4crh5 1/1 Running 0 10h 192.168.85.239 k8s-node01 <none> <none>
frontend-n4z6w 1/1 Running 0 10h 192.168.85.213 k8s-node01 <none> <none>
frontend-pmcrm 1/1 Running 0 10h 192.168.85.235 k8s-node01 <none> <none>
nginx-configmap 1/1 Running 0 119m 192.168.85.238 k8s-node01 <none> <none>
pod-secret-volume 1/1 Running 0 41s 192.168.85.229 k8s-node01 <none> <none>
查看secret信息
[root@k8s-master01 secret]# kubectl exec -it pod-secret-volume -- /bin/sh
/ # cd /etc/secret/
/etc/secret # ls
password username
/etc/secret # cat username
admin
/etc/secret # cat password
1f2d1e2e67df
将Secret导入到环境变量中
yaml文件
[root@k8s-master01 secret]# pwd
/root/k8s_practice/secret
[root@k8s-master01 secret]# cat pod_secret_env.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret-env
spec:
containers:
- name: myapp
image: registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
restartPolicy: Never
启动pod并查看状态
[root@k8s-master01 secret]# kubectl apply -f pod_secret_env.yaml
pod/pod-secret-env created
[root@k8s-master01 secret]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-example-5sjhf 1/1 Running 0 11h 192.168.85.244 k8s-node01 <none> <none>
frontend-4crh5 1/1 Running 0 11h 192.168.85.239 k8s-node01 <none> <none>
frontend-n4z6w 1/1 Running 0 11h 192.168.85.213 k8s-node01 <none> <none>
frontend-pmcrm 1/1 Running 0 11h 192.168.85.235 k8s-node01 <none> <none>
nginx-configmap 1/1 Running 0 126m 192.168.85.238 k8s-node01 <none> <none>
pod-secret-env 1/1 Running 0 19s 192.168.85.240 k8s-node01 <none> <none>
查看secret信息
[root@k8s-master01 secret]# kubectl exec -it pod-secret-env -- /bin/sh
/ # env
MYAPP_SVC_PORT_80_TCP_ADDR=10.98.57.156
MYAPP_SERVICE_PORT_HTTP=80
KUBERNETES_PORT=tcp://10.20.0.1:443
KUBERNETES_SERVICE_PORT=443
MYAPP_SVC_PORT_80_TCP_PORT=80
HOSTNAME=pod-secret-env
SHLVL=1
MYAPP_SVC_PORT_80_TCP_PROTO=tcp
HOME=/root
MYAPP_SERVICE_HOST=10.20.179.180
SECRET_PASSWORD=1f2d1e2e67df
MYAPP_SVC_PORT_80_TCP=tcp://10.98.57.156:80
MYAPP_SERVICE_PORT=80
MYAPP_PORT=tcp://10.20.179.180:80
TERM=xterm
NGINX_VERSION=1.12.2
KUBERNETES_PORT_443_TCP_ADDR=10.20.0.1
MYAPP_PORT_80_TCP_ADDR=10.20.179.180
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
MYAPP_PORT_80_TCP_PORT=80
MYAPP_PORT_80_TCP_PROTO=tcp
MYAPP_SVC_SERVICE_HOST=10.98.57.156
SECRET_USERNAME=admin
KUBERNETES_PORT_443_TCP=tcp://10.20.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
PWD=/
MYAPP_PORT_80_TCP=tcp://10.20.179.180:80
KUBERNETES_SERVICE_HOST=10.20.0.1
MYAPP_SVC_SERVICE_PORT=80
MYAPP_SVC_PORT=tcp://10.98.57.156:80
docker-registry Secret
harbor镜像仓库
首先使用harbor搭建镜像仓库,搭建部署过程参考:「Harbor企业级私有Docker镜像仓库部署」
harbor部分配置文件信息
[root@linux harbor]# pwd
/root/harbor/harbor
[root@linux harbor]# cat harbor.yml
# Configuration file of Harbor
# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: 192.168.18.131
# http related config
http:
# port for http, default is 80. If https enabled, this port will redirect to https port
port: 5000
# https related config
https:
# https port for harbor, default is 443
port: 443
# The path of cert and key files for nginx
certificate: /etc/harbor/cert/httpd.crt
private_key: /etc/harbor/cert/httpd.key
# # Uncomment following will enable tls communication between all harbor components
# internal_tls:
# # set enabled to true means internal tls is enabled
# enabled: true
# # put your cert and key files on dir
# dir: /etc/harbor/tls/internal
# Uncomment external_url if you want to enable external proxy
# And when it enabled the hostname will no longer used
# external_url: https://reg.mydomain.com:8433
# The initial password of Harbor admin
# It only works in first time to install harbor
# Remember Change the admin password from UI after launching Harbor.
harbor_admin_password: Harbor12345
# Harbor DB configuration
database:
# The password for the root user of Harbor DB. Change this before any production use.
password: root123
# The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained.
max_idle_conns: 50
# The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.
# Note: the default number of connections is 1024 for postgres of harbor.
max_open_conns: 1000
# The default data volume
data_volume: /data
启动harbor后客户端http设置
集群所有机器都要操作
所有客户端都需要添加这个配置,然后重启 docker 服务。
[root@k8s-master01 ~]# vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"registry-mirrors":[
"https://kfwkfulq.mirror.aliyuncs.com",
"https://2lqq34jg.mirror.aliyuncs.com",
"https://pee6w651.mirror.aliyuncs.com",
"http://hub-mirror.c.163.com",
"https://docker.mirrors.ustc.edu.cn",
"https://registry.docker-cn.com"
],
"insecure-registries": ["192.168.18.131:5000"]
}
添加了 “insecure-registries”: [“192.168.18.131:5000”] 这行,其中192.168.18.131为内网IP地址。该文件必须符合 json 规范,否则 Docker 将不能启动。
systemctl daemon-reload
systemctl restart docker
如果在Harbor所在的机器重启了docker服务,记得要重新启动Harbor。
创建「私有」仓库
镜像上传
docker pull registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
docker tag registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1 192.168.18.131:5000/k8s-secret/myapp:v1
# 登录
docker login 192.168.18.131:5000 -u admin -p Harbor12345
# 上传
docker push 192.168.18.131:5000/k8s-secret/myapp:v1
退出登录
之后在操作机上退出harbor登录,便于后面演示
### 退出harbor登录
[root@k8s-node02 ~]# docker logout 192.168.18.131:5000
Removing login credentials for 192.168.18.131:5000
### 拉取失败,需要先登录。表明完成准备工作
[root@k8s-master secret]# docker pull 192.168.18.131:5000/k8s-secret/myapp:v1
Error response from daemon: unauthorized: unauthorized to access repository: k8s-secret/myapp, action: pull: unauthorized to access repository: k8s-secret/myapp, action: pull
pod直接下载镜像
在yaml文件中指定image后,直接启动pod
[root@k8s-master01 secret]# pwd
/root/k8s_practice/secret
[root@k8s-master01 secret]# cat pod_secret_registry.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret-registry
spec:
containers:
- name: myapp
image: 192.168.18.131:5000/k8s-secret/myapp:v1
启动pod并查看状态
[root@k8s-master01 secret]# kubectl apply -f pod_secret_registry.yaml
pod/pod-secret-registry created
[root@k8s-master01 secret]# kubectl get pod -o wide ### 可见镜像下载失败
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-example-5sjhf 1/1 Running 1 11h 192.168.85.233 k8s-node01 <none> <none>
frontend-4crh5 1/1 Running 1 11h 192.168.85.216 k8s-node01 <none> <none>
frontend-n4z6w 1/1 Running 1 11h 192.168.85.227 k8s-node01 <none> <none>
frontend-pmcrm 1/1 Running 1 11h 192.168.85.236 k8s-node01 <none> <none>
nginx-configmap 1/1 Running 1 147m 192.168.85.247 k8s-node01 <none> <none>
pod-secret-env 0/1 Completed 0 21m 192.168.85.240 k8s-node01 <none> <none>
pod-secret-registry 0/1 ImagePullBackOff 0 12s 192.168.85.245 k8s-node01 <none> <none>
pod-secret-volume 1/1 Running 1 28m 192.168.85.237 k8s-node01 <none> <none>
[root@k8s-master01 secret]# kubectl describe pod pod-secret-registry ### 查看pod详情
Name: pod-secret-registry
Namespace: default
Priority: 0
Node: k8s-node01/192.168.18.130
Start Time: Wed, 28 Apr 2021 08:21:36 +0800
Labels: <none>
Annotations: cni.projectcalico.org/podIP: 192.168.85.245/32
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"pod-secret-registry","namespace":"default"},"spec":{"containers":[{"i...
Status: Pending
IP: 192.168.85.245
IPs:
IP: 192.168.85.245
Containers:
myapp:
Container ID:
Image: 192.168.18.131:5000/k8s-secret/myapp:v1
Image ID:
Port: <none>
Host Port: <none>
State: Waiting
Reason: ImagePullBackOff
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-k2f44 (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
default-token-k2f44:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-k2f44
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned default/pod-secret-registry to k8s-node01
Normal BackOff 21s (x2 over 22s) kubelet, k8s-node01 Back-off pulling image "192.168.18.131:5000/k8s-secret/myapp:v1"
Warning Failed 21s (x2 over 22s) kubelet, k8s-node01 Error: ImagePullBackOff
Normal Pulling 5s (x2 over 22s) kubelet, k8s-node01 Pulling image "192.168.18.131:5000/k8s-secret/myapp:v1"
Warning Failed 5s (x2 over 22s) kubelet, k8s-node01 Failed to pull image "192.168.18.131:5000/k8s-secret/myapp:v1": rpc error: code = Unknown desc = Error response from daemon: unauthorized: unauthorized to access repository: k8s-secret/myapp, action: pull: unauthorized to access repository: k8s-secret/myapp, action: pull
Warning Failed 5s (x2 over 22s) kubelet, k8s-node01 Error: ErrImagePul
pod通过Secret下载镜像
通过命令行创建Secret,并查看其描述信息
[root@k8s-master01 secret]# kubectl create secret docker-registry myregistrysecret --docker-server='192.168.18.131:5000' --docker-username='admin' --docker-password='Harbor12345'
secret/myregistrysecret created
[root@k8s-master01 secret]# kubectl get secret
NAME TYPE DATA AGE
db-user-pass Opaque 2 35m
default-token-k2f44 kubernetes.io/service-account-token 3 22d
myregistrysecret kubernetes.io/dockerconfigjson 1 25s
mysecret Opaque 2 34m
[root@k8s-master01 secret]# kubectl get secret myregistrysecret -o yaml ### 查看详细信息
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyIxOTIuMTY4LjE4LjEzMTo1MDAwIjp7InVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IkhhcmJvcjEyMzQ1IiwiYXV0aCI6IllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSJ9fX0=
kind: Secret
metadata:
creationTimestamp: "2021-04-28T00:24:03Z"
name: myregistrysecret
namespace: default
resourceVersion: "154358"
selfLink: /api/v1/namespaces/default/secrets/myregistrysecret
uid: 317d6799-337e-4eda-9002-23707c13f8e4
type: kubernetes.io/dockerconfigjson
[root@k8s-master01 secret]# kubectl describe secret myregistrysecret ### 查看描述信息
Name: myregistrysecret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/dockerconfigjson
Data
====
.dockerconfigjson: 113 bytes
修改之前的yaml文件
[root@k8s-master01 secret]# cat pod_secret_registry.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret-registry
spec:
containers:
- name: myapp
image: 192.168.18.131:5000/k8s-secret/myapp:v1
imagePullSecrets:
- name: myregistrysecret
启动pod并查看状态
[root@k8s-master01 secret]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
daemonset-example-mvptr 1/1 Running 0 79s 192.168.85.255 k8s-node01 <none> <none>
frontend-6jpsr 1/1 Running 0 97s 192.168.85.200 k8s-node01 <none> <none>
frontend-6tzs6 1/1 Running 0 97s 192.168.85.250 k8s-node01 <none> <none>
frontend-lvsdl 1/1 Running 0 97s 192.168.85.253 k8s-node01 <none> <none>
pod-secret-registry 1/1 Running 0 31s 192.168.85.202 k8s-node01 <none> <none>
[root@k8s-master01 secret]# kubectl describe pod pod-secret-registry
Name: pod-secret-registry
Namespace: default
Priority: 0
Node: k8s-node01/192.168.18.130
Start Time: Wed, 28 Apr 2021 08:29:06 +0800
Labels: <none>
Annotations: cni.projectcalico.org/podIP: 192.168.85.202/32
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"pod-secret-registry","namespace":"default"},"spec":{"containers":[{"i...
Status: Running
IP: 192.168.85.202
IPs:
IP: 192.168.85.202
Containers:
myapp:
Container ID: docker://a86ddde7e21a47110ae8117c5f359ab160de9fd67cea5cc4e9254c7355ef7efa
Image: 192.168.18.131:5000/k8s-secret/myapp:v1
Image ID: docker-pullable://192.168.18.131:5000/k8s-secret/myapp@sha256:9eeca44ba2d410e54fccc54cbe9c021802aa8b9836a0bcf3d3229354e4c8870e
Port: <none>
Host Port: <none>
State: Running
Started: Wed, 28 Apr 2021 08:29:07 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-k2f44 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-k2f44:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-k2f44
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned default/pod-secret-registry to k8s-node01
Normal Pulling 40s kubelet, k8s-node01 Pulling image "192.168.18.131:5000/k8s-secret/myapp:v1"
Normal Pulled 40s kubelet, k8s-node01 Successfully pulled image "192.168.18.131:5000/k8s-secret/myapp:v1"
Normal Created 40s kubelet, k8s-node01 Created container myapp
Normal Started 40s kubelet, k8s-node01 Started container myapp
由上可见,通过secret认证后pod拉取私有镜像是可以的。