docker + gitlab + 钉钉机器人实现前端自动化部署

1. 功能简介

通过docker容器化安装gitlab存储代码,安装gitlab-runner实现前端项目的install,build,deploy阶段,最后通过钉钉的自定义webhook功能实现部署信息通知到部门开发群。

2. Centos 安装 docker

centos 安装 docker官方地址

如有必要可以先执行清除操作,清除已有安装残留

$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
复制代码

1. 安装

$ sudo yum install -y yum-utils

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
    或者使用阿里云镜像源
$ sudo yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
$ sudo yum install docker-ce docker-ce-cli containerd.io
复制代码

2. 设置开机自启动

$ sudo systemctl enable docker
$ sudo systemctl daemon-reload
$ sudo systemctl start docker
复制代码

3. 测试

 $ sudo docker run hello-world
复制代码

如果安装成功了执行hello-world镜像就会有下面的提示(或者执行 docker --version 能出现docker的版本信息)

截屏2021-11-22 下午10.52.54.png

4. 优化(阿里云镜像加速)

阿里云镜像加速官方地址 操作超级简单,进去按步骤操作有手就行

$ sudo mkdir -p /etc/docker
$ sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxxxx.mirror.aliyuncs.com"]
}
EOF
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
复制代码

3. Docker 安装 gitlab

1. 拉取gitlab镜像

$ docker pull gitlab/gitlab-ce
复制代码

2. 创建本地卷的存放地址

# $HOME 表示服务器的~目录(默认)

# 创建一个gitlab根目录,需要提前创建好 ~/docker/gitlab 目录
$ export GITLAB_HOME=$HOME/docker/gitlab

$ mkdir -p $GITLAB_HOME/config 创建配置目录
$ mkdir -p $GITLAB_HOME/logs   创建日志目录
$ mkdir -p $GITLAB_HOME/data   创建data目录
复制代码

3. 启动gitlab容器

$ docker run --detach \
    --publish 7001:443 --publish 7002:80 --publish 7003:22 --publish 7004:7004  \
    --name gitlab \
    --restart always \
    --volume $GITLAB_HOME/config:/etc/gitlab \
    --volume $GITLAB_HOME/logs:/var/log/gitlab \
    --volume $GITLAB_HOME/data:/var/opt/gitlab \
    gitlab/gitlab-ce(或者直接输入镜像id ---- 123qweasdzxc)
复制代码

4. 修改gitlab.rb配置文件

可以先尝试着不走这一步,直接先走最后一步访问 xx.xx.xx.xx:7004 (gitlab仓库地址),进去后新建的项目clone地址,你会发现其实是有问题的,代码拉取地址是默认的80,runner也是无法正常执行的,当然暂时你可能发现不了这个问题,原因是我这里的80端口映射是7002,而这个配置默认走的是80,我宿主机的80端口并不是gitlab入口

$ vim $GITLAB_HOME/config/gitlab.rb

#将下面的设置丢进去
external_url 'http://xx.xx.xx.xx:7004'
gitlab_rails['gitlab_ssh_host'] = 'xx.xx.xx.xx'
gitlab_rails['gitlab_shell_ssh_port'] = 7003
复制代码

5. 进gitlab容器重启配置服务

$ docker exec -it gitlab /bin/bash  进去gitlab容器的命令
$ gitlab-ctl reconfigure  重置gitlab配置的命令
复制代码

6.常用命令

# gitlab容器命令
$ docker start gitlab    // 启动命令
$ docker restart gitlab  // 重启命令
$ docker stop gitlab     // 停止命令

# 检查启动信息 
$ docker ps 
$ netstat -tnl 命令

# GitLab常用命令
$ gitlab-ctl reconfigure  // 重新应用gitlab的配置
$ gitlab-ctl restart      // 重启gitlab服务
$ gitlab-ctl status       // 查看gitlab运行状态
$ gitlab-ctl stop         // 停止gitlab服务
$ gitlab-ctl tail         // 查看gitlab运行日志
复制代码

7. 访问

打开 xx.xx.xx.xx:7004

如果打不开,首先检查自己的服务器的安全组是否开放7004端口(我这里使用的是腾讯云,阿里云同理)

