從0到1進行服務docker化
背景
1. 隨著時間的積累,網路管理服務日趨複雜,運維同學很難完全弄清楚各個迭代版本的差異,而研發同學對於現網管理服務的部署細節也不是完全清楚,服務的交付成為一個痛苦的過程。
2. 因為網路管理服務的配置往往是跟機房相關的,新增一個機房需要對現網所有服務的配置文件進行修改。可想而知,新增一個機房需要投入多大的人力,而且容易出錯。
3. 變更失敗時,服務回退需要同時回退二進位文件,對應版本的配置文件以及其他依賴項,也是比較容易出錯。
4. 服務的遷移也是需要將同一個服務的二進位文件,配置文件以及其他依賴項同時部署到新機器上
隨著服務規模擴大,數量增多,研發和運維之間的矛盾會變得非常突出。本質是因為服務運行成功與部署成功之間存在一條溝,受到很多條件限制。
所以我們嘗試用容器的方法將服務及其運行環境放到一起,簡化部署過程,使得部署成功盡量等價於運行成功。
工作流
研發:gitlab + jenkins + 配置中心
運維:維護docker-compose.yml
研發->運維:docker鏡像ID
說明:
1. 對於研發而言所有的docker鏡像的編譯配置都放在jenkins中
2. 配置中心:放置服務實際的配置+各服務的配置模版,服務的配置文件是編譯docker鏡像時動態生成,而非直接由研發提供。新增機房時無需提供新的配置文件,只需要在配置中心增加新機房配置,所有的服務都能夠自動生成對應機房的配置。
3. docker-compose.yml:啟動docker的配置文件,詳見:Docker Compose
例子
以部門的一個服務unet3manager為例,服務由一個so文件+配置文件組成。
1. jenkins配置
- 設置服務的gitlab連接,如下圖所示:
- 設置編譯命令,包括生成可執行文件,製作docker鏡像。第一個Shell Command作用是編譯出unet3manager.so;第二個是製作出docker鏡像。
主要看第二個shell命令
1) wiwo_cfg承擔了配置中心的功能。build_images.sh是編譯鏡像的腳本;run.sh中集成了 所有機房相關的配置,將會根據模版生成配置文件;templates是各服務的配置文件模版。
2) build_image.sh和Dockerfile代碼如下所示。最終將unet3manager.so、run.sh和配置文件模版放到了容器中。
cat build_image.sh---#!/bin/bashsub_sys=$1module=$2tag=$3typeset -l module_lowmodule_low=${module}sed -i "s#%{sub_sys}#${sub_sys}#g" Dockerfilesed -i "s#%{module}#${module}#g" Dockerfileurl="preugistry.XX/YY/${module_low}:${tag}"docker build -t ${url} .docker push ${url}cat Dockerfile---FROM image_idADD run.sh root/RUN mkdir -p root/%{sub_sys}/%{module}COPY *.so /root/%{sub_sys}/%{module}/COPY templates /root/templates
3) 最後給出docker鏡像的ID。
如果$BUILD_NUMBER=42,則編譯出來的鏡像ID為:preugistry.XX/YY/unet3manager:42
2. 配置中心(run.sh+templates)
1) run.sh: 容器啟動後的第一個命令,負責生成配置文件,啟動服務。
- 存儲所有的配置項,主要包括四類:環境變數,機房級別通用變數,各業務特殊通用變數,配置模版中基本不變的配置
- 通過sed替換,根據配置文件模版生成配置文件
- 前台運行服務
腳本結構如下:(為了方便描述,只抽取出部分示意配置)
# 解析輸入:/root/run.sh --azid=XX --module=YY# 獲取參數, 過程省略# azid=XX# module=XX# 獲取環境變數, 過程省略# serviceip=XX # serviceport=XX# 機房級別的變數case "$azid" in666888) _zone="pre" _zoneid="666888" _regionid="666888" _ns_unet_setr="${NS_UNET}/set${_regionid}" _ns_unet_setz="${NS_UNET}/set${_zoneid}" _ns_ulb_setr="${NS_ULB}/set${_regionid}" # _unet3manager _unet3manager_conf_lan_gw_ip="10.21.0.1" # 其他配置 <...省略...> ;;4001) ;;*) echo "wrong azid name: ${azid}" exit 1 ;;esacecho ${_name_unet3manager:="${_ns_unet_setr}/UNet3Manager"}###### 找到服務模版 ##########cd /rootfile=$module".conf"cp -f "templates/${file}.template" $file####### 環境變數 ##########sed -i "s#%{listen_ip}#${serviceip}#" $filesed -i "s#%{listen_port}#${serviceport}#" $file####### 通用變數 ##########sed -i "s#%{name_unet3manager}#${_name_unet3manager}#" $file####### 各業務相關配置替換 ##########sed -i "s#%{unet3manager_conf_lan_gw_ip}#${_unet3manager_conf_lan_gw_ip}#" $file###### 啟動服務 ########mv -f $file /root/XX/confXX_start -c /root/XX/conf/$file
2) templates: 配置文件模版%{變數}的方法指代一個實際變數,運行時由run.sh根據配置信息生成實際的配置文件,unet3mananger配置文件如下:
$ cat templates/unet3manager.conf.template[common]subsys = usdnmodule = UNet3Manager[network]listen-pair = 0.0.0.0:%{listen_port}:${HOME}/@{common.subsys}/@{common.module}/@{common.module}.soclient-pair = *:*:${HOME}/@{common.subsys}/@{common.module}/@{common.module}.so:listen-ip = %{listen_ip}listen-port = %{listen_port}[log]level = %{log_level}maxsize = 10M[name]myname = %{unet3manager_name_myname}udatabase = %{name_udatabase}uvroutermanager = %{name_uvroutermanager}unet3manager = %{name_unet3manager_notexist}[plugin]zookeeper = ${HOME}/aioplug/aioplug_zookeeper/aioplug_zookeeper.so[zookeeper]server = %{zookeeper_server}[conf]region_id = %{unet3manager_conf_region_id}lan_gw_ip = %{unet3manager_conf_lan_gw_ip}[mode]pnat_only = %{unet3manager_mode_pnat_only}
3. 啟動docker:運維同學拿到docker鏡像之後,修改docker-compose.yml再重啟docker就可以完成部署。
- docker-compose.yml
unet3manager: image: preugistry.XX/YY/unet3manager:42 command: /root/run.sh --azid=666888 --module=unet3manager container_name: unet3manager_ins1 ports: - "192.168.153.97:XX:XX" volumes: - /var/log:/var/log environment: - SERVICEIP=192.168.153.97 - SERVICEPORT=7250 restart: always
- 啟動docker:docker-compose up -d unet3manager
TODO: 增加管理工具,配置從run.sh進入到資料庫
推薦閱讀:
※國內程序員怎樣競爭 Google 總部的工作機會,需要滿足哪些條件?
※SRE就是程序測試員么?
※「開發靠 Google,運維靠 Baidu」的說法靠譜嗎?
TAG:Docker | 云计算 | SRESiteReliabilityEngineer |