聯調環境快速部署——基於docker-compose的CI/CD實踐

Wilee發表於2018-08-19

專案地址: github.com/xiongwilee/…

基本特性:

  1. 快捷部署多人nginx+php的開發測試環境,也可以擴充套件構建其他語言;
  2. 基於Docker和docker-compose,不依賴K8S等高階編排工具,成本低廉、部署簡單;
  3. Docker內建整合jenkins,一鍵新增開發測試角色,無需額外配置;
  4. 支援微服務架構,適用於小公司or敏捷專案團隊,也可以作為Docker學習入門的case

一、背景

在角色分工明確的團隊裡,什麼樣的條件才算是最優雅的聯調和測試環境?在大廠裡肯定都有很多高階的解決方案,比如這些:

大型團隊的合作框架下,必須依賴更復雜的DevOps架構(參考:DevOps詳解)。但對於成員不多、負責的Web專案工程量也不大的團隊,面臨的問題肯定也更單純:

  1. 前後端角色工程解耦,開發環境分離;
  2. 工程師只關注業務邏輯本身,持續整合;
  3. 環境和角色一鍵建立、一鍵更新、一鍵銷燬,環境之間不受影響;

即便是隻有這些需求,在以往的“開發機”的聯調環境裡,一旦需要新增開發或者測試人員,或者需要更新nginx的配置,再或者需要更新PHP、Nodejs的版本……對於測試環境的維護來說都是很痛苦的。

二、快速開始

注意: 當前部署方案僅依賴:Docker,Docker-compose,git

1、下載程式碼

$ git clone https://github.com/xiongwilee/docker-compose-boilerplate.git
複製程式碼

2、新增測試角色demo

$ cd docker-compose
$ sh build.sh -u demo -m admin:master
複製程式碼

此時,在app/會建立demo目錄,在nginx/conf.d會建立demo.conf檔案。

3、啟動服務

$ docker-compose up -d
複製程式碼

此時,再執行docker-compose ps會發現建立了三個映象。然後,配置hosts使sample.demo.testdomain.com指向當前機器,然後訪問http://sample.demo.testdomain.com 返回phpinfo()資訊,說明建立成功。

三、部署架構說明

TIPS: 這個方案僅適用於小公司or敏捷專案團隊聯調測試環境的部署,同時也可以作為Docker學習入門的case,並不適用於有一定規模的生產環境。

在“開發機”上僅僅安裝docker、docker-compose、git之後就能跑起來Nginx、PHP的應用,當然得益於docker容器化的思想。其實這個的實現也僅僅利用了容器化的這個特性,最終docker-compose打包的整個服務會長駐記憶體,無需太多的管理成本。

最終的實現還具備兩個特點:

  1. 基於這個實現的boilerplate你可以輕易的遷移到其他專案,以及其他語言;
  2. 每個sample管理每個應用的倉儲地址、環境變數配置、更新程式碼後的鉤子等操作;

其實現原理為:通過指令碼檔案,管理docker-compose隱射到宿主機的配置、原始碼,同時將docker-compose暴露出來以實現服務的管理。架構圖如下:

聯調環境快速部署——基於docker-compose的CI/CD實踐

1、docker-compose配置檔案:docker-compose.yml

先看docker-compose的配置檔案docker-compose.yml(篇幅原因,刪掉了一部分配置):

version: '3'
services:
    # 所有的PHP環境構建在app容器裡
    php:
        build: ./php
        expose:
            - "9000"
    # nginx容器
    nginx:
        build: ./nginx
        # 埠對映
        ports:
            - "80:80"
        # 依賴關係宣告,先跑php所有服務
        depends_on:
            - "php"
    # jenkins容器
    jenkins:
        image: jenkins:latest
        ports:
            - "8080:8080"
            - "50000:50000"
複製程式碼

這其實就是一個普通的PHP開發環境示例:可以看到就phpnginxjenkins三個基本容器,除了jenkins,其他的容器均使用Dockerfile(build配置)來構建。

2、構建指令碼:build.sh

由於在docker中實現了nginx配置檔案及php原始碼檔案的對映到宿主機,需要通過管理宿主機上檔案就可以管理程式碼的釋出和部署了,build.sh就是用來做這件事情的。

當然了,如果需要在部署程式碼完成之後,做重啟、編譯等操作,通過sample目錄下的鉤子就可以實現了。

具體實現可以參考build.sh原始碼。

四、詳細配置

1、開發測試環境域名配置

nginx/conf.d/sample修改測試環境域名,示例中使用的testdomain.com改成自己的測試環境域名即可。

另外,建議把測試域名泛解析到部署這臺服務的機器。

