docker webhook - 图1
主要使用技术,gitee中的webhook钩子,然后通过node的子进程执行前/后端sh文件。
在sh脚本中添加docker构建镜像,并创建容器。

前端项目cicd-front

使用vue-cli初始化项目

  1. vue create cicd-front

创建完成后安装axios库,用来获取服务端数据。
修改App.vue

  1. <template>
  2. <div id="app">
  3. <ul>
  4. <li v-for="user in users" :key="user.id">
  5. {{ user.name }} : {{ user.age}}
  6. </li>
  7. </ul>
  8. </div>
  9. </template>
  10. <script>
  11. import axios from "axios";
  12. export default {
  13. name: "App",
  14. data() {
  15. return {
  16. users: [],
  17. };
  18. },
  19. mounted() {
  20. axios.get("/api/users").then((res) => {
  21. this.users = res.data;
  22. });
  23. },
  24. };
  25. </script>

添加Dockerfile文件

前端使用nginx作为基础镜像

  1. FROM nginx
  2. LABEL name="cicd-front"
  3. LABEL version="1.0"
  4. COPY ./dist /usr/share/nginx/html
  5. COPY ./nginx_front.conf /etc/nginx/conf.d
  6. EXPOSE 80

前端项目需要上传的是dist文件夹,并将其拷贝到/usr/share/nginx/html目录下。

新建nginxserver配置文件

新建nginx_front.conf文件,该文件会被复制到/etc/nginx/conf.d下。作用是修改nginx的启动配置

  1. server {
  2. listen 80;
  3. server_name 1.123.34.56;
  4. location / {
  5. root /usr/share/nginx/html;
  6. index index.html index.htm;
  7. try_files $uri $uri/ /index.html;
  8. }
  9. location /api {
  10. # 前端请求/api接口,会进行代理
  11. proxy_pass http://1.123.34.56:3666;
  12. }
  13. }

后端cicd-back

初始化项目

npm init -y
创建server.js,使用node基础模块http创建服务器

  1. let http = require("http");
  2. let users = [
  3. { id: 1, name: "John", age: 27 },
  4. { id: 2, name: "Tom", age: 37 },
  5. { id: 3, name: "sam", age: 47 },
  6. ];
  7. let server = http.createServer((req, res) => {
  8. res.setHeader("Access-Control-Allow-Origin", "*");
  9. if (req.url === "/api/users") {
  10. res.end(JSON.stringify(users));
  11. } else {
  12. res.end("not found");
  13. }
  14. });
  15. server.listen(3666, () => {
  16. console.log("server running in 3666");
  17. });

添加 res.setHeader(“Access-Control-Allow-Origin”, “*”); 解决跨域请求资源报错。

在package.json中配置启动脚本

  1. {
  2. "scripts": {
  3. "start": "node ./server.js"
  4. }
  5. }

添加Dockerfile文件

  1. FROM node
  2. LABEL name="cicd-back"
  3. LABEL version="1.0"
  4. COPY . /app
  5. WORKDIR /app
  6. RUN npm install
  7. EXPOSE 3666
  8. CMD npm start

webhook钩子服务器

创建服务器,开放端口4000

此处的端口设置是,配置前端和后端项目配置webhooks的依据。

  1. let http = require("http");
  2. let server = http.createServer(function (req, res) {
  3. console.log(req.method, req.url);
  4. if (req.method == "POST" && req.url == "/webhook") {
  5. // 配置特殊的请求路径,用来设置前端和后端项目中webhooks的路径地址
  6. res.setHeader("Content-Type", "application/json");
  7. res.end(JSON.stringify({ ok: true }));
  8. }else{
  9. res.end("not found");
  10. }
  11. })
  12. server.listen(4000, () => {
  13. console.log("webhook server running 4000");
  14. });

通过以上配置就可以测试webhook的功能。在webhook中填写地址为http://1.123.34.456:4000/webhook。当cicd-front或者cicd-back有代码推送时,可以测试webhook的返回结果。

更新webhook.js文件

