基于docker-compose的Gitlab CI/CD实践排坑指南

长话短说

经过长时间实操验证,终于完成基于Gitlab的CI/CD实践,本次实践的坑位很多, 实操过程尽量接近最佳实践(不做hack, 不做骚操作),记录下来加深理解。

看过博客园《docker-compose真香》一文的园友留意到文中[把部署dll文件拷贝到生产机器],现场打包成镜像并启动容器,并没有完成CI/CD.

 P1:Gitlab CI/CD原理和Gitlab Runner安装(这里使用shell执行器)

 P2:基于Docker-compose的Gitlab CI/CD 实践:

  • 宏观业务架构图

  • .gitlab-ci.yml文件

  • 项目部署文件

Gitlab CI/CD部署准备

Gitlab CI/CD原理

  • Gitlab CI/CD   存储[构建]、[构建状态]的api应用程序, 提供友好的管理界面,  构建过程由 .gitlab-ci.yml文件定义(该文件一般置于代码仓库的根目录)

  • Gitlab Runner 执行构建任务的应用程序,可独立部署,如上图所示其通过api与Gitlab Server交互

搭建Gitlab CI/CD环境

Gitlab CI/CD提供配置界面(项目菜单栏-设置-CI/CD),可指定

   将要使用何种形式的Runner

   配置Runner要用到环境变量

界面配置权限取决于你在Gitlab Server的角色 + https://docs.gitlab.com/ee/user/permissions.html

本次手动设置特定Gitlab Runner

Runner安装完毕,注册Runner(与Gitlab Projects实例建立绑定关系)

注册时要关注的两个配置:

  • Tags    与此Runner相关的任务标签, 用于在共享Runner中区分不同的Project,.gitlab-ci.yml会用到

  • Runner Executor    执行构建任务的方式,这里使用shell方式

Shell是最简单的配置执行器,需要将构建所需的所有依赖项手动安装在安装了Runner的同一台计算机上。

注册过程和结果请参考下图:

Gitlab CI/CD实践

宏观业务架构图

原则上不允许自动部署Prod,本次使用Gitlab Runner服务器作为Gitlab CD的部署机器。

Gitlab-CI Pipeline构建ReceiverAPP、webAPP镜像(附带本次git:tag)并推送到hub.docker.com;

Gitlab-CD docker-compose拉取远端nginx、ReceiveAPP、webapp镜像,启动容器。 

  • Pipeline对每一次提交或合并都会执行build任务,形成Continous Intergation

  • Pipeline对git: tag会触发build_Image任务,成功之后构建deploy:staging任务,这样就能形成基于git:tag的部署版本管理(部署出错,也能很快回滚到上次的部署tag)

.gitlab-ci.yml文件

    

以上Gitlab Pipeline定义build->build_image->deploy3个任务,某些任务还包括不同分支Job,写.gitlab-ci.yml 的过程就是将以上执行动作脚本化。

