一、前言
在k8s中,ConfigMap这一概念相信很多小伙伴都知道吧?它是Kubernetes中一种机制,很多应用在其初始化或者运行期间要依赖一些配置信息,可让你将配置数据注入到应用的Pod内部,允许你将配置清单与镜像内容,以保持容器化的应用程序的可移植性。前几天在某一公众号看到关于网友留言提出疑问:应用程序配置如环境变量或者以ConfigMap的方式可以不重建实现动态更新吗?,先不说结论,那么我们就这个问题进行实验
二、实施流程
我们可以将配置文件注入到Configmap中,而ConfigMap可以基于环境变量以及数据卷挂载的形式注入到Pod资源中。
2.1、创建ConfigMap
基于YAML创建一个ConfigMap来存储Nginx静态配置,先定义index.html页面内容
apiVersion: v1
kind: ConfigMap
metadata:
namespace: mdt-demo
name: indexhtml
data:
index.html: |
<html>
<body>
<h1>Welcome to 宇轩辞白技术博客!https://blog.51cto.com/u_11880730</h1>
</body>
</html>
2.2、创建Nginx Deployment
创建Nginx 资源,将ConfigMap挂载为数据卷
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: mdt-demo
name: my-nginx
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-beijing.aliyuncs.com/devops-op/nginx:stable-alpine
ports:
- containerPort: 80
volumeMounts: #以数据卷存储的方式进行挂载,指定挂载卷组名称
- name: config-volume #与configmap定义的数据卷名称一致
mountPath: /usr/share/nginx/html #定义数据卷挂载的容器目录位置
volumes:
- name: config-volume #定义configmap 的数据卷名称
configMap:
name: indexhtml #指定前面定义好的configmap名称
2.3、创建Service
创建Nginx service资源,定义访问端口,便于后续验证测试
apiVersion: v1
kind: Service
metadata:
namespace: mdt-demo
name: my-service
spec:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
三、验证
3.1、ConfigMap是否热更新
尝试更新ConfigMap内容,验证当对其内容进行变更是否会同步至Pod所挂载的路径资源文件中
将configmap里面的idnex.html内容修改如下:
apiVersion: v1
kind: ConfigMap
metadata:
namespace: mdt-demo
name: indexhtml
data:
index.html: |
<html>
<body>
<h1>Welcome to 宇轩辞白技术博客!https://blog.51cto.com/u_11880730</h1>
<h1>Welcome to 宇轩辞白技术博客!https://blog.51cto.com/u_11880730</h1>
</body>
</html>
此时,等待一会再次使用curl,会看到已经更新
3.2、验证subPath是否支持热更新
我们在验证一下引用"subPath"机制指定子路径验证一下是否会热更新
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: mdt-demo
name: my-nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: harbor.51trust.net/zyyl/nginx:stable-alpine
ports:
- containerPort: 80
volumeMounts: #这里制定了两个挂载路径,分别为引用了subPath和没有引用subPath
- name: config-volume
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
- name: config-volume
mountPath: /tmp/
volumes:
- name: config-volume
configMap:
name: indexhtml
关于subpath知识点拓展
在deployment资源定义中,subPath和mountPath有什么区别?
subPath用于指定configmap特定的子路径挂载,可以选择性的将ConfigMap中特定的子文件路径进行挂载指定,而如果不加subPath,会直接将ConfigMap中的子路径文件全部挂载到容器中
有人可能会说,subpath不就是单独指定configmap子路径文件嘛,我不引用subPath,直接只用mountpath后面跟上绝对路径不行吗?
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html/index.html
volumes:
- name: config-volume
configMap:
name: indexhtml
答案是肯定不行的,这样会报错
随后更新index.html内容,看看容器中所挂载的目录文件是否更新,为了更加直观,我们可以直接切换到Pod里面看
apiVersion: v1
kind: ConfigMap
metadata:
namespace: mdt-demo
name: indexhtml
data:
index.html: |
<html>
<body>
<h1>Welcome to 宇轩辞白技术博客 非常棒!https://blog.51cto.com/u_11880730</h1>
</body>
</html>
可以发现,ConfigMap虽说均已数据卷形式挂载,但是"Volume subPath"所挂载的文件并不支持热更新,还是之前旧版本内容
官方参考链接:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/
如想使其生效,只能重建Pod即可完成ConfigMap更新
3.3、验证env是否支持热更新
cat nginx-env-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: mdt-demo
data:
SPECIAL_LEVEL: very
SPECIAL_TYPE: charm
在已有的Deployment资源中引用以环境变量(ENV)的方式挂载ConfigMap
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: mdt-demo
name: my-nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: harbor.51trust.net/zyyl/nginx:stable-alpine
env:
- name: SPECIAL_LEVEL_KEY #定义最终环境变量名称
valueFrom:
configMapKeyRef:
name: special-config #指定configmap名称
key: SPECIAL_LEVEL #指定configmap中的变量名称
- name: SPECIAL_TYPE_KEY ##定义最终环境变量名称
valueFrom:
configMapKeyRef:
name: special-config #指定configmap名称
key: SPECIAL_TYPE #指定configMap中的变量名称
ports:
- containerPort: 80
volumeMounts:
- name: config-volume
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
- name: config-volume
mountPath: /tmp/
volumes:
- name: config-volume
configMap:
name: indexhtml
可以发现环境变量已在容器中生效,于是乎尝试修改configmap中的值,看看是否热更新
#vim nginx-env-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: mdt-demo
data:
SPECIAL_LEVEL: very-new
SPECIAL_TYPE: charm-new
可以发现,以环境变量挂载的ConfigMap不支持热更,需将Pod重载才能完成生效
四、总结
环境变量无法动态更新,ConfigMap
通过挂载的方式可以动态更新,但挂载时不能使用 subPath
,ConfigMap/Secret 作为 volume 挂载在 Pod 中,如果 ConfigMap 的值发生变化,最大的等待时间就是 kubelet 的同步周期(默认1分钟),但是作为环境变量的 env 和 volume subPath 不支持热更新,环境变量在 Pod 启动的时候就已经固定了。