TOC
Secret资源
ConfigMap和Secret都是Kubernetes标准资源,都是用于实现为Pod中的容器提供配置信息的,而这个配置信息,还有这样额外的一层作用,它扮演了Kubernetes系统之上一组类似应用的配置中心,当配置发生变更的时候,我们只需要修改中心存储当中的配置,而后让我们的配置中心应用程序更新自己的配置信息并且让其重载应用程序;
配置中心都需要存储大量的配置数据,那么这些配置数据可以存储在各式各样的存储系统当中,KV存储最为常见,比如zookepper、etcd这些配置工具,ConfigMap提供的配置信息,一般而言可以被我们的Pod容器以两种方式进行加载,所以Pod中的容器加载ConfigMap资源中的信息第一种为环境变量为容器提供环境变量实现,第二种方式就是通过volumes存储卷的方式配置,因为ConfigMap和Pod都是名称空间级别的资源,因此而者必须在同一名称空间下面引用;
ConfigMap也允许我们在必要时进行修改,如果使用存储卷进行修改能够以过一段随机时间间隔以后同步到我们的Pod容器内部,如果容器自身不能够支持自动进行重载,我们可以在外部发送一个重载命令,让其进行重载,这个时候也可以以灰度的方式进行,从这个角度来讲它的发布方式可能会有一定的问题,有一些建构的Kubernetes之上的非常高级的工具也能够帮助我们完成Kubernetes所不支持的各式各样的功能;
我们去构建ConfigMap资源的方式有两种第一种是命令行和配置清单,其实创建ConfigMap配置清单使用命令行反而更简单,但是在命令行去维护的资源是没办法被Kubernetes跟踪的,所以最好使用配置清单进行创建, 如果需要通过命令创建也有两种方式第一种使用--from-literal=key=value还可以让其从文件中加载键值--from-file=key=file_name,如果不指定文件方式的键名,一般文件名就是键名;
对于配置清单的方式的创建,如果我们要嵌套进去的是一个文件内容的话,稍微复杂一点,如下示例;
kind: ConfigMap
apiVersion: v1
metadata:
name: kube-flannel-cfg
namespace: kube-system
labels:
tier: node
app: flannel
data:
cni-conf.json: | # 如果需要多行配置,那么一般用|进行声明
{
"name": "cbr0",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "flannel",
"delegate": {
"hairpinMode": true,
"isDefaultGateway": true
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
}
]
}
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
ConfigMap是针对那些非敏感数据的配置,但我们很多时候需要把一些敏感信息保存在应用程序的配置当中,被应用程序自身加载引用,比如MYSQL容器,它为了能够在初始化MySQL的时候给它初始化一个密码,所以在这个容器会有一个MYSQL_ROOT_PASSWORD的环境变量,我们通过这个环节变量给它传递过去管理员的密码信息,那么就能够让它自动化初始管理员密钥,但是如果把这样的一个容器运行在Kubernetes的Pod当中,通常提供这个配置的信息,我们有可能会把它保存在一个配置中心的配置资源当中,比如ConfigMap,但是ConfigMap定义完成之后,任何能够访问这个名称空间的用户只要授权读取所有资源,它就能够轻松的拿到这些敏感信息,那就存在数据泄露的问题,所以为了避免这个信息被泄露,我们应该使用一个加密的资源当中,这就是我们的Secret,Secret的使用逻辑和ConfigMap没什么区别,唯一不同的是Secret的数据都经过Base64编码的;
Secret资源还存在三种类型
docker-registry:在Kubernetes上使用私有仓库的账号密码,专用于docker-registry,在docker-registry我们创建Pod资源时,在spec当中有一个imagePullSecrets,它是一个对象列表,意味着我们可以给出多个Secret,一个Secret就是一组账号密码,如果第一个能够认证成功,那就用第二个,否则我们就使用第二个,自上而下依次进行检索;
generic:专用于存储非tls类型的敏感信息,比如MySQL密码;
tls:专用于ssl或者tls的x509格式的证书和私钥打包进Secret,证书和私钥本身就是base64编码,因此需要特有的逻辑来组织,不管文件名叫做什么,在tls这种格式来组织的证书通通统一为tls.cert,私钥名为tls.key;
generic
generic的方式主要是存储一些用户自定义的密码,非tls类型的,比如MySQL密码等,示例如下;
通过环境变量的方式
# 创建一个带有环境变量的镜像
[root@node3 nginx]# cat Dockerfile
FROM nginx:1.14-alpine
RUN mkdir -p /data/www/server
COPY entrypoint.sh /bin/
CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
WORKDIR /etc/nginx/conf.d/
ENV PORT 8080
ENV PASSWORD caichangen
EXPOSE 80/TCP 8080/TCP
[root@node3 nginx]# cat entrypoint.sh
#!/bin/sh
cat >> /etc/nginx/conf.d/server1.conf << EOF
server {
server_name 0.0.0.0;
listen ${PORT};
root /data/www/server;
}
EOF
echo "MySQL_ROOT_PASSWORD: ${PASSWORD}" > /data/www/server/index.html
exec "$@"
[root@node2 nginx]# docker build -t env_mysql:latest .
# 创建secert资源,定义密码为Custom password
[root@node1 ~]# kubectl create ns config
namespace/config created
[root@node1 ~]# kubectl create secret generic mysql-root-password -n config --from-literal=mysql-password="Custom password"
secret/mysql-root-password created
# 查看创建的secert
[root@node1 ~]# kubectl get secrets -n config mysql-root-password -o yaml
apiVersion: v1
data:
mysql-password: Q3VzdG9tIHBhc3N3b3Jk
kind: Secret
metadata:
creationTimestamp: "2019-11-30T04:21:33Z"
name: mysql-root-password
namespace: config
resourceVersion: "19652"
selfLink: /api/v1/namespaces/config/secrets/mysql-root-password
uid: d2b1da1a-e428-4556-9562-f33988c65cf2
type: Opaque
# 测试解码(不是很安全,是可以解码的)
[root@node1 ~]# echo Q3VzdG9tIHBhc3N3b3Jk|base64 -d
Custom password[root@node1 ~]#
# 编写Pod配置清单
[root@node1 ~]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: secert-config
namespace: config
spec:
containers:
- name: env-mysql
imagePullPolicy: IfNotPresent
image: env_mysql:latest
env:
- name: PASSWORD
valueFrom:
secretKeyRef:
name: mysql-root-password
key: mysql-password
- name: PORT
value: "8081"
[root@node1 ~]# kubectl apply -f pod.yaml
pod/secert-config created
# 测试效果
[root@node1 ~]# kubectl get pods -n config -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
secert-config 1/1 Running 0 43s 10.244.1.6 node2.cce.com <none> <none>
[root@node1 ~]# curl 10.244.1.6:8081
MySQL_ROOT_PASSWORD: Custom password
通过volume的方式
volume是通过文件的方式载入配置,比如我们的tomcat的默认配置有指定一个管理的user,那么这个时候我们就可以把这个文件提取出来,载入Kubernetes作为Secret,而后通过volume的方式挂在到指定的目录下(可以挂载单个文件),覆盖原有文件;
tls
tls没有--from-literal或者--from-file,而是直接指明--cert(证书)和--key(私钥),无论证书文件名是什么都会映射为tls.cert,无论私钥文件名是什么都会映射为tls.key,示例如下;
使用volume的方式
使用volume的方式其实也就是将Secert资源以文本的形式写入Pod,然后让应用使用,在Kubernetes官方提供的ingress可以直接使用secert的方式挂在,无需使用volume;
# 创建一个ssl的nginx服务器
[root@node2 nginx]# cat Dockerfile
FROM nginx:1.14-alpine
RUN mkdir -p /data/www/server
COPY entrypoint.sh /bin/
CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
WORKDIR /etc/nginx/conf.d/
ENV PORT 443
ENV PASSWORD caichangen
EXPOSE 443/TCP
[root@node2 nginx]# cat entrypoint.sh
#!/bin/sh
cat >> /etc/nginx/conf.d/ssl.conf << EOF
server {
server_name cce.doorta.com;
listen 443 ssl;
root /data/www/server;
ssl_certificate /etc/nginx/cers/fullchain.pem;
ssl_certificate_key /etc/nginx/cers/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
}
EOF
echo "MySQL_ROOT_PASSWORD: ${PASSWORD}" > /data/www/server/index.html
exec "$@"
[root@node2 nginx]# docker build -t webssl:latest .
# 将证书转为Kubernetes之上的Secert资源
[root@node1 ~]# kubectl create secret tls nginx --cert=fullchain1.pem --key=privkey1.pem -n config
secret/nginx created
[root@node1 ~]# kubectl get secrets -n config nginx
NAME TYPE DATA AGE
nginx kubernetes.io/tls 2 95s
# 编写Pod配置清单
[root@node1 ~]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: secert-tls
namespace: config
labels:
type: ssl
spec:
hostNetwork: true
containers:
- name: nginx-tls
imagePullPolicy: IfNotPresent
image: webssl:latest
volumeMounts:
- name: tls-volumes
mountPath: /etc/nginx/cers
volumes:
- name: tls-volumes
secret:
secretName: nginx
items:
- key: tls.crt
path: fullchain.pem
- key: tls.key
path: privkey.pem
[root@node1 ~]# kubectl apply -f pod.yaml
pod/secert-tls created
[root@node1 ~]# kubectl get pods -n config secert-tls -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
secert-tls 1/1 Running 0 13s 172.16.1.4 node3.cce.com <none> <none>
# 测试访问(此时需要在宿主机将hosts文件写入172.16.1.4 cce.doorta.com)