stages:- build- build_image- deployvariables:         
# CI_DEBUG_TRACE: "true"                                         deploy_path: "/home/xxxx/eqidmanager"     # CI变量,用于配置部署目录before_script:- "docker info"build:stage: buildscript: - "for d in $(ls src);do echo $d;prog=$(pwd)/src/$d/$d.csproj; dotnet build $prog; done"tags:                                                 - another-tagbuild_image:EqidManager:stage: build_imagescript:- dotnet publish src/EqidManager/EqidManager.csproj  -c release -o ../../container/app/publish/    - docker build --pull  -t $CI_REGISTRY_USER/eqidmanager:$CI_COMMIT_REF_NAME  container/app- docker login -u $CI_REGISTRY_USER  -p $CI_REGISTRY_PASSWORD      - docker push $CI_REGISTRY_USER/eqidmanager:$CI_COMMIT_REF_NAME     tags:    - another-tagonly:                #Pipeline Job构建策略,代码仓库打tag会执行该任务, 支持正则- tagsbuild_image:EqidReceiver:stage: build_imagescript:- dotnet publish src/EqidReceiver/EqidReceiver.csproj  -c release -o ../../container/receiver/publish- docker build -t $CI_REGISTRY_USER/eqidreceiver:$CI_COMMIT_REF_NAME container/receiver- docker login -u $CI_REGISTRY_USER  -p $CI_REGISTRY_PASSWORD- docker push $CI_REGISTRY_USER/eqidreceiver:$CI_COMMIT_REF_NAMEtags: - my-tagonly:- tagsdeploy:staging:stage: deployscript:- cd $deploy_path- export TAG=$CI_COMMIT_REF_NAME        # 引入本次CI的git:tag名称,覆盖.env文件默认配置- "docker-compose -f docker-compose.yml -f docker-compose.prod.yml build"                        - "docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d" tags: - my-tagdeploy:prod:stage: deployscript:- # TODO 需要写脚本登陆到Prod机器上- export TAG=$CI_COMMIT_REF_NAME        - cd $deploy_path- "docker-compose -f docker-compose.yml -f docker-compose.prod.yml build"- "docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d" tags:- my-tagwhen: manual

这里有些知识点、坑位需要指出:

第8行:预先定义的环境变量,该变量定义gitlab CD的部署目录

第16行: 对src开发目录下两个程序执行dotnet build命令

第17行:tags定义具备该tags的Runner可以执行该任务,注意这里的tags必须是字符串数组

第23-26行:构建镜像并推送到镜像仓库的过程,用到两类CI变量

 - 密钥变量CI_REGISTRY_USERCI_REGISTRY_PASSWORD,可在Gitlab-CI界面配置

  - 预定义变量CI_COMMIT_REF_NAME,该变量标记构建项目的git:branch或git:tag名称,用于生成Image:Tag

注意变量可被重写,重写优先级:http://www.ttlsa.com/auto/gitlab-cicd-variables-zh-document/

第29行:only定义此Job只在产生git:tag时被触发,与上面我们使用CI-COMMIT_REF_NAME 变量相呼应

第47行:Gialab-CI pipeline每个Job会重新拉取git源码执行Job任务(可登录到Gitlab Runner工作目录下观察Runner执行过程),CD时需要选择合适目录,这是deploy_staging上使用deploy_path CI变量的原因

第48行:注入本次Gitlab-CI git:tag名称,实际上是覆盖了.env同名环境变量

第49行:若存在docker-compose.yml、docker-compose.override.yml 两个文件,docker-compose命令会自动merge这2个文件(使用docker-compose config命令查看merge之后的结果)。

第64行:前置任务未出错,会自动执行后继任务;而when指令定义该任务需要界面上手动执行 

部署目录

 

在Gitlab Runner服务器的{deploy_path}路径下建立了如下部署文件:

├── appsettings.secrets.json
├── docker-compose.prod.yml
├── docker-compose.yml
├── .env
├── EqidManager.db
├── nginx
│   ├── Dockerfile
│   └── nginx.conf
└── receiver.secrets.json
  • 部署目录定义docker-compose.yml、docker-compose.prod.yml 两个yml文件,前者定义常规容器服务,后者定义适用于本部署环境的附加服务

  • 密钥文件不要进入代码管理,因此我们定义appsetting.secrets.json 和 receiver.secrets.json密钥文件,由dccker-compose.yml挂载进入容器

  • env文件存储相对固定且与本次docker-compose命令相关的环境变量,docker-compose命令默认寻找同级目录下.env文件

------.env 文件----
TAG=master    # 该TAG变量会在Pipeline:deploy_staging任务中被覆盖,形成基于git:tag的imageName:tag
docker_host=172.16.1.1
COMPOSE_PROJECT_NAME=EqidManager
DOCKER_REGISTRY=***

Project打上git:tag之后,触发Gitlab Runner CI/CD Pipeline: 

跳转到部署目录->应用本次git:tag->执行docker-compose命令拉取指定tag镜像并启动容器。

