介绍
CI/CD 即 Continuous Integration
和 Continuous Deployment
的缩写,是一种软件开发流程,旨在通过自动化的工具交付,使软件的构建、测试和发布更加的高效、稳定。
通常步骤包含如下:
- 代码提交到版本托管平台,触发自动化构建和测试钩子
- 执行任务后,自动部署到生产环境
流程涉及到的环境和工具:
- 环境:本地 localhost。
- Docker: 版本 24.0.5
- GitLab CE: 基于 Git 实现的代码仓库管理系统平台,类似于 GitHub,但有更加强大的管理、权限功能,适合公司搭建内部的代码托管。(版本 16.4.1)
- GitLab-Runner :GitLab CI 是 GitLab 内置的持续集成工具,在仓库根目录下创建
.gitlab-ci.yml
文件,并配置GitLab Runner
,每次提交代码时 Runner 将执行 CI/CD pipeline 流程。(版本 16.4.1)
思路
- Docker 本地启动 GitLab,GitLab-Runner 两个容器
- 在 GitLab 创建一个项目,在项目根目录里创建
.gitlab-ci.yml
文件,用于定义 CI/CD pipeline 流程 - 在 GitLab-Runner 注册一个 Runner,关联项目
- 将代码推送到 GitLab,触发 GiLab-Runner 执行
.gitlab-ci.yml
内的若干指令:构建、部署等
Docker 的内存和 CPU 最好配高点,避免出现一些不好定位的问题(推荐 2 核 + 6 GB)
部署 GitLab
步骤
- 挂载配置、日志和数据信息,避免容器删除后数据全部丢失。先创建一个环境变量执指向 GitLab 目录
bash
export GITLAB_HOME=$HOME/gitlab
- 运行 GitLab 镜像
bash
sudo docker run --detach \
--hostname localhost \
--publish 443:443 --publish 80:80 --publish 22:22 \
--name gitlab \
--restart always \
--volume $GITLAB_HOME/config:/etc/gitlab \
--volume $GITLAB_HOME/logs:/var/log/gitlab \
--volume $GITLAB_HOME/data:/var/opt/gitlab \
--shm-size 256m \
gitlab/gitlab-ce:latest
GitLab 本身镜像大及启动的服务较多,整个过程时间长到 3~5min,使用 docker ps
查看容器是否为由 starting 变成 healthy 状态,即启动完成
常见命令
bash
gitlab-ctl start/stop/restart 启动/停止/重启 gitlab 所有组件
gitlab-ctl status 查看服务状态
gitlab-ctl reconfigure 重启服务
gitlab-ctl tail 查看日志
- 登录
在 localhost 登录 GitLab,用户名默认为 root, 密码使用命令获取 sudo docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
,注意密码将在容器启动后 24 小时删除
部署 GitLab-Runner
步骤
- 启动 GitLab-Runner 容器
bash
docker run -d --name gitlab-runner \
--restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest
- 注册 Runner
在 GitLab 项目的 Settings => CI/CD settings => Runners,点击 New project runner 按钮,按步骤填写信息后,最后点击 Create runner。
然后在 GitLab-Runner 注册一个 Runner, 关联具体的仓库。执行 gitlab-runner register
,按步骤填写信息,有个一坑是:url 填 ip 地址,不能填 localhost。
- 创建
.gitlab-ci.yml
文件,提交文件后触发 GitLab Runner 执行 pipeline 任务
yml
image: node:16-alpine
stages:
- init
- build
- deploy
cache:
key: ${CI_BUILD_REF_NAME}
paths:
- node_modules/
- dist/
init:
stage: init
script:
- npm install
build:
stage: build
script:
- npm run build
deploy:
image: docker
stage: deploy
script:
- docker ps
- docker build -t front-cicd-image .
- if [ $(docker ps -aq --filter name=front-cicd-container) ]; then docker rm -f front-cicd-container;fi
- docker run -d -p 8888:80 --name front-cicd-container front-cicd-image
在 Docker 打包部署时,项目根目录下要 Dockerfile 和 nginx.conf 配置文件,可以简单配置如下
Dockerfile
bash
# build stage
FROM node:16-alpine as build-stage
WORKDIR /app
COPY . /app
RUN npm install && npm run build
# production stage
FROM nginx:latest as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY --from=build-stage /app/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx.conf
bash
server {
listen 80;
access_log /var/log/nginx/host.access.log main;
error_log /var/log/nginx/error.log error;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
- 一切顺利后,在 localhost:8888 访问前端项目
碰到的问题
postgresql 无法正常启动
最直观的反馈是本地 GitLab 访问显示 localhost refuse to connect,遂用 gitlab-ctl status
查看所有内置服务是否启动成功,发现 postgresql 一直在重试。
经查发现是新版的 Docker 默认使用 VirtioFS 模式用于文件共享,修改为 gRPC FUSE 即可,问题解决!
GitLab 界面报 502 错误
根据 gittal-ctl tail
查看日志发现一直提示 raven 3.1.2 configured not to capture errors DSN not set,但谷歌一直查不到错误的根源。遂从 502 错误码一个个排除网上常见的问题
- 判断端口是否被其他应用占用
- 判断容器空间是否满足
最终提高内存空间到 6G 后,终于登录页面出来了
GitLab Runner 无法使用 git 访问项目
具体报错信息为:fatal: unable to access http://ip/xxx/project.git Failed to connect to localhost port 80: Connection refused
项目都是本地容器化部署,容器内服务不能直接使用局域网 ip 访问,需修改网络模式为宿主 network_mode = "host",即与宿主机共用网络
GitLab Runner 报错:Is the docker daemon running?
错误很明显无法识别 docker 指令,解决办法让容器内使用宿主机的 docker.sock,修改容器文件如下
toml
# /etc/gitlab-runner/config.toml
concurrent = 1
check_interval = 0
shutdown_timeout = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "test"
url = "http://192.168.1.3/"
id = 14
token = "glrt-ScfCBNPTAH6EzzF_SyCG"
token_obtained_at = 2023-10-17T02:11:29Z
token_expires_at = 0001-01-01T00:00:00Z
executor = "docker"
[runners.cache]
MaxUploadedArchiveSize = 0
[runners.docker]
tls_verify = false
image = "docker"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0
network_mode = "host" # 修改1
volumes = ["/var/run/docker.sock:/var/run/docker.sock"] # 修改2