一.背景
隨着公司項目使用gitlab越來越多,業務發布的次數越來越頻繁,對於發布效率提出了更高的要求。從2012開始,Gitlab官方開始集成了Continuous Integration (CI) & Continuous Delivery (CD)功能。本文主要針對該功能的實踐做一個分享。
GitLab CI/CD可以做很多事情,下圖展現了GitLab CI/CD工作流程中整個的服務能力,而無需使用外部工具來交付軟件。
在介紹實踐方案之前,我們先簡單的了解一下和Continuous Integration (CI) & Continuous Delivery (CD)功能有關的相關知識。
二.基礎知識
術語介紹
gitlab-pipeline
一次pipeline其實相當於一次任務構建,里面可以包含多個流程,如安裝依賴、運行測試、編譯代碼、部署測試服務器、部署生產服務器等。任何提交或者Merge Request的合並都可以觸發pipeline,觸發pipeline創建的方式主要有如下。如需詳細了解,請查閱官網
gitlab-stage
Stage表示一個構建階段,我們可以在一個Pipeline中定義多個Stage,這些Stage會有以下特點:
所有Stage會按照Stages參數里定義的順序串行執行,即當一個Stage完成后,才會執行下一個Stage。
默認情況下只有當所有Stage成功后,最終的pipeline構建任務才會成功。
默認情況下任何一個Stage失敗,那么后面的Stage不會執行,該構建任務最終會失敗。
pipeline和stage的關系簡單理解為下圖。
gitlab-job
job表示構建工作,即某個Stage里面執行的工作內容。我們可以在同一個Stage里面定義多個Job,這些Jobs會有以下特點:
相同Stage中的Job會並行執行。
相同Stage中的Job都執行成功時,該Stage才會成功。
如果任何一個Job失敗,那么該Stage失敗,即該構建任務失敗。
stage和jobs的關系簡單理解為下圖。
我們以某個pipeline為例解釋pipeline、stage、job的含義,具體請看下圖。
gitlab-ci-yaml
pipeline執行的內容使用ymal語言進行描述,默認文件名為.gitlab-ci.yml,該文件默認放在倉庫的根目錄下即可生效。
下表對gitlab 11.11.4版本中.gitlab-ci.yml文件里常用的關鍵字參數進行簡單說明。
gitlab-runner
.gitlab-ci.yml文件里的內容由誰來執行呢,答案就是gitlab-runnter,一般gitlab-runner會和gitlab所在服務器進行隔離,因為一個任務的構建,往往會執行編譯、測試、發布的過程,這個過程會大量消耗系統資源。gitlab-runner幾乎可以安裝在任何機器上。下面介紹gitlab-runner的官方倉庫源安裝方式。關於gitlab-runner的其他安裝方式請查閱官方文檔(https://docs.gitlab.com/runner/install/)。
1.添加倉庫源
# For Debian/Ubuntu/Mint
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
# For RHEL/CentOS/Fedora
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash
2.安裝指定的gitlab-runner版本,比如這里安裝11.11.4版本。
sudo apt-get install gitlab-runner=11.11.4
# for RPM based systems
sudo yum install gitlab-runner-11.11.4
3.點擊左側欄Settings->CI/CD->Runners->Collapse獲取runner的token,如下圖。
4.注冊gitlab-runner到gitlab實例。
三.實踐方案
該實踐方案主要介紹微服務項目使用gitlab自帶的GitLab Continuous Integration (CI) & Continuous Delivery (CD)功能,在gitlab提供的runner里面進行打包、測試、發布。
持續集成主要是代碼編譯和打包的過程,一般最終會集成一個適合業務場景的系統層docker鏡像。下面為集成系統層docker鏡像Dockerfile的主要內容:
FROM debian:stretch
# 准備軟件包文件
ADD soft/ /data/soft/
# 安裝基本軟件
RUN DEBIAN_FRONTEND=noninteractive apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y vim htop wget dnsutils dmidecode ipmitool pciutils perl \
rsync screen less sysstat at stress tcpdump lsof curl telnet ntp rsyslog sudo locales logrotate cron supervisor \
numactl openssh-server-x509 openssh-client iptables gawk filebeat mongodb3.4.16 graphviz \
&& apt-get clean
# 安裝開發環境
RUN DEBIAN_FRONTEND=noninteractive apt-get update \
&& apt-get install -y python python-pip gcc g++ build-essential python-dev python-setuptools python-smbus \
build-essential libncursesw5-dev libgdbm-dev libc6-dev zlib1g-dev libsqlite3-dev tk-dev libssl-dev openssl \
libffi-dev cmake automake python-setuptools libtcmalloc-minimal4 sockstat strace gdb graphviz \
&& apt-get clean
# 安裝python3.7
RUN cd /data/soft/ && tar xf /data/soft/Python-3.7.0.tgz && cd Python-3.7.0 && ./configure --enable-optimizations --with-ssl-default-suites=openssl --enable-shared \
&& make && make install && cp libpython3.7m.so.1.0 /lib64/ && ldconfig && rm -rf /data/soft
# 業務啟動腳本
COPY entrypoint.sh /sbin/entrypoint.sh
ENTRYPOINT ["/bin/bash", "-x", "/sbin/entrypoint.sh"]
那么怎么把docker鏡像推送到docker倉庫呢?可在.gitlab-ci.yml文件中進行描述,把build好的鏡像推送到gitlab內置的registry中。關於gitlab內置的registry部署可參考官網說明
(https://docs.gitlab.com/ce/user/packages/container_registry/index.html)。下面為打包並上傳容器鏡像stage的主要內容。
build_push:
only:
refs:
- tags
variables:
- $CI_COMMIT_REF_NAME =~ /^rel_[0-9].*$/ # 規定必須通過打tag且名字為rel_xxx的格式才觸發pipeline。
tags:
- docker
stage: ex_build
script:
# build docker image
- docker login $DOCKER_REGISTRY
- echo "$ docker pull $BUILD_IMAGE"
- docker pull $BUILD_IMAGE # 防止$BUILD_IMAGE更新后,runner會緩存,故在build之前先pull一次。
- echo "$ docker build -t $image"
- docker build --no-cache -t $image .
- echo "$ docker tag $image $latest"
- docker tag $image $latest
# push docker image
- echo "$ docker push $image"
- docker push $image
- echo "$ docker push $latest"
- docker push $latest
- docker logout $DOCKER_REGISTRY
when: manual # 手工確認
allow_failure: false
environment:
name: build
gitlab-runner中對應job的部分日志截圖如下:
持續交付CD
持續交付或者持續發布的方式其實有很多種,理論上只要服務方提供了發布接口,你就可以封裝在.gitlab-ci.yml文件里使用gitlab-runner調用api進行自動發布。下面主要介紹容器的發布方式。
發布容器時主要調用自建容器服務的發布接口,其中主要的stage內容如下:
deployment_production:
only:
refs:
- tags
variables:
- $CI_COMMIT_REF_NAME =~ /^exrel_[0-9].*$/
tags:
- docker
stage: ex_deployment_production
script:
# 更新當前環境下指定渠道
- deploy_service ${CI_ENVIRONMENT_NAME} "$image" #image為持續集成build后push到registry的docker鏡像。deploy_service是封裝容器發布過程的函數。該函數主要是根據傳入的image,請求k8s的kube接口進行微服務發布。
when: manual
environment:
name: production
gitlab-runner中發布game微服務的job日志截圖如下。
發布流程
微服務的發布流程主要分2種類型:常規發布和熱更發布。常規發布需要重建容器,熱更發布無需重建容器。
下面為常規發布場景下整體的發布流程。
熱更發布
核心思路是把需要熱更的內容put到etcd集群,服務端集群自動獲取內容進行熱更,下面為熱更發布場景下整體的發布流程。
四.效果展示
常規發布下的pipeline
熱更發布下的pipeline