前言
前一段时间写了WebHooks实现项目CI/CD - 掘金 (juejin.cn),了解了一下最简单的CI/CD。但是有局限性,环境无法跟我们开发时一致,而导致依赖安装失败或者是项目打包失败。现在在原本CI/CD的基础上加上Docker。其主要原因是项目安装了个东西,必须要node18版本以上,但是我的服务器无法安装18版本的node(操作系统版本过低,该Node版本不兼容此操作系统),那就上Docker吧。
正文
跟之前的版本流程差不多,提交代码到master分支,触发WebHook发送请求,服务器在接受到请求执行脚本。只是这个脚本的内容有所变化,之前是
- 切换到对应目录
- 拉取代码
- 安装依赖
- 打包
现在是
- 切换到对应目录
- 拉取代码
- 检查是否已经有该项目容器运行,有则停止删除
- 检查是否已经有该项目容镜像,有则删除
- 执行
Dockerfile(包括环境的配置、依赖安装、打包)- 运行容器
过程就两个难点,Dockerfile文件编写和脚本编写,我们一一解决
Dockerfile文件编写
- 在项目下添加两个文件
- 编写
.dockerignore
- 编写
Dockerfile
我们这里使用Docker多阶段构建
多阶段构建(Multi-stage Build)是
Dockerfile的一种技术,它允许你在一个Dockerfile中定义多个构建阶段,从而减少最终镜像的大小,并提高构建过程的效率和安全性。这对于需要构建应用程序然后将其部署到轻量级运行时环境的情况特别有用。
在多阶段构建中,你可以定义多个FROM指令来创建多个构建阶段。在每个阶段中,你可以执行不同的操作,然后在后续阶段中选择性地复制所需的文件。这避免了在最终镜像中包含不必要的构建工具和依赖项
#前端项目基本的node环境就可以了,第一个阶段安装node
FROM node:18.20.4 as builder
# 设置工作目录
WORKDIR /app
#复制package.json pnpm-lock.yaml文件
COPY package.json pnpm-lock.yaml ./
RUN npm config get registry
#更换npm源(依赖装得上就不换)
RUN npm config set registry https://registry.npmmirror.com/
RUN npm install -g pnpm
RUN pnpm i
#将项目中别的文件copy过来除了/node_modules,我们在.dockerignore文件中写了
COPY . .
#打包
RUN pnpm run build
#第二个阶段安装nginx
FROM nginx:latest
#将第一个阶段打包完的产物复制到nginx的默认根目录下
COPY --from=builder /app/dist/ /usr/share/nginx/html
#暴露80,因为nginx默认是80
EXPOSE 80
编写脚本
#切换到项目目录
cd /www/wwwroot/www.hewkq.top
# 拉取代码
git pull 'git@gitee.com:lin-zhiteng/function-realization.git' master
#设定项目镜像以及容器的名称变量
IMAGE_NAME="my_blogs_image"
CONTAINER_NAME="my_blogs_container"
#是否存在运行的容器,有则停止删除
if docker ps --filter "name=^/${CONTAINER_NAME}$" --filter "status=running" --format "{{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then
docker stop "${CONTAINER_NAME}"
docker rm "${CONTAINER_NAME}"
fi
#判断是否存在镜像,有则删除
if docker images --format "{{.Repository}}" | grep -q "^${IMAGE_NAME}$"; then
docekr rmi -f "^${IMAGE_NAME}:latest$"
fi
#构建镜像
docker build -t "${IMAGE_NAME}:latest" .
#运行容器
docker run -d --name "${CONTAINER_NAME}" -p 4500:80 "${IMAGE_NAME}:latest"
接下来我们只要访问 服务器ip:4500(要开放4500端口),就可以看到页面了。有域名的话,创建一个网站配置一下nginx就可以使用域名访问
WebHook触发接口
注意事项
- 对脚本使用
sudo- 用户有
sudo的权利- 用户要在
docker组里面,否则不能使用docker命令,使用docker ps测试一下。
Router.post('/api/build', async (ctx) => {
const payload = ctx.request.body;
const branch = payload.ref.split('/').pop();
if (branch === 'master') {
const scriptPath = path.join(__dirname, 'todoList.sh');
const args = [`${branch}`];
const child = spawn('sudo',[scriptPath, ...args]);
// 捕获并打印子进程的标准输出和标准错误
child.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
child.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
ctx.body = `${scriptPath} ${args} master分支打包`
} else {
ctx.body = "非master分支,不打包"
}
})
其他注意事项
- 从
Docker Hub拉取镜像慢,记得配置阿里云镜像加速(用阿里云的话)
- 配置了加速,还是下载不下来(我就是
node18版本死活下不了),使用docker的save和load命令将镜像从本地上传到服务器。 npm装不上换源- 还有问题多问
AI(管用)。
结语
感兴趣的可以去试试