2、docker-compose.yml配置說明

docker-compose的配置檔案基本不需要修改,只需要關注:nginx是80埠對映到80埠,jenkins是8080埠,而php-fpm的9000埠不對外開放即可。

當然了,如果php環境需要安裝依賴,就需要修改./php/Dockerfile。此外,如果需要新增其他的語言環境,就需要新增一個容器的宣告。

3、模組配置

1)部署指令碼build.sh

業務模組的配置基本是通過部署指令碼build.sh來操作的。執行./build.sh提示如下:

Example:
  ./build.sh -u xiongwilee -m php:online,service:online
Usage:
  -u 必填,角色名                       示例:default
  -m 選填,要更新程式碼的業務模組         示例:php:online,service:online
  -e 選填,更新業務模組對應的環境變數   示例:php:true,service:false
  -d 選填,刪除角色                     示例:default
複製程式碼

2)PHP模組

新增角色實時上是根據php/sample目錄建立了一個角色名對應的資料夾。在sample裡只有四個檔案:

a. 倉儲配置
  • .gitaddress:宣告當前模組的遠端倉儲地址
b. 鉤子
  • on_add.sh:建立角色時下載PHP模組程式碼完成之後的回撥鉤子,用已更新環境變數等檔案,執行./build.sh -u {name}會被呼叫
  • on_upd.sh:某個模組更新完成之後的回撥鉤子,用以編譯、重啟服務等操作,執行./build.sh -u {name} -m web:master會被呼叫
  • on_env.sh:更新環境變數的鉤子,執行./build.sh -u {name} -m web:master -e web:true都會被呼叫。
c. 示例目錄app/sample/sample

在sample目錄下還有個sample目錄,這個是一個php模組示例;新增角色之後訪問sample.{name}.testdomain.com就可以來測試是否成功新增。

3)Nginx配置

a. nginx/conf.d目錄

和php/sample目錄一樣,在nginx/conf.d下也有個sample檔案,這個也是在新增角色時使用的示例配置檔案。注意,新增角色會把sample中的${name}替換成當前角色名。

b. nginx/log目錄

nginx/log目錄及nginx所有日誌檔案的宿主機對映目錄。

4)Jenkins配置方案

jenkins預設開啟8080埠,你可以直接通過http://jenkins.testdomain.com:8080訪問jenkins服務。具體初始化過程這裡不詳述。

a. 安裝外掛獲取當前使用者名稱

在通過Jenkins執行build.sh指令碼時,上文提到的角色名怎麼獲取呢?其實就是jenkins的使用者名稱,你可以通過建立多個jenkins的使用者來建立測試環境角色。

參考jenkins外掛-Build User Vars Plugin簡單說明安裝jenkins外掛。

安裝完成之後就可以通過BUILD_USER環境變數獲取當前jenkins的使用者名稱了(當然了,新建jenkins使用者的使用者名稱最好是拼音或英文)。

b. Docker映象中的Jenkins與宿主機通訊

由於jenkins存在Docker映象中,每次jenkins操作需要執行build.sh都需要使映象中的jenkins與宿主機通訊。這裡使用的方法是,在jenkins的映象新增到宿主機的信任關係。

然後就可以通過ssh apple@{jenkins內網IP} "sh build.sh"來直接執行宿主機裡的指令碼了(這裡肯定還有更優雅的方法)。

c. 新增job

新增一個任務後只需要配置兩項:

  1. general:“引數化構建過程”:
    • 選擇 "String Parameter",新增"web"、"web-fe"、"service"欄位
    • 選擇"Boolean Parameter",新增"web_env"、“service_env”欄位。
  2. 構建:"Execute Shell":
echo "正在將 web-fe:${web_fe},web:${web},service:${service}  部署到 ${BUILD_USER_ID} 環境"

ssh apple@{jenkins內網IP} "sh ~/docker-compose/build.sh -u ${BUILD_USER_ID} -m web-fe:${web_fe},web:${web},service:${service} -e web:${web_env},service:${service_env}";
複製程式碼

這樣,通過這個任務就可以直接在jenkins中執行宿主機中的build.sh指令碼,從而實現新增角色、更新程式碼的操作了。

最後,如果需要在PHP的服務基礎上整合其他語言的服務,比如Nodejs,涉及到的改動有:

  1. 新增Nodejs映象:docker-compose.yml
  2. 新增部署任務:build.sh
    • 建立及刪除角色流程
    • 部署流程
  3. nginx配置檔案示例:nginx/conf.d/sample

五、貢獻

歡迎提供其他更專業的思路,歡迎提issue、fork;也可以郵件聯絡:xiongwilee[at]foxmail.com

相關文章