当然如果开始第4步没有走,访问的地址应该是xx.xx.xx.xx:7002 安全组开放的端口也应该是7002

Snipaste_2021-11-22_23-41-23.png

如果一切成功,打开访问地址后就会显示gitlab的登录入口

Snipaste_2021-11-22_23-47-59.png

8. root 登录

首先这里不建议自己注册,也建议管理员进去后屏蔽掉注册功能,否则不利于管理

使用root账户进行最高权限登录

初始密码在这个文件中 $GITLAB_HOME/config/initial_root_password

进入后可以在admin模块进行用户的管理操作

Snipaste_2021-11-22_23-54-39.png

4. Docker 安装 gitlab-runner

1.拉取镜像

$ docker pull gitlab/gitlab-runner
复制代码

2.启动容器

$ export GITLAB_RUNNER_HOME=$HOME/docker/gitlab-runner

$ docker run --rm -v $GITLAB_RUNNER_HOME/config:/etc/gitlab-runner -d \
    --name gitlab-runner \
    --restart always \
    -v $GITLAB_RUNNER_HOME/config:/etc/gitlab-runner \
    -v /var/run/docker.sock:/var/run/docker.sock \
    gitlab/gitlab-runner
复制代码

3.查看并注册

# 查看正在运行的容器
$ docker ps
复制代码

Snipaste_2021-11-24_00-23-51.png

# 注册
$ docker exec -it [container id] [cmd]

eg:
docker exec -it 8bb028d2edb2 gitlab-runner register
复制代码

Snipaste_2021-11-24_00-55-53.png

如果成功了,在你gitlab CI/CD 的runner配置里就会多出一个可执行的runner,可以是针对单个项目的,也可以是一个组的runner(这里由于我服务器安装的东西比较多,再跑一个gitlab仓库比较卡,我就直接用官网的仓库来演示了,操作基本无差异)

Snipaste_2021-11-24_00-57-37.png

4. 测试

进入刚才新建的项目,新建一个 .gitlab-ci.yml 文件或者直接点击下面这个配置按钮,创建一份位于项目根目录的的runner配置文件

Snipaste_2021-11-24_01-13-35.png

