Nginx + Docker持续集成

创建三端代码:
  • 服务端Server
  • 客户端Client
  • WebHook同步更新脚本(后面将会记录)
安装git, 新建project目录下载git代码

yum install git -y
sudo mkdir /usr/project 目录可自定义
sudo ssh-keygen -t rsa -b 4096 -C “1084983891@qq.com” 创建公钥和git进行关联
cd /user/project
git clone git@github.com:webChen725/clientTest.git 下载git上代码

安装node环境:(使用nvm安装)

wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
(上面的方法可能安装不了,我的就没安装上,所以这里给第二种方法: 直接clone git上的nvm包)
git clone https://github.com/creationix/nvm.git
source nvm/nvm.sh
nvm --version 这里出现了nvm的版本号,说明nvm安装完毕
nvm install stable 使用nvm安装最新的node稳定版本
node -v
npm -v 检验node和npm均已安装完毕
npm install nrm -g 安装nrm包,用于切换npm安装的镜像源,否则之后装包会很慢
nrm use taobao 安装完毕nrm后切换到taobao镜像源

安装docker:

yum install -y yum-utils device-mapper-persistent-data lvm2 这是centos中特有的一个命令
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 配置阿里的安装源
yum install -y docker-ce docker-ce-cli containerd.io 安装docker社区版
docker -V 检测docker是否安装成功

配置docker阿里云加速

mkdir -p /etc/docker
tee /etc/docker/daemon.json <<- ‘EOF’
{
“registry-mirrors”: [“https://fwvjnv59.mirror.aliyuncs.com”]
}
EOF 从第二行到这里结束是一条命令,将以上的内容写入daemon.json文件的意思
systemctl daemon-reload 重载配置文件
systemctl restart docker 重启docker

安装项目相关依赖:

cd /usr/project 就是git clone项目下来的文件夹
cd server 进入服务目录
npm i 安装项目相关依赖 客户端项目的依赖安装类似

为服务端代码git仓库和客户端代码配置webHook

进入github项目 -> settings -> webhooks -> Add webhooks -> 填写相关信息
注意: webhooks中需要填写一个secret,这个密钥需要于后面编写的webHook脚本的指定的密钥相同,否则之后进行签名验证的时候会出现错误
(webhook的作用是在每次代码仓库出现更改的时候发送一个post请求到指定的地址,可以通过这个请求来完成持续集成自动化部署)

开始编写webhook服务接口,应对github的webhooks请求:
let http = require("http")
let crypto = require("crypto")
let spawn = require("child_process")
let sendMail = require("./sendMail")
const SECRET = "chenSir123"

// 计算数字签名
function sig(body){
    return `sha1=` + crypto.createHmac("sha1", SECRET).update(body).digest('hex');
}

let server = http.createServer(function(req, res){
    if(req.method == "POST" && req.url == "/webhook"){
        let buffers = [];
        req.on("data", function(buffer){
            buffers.push(buffer)
        })
        req.on('end', function(buffer){
            let body = Buffer.concat(buffers)
            // 解析webhook的请求
            let event = req.headers['X-github-event'];
            // github请求到来的时候,要传递一个body,还会带一个signature过来,需要验证签名是否正确
            let signature = req.headers['x-hub-signature'];
            if(signature !== sig(body)){
                return res.end('Not Allowed');
            }
            res.setHeader('Content-Type', 'application/json');
            res.end(JSON.stringify({ok: true}))
            if(event === "push"){
                let payload = JSON.parse(body);
                // 开启子进程执行对应仓库的sh脚本
                let child = spawn('sh', [`./${payload.repository.name}.sh`]);
                let buffers = [];
                child.stdout.on("data", function(buffer){
                    buffers.push(buffer)
                });
                child.stdout.on("end", function(buffer){
                    let log = Buffer.concat(buffers).toString();
                    // 发送邮件通知
                    sendMail(`
                        <h1>部署日期: ${new Date()}</h1>
                        <h2>部署人: ${payload.pusher.name}</h2>
                        <h2>部署邮箱: ${payload.pusher.email}</h2>
                        <h2>提交信息: ${payload.head_commit && payload.head_commit}</h2>
                        <h2>部署日志: ${log.replace("\r\n", "<br />")}</h2>
                    `)
                })
            }
        })
    }else{
        res.end("Not Found")
    }
})

server.listen(4000, () => {
    console.log("webhook 启动在4000端口")
})
// 编写邮件发送代码:
const nodemailer = require("nodemailer")
let transporter = nodemailer.createTransport({
    host: "smtp.qq.com",
    port: 465,
    secure: true,
    auth: {
        user: "1084983891@qq.com",
        pass: "这里是邮箱的授权码"
    }
})


function sendMail(message){
    let mailOptions = {
        from: "1084983891@qq.com",
        to: "1084983891@qq.com",
        subject: "部署通知",
        html: message
    }
    transporter.sendMail(mailOptions, (err, info) => {
        if(err){
            return console.log(err)
        }
        console.log('Message sent: %s', info.messageId)
    })
}

module.exports = sendMail

编写完成后将项目放到git上并在服务器上clone下来,等待之后的执行

在webhook中编写一个用于构建执行服务端代码的sh脚本:

(developmentTest.sh: 这个脚本文件需要放在webHook的目录中)

#! /bin/bash
WORK_PATH='/usr/project/developmentTest'  # 创建工作目录,就是指定服务项目的目录
cd $WORK_PATH
echo "开始清除老代码"
git reset --hard origin/master            # 将代码还原,清除旧代码
git clean -f
echo "开始拉取最新代码"
git pull origin master
echo "开始执行构建"
docker build -t development-test:1.0 .    # 这里开始构架会调用服务目录中的DockerFile文件进行docker构建, 所以之后会在后端项目文件中写这样一个文件
echo "停止旧容器并删除"
docker stop developmentTest-container
docker rm developmentTest-container
echo "启动新容器"
docker container run -p 3000:3000 --name developmentTest-container -d development-test:1.0  # 这里的--name参数指定的名字需要和前面删除容器中的名字相对应
编写服务端代码docker运行的Dockerfile文件

(Dockerfile: 这个文件需要放在服务端项目目录中)

FROM node  # 拉取node的镜像源
LABEL name="server"
LABEL version="1.0"
COPY . /app     # 将当前目录拷贝到docker容器的/app目录中
WORKDIR /app
RUN npm install  # docker容器中安装依赖
EXPOSE 3000      # 向外暴露3000端口
CMD npm start    # 在/app目录执行执行项目的运行命令: npm start
编写用于自动构建客户端的sh脚本

(clientTest.sh: 这个脚本文件需要放在webHook的目录中)

#! /bin/bash
WORK_PATH='/usr/project/clientTest'
cd $WORK_PATH
echo "开始清除老代码"
git reset --hard origin/master
git clean -f
echo "开始拉取最新代码"
git pull origin master
# npm install           # 编译构建代码之前安装项目所需要的包,若是已经安装过了没有新的包,可以省略这一步, 或者是可以在每次构建之前先删除项目中的node_modules进行重新安装
echo "更新项目依赖库"
rm -rf node_modules
npm install
echo "开始编译代码"
npm run build         # 这步操作是对于客户端框架的代码需要进行build构建
echo "开始执行构建"
docker build -t client-test:1.0 .
echo "停止旧容器并删除"
docker stop clientTest-container
docker rm clientTest-container
echo "启动新容器"
docker container run -p 80:80 --name clientTest-container -d client-test:1.0
创建客户端项目目录下的Dockerfile文件:

(Dockerfile: 这个文件需要放在客户端项目目录中)

FROM nginx    # 暗转nginx的镜像
LABEL name="client"
LABEL version="1.0"
COPY ./dist /usr/share/nginx/html   # 拷贝打包编译好的项目文件到docker中的nginx指定的静态文件目录中
COPY ./client.conf /etc/nginx/conf.d # 编写一份nginx的配置文件拷贝到nginx的配置文件目录下
EXPOSE 80
编写客户端nginx配置文件:

(client.conf: 这个文件需要放在客户端项目目录中)

server {
    listen 80;
    server_name 192.168.43.176;
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
    location /api {
        proxy_pass http://192.168.43.176:3000;
    }
}
将以上项目clone到服务器,并将webhook服务启动

(如果需要启动服务后在后台运行并自启动之类的操作可以为webhook服务配置pm2服务)