That'all, 本次应用Gitlab Runner(shell执行器)实践CI/CD, Gitlab菜单界面有所有构建构成的日志(便于排查构建问题);另外上文对于关键知识均附带传送门,可进一步对比研究。

+ https://www.cnblogs.com/JulianHuang/p/10919346.html

+ https://docs.gitlab.com/runner/register/index.html

+ https://docs.gitlab.com/runner/executors/README.html

往期精选 

实例解读Docker Swarm

docker stack,docker-compose前世今生

据说点赞的朋友2020都加薪了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312581.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Is It a Complete AVL Tree AVL树

思路: 考察的点是建立AVL树以及如何判断是否为满二叉树。 建立AVL树需要搞清楚LL、LR、RR、RL四种情况如何左旋和右旋,如下: 类型BF条件操作LLBF(root)2,BF(root->lchild)1root右旋LRBF(root)2,BF(root->lchild)-1先root->lchild左…

AcWing 删减 栈思想

思路: 这道题要是不卡时间复杂度,是道大水题,然而字符串的长度到了6次方,若使用string中的erase函数,看似时间复杂度不高,其实,每次删除子字符串后,后边的字符串需要移动到前面来&am…

读《可复制的领导力》

最近很忙,是特别忙,连上厕所的时间都在回复着各种消息,但还是挤时间看完了《可复制的领导力》,这本书也是领导推荐的。说起领导力,大多数人都会觉得得靠悟,并不能做到言传身教,但书名中却提到了…

AcWing 构造数组 区间合并

思路: 这道题第一眼来看以为是动态规划类型的题目,然而尝试了用dp的方法做,然而超时了,过了差不多一半的测试店,显示的是超时。那么应该来说动态规划是可以做的,但数据卡的比较严。在看其他同学的评论后&am…

为什么需要动态SQL

为什么需要动态SQL在使用 EF或者写 SQL语句时,查询条件往往是这样一种非常常见的逻辑:如果客户填了查询信息,则查询该条件;如果客户没填,则返回所有数据。我常常看到很多人解决这类问题时使用了错误的静态 SQL的解决办…

PAT Family Property DFS+哈希

题目链接 思路: 本题将每个人作为一个单独的结点,若两个人之间是家人关系,则建立边关系。通过哈希法建立人名与编号,编号与人名之间的映射。最后统计每个家庭的人数时,用DFS遍历即可。 对于本题我犯过两个错误&#…

【好文】为什么必须学好.Net Core?怎样弯道超车新年高薪?这样做,一周就够了!(文末彩蛋)...

都2020了你还不会.Net Core?恕我直言,2020年还不会.Net Core是会被淘汰的!12月3号,.Net Core3.1的LTS版正式发布,4年来7个正式版本和几十个Preview版本,热烈可见一斑!越来越多的互联网软件公司开…

最短路径SPFA和Bellman-Ford算法

参考模板&#xff1a; #include<bits/stdc.h> using namespace std; #define INF 0x3f3f3f3f typedef long long ll;struct node {int v, dis;node(int v, int dis) {this->v v, this->dis dis;} }; vector<node> adj[1005]; int n, d[1005], num[1005]; …

基于 Kubernetes 的基础设施即代码

11 月 9、10 号两天&#xff0c;.NET 社区第一次以“.NET 大会”为品牌在上海召开了第一届峰会&#xff0c;现场与会者达到 600 人规模。大会的第 1 天是各类演讲分享&#xff0c;第 2 天有多个动手实践课。张善友队长、 刘腾飞 和我一起策划了基于 Kubernetes 的 .NET Core 微…

最小生成树Prim和Kruskal算法

两种算法都是基于贪心的方法。 Prim算法&#xff1a; 适用于稠密图。时间复杂度为O(V^2)。(V为顶点数&#xff09; 与Dijkstra算法相似&#xff0c;每次选择离离原点最近的点&#xff0c;加入到现有的生成树中。 Kruskal算法&#xff1a; 适用于稀疏图。时间复杂度为O(E*logE)…