这里随便先输出一点东西,然后提交保存(注意在这里的tags 就是我们注册runner时的tag,表示这个项目用当时注册的那个runner来执行

Snipaste_2021-11-24_02-11-27.png

然后切换到pipeline面板就可以看到执行的详情了

Snipaste_2021-11-24_02-13-32.png

看到最后输出的hello-world,跟Job successded runner就运用成功了!!!

5. .gitlab-ci.yml编写

1.创建一个项目

使用 vue-cli 或者 create-react-app 创建一个项目并且推送到 gitlab 远程仓库

$ vue create vue-deploy-test
复制代码

2.打包yml脚本编写

在项目根目录创建gitlab-ci.yml文件,这应该只要有点基础的都看得懂,所以也没必要做啥多的解释了

gitlab-ci.yml 官网地址

Gitlab CI 使用高级技巧(简书)

.gitlab-ci.yml语法完整解析

Gitlab CI yaml官方配置文件翻译

stages:
  - install
  - build
  #因为每一个阶段都是独立的,所以要将一些需要承接的文件缓存起来
cache:
  key: deploy-cache
  paths:
    - node_modules
    - dist
    
install-job:
  stage: install
  tags: 
    - vue-group
  script:
    - npm config set registry https://registry.npm.taobao.org
    - npm install
    
 build-job:
  stage: build
  tags:
    - vue-group
  script:
    - npm run build
    
    #https://docs.gitlab.com/ee/ci/yaml/index.html#artifacts
  artifacts:
    name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
    paths:
      - dist/
    expire_in: 2 days
     
复制代码

OK,先提交一下!然后打开gitlab仓库地址会发现,代码的确提交了,并且触发了pipeline,但是报错了

Snipaste_2021-11-24_23-12-14.png

Snipaste_2021-11-24_23-14-55.png

我们看到执行第一句脚本就报错了,npm not found,这是因为我们注册runner的时候只提供了一个alpine的基础镜像,并没有node执行环境,所以我们这里有两种解决办法,一种是将基础镜像改为node,另一种是利用 image 关键字处理

建议这里直接在注册runner的时候就直接用 node:xx.xx.xx 做为基础镜像

# 头部加入node镜像,那么整个流水线都可以用到node环境(node:alpine 可能不稳定)
image: node:14.18.1

stages:
    - install
    ...
复制代码

Snipaste_2021-11-25_00-10-37.png

我们看到pipeline已经走通,并且给我们提供了一个可供下载的制品,这就是我们本机执行 npm run build 后的包一样,你可以下载下来到任意服务器部署。

3.构建docker镜像

stages:
  - install
  - build
  - deploy

......

deploy-job:
  stage: deploy
  # docker in docker
  image: docker
  variables:
    IMAGE_NAME: "vue-deploy-test-image"
    CONTAINER_NAME: "vue-deploy-test-container"
  tags:
    - vue-group
  script:
  # build会自动读取根目录下的 Dockerfile 文件
    - docker build -t $IMAGE_NAME .
    # 先查找是否有正在运行的容器,如果有就停止并删除
    - if [ $(docker ps -aq --filter name=$CONTAINER_NAME) ];
        then
          docker stop $CONTAINER_NAME;
          docker rm -f $CONTAINER_NAME;fi
          #使用自定义的镜像包启动一个nginx容器
    - docker run -d -p 9002:80 --name $CONTAINER_NAME $IMAGE_NAME
复制代码

#Dockerfile 我们简单一点,直接部署,同理可以根目录自定义nginx.conf,同样的方式COPY上去

FROM nginx:latest

COPY ./dist /usr/share/nginx/html

复制代码

前往pipeline查看,可以发现不成功,原因是这里涉及一个Docker run Docker的概念,我们在上面的脚本中执行了docker的命令,而我们的运行环境并没有docker,所以执行失败,这里我们需要指定一个image:docker

Snipaste_2021-11-25_20-39-57.png

很奇怪的是还是报错,在启动容器的时候我已经配置了目录卷,但是去到runner配置文件中居然没有配置进去,所以这里我们手动去修改runner配置文件config.toml$GITLAB_RUNNER_HOME/config/config.toml

# 没有起作用,迷惑
$ docker run ...
    -v /var/run/docker.sock:/var/run/docker.sock \
    ...
复制代码

Snipaste_2021-11-25_21-05-08.png

4.测试

当所有job都执行成功后,我们在服务器执行 docker ps 如果有你的容器,那么恭喜你成功了!

Snipaste_2021-11-25_21-29-19.png

打开你的 http://www.牛皮.com:9002 看一下!然后改点代码再提交测试一下效果吧!

Snipaste_2021-11-25_21-40-33.png

6.链接钉钉机器人

钉钉机器人文档官网

1.添加智能群助手

自己新建一个钉钉群,用来做测试,然后添加一个自定义的机器人

Snipaste_2021-11-25_21-52-21.png

Snipaste_2021-11-25_21-49-48.png

Snipaste_2021-11-25_21-50-52.png

2.触发机器人提示

webhook地址就是使用上面钉钉自动生成的一个地址

$ curl 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxx' \
 -H 'Content-Type: application/json' \
 -d '{"msgtype": "text","text": {"content":"我就是我, 是不一样的烟火"}}'
复制代码

直接shell行里输入上面的脚本不出意外你的钉钉机器人就触发了!(我这里使用了关键字触发,所以加了xxx)

Snipaste_2021-11-25_21-59-38.png

3.node触发

// /scripts/notify.js

const axios = require("axios");
const webhookPath = 'xxxxx'

function getGitlabInfo() {
  const env = process.env;
  const CI_PROJECT_NAME = env.CI_PROJECT_NAME; // 项目仓库名称
  const CI_PROJECT_URL = env.CI_PROJECT_URL; // 项目仓库地址
  const CI_COMMIT_BRANCH = env.CI_COMMIT_BRANCH; // 项目提交分支
  const CI_COMMIT_TAG = env.CI_COMMIT_TAG; // 项目提交tag(与分支不能共存)
  const CI_COMMIT_MESSAGE = env.CI_COMMIT_MESSAGE; //项目最后提交信息
  const CI_COMMIT_SHORT_SHA = env.CI_COMMIT_SHORT_SHA; //项目提交hash值
  const CI_PIPELINE_URL = env.CI_PIPELINE_URL;// 项目Pipeline地址
  const CI_COMMIT_AUTHOR = env.CI_COMMIT_AUTHOR; //提交人姓名
  const GITLAB_USER_EMAIL = env.GITLAB_USER_EMAIL; //登录人email
  const GITLAB_USER_NAME = env.GITLAB_USER_NAME; //登录人姓名
  const date = new Date().toLocaleString();

  const CI_LAST_COMMIT_NAME = CI_COMMIT_BRANCH || CI_COMMIT_TAG;
  const CI_LAST_COMMIT_URL = `${CI_PROJECT_URL}/tree/${ CI_LAST_COMMIT_NAME }`; //项目最后提交仓库地址
  const CI_COMMIT_SHORT_SHA_URL = `${CI_PROJECT_URL}/commit/${CI_COMMIT_SHORT_SHA}`; //项目最后提交的hash值地址
  return {
    CI_PROJECT_NAME,
    CI_PROJECT_URL,
    CI_COMMIT_BRANCH,
    CI_COMMIT_TAG,
    CI_COMMIT_MESSAGE,
    CI_COMMIT_SHORT_SHA,
    CI_PIPELINE_URL,
    CI_COMMIT_AUTHOR,
    GITLAB_USER_EMAIL,
    GITLAB_USER_NAME,
    date,
    CI_LAST_COMMIT_NAME,
    CI_LAST_COMMIT_URL,
    CI_COMMIT_SHORT_SHA_URL,
  } 
}

function getCard(info) {
  let card = {
    title: `${info.CI_PROJECT_NAME}${info.CI_LAST_COMMIT_NAME}分支/tag的构建详情`,
    text: `
    \n > ### ----《部署信息》----
    \n **构建项目**: [${info.CI_PROJECT_NAME}](${info.CI_LAST_COMMIT_URL})
    \n **构建commitID**: [${info.CI_COMMIT_SHORT_SHA}](${info.CI_COMMIT_SHORT_SHA_URL})
    \n **构建分支**: [${info.CI_LAST_COMMIT_NAME}](${info.CI_LAST_COMMIT_URL})
    \n **构建时间**: ${info.date}
    \n **提交信息**: ${info.CI_COMMIT_MESSAGE}
    \n **提交人**: *${info.CI_COMMIT_AUTHOR}* 
    \n
    `,
    btnOrientation: "0",
    btns: [
      {
        title: "查看详情",
        actionURL: info.CI_PIPELINE_URL
      }
    ]
  };
  return card;
}

function send(content) {
  return axios.request(webhookPath, {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    data: JSON.stringify(content)
  });
}

function notify() {
  let gitInfo = getGitlabInfo()
  let card = getCard(gitInfo)
  send({
    msgtype: "actionCard",
    actionCard: {
      title: card.title,
      text: card.text,
      btnOrientation: card.btnOrientation || 0,
      btns: card.btns || []
    }
  }).then(()=>{
    console.log('notify success!!');
  })
}

notify()

复制代码

我们理想状态,当deploy完后,或者哪一个job失败后,我们可以通知到部门钉钉群,请人及时处理,这里我们就只处理成功后了,其他只需要在job失败的时候触发失败提醒是一样的道理。成功的话我们只需要在deploy后面再加一个notify的job就行了,因为只要上面的都成功了才会走到最后一个job。

stages:
    - install
    - build
    - deploy
    - notify
......
notify-job:
  stage: notify
  tags:
    - vue-group
  script:
    - node ./script/notify.js
复制代码

直接提交代码!!!

Snipaste_2021-11-25_22-29-18.png

至此!使用docker -> gitlab -> gitlab-runner -> deploy -> 钉钉机器人 整条基础流水线已经完成,一些细节方面需要针对不同的项目需求做不同的处理即可!

如果文章对你有帮助,记得收藏点赞哦!大家的支持才是我坚持的动力!

猜你喜欢

转载自juejin.im/post/7034517195463852039