前言
文章開始前,先嚐試回答幾個問題:-
在日常工作中,程式的打包和部署方式流程是怎樣的?
-
如果使用Docker容器部署方式,是用原生Docker命令,還是Kaniko這類工具?
-
除了業務服務外,如果還需要同時執行其他程序,應該怎麼辦?舉個例子:除了主服務程序(比如Web伺服器),還需要同時啟動Nginx程序(用於代理轉發部分前端流量,解決跨域問題)。
-
屬於 CI 整合的概念:GitLab和Docker的整合是一種主流方式,其他工具也大同小異。
-
與核心態和使用者態有關。Kaniko是一種常用的容器映象構建工具。
-
需要用到程序管理工具,在Docker容器中同時管理多個程序。
一個個來說。
GitLab 和 Docker 的整合
兩者的整合主要有三種方式,手段大同小異,但核心目的都是把Docker打包映象的流程放到GitLab的流水線中執行。可參見官 https://docs.gitlab.com/ee/ci/docker/using_docker_build.html:
以 shell executor 為例:
可見,做法很簡單:將Docker命令作為流水線指令碼執行即可,映象打包出來後可用來部署。以近期熱度較高的大模型服務為例,經典的整合架構如下圖所示:
其他CI整合的主流程萬變不離其宗,不同之處在於在此基礎上做一些最佳化,比如快取加速等。
常用的容器映象構建工具:Kaniko
同樣,先看官網 https://github.com/GoogleContainerTools/kaniko 定義:
可見,Kaniko 是一個用於構建容器映象的工具,它允許我們從Dockerfile構建映象,且不需要Docker守護程序。Kaniko executor 構建映象的詳細步驟如下:
-
Kaniko Executor Image:Kaniko執行器映象是一個特殊的容器映象,它包含了所有必要的工具和依賴,以便在容器內部構建新的Docker映象。
-
Building an Image from a Dockerfile:使用者提供一個Dockerfile,Kaniko執行器映象將根據這個Dockerfile來構建一個新的映象。Dockerfile包含了一系列的指令,這些指令定義瞭如何構建一個新Docker映象,例如
FROM
,RUN
,COPY
,ADD
等。 -
Extracting the Filesystem of the Base Image:在Dockerfile中,
FROM
指令指定了基礎映象,Kaniko 首先需要提取這個基礎映象的檔案系統。這個檔案系統被複制到 Kaniko 執行器映象的臨時目錄中,以便後續的構建過程可以在使用者空間中對其進行操作。 -
Executing Commands in the Dockerfile:Kaniko逐個執行Dockerfile中的指令。對於每個指令,Kaniko都會在使用者空間中模擬該指令的效果。例如,如果指令是
RUN apt-get update
,Kaniko會在容器內部執行這個命令,就像在普通的Docker構建過程中一樣。 -
Snapshotting the Filesystem in Userspace:在每個指令執行之後,Kaniko 會在使用者空間中對檔案系統進行快照。這個快照捕獲了自上一個快照以來檔案系統的所有變化,這些變化包括新建立的檔案、修改過的檔案和刪除的檔案。
-
Appending a Layer of Changed Files:如果在執行某個指令後檔案系統發生了變化,Kaniko 會將這些變化作為一個新層新增到基礎映象上。這個過程是逐層進行的,每個指令可能對應一個或多個層,這取決於檔案系統的變化。
-
Updating Image Metadata:除了新增檔案系統的變化之外,Kaniko還會更新映象的後設資料,包括標籤、環境變數、工作目錄等。這些後設資料資訊也是 Dockerfile 中指令的一部分,Kaniko會確保這些資訊被正確地應用到新構建的映象上。
- Pushing the Image to a Registry:一旦所有的指令都被執行完畢,並且所有的變化都被新增到映象中,Kaniko 會將這個新構建的映象推送到指定的容器映象倉庫(registry)。這個步驟需要提供倉庫的認證資訊,以便Kaniko能夠成功地將映象推送到倉庫。
在 Docker 容器中管理多個程序
現實中,大部分情況下容器中僅會有一個程序,也即1號程序。但總會有例外發生,以上文中的例子來說,某個容器中不僅需要主服務程序提供Web服務,還需要Nginx程序用於代理轉發部分前端流量,以解決跨域問題。此時就需要同時啟動並管理多個程序。有需求就有實現,目前多程序管理工具有很多了,一種常見的方案是使用Python編寫的程序管理工具supervisord,它可以管理多個程序,包括啟動、停止、重啟等操作。針對上述例子,整體整合方式如下:- 製作基礎映象:基於centos系統映象,安裝supervisord 和nginx。
/bin/sh -c yum install -y epel-release
/bin/sh -c yum install -y supervisor
/bin/sh -c yum install -y nginx-1.10.3
/bin/sh -c yum clean all
# 注意只列出了本文涉及到的幾個命令,還有很多其他功能需要安裝
# 可參考倉庫 https://github.com/CentOS/sig-cloud-instance-images
# 該倉庫包括了centos系統的各種映象的構建命令,囊括了很多實用命令安裝指令碼
2. 編寫 /etc/supervisord.conf,它是supervisord的主配置檔案,定義了supervisord 程序管理器的全域性設定和行為,確保所有被管理的程序都能按照預期的方式啟動和執行。透過這個配置檔案,可以集中管理多個服務,使得服務的部署和維護更加方便。
[unix_http_server]
file=/var/run/supervisor.sock
chmod=0700
[supervisord]
logfile=/var/log/supervisor/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/var/run/supervisord.pid
nodaemon=false
minfds=1024
minprocs=200
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock
[include]
files = /etc/supervisor/conf.d/*.ini
[unix_http_server]:定義了
supervisord
的 Unix 套接字 HTTP 伺服器的配置,用於supervisorctl
命令列工具或其他客戶端與supervisord
進行通訊。[supervisord]:包含了
supervisord
守護程序的全域性配置,如日誌檔案位置、日誌大小限制、日誌備份數量、程序檔案位置、最小檔案描述符和程序數量等。[rpcinterface:x]:定義了 RPC 介面的配置,允許遠端管理
supervisord
。這通常用於supervisorctl
命令列工具。[supervisorctl]:定義了
supervisorctl
命令列工具的配置,如連線到supervisord
的 URL。[include] :允許
supervisord
包含其他配置檔案。這使得你可以將不同的程式配置在不同的檔案中,然後由主配置檔案統一管理。通常,這個節會包含/etc/supervisor/conf.d/*.ini
,這樣supervisord
就會自動載入/etc/supervisor/conf.d/
目錄下的所有.ini
檔案。
-
為各工程使用方便,將 /etc/supervisor/conf.d/nginx.ini 提前打包到映象中,後續只需配置 nginx.conf 即可。
[program:nginx]
command=/etc/nginx/sbin/nginx
user=xiaoxi666
priority=999
numprocs=1
autostart=true
autorestart=true
startsecs=1
startretries=3
stopsignal=KILL
stopwaitsecs=10
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx.err
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=5
stopasgroup=true
[program:nginx]:定義了一個名為
nginx
的程式。supervisord
會根據這個名稱來識別和控制這個程序。各個欄位含義:
command
:指定啟動程序的命令。
user
:指定以哪個使用者身份執行 Nginx 程序。通常建議使用非 root 使用者來執行服務以提高安全性。
priority
:設定程式的啟動優先順序。較小的數字表示更高的優先順序,即supervisord
會先啟動優先順序數值較小的程式。
numprocs
:指定應該啟動多少個程序。這裡設定為1,意味著只啟動一個 Nginx 程序。
autostart
:設定為true
時,supervisord
會在啟動時自動啟動這個程式。
autorestart
:設定為true
時,如果nginx
程序意外退出,supervisord
會自動重啟它。
startsecs
:指定 Nginx 程序啟動後多少秒內被認為是穩定的。如果在這個時間內程序退出,supervisord
會認為啟動失敗。
startretries
:如果 Nginx 程序在startsecs
時間內退出,supervisord
會嘗試重啟它。這個值指定了最大重啟次數。
stopsignal
:指定停止 Nginx 程序時傳送的訊號。KILL
訊號是一個強制終止程序的訊號。
stopwaitsecs
:指定supervisord
等待 Nginx 程序停止的時間(以秒為單位)。如果超時,supervisord
會傳送KILL
訊號。
stdout_logfile
:指定 Nginx 程序的標準輸出日誌檔案的位置。
stderr_logfile
:指定 Nginx 程序的標準錯誤日誌檔案的位置。
stdout_logfile_maxbytes
:設定標準輸出日誌檔案的最大大小。當檔案達到這個大小後,會滾動切分輸出。
stdout_logfile_backups
:設定標準輸出日誌檔案的備份數量。當日志檔案滾動切分時,舊的日誌檔案會被保留的備份數量。
stopasgroup
:設定為true
時,supervisord
會向整個程序組傳送停止訊號,這可以確保所有子程序都被正確終止。
做完這一步,該映象就可以提供給“同時需要Web服務和Nginx服務”的工程使用了。
- 各工程編寫自己的Dockerfile檔案,將自定義的服務ini檔案(假設名字為supervisor-app.ini)和 nginx.conf 檔案複製到指定目錄,然後啟動supervisord。
# 定義環境變數
ENV SUPERVISOR_CONF_DIR=/etc/supervisor/conf.d
ENV NGINX_CONF_DIR=/etc/nginx/conf.d
ENV APP_DIR=/app
ENV PROJECT_NAME=xiaoxi666_demo_project
# 複製supervisord的配置檔案到supervisord的配置目錄
COPY supervisor-app.ini ${SUPERVISOR_CONF_DIR}/supervisor-app.ini
# 複製nginx配置檔案到指定的nginx配置目錄
COPY nginx.conf ${NGINX_CONF_DIR}/nginx.conf
# 複製當前目錄下的所有檔案到APP_DIR
COPY . ${APP_DIR}
# 建立專案目錄並移動target目錄下的內容到專案目錄
RUN mkdir -p ${APP_DIR}/${PROJECT_NAME} \
&& mv ${APP_DIR}/target/* ${APP_DIR}/${PROJECT_NAME} \
&& chown -R xiaoxi666:xiaoxi666 ${APP_DIR}
# 暴露埠
EXPOSE 8080 其他要暴露的埠
# 啟動supervisord
CMD ["/usr/bin/supervisord", "-n"]
其中,supervisor-app.ini檔案內容為主程序的啟動命令,一個示例:
[program:xiaoxi666-demo-project]
command=java -jar 其他虛擬機器引數 xiaoxi666-demo-project.jar
user=root
priority=999
numprocs=1
autostart=true
autorestart=true
startsecs=1
startretries=3
stopsignal=KILL
stopwaitsecs=20
stdout_logfile=%(ENV_LOG_DIR)/supervisor/xiaoxi666-demo-project.log
stderr_logfile=%(ENV_LOG_DIR)/supervisor/xiaoxi666-demo-project.err
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=5
stopasgroup=true
而 nginx.conf 根據實際代理需求配置即可。
整體來看,檔案引用層級是這樣的:
後記
本文以實際工程中的例子為切入點,圍繞“Docker容器映象構建”、“GitLab整合部署”,以及“容器多程序管理”這幾個側重點做了一些探討和梳理,同時給出了對應的官方參考資料連結,有興趣的讀者可進一步深入學習。也歡迎大家留言,談談你所經歷的容器整合部署方式是怎樣的。