本文更多的是对之前gitlab部署的补充,单机环境不会涉及k8s滚动部署之流
环境
测试环境:局域网测试服务器(1台)
生产环境:阿里云生产服务器(1台)
在局域网的服务器中用gitlab存储代码,以及运行了gitlab runner用来执行ci脚本
持续交付
版本控制
局域网中部署gitlab,在上面提交代码
分支策略
主分支策略:仓库只保留主干,其他非核心开发者只能分出新分支,当新功能完成后,上传代码请提出合并请求(PR)
多分支策略:在主分支策略的基础上开几个新的分支,可能是专门用于测试环境的分支(测试完成后合并到master),可能是release分支(大版本更新的分支),可能是对一些大型功能进行重构的分支,可能是专门用来解决bug的分支…
代码提交规范
可以使用 Checkstyle,ESLint 等规范代码风格
用 Husky 等工具使用 git hook
如果是规范
git commit
信息,可以直接在.git/hooks/commit-msg
中写入#!/bin/sh # 提交信息格式正则表达式 commit_regex='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9_-]+\))?: .{1,50}$' # 读取提交信息 commit_message=$(cat "$1") # 检查提交信息是否符合正则表达式 if ! echo "$commit_message" | grep -Eq "$commit_regex"; then echo "Error: Invalid commit message format." echo "Proper commit message format is required for automated changelog generation." echo "Examples: " echo " feat(module): add a new feature" echo " fix(module): fix a bug" exit 1 fi
这样,如果
git commit
信息不符合规范就会无法提交
部署自动化
根据gitlab ci脚本可以选择不同的策略:
- 指定master/main分支,有新提交就自动执行ci脚本
- 指定分支,当新提交有指定tag(例如test-0.2.1,prod-0.2.2)时执行ci脚本
- 当有新的PR也可以执行ci脚本
单机部署方式探讨
单服务器,以何种方式进行部署更合适?
- 线上一套环境(当项目出现bug时需要停机回滚)
- 线上两套环境相互切换,即蓝绿部署(用nginx切换两套环境,当更新后出问题了就切换回原环境)
- 其他…
蓝绿部署还有一种,是直接切软链接,但我觉得不太靠谱(强制停机软链接可能会丢失,但其他的问题我就不清楚了)
复杂的项目限制,我在实践中选择了蓝绿部署
- 缺点:占空间,需要维护两套环境
- 优点:回滚方便,回滚的速度也快
其他的滚动部署,金丝雀部署等方式不适用单机环境
.gitlab-ci.yml的不同场景
# Executors用docker还是ssh
docker的开启和关闭是需要时间的,缓存的上传和下载也是需要时间的,这时候为了减少时间可以专门开一个构建用的docker,把环境弄好,构建的时候用ssh执行器直接连接,这样依赖无需下载也无需docker开启关闭的时间
我之前写的就是ci太慢了,部署springboot项目,maven构建好了,那么又把构件移到rsync的docker里发往远程服务器,这不是浪费了相当多时间吗
专门的docker构建环境
可能需要安装的:
- rsync
- git
- maven
- node
- java jdk/jre(如果是构建jar包就需要jdk,不然jre就行)
可以考虑用nvm
,mise
这种版本切换工具来切换不同环境,且这种工具一般是无需root权限的,是用户级别的命令
大部分此类工具在非交互式shell里和一般的操作是不一样的,例如非交互式shell里直接使用
nvm
是不行的,需要先source ~/.bashrc
一下
当然,也可以自行编写dockerfile
ssh 执行器取消git clone操作
单个作业脚本中添加:
variables:
GIT_STRATEGY: none
指定分支/标签
only:
refs:
- /^prod-.*$/
variables:
- $CI_COMMIT_REF_NAME == "master"
Git回滚时指定SHA
stage: build
variables: {} # 可以用来跳过单个作业中的全局变量
script:
- |
git checkout $COMMIT_SHA
echo "COMMIT_SHA: $COMMIT_SHA"
点入作业,可以手动修改变量(覆盖变量)后提交
rsync传输文件
script:
rsync -av ~/A/ devops@$PROD_SERVER:/home/devops/cache/
rsync
- 排除文件夹 :
rsync -av --chmod=755 --exclude '.git' ~/A/ devops@$PROD_SERVER:/home/devops/cache/
- 修改文件权限 :
rsync -av --chmod=755 ~/A/ devops@$PROD_SERVER:/home/devops/cache/
- 默认会把
.
和..
的权限也同步,所以需要加上--no-implied-dirs
:rsync -av --no-implied-dirs ~/A/ devops@$PROD_SERVER:/home/devops/cache/
减少依赖安装次数
可以考虑,当依赖文件发生变化才安装依赖
可以使用 git diff
查询本次提交和上次的提交有什么区别,如果以下文件不一样就构建
- ‘pom.xml’
- ‘package.json’
- ‘package-lock.json’
- ‘yarn.lock’
- …
并行策略
有时可以考虑并行执行任务
build_source m-source m &
build_source n-source n &
wait
跨pipelines缓存
node依赖,maven依赖等
cache:
key: "XXX_CACHE"
paths:
- node_modules
普通不加key的缓存不能跨pipelines
部分执行器是不支持缓存的,例如ssh执行器(但是ssh执行器本身就不需要缓存)
dockerhub访问问题
可以考虑用docker_image_pusher〰转成国内的镜像
单独开一个构建专用的容器的利弊
单独开一个容器进行:
- 构建(maven的打包,npm的build等)
- 推送(rsync等)
优点:
- 省时间(好处是构建的依赖不会丢失,比每次用缓存上传下载依赖省时间,且无需找到rsync或者node,maven容器再启动)
- 环境一致
- 与主机环境隔离
缺点:
- 需要单独创建一个容器,并在里面安装好对应的依赖
- 容器管理麻烦(需要将容器的22端口映射到外部,使用ssh执行器连接)
- 需要占用一定资源
其实在测试环境开一个新用户,在里面直接安装需要的工具并构建,也是可行的,但就是没有与主机隔离就是了
无需root启动容器
可以使用docker的替代品podman代替docker操作,命令几乎完全一样
docker反复构建镜像造成空间不够
解决办法:
- 在构建完成后直接删除多余的容器
- 直接用脚本定期清理多余的构建容器
重复构建相同名称相同标签相同的容器,会造成悬空镜像(可以用时间戳随机生成来打标签,防止生成悬空镜像)
修改dockerfile时旧的镜像层次可能会变成悬空镜像
手动清理空间步骤:
查看命令:
# 查看docker网络
docker network ls
# 查看容器卷
docker volume ls
# 查看容器镜像
docker image ls
## 或者
docker images
# 查看悬空镜像
docker image ls -f dangling=true
# 查看所有悬空卷:
docker volume ls -f dangling=true
# 查看未使用镜像
docker image prune -a --filter "until=24h"
删除命令:
# 删除镜像
docker rmi mh-go
# 删除所有悬空镜像
docker image prune
# 删除所有悬空卷
docker volume prune
# 删除所有未使用的 Docker 对象(包括停止的容器,未使用的网络,悬空镜像和未使用的镜像,构建缓存,不包括悬空卷)
docker system prune -a