基于Docker的持续集成

1,673 阅读7分钟

先说一下我为什么要做这个事情

最近手里的项目版本迭代非常多,然后每次都要重新部署,真的非常非常非常麻烦,所有想做一下这样的一些自动化部署功能,应该算是一个迫切的小需求。。。。。

Docker是什么

  • 操作系统层面的虚拟化技术
  • 是一个容器独立于宿主和其他进程

特点

  • 比传统虚拟机占用更少的系统资源
  • 比传统虚拟机启动速度快
  • 持续交付和部署(这个是我主要想做的,因为我们的项目部署非常频繁)
  • 更轻松的迁移

核心概念

  • 镜像
  • 容器
  • 仓库

Docker安装(因为我们的服务是linux,这里的安装主要是linux,windows安装,mac安装教程)

1. 先查看CentOS版本,Docker要求内核版本高于 3.10

uname -r

2. 更新yum包

sudo yum update

3. 安装需要的包

// yum-utils提供yum-config-manager功能
// device-mapper-persistent-data lvm2是devicemapper驱动依赖的
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

4. 添加软件源信息

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

5. 查看可用版本的 Docker-ce

yum list docker-ce --showduplicates | sort -r
// 如果需要只显示table版本,可以关闭测试版本的list
sudo yum-config-manager --enable docker-ce-edge
sudo yum-config-manager --enable docker-ce-test

6. 安装指定版本的docker-ce

sudo yum install docker-ce-18.06.3.ce-3.el7

7. 设置开机启动

// 添加docker服务
sudo systemctl enable docker
// 启动docker服务
sudo systemctl start docker

8. 验证安装是否成功(有client和service两部分表示docker安装启动都成功了)

docker version

9. docker启动状态

systemctl status docker

10. 配置镜像加速

// 创建daemon.json
 vi /etc/docker/daemon.json
 
// 配置/etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://dockerhub.azk8s.cn",
    "https://reg-mirror.qiniu.com"
  ] 
}
// 重启docker服务,让它生效
sudo systemctl daemon-reload
sudo systemctl restart docker

11. 下载一个nginx测试一下快不快

docker pull nginx

======================= 安装就结束了 =======================

Nginx服务

1. 拉取官方镜像 - 面向docker的只读模板(之前测试docker镜像的时候已经做了就不需要了)

docker pull nginx

2. 查看安装结果

docker images nginx

3. 创建一个index.html并写入hello docker!!

mkdir www
echo 'hello docker!!' >> www/index.html

4. 查看index.html内容

cat www/index.html

5. 启动并映射端口

docker run -p 8000:80 -v $PWD/www:/usr/share/nginx/html nginx

6. 在页面输入ip和端口,就会显示index里面的内容。

7. 后台执行(这句执行后会给你一个uuid,关闭服务的时候可以使用)

docker run -p 8000:80 -v $PWD/www:/usr/share/nginx/html -d nginx

8. 停止服务

// 这个050是上面后台启动的时候返回的uuid的前三位
docker stop 050
// 如果想重新启动的话
docker start 050

9. 查看进程

//查看进程
docker ps
// 查看全部进程
docker ps -a

10. 伪终端 050容器的uuid

 docker exec -it 050 /bin/bash

11. 在伪终端去查看之前创建的index.html

cd /usr/share/nginx/html
cat index.html

12. 退出伪终端

exit

12. 删除镜像

// 先关闭docker服务
docker stop 050
// 删除
docker rm 050

===================== 启动一个简单的nginx服务就完成了 ====================

Docker运行过程

1. 镜像(Image) -----面向Docker的只读模板

2. 容器(Container) ------镜像的运行实例

3. 仓库 (Registry) ------存储镜像的服务器

============================ 华丽的分割线 ============================

Dockerfile 定制镜像

1. 创建一个nginx

cd docker
mkdir nginx

2. 创建一个Dockerfile文件,写入配置

cd nginx
vi Dockerfile
// Dockerfile文件
FROM nginx:latest
RUN echo '<h1>Hello, candy!</h1>' > /usr/share/nginx/html/index.html

3. 定制镜像

// nginx镜像,版本为candy
// 注意: 最后面.的意思是当前目录下的文件,也就是Dockerfile文件
docker build -t nginx:candy .

4. 运行

// 指定candy这个版本
docker run -p 8000:80 nginx:candy
 

============================ 华丽的分割线 ============================

定制PM2镜像

Pm2 - 利用多核资源

1. 创建一个pm2文件夹

mkdir pm2

2. 创建package.json

npm init -y

3. 创建一个简单的程序---app.js

vi app.js

4. app.js随便写一点内容

const Koa = require('koa')
const app = new Koa()
app.use(ctx => {
    Math.random() > 0.8 ? abc() : ''
    ctx.body = 'Hello Docker'
})
app.listen(3000, () => {
    console.log('app started at http://localhost:3000/')
})

5. 创建process.yml文件

vi process.yml

6. process.yml

apps:
  - script : app.js
    instances: 2
    watch  : true
    env    :
      NODE_ENV: production

7. 定制Dockerfile

vi Dockerfile

8. 编辑Dockerfile

# 制定pm2镜像的版本
FROM keymetrics/pm2:latest-alpine
#进入到app目录下面,类似cd
WORKDIR /usr/src/app
#移动当前目录下面的文件到app目录下
ADD . /usr/src/app
#设置淘宝镜像并安装依赖
RUN npm config set registry https://registry.npm.taobao.org/ && \    
    npm i
#对外暴露的端口
EXPOSE 3000
#pm2在docker中使用命令为pm2-docker
CMD ["pm2-runtime", "start", "process.yml"]