Steeltoe 2.4新增代码生成工具、全新入门指南等,助力.NET微服务开发

Steeltoe框架现可帮助.NET开发人员创建云原生应用。随着其功能的扩充&#xff0c;该框架越来越受欢迎&#xff0c;下载量达到580万&#xff08;并且仍在增加&#xff09;&#xff0c;这其中大部分的功能创新都源自于用户反馈、社区贡献和.NET运行环境各方面的改进。但这些还不够…

AcWing 自动补全 二分

题目链接 先上AC代码。 参开代码&#xff1a; #include<bits/stdc.h> #include<unordered_map> using namespace std; #define INF 0x3f3f3f3f typedef long long ll;string s[100005]; unordered_map<string, int> m; bool check(string a, string b) {if…

2019 年终回顾:不忘初心,负重前行

点击上方蓝字关注“汪宇杰博客”导语2019 年就要接近尾声&#xff0c;这一年对于我来说&#xff0c;有许多有意义的事件。我成长了许多&#xff0c;并依然保持着对技术的热情。在辞旧迎新之际&#xff0c;我想回顾一下我这一年中有意义的事件与收获&#xff0c;期待与大家一起在…

机试真题1 反序输出 cin判断读取结束

题目链接 解题思路 这题是纯纯的送分题&#xff0c;但我忘记了怎么判断读取结束。应该用&#xff1a; while (cin >> s){}在Windows中&#xff0c;CtrlZ输出输入结束符号。 参考代码 #include<bits/stdc.h> using namespace std;void print(string s) {int len…

【C#】设计模式的学习征途系列文章目录(2019版)

Photo &#xff1a;Design Patterns文 | Edison Zhou2017年&#xff0c;我开始系统学习设计模式&#xff0c;参考了《大话设计模式》、《设计模式的艺术》等书籍&#xff0c;并通过C#语言写了各种模式的代码示例&#xff08;已经放到了我的github上并收获了120个star&#xff0…

机试真题2 进制转换 高精度除法

题目链接 解题思路 这题需要通过高精度加除法来解决。原本以为高校机试题最多考到高精度的加减法&#xff0c;没想到还会考高精度和低精度的乘除法&#xff0c;不亏是你清的题。 需要注意的是&#xff0c;一开始存储需要是逆序存储&#xff0c;方便后面的操作&#xff0c;同时…

原创 | 为什么年终奖是一个彻头彻尾的职场圈套?

0前言之前写过几篇职场专题的文章&#xff0c;反响不错&#xff0c;也先后被不少公众号转载过&#xff0c;这几天来了不少新朋友&#xff0c;如果之前没阅读过&#xff0c;可以在后台回复“职场”2个字&#xff0c;查看系列文章。转眼又到年底了&#xff0c;不知道有多少人在心…

机试真题3 进制转换2 高精度除法

题目链接 解题思路 这题还是通过高精度的除法来做&#xff0c;思路与上一篇文章类似&#xff0c;区别就是输入输出的进制位数不是固定的。对于输入的进制m&#xff0c;在divide函数中更新余数的时候乘以的数字改成m&#xff1b;对于输出的进制n&#xff0c;在divide函数中取余…

Blazor 机制初探以及什么是前后端分离,还不赶紧上车?

上一篇文章发了一个 BlazAdmin 的尝鲜版基于 Blazui 的 Blazor 后台管理模板 BlazAdmin 正式尝鲜&#xff0c;这一次主要聊聊 Blazor 是如何做到用 C# 来写前端的&#xff0c;传送门&#xff1a;https://www.cnblogs.com/wzxinchen/p/12057171.html飚车前需要说明的一点是&…

机试真题4 成绩排序

题目链接 解题思路 题目非常简单&#xff0c;就是需要注意一下直接用sort方法做的话&#xff0c;会导致同分时输出的人名顺序与输入时不一致&#xff0c;这是因为sort函数是不稳定的算法&#xff08;sort排序为了提升性能&#xff0c;会根据不同的情况选用不同的排序算法&…