本文作者 / 龙少
开源软件、自动化爱好者。资深马拉松酱油选手。
在Kubernetes的使用过程中,很多人会使用 Configmap 资源来进行配置文件的加载。Configmap 对象是支持热更新的,也就是说,对 Configmap 的变更,会同时反应到加载该 Configmap 的 Pod 之中。但美中不足的是,很多应用都不会检测配置文件的更新,因此就算是通过对 Configmap 的变更,完成了配置文件的修改,应用还是无法做出即时的响应的。可以在外部进行滚动更新;或者改写业务容器,监控文件变化之后重新启动业务进程。
在 Kubernetes 1.10 中新增的 Pod 内共享进程命名空间的功能,给这个问题带来了一点新思路:做一个 Sidecar 用于对配置文件进行监控,发现文件变化之后,发送重新载入的信号给业务进程,要求业务进程自行刷新。这样就无需对业务容器所在镜像进行修改了。
这种方法当然也有个局限性,需要业务进程支持这种信号。
下面以 Apache 为例,看看这种方式的用法。
一、创建 Configmap
用一个简化的 httpd.conf
文件,生成 Configmap,例如:
kubectl create cm apache --from-file httpd.conf
如此就生成了一个名为 apache 的 Configmap。
二、创建 Sidecar 容器镜像
这个镜像要完成的任务有两个:监控文件变化,如果内容变化,则发送信号给业务进程。文件内容变化的监控,可以用哈希码或者 inotify 调用来完成,这里使用 inotifywait
命令做一个死循环,发现特定事件后,则发出信号:
#!/bin/sh
while :
do
# 获取文件名称
REAL=`readlink -f ${FILE}`
# 监控指定事件
inotifywait -e delete_self "${REAL}"
# 获取特定进程名称的 PID
PID=`pgrep ${PROCESS} | head -1`
# 发送信号
kill "-${SIGNAL}" "${PID}"
done
这里没有用监控本地文件的
-m
或者-e modify
事件,而是用了delete_self
,这是 Configmap 加载生成文件的差异,也可以考虑用环境变量来替换这一事件。
然后构建镜像:
FROM alpine
RUN apk add --update inotify-tools
ENV FILE="/tmp" PROCESS="httpd" SIGNAL="USR1"
COPY entry.sh /usr/local/bin
CMD ["/usr/local/bin/entry.sh"]
这里假设镜像名称为 dustise/inotify:latest
。
三、创建实验负载
我们选择 Apache 作为业务应用的示范,它能够接受 USR1
信号进行重新载入。
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: apache
spec:
selector:
matchLabels:
app: apache
template:
metadata:
labels:
app: apache
spec:
shareProcessNamespace: true
containers:
- name: apache
image: httpd:alpine
ports:
- containerPort: 80
volumeMounts:
- name: apache
mountPath: /usr/local/apache2/conf/
- name: refresh
image: dustise/inotify
securityContext:
capabilities:
add:
- SYS_PTRACE
volumeMounts:
- name: apache
mountPath: /etc/httpd
env:
- name: FILE
value: "/etc/httpd/httpd.conf"
- name: PROCESS
value: "httpd"
- name: SIGNAL
value: "USR1"
volumes:
- name: apache
configMap:
name: apache
---
apiVersion: v1
kind: Service
...
type: ClusterIP
这段代码:
1.在 template.spec
中加入了 shareProcessNamespace: true
,表示启用进行命名空间共享功能;
2.新建了一个伴行的 Sidecar 容器;
3.Apache 和 Sidecar 共享来自同一个 Configmap 的配置文件,根据加载情况为 Sidecar 定义了环境变量。
四、测试一下
接下来可以使用 kubectl logs
命令来监控两个容器的日志输出:
$ kubectl logs -f apache-6b8b68c857-dp6xx -c refresh
Setting up watches.
Watches established.
$ kubectl logs -f apache-6b8b68c857-dp6xx -c apache
...
[Wed May 15 18:46:47.795261 2019] [mpm_event:notice] [pid 7:tid 139810635549544] AH00489: Apache/2.4.39 (Unix) configured -- resuming normal operations
[Wed May 15 18:46:47.795330 2019] [core:notice] [pid 7:tid 139810635549544] AH00094: Command line: 'httpd -D FOREGROUND'
然后使用 kubectl edit cm apache
,修改配置文件(例如删除点注释)。稍候片刻,发现两个容器的输出都发生了变化:
五、Sidecar
/etc/httpd/..2019_05_15_18_43_33.773288813/httpd.conf DELETE_SELF
Setting up watches.
Watches established.
脚本检测到了配置文件发生了删除事件,发送信号,并重新启动监控。
六、Apache
[Wed May 15 18:46:47.775392 2019] [mpm_event:notice] [pid 7:tid 139810635549544] AH00493: SIGUSR1 received. Doing graceful restart
Apache 收到了 USR1 信号,进行了优雅重启。
七、结论
对于支持信号控制的第软件,例如 Nginx、Gunicorn、HA-Proxy 等都可以使用这种方式来完成配置刷新工作。能够有效的避免重启或修改业务应用的老大难问题。
猜你还想看这些内容
●Kustomize上篇丨Helm 和 Kustomize:不只是含谷量的区别
· END ·
记得文末点个好看鸭~
点就完事儿了!