9. 运行定制

docker build -t pm2 .

10. 运行docker

docker run -p 3000:3000 pm2

11. 后台启动

docker run -p 3000:3000 -d pm2

12. 关闭

docker stop a06

============================ 华丽的分割线 ============================

Docker Compose "批处理"

  • 负责实现对 Docker 容器集群的快速编排(如果有好几个docker,想一起工作,这时候可以用Docker Compose)
  • Docker Compose 是一个工具,命令行工具。
  • 这个工具可以通过yml文件定义多容器的docker应用
  • 通过一条命令就可以根据yml文件的定义去创建或者管理这多个容器

1. 安装docker-compose

yum install docker-compose

2. 新建一个文件夹

mkdir helloworld
cd helloworld

3. 新建docker-compose.yml

version: '3.1'
services:
  hello-world:
    image: hello-world

4. 启动

docker-compose up

5. 解析一下参数

# docker-compose.yml
# docker-compose的版本
version: '3.1'
# 有几个镜像要启动就配置到services下面
services:
  mongo:
    image: mongo
    # 如果死机的话,会一直尝试重启
    restart: always
    # 映射端口
    ports:
        - 27017:27017
  mongo-express:
    image: mongo-express
    restart: always
    ports:
- 8000:8081

实战nginx----docker部署一个前后端分离的项目

1. 在根目录把本地代码同步到服务器上

  • 我的编辑器是用的webstorm,所以使用了它自带的插件Deployment

  • 编辑配置文件 !

  • 编辑映射信息

  • 编辑忽略文件(划重点,,一定要把node_modules忽略,否则极容易上传不成功,我最开始的时候就是这里没有配置,卡这里好一会)

  • 选中需要的文件,右键就可以同步到服务器啦

2.在根目录nginx/conf.d/docker.conf,配置端口,路径,代理服务

server {
    listen       80;
    location / {
        root   /var/www/html;
        index  index.html index.htm;
    }

   location /cds {
     proxy_pass http://192.168.0.210:9008/cds;
     proxy_redirect off;
     proxy_cookie_path / "/; httponly; SameSite=Lax";
   }
}

3.在根目录创建docker-compose.yml对所有项目集群

version: '3.1'
services:
  nginx:
    restart: always
    image: nginx
    ports:
      - 3000:80
    volumes:
      - ./nginx/conf.d/:/etc/nginx/conf.d
      - ./hellowVue/dist:/var/www/html/

4. 对前端项目执行build并Deployment同步到服务商

5. 启动服务

docker-compose up -d

============================ 未完待续 ============================

到这里其实已经部署好项目了,明天会持续更新自动化执行的脚本文件让每次本地build的时候,自动更新代码并重启服务。

webhook实现持续集成

1. 概念

webhook与异步编程中"订阅-发布模型"非常类似,一端触发事件,一端监听执行。就是我本地代码更改,执行某些操作的时候,服务端代码也自动更新,并执行一些自定义脚本,比如我push的时候,服务器自动pull代码并更新重启

2. 线上配置

  • 登录github,或者gitlab,我的项目是在gitlab上所以以这个为例

2. 本地根目录下新建一个webhooks.js

var http = require('http')
// 注意,如果你是github的话,应该是require('github-webhook-handler')
var createHandler = require('gitlab-webhook-handler')
var handler = createHandler({ path: '/webhooks', secret: 'zjcds123456' })
// 上面的 secret 保持和 GitHub 后台设置的一致

function run_cmd(cmd, args, callback) {
    var spawn = require('child_process').spawn;
    var child = spawn(cmd, args);
    var resp = "";

    child.stdout.on('data', function (buffer) { resp += buffer.toString(); });
    child.stdout.on('end', function () { callback(resp) });
}
// debug用
// run_cmd('sh', ['./deploy-dev.sh'], function(text){ console.log(text) });

http.createServer(function (req, res) {

    handler(req, res, function (err) {
        res.statusCode = 404
        res.end('no such location')
    })
}).listen(3000,() =>{
    console.log('WebHooks Listern at 3000');
})

handler.on('error', function (err) {
    console.error('Error:', err.message)
})


// handler.on('*', function (event) {
//     console.log('Received *', event.payload.action);
//     //   run_cmd('sh', ['./deploy-dev.sh'], function(text){ console.log(text) });
// })

handler.on('push', function (event) {
    console.log('Received a push event for %s to %s',
        event.payload.repository.name,
        event.payload.ref);
        // 分支判断
        if(event.payload.ref === 'refs/heads/master'){
            console.log('deploy master..')
            run_cmd('sh', ['./deploy-dev.sh'], function(text){ console.log(text) });

        }
})


// handler.on('issues', function (event) {
//     console.log('Received an issue event for % action=%s: #%d %s',
//         event.payload.repository.name,
//         event.payload.action,
//         event.payload.issue.number,
//         event.payload.issue.title)
// })

4. 根目录下新建一个脚本文件deploy-dev.sh

echo Deploy Project
# docker-compose up -d --force-recreate --build

# 获取最新版代码
git pull

# 强制重新编译容器
docker-compose down
docker-compose up -d --force-recreate --build


# 定制镜像
# docker build -t myapp:pm2 ./backend

# 重启启动容器
# docker stop myapp
# docker rm myapp
# docker run --name myapp -p 3000:3000  -d myapp:pm2

5. 同样Deployment一下,发送到服务器

6. 起一个服务运行一下webhooks.js,这样就能监听到你每次的push操作啦

node webhooks.js

=============到这里每次push的时候就会自动更新服务部署啦==================