前言
本文是个实践文,具体技术来源来自于大佬的文章 docker + webhook 从零实现前端自动化部署。这里讲一下自己在搭建过程中遇到的问题,以及查阅了哪些资料。
所涉及的技术栈
- docker
- node
- pm2
- shell
- webhook
具体实现的步骤
- 环境配置
- github配置
- 云服务器配置
环境配置
-
docker说明及配置 docker入门及实践
这里咱们就不展开讲了,原作者已经讲的非常棒了,你可以理解为docker
是在服务器中的一个独立的"服务器",这里用docker
去做持续交付和部署。本次部署需要两个docker
文件,一个是docker
配置文件Dockerfile
,另一个是.dockerignore
文件。具体内容如下Dockerfile
# dockerfile # build stage FROM node:lts-alpine as build-stage WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # production stage FROM nginx:stable-alpine as production-stage COPY --from=build-stage /app/dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
.dockerignore
# .dockerignore node_modules
-
云服务器环境的安装
- docker
弹出# Step 1: 安装必要的一些系统工具 sudo yum install -y yum-utils # Step 2: 添加软件源信息,使用阿里云镜像 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # Step 3: 安装 docker-ce sudo yum install docker-ce docker-ce-cli containerd.io # Step 4: 开启 docker服务 sudo systemctl start docker # Step 5: 运行 hello-world 项目 sudo docker run hello-world
Hello from Docker!
证明 Docker 已经成功安装啦~
- docker
-
git
yum install git
-
node
- nvm安装
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # 注册nvm命令,然后退出连接,再次进入就可以使用nvm命令了
- nvm 安装 node
nvm install lts # 安装最新的长期稳定版
- nvm安装
-
pm2 你可以理解这个是在后台帮你执行js脚本,功能还是很多的
npm install pm2 -g
真正动手了
- 配置云服务器
- 腾讯云或者阿里云都行,登录云平台控制台,找到端口并开放
3000
端口,80
和443
默认开放的,这里咱们只增加一个3000
端口,用于webhook
能够访问。
- 腾讯云或者阿里云都行,登录云平台控制台,找到端口并开放
- github新建个仓库,在仓库的
setting
里面设置webhook
。然后clone到本地webhook
类似于生命周期,在你的仓库触发了某些事件的时候就会触发该周期,从而执行某些特定操作。这里我们选择默认的push
操作。payload
就是webhook
触发时会去请求的地址。输入你的服务器地址或者域名,协议看你的服务器支持什么。例如http://123.123.12.3:3000
,端口号是3000
,因为我们只开放了3000
- Content type 选择
application/json
点击提交,然后查看是否修改正确。
- 在clone下来的仓库中创建一个vue应用
vue create hello-world
- 然后在
app.vue
中修改下字眼,确保等下部署时你能够发现改变。我是增加了一句话<p>CI/CD project</p>
- 服务器操作
- 登录服务器。
- 通过rz上传我们前面生成的
docker
文件,Dockerfile
和.dockerignore
。 - 编写
node
应用(index.js 内容如下),使用pm2
启动node
应用(pm2 start index.js
),用来接收github
仓库触发的webhook
操作,接收仓库信息,执行相应的逻辑。
启动和部署成功后,就可以在你的服务器上打开就可以看到新的内容了。// index.js const http = require("http") const { execSync } = require("child_process") const fs = require("fs") const path = require("path") // 递归删除目录 function deleteFolderRecursive(path) { if (fs.existsSync(path)) { fs.readdirSync(path).forEach(function (file) { const curPath = path + "/" + file; if (fs.statSync(curPath).isDirectory()) { // recurse deleteFolderRecursive(curPath); } else { // delete file fs.unlinkSync(curPath); } }); fs.rmdirSync(path); } } const resolvePost = req => new Promise(resolve => { let chunk = ""; req.on("data", data => { chunk += data; }); req.on("end", () => { resolve(JSON.parse(chunk)); }); }); http.createServer(async (req, res) => { console.log('receive request') console.log(req.url) if (req.method === 'POST' && req.url === '/') { const data = await resolvePost(req); const projectDir = path.resolve(`./${data.repository.name}`) deleteFolderRecursive(projectDir) // 拉取仓库最新代码 如 https://github.com/vuejs/vue.git execSync(`git clone https://github.com/你的github/${data.repository.name}.git ${projectDir}`, { stdio: 'inherit', }) // 复制 Dockerfile 到项目目录 fs.copyFileSync(path.resolve(`./Dockerfile`), path.resolve(projectDir, './Dockerfile')) // 复制 .dockerignore 到项目目录 fs.copyFileSync(path.resolve(__dirname, `./.dockerignore`), path.resolve(projectDir, './.dockerignore')) // 创建 docker 镜像 execSync(`docker build . -t ${data.repository.name}-image:latest `, { stdio: 'inherit', cwd: projectDir }) // 销毁 docker 容器 execSync(`docker ps -a -f "name=^${data.repository.name}-container" --format="{{.Names}}" | xargs -r docker stop | xargs -r docker rm`, { stdio: 'inherit', }) // 创建 docker 容器 这里我们用主机的80转到容器的80端口 execSync(`docker run -d -p 80:80 --name ${data.repository.name}-container ${data.repository.name}-image:latest`, { stdio: 'inherit', }) console.log('deploy success') res.end('ok') } }).listen(3000, () => { console.log('server is ready') })
查看效果步骤
- 在服务器上启动接收程序即
pm2 start index.js
,查看logpm2 logs
- 本地应用,更新代码,并推送
- 静候,然后就可以在你的网站看到部署成功后的样子
tips
- 一些操作
- 调试时每次都要提交push操作才触发?
- 可以用
Redeliver
主动触发,然后服务上看日志
- 可以用
- 出现
We couldn’t deliver this payload: timed out
?- 我这边暂时不影响,在处理当中,可以正常触发。调试时可以用postman测试应用是否正常,请求是否收到等
- git clone 异常慢
- 没有办法,可以绑定hosts,加快一丢丢。github加快
- ...
- 调试时每次都要提交push操作才触发?
存在的问题
- 监听了push操作,无法监听具体某个分支,需要在node应用中获取到 requset的data中去做处理和判断。
- 部署和操作,无法直接获取到日志,需要自己去做处理。
- docker的启删创会导致应用有一段时间不可用,真实环境需要更合理的配置
- 云服务器和github之间的网络通讯太慢了,建议 搭建
gitlab
,避免这个问题
总结
总的来说,这是一次CI/CD的尝试,但是离真正在项目中应用还需要很长的一段路。这是一次学习,向大佬表示敬意,同时也在慢慢的用自己的知识,去解决上面存在的问题。