主要是更新http.createServer函数中的逻辑处理

  1. http.createServer(function (req, res) {
  2. console.log(req.method, req.url);
  3. if (req.method == "POST" && req.url == "/webhook") {
  4. let buffers = [];
  5. req.on("data", function (buffer) {
  6. buffers.push(buffer);
  7. });
  8. req.on("end", function () {
  9. let body = Buffer.concat(buffers);
  10. let event = req.headers["x-gitee-event"]; // "push hook"
  11. let token = req.headers["x-gitee-token"]; // webhook配置密码
  12. let timestamp = req.headers["x-gitee-timestamp"]; // 返回的时间戳,用于加解密
  13. // console.log(token, timestamp, sign(timestamp), "-=-=mimi-=-=");
  14. // https://gitee.com/help/articles/4290#article-header0
  15. // if(token !== "123456")
  16. if (
  17. crypto
  18. .createHmac("sha256", token)
  19. .update(timestamp + "\n" + token)
  20. .digest("hex") !== sign(timestamp)
  21. ) {
  22. console.log("not allowed");
  23. // 未通过验证的,不进行部署构建
  24. return res.end("not allowed");
  25. }
  26. // 以下是通过验证后进行的构建部署
  27. res.setHeader("Content-Type", "application/json");
  28. res.end(JSON.stringify({ ok: true }));
  29. // console.log(event.toLowerCase().toString(), event.toLowerCase().toString().includes("push"),"-=-=");
  30. if (event.toLowerCase().toString().includes("push")) {
  31. let payload = JSON.parse(body);
  32. // https://gitee.com/help/articles/4186#article-header2
  33. // console.log(payload, "payload");
  34. // 子进程执行 cicd-front.sh 或者cicd-back.sh
  35. let child = spawn("sh", [`./${payload.repository.name}.sh`]);
  36. let buffes = [];
  37. child.stdout.on("data",function(chunk) {
  38. buffes.push(chunk);
  39. })
  40. child.stdout.on("end",function() {
  41. let log = Buffer.concat(buffes);
  42. console.log("cicd success",log);
  43. })
  44. }
  45. });
  46. } else {
  47. res.end("not found");
  48. }
  49. });

image.png
webhook中采用webhook密码,验证比较简单,直接比对req.headers[“x-gitee-token”] 和 服务器上的密码即可。如果采用签名密钥,需要进行加密解密对比。

添加sh执行脚本

cicd-front.sh脚本

  1. #! /bin/bash
  2. WORK_PATH="/home/cicd/docker_webhook/cicd-front"
  3. cd $WORK_PATH
  4. echo "clean old code..."
  5. git reset --hard origin/master
  6. git clean -f
  7. echo "pull latest code..."
  8. git pull origin master
  9. echo "bundle latest code..."
  10. rm -rf node_modules
  11. npm config set registry https://registry.npm.taobao.org
  12. npm install
  13. npm run build
  14. echo "start build..."
  15. docker build -t cicd-front:1.0 .
  16. echo "stop and destroy old container..."
  17. docker stop cicd-front-container
  18. docker rm cicd-front-container
  19. echo "start new container..."
  20. docker container run -p 8081:80 --name cicd-front-container -d cicd-front:1.0

cicd-back.sh脚本

  1. #! /bin/bash
  2. WORK_PATH="/home/cicd/docker_webhook/cicd-back"
  3. cd $WORK_PATH
  4. echo "clean old code..."
  5. git reset --hard origin/master
  6. git clean -f
  7. echo "pull latest code..."
  8. git pull origin master
  9. echo "start build..."
  10. docker build -t cicd-back:1.0 .
  11. echo "stop and destroy old container..."
  12. docker stop cicd-back-container
  13. docker rm cicd-back-container
  14. echo "start new container..."
  15. docker container run -p 3666:3666 --name cicd-back-container -d cicd-back:1.0

项目配置相关

本地ssh登录远程服务器

  1. ssh -p 22 root@47.96.0.230
  2. # 接下来输入密码
  3. root@47.96.0.230's password:

设置gitee的ssh免密码登录

  1. ssh-keygen -t rsa -b 4096 -C "email@qq.com"

在~ /.ssh 目录下生成id_rsa和id_rsa.pub公钥和私钥。把公钥添加到gitee账号中。https://gitee.com/profile/account_information,设置ssh公钥。

设置webhooks

在gitee中给前/后端项目仓库设置webhooks
Snipaste_2021-11-29_11-33-15.jpg

打开或关闭某个端口

  1. firewall-cmd --zone=public --add-port=4000/tcp --permanent // 开放4000端口
  2. firewall-cmd --remove-port=3306/udp --permanent //关闭4000

开启Linux服务器防火墙状态: systemctl start firewalld
停止Linux服务器防火墙状态: systemctl stop firewalld
查询Linux服务器防火墙所有开放端口: firewall-cmd —list-ports
重启Linux服务器防火墙: firewall-cmd —reload