用 Sidecar 刷新應用配置

在 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

這段代碼:

  • 在 template.spec 中加入了 shareProcessNamespace: true,表示啟用進行命名空間共享功能;
  • 新建了一個伴行的 Sidecar 容器;
  • 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 等都可以使用這種方式來完成配置刷新工作。能夠有效的避免重啟或修改業務應用的老大難問題。


分享到:


相關文章: