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服务)