![4ee49f5a4250d7c737b43748563063ea.png](https://i-blog.csdnimg.cn/blog_migrate/f1b023b417d5967b6808c0d285e3fa91.png)
![b7eb4855194c12a484192da96b59f8d3.png](https://i-blog.csdnimg.cn/blog_migrate/9c0200baffa9ee4f804c628d740af839.png)
lyonger
18年加入网易,先后负责过多个游戏产品的运维工作,多年运维生涯。负责小游戏CI/CD、事件处理平台开发、游戏Nomad运维模式探索、gitlab平台维护等工作。主要关注Linux性能优化、DevOps、云原生领域。探索和分享是一趟美好的旅程。
背景
- 随着公司项目使用
gitlab
越来越多,业务发布的次数越来越频繁,对于发布效率提出了更高的要求。从2012开始,Gitlab官方开始集成了Continuous Integration (CI) & Continuous Delivery (CD)
功能。本文主要针对该功能的实践做一个分享。
基础介绍
GitLab CI/CD
可以做很多事情,下图展现了GitLab CI/CD
工作流程中整个的服务能力,而无需使用外部工具来交付软件。
![d9e7ff30cfc86db0c5463eee62865dcb.png](https://i-blog.csdnimg.cn/blog_migrate/c1745b104709fa6270f8f24fbea16bb7.png)
- 在介绍实践方案之前,我们先简单的了解一下和
Continuous Integration (CI) & Continuous Delivery (CD)
功能有关的相关知识。
术语介绍
![21b5f269d2da5244363b7d032d80ca6e.png](https://i-blog.csdnimg.cn/blog_migrate/f0b9cd67f6e9a97102ec2f648099ed25.png)
gitlab-pipeline介绍
- 一次
pipeline
其实相当于一次任务构建,里面可以包含多个流程,如安装依赖、运行测试、编译代码、部署测试服务器、部署生产服务器等。任何提交或者Merge Request
的合并都可以触发pipeline
,触发pipeline创建的方式主要有如下。如需详细了解,请查阅官网(https://about.gitlab.com/blog/2019/07/12/guide-to-ci-cd-pipelines/)。
![bea25a0c8863f53f18427cb35bac43d4.png](https://i-blog.csdnimg.cn/blog_migrate/38f30c3d4fb6e682bd5c17c4bea58dcb.png)
gitlab-stage介绍
Stage
表示一个构建阶段,我们可以在一个Pipeline
中定义多个Stage
,这些Stage
会有以下特点:- 所有
Stage
会按照Stages
参数里定义的顺序串行执行,即当一个Stage
完成后,才会执行下一个Stage
。 - 默认情况下只有当所有
Stage
成功后,最终的pipeline
构建任务才会成功。 - 默认情况下任何一个
Stage
失败,那么后面的Stage
不会执行,该构建任务最终会失败。
- 所有
pipeline
和stage
的关系简单理解为下图。
![8b45302e71cfae2c7a71bcd973af58ce.png](https://i-blog.csdnimg.cn/blog_migrate/65ec5317d2f154fcfc7bcdb03bf0cde4.png)
gitlab-job介绍
job
表示构建工作,即某个Stage
里面执行的工作内容。我们可以在同一个Stage
里面定义多个Job
,这些Jobs
会有以下特点:- 相同
Stage
中的Job
会并行执行。 - 相同
Stage
中的Job
都执行成功时,该Stage
才会成功。 - 如果任何一个
Job
失败,那么该Stage
失败,即该构建任务失败。
- 相同
stage
和jobs
的关系简单理解为下图。
![f83122b5769bc09bbedf9c905323d245.png](https://i-blog.csdnimg.cn/blog_migrate/6af077857053380d62ef27ed92e359e2.png)
- 我们以某个
pipeline
为例解释pipeline
、stage
、job
的含义,具体请看下图。
![45a35c238d2e47d70a19794f160b9148.png](https://i-blog.csdnimg.cn/blog_migrate/499699fb1668ea664b15bf68a579af14.png)
gitlab-ci-yaml介绍
pipeline
执行的内容使用ymal
语言进行描述,默认文件名为.gitlab-ci.yml
,该文件默认放在仓库的根目录下即可生效。关于ymal
语言的使用可点击这里。(https://www.ruanyifeng.com/blog/2016/07/yaml.html)
下表对gitlab 11.11.4
版本中.gitlab-ci.yml
文件里常用的关键字参数进行简单说明。如需深入了解可查阅官方文档(https://docs.gitlab.com/ee/ci/yaml/)。
![0aac479504f8cf76ab7fecf194d68e71.png](https://i-blog.csdnimg.cn/blog_migrate/d5c540064ba39c7b70cdf91ed8d214cc.png)
![9088dc3ca8847af321b19c800218bad3.png](https://i-blog.csdnimg.cn/blog_migrate/97cbdddcad0eaf347229a809e87d8dfa.png)
![44a19b59c72af7157c7f7f0c74098c55.png](https://i-blog.csdnimg.cn/blog_migrate/301af09c1007941ddf6316e58fc57c69.png)
gitlab-runner介绍
.gitlab-ci.yml
文件里的内容由谁来执行呢,答案就是gitlab-runnter
,一般gitlab-runner
会和gitlab
所在服务器进行隔离,因为一个任务的构建,往往会执行编译、测试、发布的过程,这个过程会大量消耗系统资源。gitlab-runner
几乎可以安装在任何机器上。下面介绍gitlab-runner
的官方仓库源安装方式。关于gitlab-runner
的其他安装方式请查阅官方文档(https://docs.gitlab.com/runner/install/)。- 添加仓库源
# 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
- 安装指定的gitlab-runner版本,比如这里安装11.11.4版本。
# for DEB based systems
sudo apt-get install gitlab-runner=11.11.4
# for RPM based systems
sudo yum install gitlab-runner-11.11.4
- 点击左侧栏
Settings->CI/CD->Runners->Collapse
获取runner的token,如下图。
![3ecfb13b9a9080e5049ebc97db38f3f5.png](https://i-blog.csdnimg.cn/blog_migrate/11b57e8ff4e10ed80650d6d02923a044.png)
- 注册gitlab-runner到gitlab实例。
![99ccbed2861a337b4e29416ce83e14b5.png](https://i-blog.csdnimg.cn/blog_migrate/ab732335bb547ad587de22baa175f234.png)
实践方案
- 该实践方案主要介绍微服务项目使用
gitlab
自带的GitLab Continuous Integration (CI) & Continuous Delivery (CD)
功能,在gitlab
提供的runner
里面进行打包、测试、发布。
持续集成CI
- 持续集成主要是代码编译和打包的过程,一般最终会集成一个适合业务场景的系统层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的部分日志截图如下:
![d47b32cfae55f718fa9168ea31e57a94.png](https://i-blog.csdnimg.cn/blog_migrate/cf34a2aeaf6c6799bc680fae02e53bb5.png)
持续交付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日志截图如下。
![eada66dd437a8ddb6f0026d2d685ec5b.png](https://i-blog.csdnimg.cn/blog_migrate/fd3605c0eefd3fe282e4d3381f7ce109.png)
发布流程
- 微服务的发布流程主要分2种类型:常规发布和热更发布。常规发布需要重建容器,热更发布无需重建容器。
常规发布
- 下面为常规发布场景下整体的发布流程。
![cad5fb9d265cb06e155d65145fd8b842.png](https://i-blog.csdnimg.cn/blog_migrate/54bfe2dac6542cac9818479c56e79f1a.png)
热更发布
- 核心思路是把需要热更的内容put到etcd集群,服务端集群自动获取内容进行热更,下面为热更发布场景下整体的发布流程。
![580ee19f024418983fc883f222dbc4a5.png](https://i-blog.csdnimg.cn/blog_migrate/30cf0df65517c42e4ce6779b924a3016.png)
效果展示
常规发布下的pipeline
![40b9c7f542e143daa13c6340e7521821.png](https://i-blog.csdnimg.cn/blog_migrate/0007092490d8781ba3f19fb8a5611ebf.png)
热更发布下的pipeline
![040f57d8737210ccd46bb3f9266b28a8.png](https://i-blog.csdnimg.cn/blog_migrate/16af4d4e8690d08c3bf6a6f9a0cc440b.png)
资料参考
- https://about.gitlab.com/product/continuous-integration
- https://docs.gitlab.com/ce/ci/introduction/index.html
往期精彩
﹀
﹀
﹀
iOS 消息推送那些事儿
Dockerfile最佳实践
ceph部分数据所有副本先后故障的抢救
那些年,CDN踩过的坑
智能监控中的时间序列预测