1. 功能简介
通过docker容器化安装gitlab存储代码,安装gitlab-runner实现前端项目的install,build,deploy阶段,最后通过钉钉的自定义webhook功能实现部署信息通知到部门开发群。
2. 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的版本信息)
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. 访问
如果打不开,首先检查自己的服务器的安全组是否开放7004端口(我这里使用的是腾讯云,阿里云同理)
当然如果开始第4步没有走,访问的地址应该是xx.xx.xx.xx:7002 安全组开放的端口也应该是7002
如果一切成功,打开访问地址后就会显示gitlab的登录入口
8. root 登录
首先这里不建议自己注册,也建议管理员进去后屏蔽掉注册功能,否则不利于管理
使用root账户进行最高权限登录
初始密码在这个文件中 $GITLAB_HOME/config/initial_root_password
进入后可以在admin模块进行用户的管理操作
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
复制代码
# 注册
$ docker exec -it [container id] [cmd]
eg:
docker exec -it 8bb028d2edb2 gitlab-runner register
复制代码
如果成功了,在你gitlab CI/CD 的runner配置里就会多出一个可执行的runner,可以是针对单个项目的,也可以是一个组的runner(这里由于我服务器安装的东西比较多,再跑一个gitlab仓库比较卡,我就直接用官网的仓库来演示了,操作基本无差异)
4. 测试
进入刚才新建的项目,新建一个 .gitlab-ci.yml
文件或者直接点击下面这个配置按钮,创建一份位于项目根目录的的runner配置文件
这里随便先输出一点东西,然后提交保存(注意在这里的tags 就是我们注册runner时的tag,表示这个项目用当时注册的那个runner来执行)
然后切换到pipeline面板就可以看到执行的详情了
看到最后输出的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文件,这应该只要有点基础的都看得懂,所以也没必要做啥多的解释了
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,但是报错了
我们看到执行第一句脚本就报错了,npm not found,这是因为我们注册runner的时候只提供了一个alpine的基础镜像,并没有node执行环境,所以我们这里有两种解决办法,一种是将基础镜像改为node,另一种是利用 image
关键字处理
建议这里直接在注册runner的时候就直接用 node:xx.xx.xx 做为基础镜像
# 头部加入node镜像,那么整个流水线都可以用到node环境(node:alpine 可能不稳定)
image: node:14.18.1
stages:
- install
...
复制代码
我们看到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
很奇怪的是还是报错,在启动容器的时候我已经配置了目录卷,但是去到runner配置文件中居然没有配置进去,所以这里我们手动去修改runner配置文件config.toml
($GITLAB_RUNNER_HOME/config/config.toml
)
# 没有起作用,迷惑
$ docker run ...
-v /var/run/docker.sock:/var/run/docker.sock \
...
复制代码
4.测试
当所有job都执行成功后,我们在服务器执行 docker ps
如果有你的容器,那么恭喜你成功了!
打开你的 http://www.牛皮.com:9002 看一下!然后改点代码再提交测试一下效果吧!
6.链接钉钉机器人
1.添加智能群助手
自己新建一个钉钉群,用来做测试,然后添加一个自定义的机器人
2.触发机器人提示
webhook地址就是使用上面钉钉自动生成的一个地址
$ curl 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text","text": {"content":"我就是我, 是不一样的烟火"}}'
复制代码
直接shell行里输入上面的脚本不出意外你的钉钉机器人就触发了!(我这里使用了关键字触发,所以加了xxx)
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
复制代码
直接提交代码!!!
至此!使用docker -> gitlab -> gitlab-runner -> deploy -> 钉钉机器人
整条基础流水线已经完成,一些细节方面需要针对不同的项目需求做不同的处理即可!
如果文章对你有帮助,记得收藏点赞哦!大家的支持才是我坚持的动力!