建木持续集成平台简单使用教程
前言
建木持续集成平台基于建木,致力于为国内开发者与 DevOps 人员提供极致用户体验,提升开发、上线、运维的效率,让软件用户专注于提供业务价值。
以下为简略文档,详细文档请访问:官方文档
部署
前置条件
资源和系统要求
建议操作系统:Ubuntu 21.04(macOS Monterey)
建议配置:
- CPU:2C
- 内存:8GB
- 磁盘:100GB
软件版本要求
- 推荐使用
Ubuntu 21.04
系统安装; -
Docker 19.30
以上,官方安装手册; -
Docker-Compose 1.29.2
以上,官方安装手册; -
Kubernetes 1.18
以上, 官方安装手册;
安装建木
下载 docker-compose
注意:Mysql
版本需要 8.0
以上
wget https://gitee.com/jianmu-dev/jianmu-deploy/raw/master/docker-compose.yml
示例如下(修改成自己的配置):
version: '3'
services:
jianmu-mysql:
container_name: jianmu-mysql
image: mysql:8
command: --init-connect='SET NAMES utf8' --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=1200 --max-user-connections=1000
ports:
- "3306:3306"
restart: always
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: "jianmu"
TZ: "Asia/Shanghai"
volumes:
- /home/jianmu/mysql/conf:/etc/mysql
- /home/jianmu/mysql/data:/var/lib/mysql
- /home/jianmu/mysql/mysql-files:/var/lib/mysql-files
ci-server:
image: docker.jianmuhub.com/jianmu/jianmu-server:v2.7.0
container_name: jianmu-ci-server
restart: always
environment:
SPRING_PROFILES_ACTIVE: dev
SPRING_DATASOURCE_URL: jdbc:mysql://jianmu-mysql:3306/jianmu?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: 123456
JIANMU_WORKER_SECRET: worker-secret
JIANMU_API_ADMINPASSWD: 123456
# REGISTRY_AK:
# REGISTRY_SK:
volumes:
- /home/jianmu/ci:/ci
depends_on:
- jianmu-mysql
entrypoint: ["wait-for-it.sh", "jianmu-mysql:3306", "-t", "0", "--", "java", "-Duser.timezone=Asia/Shanghai", "-jar", "jianmu-server.jar"]
worker:
image: docker.jianmuhub.com/jianmu/jianmu-worker-docker:v1.0.9
container_name: jianmu-worker
restart: always
environment:
JIANMU_SRV_ADDRESS: http://ci-server:8081
JIANMU_SRV_SECRET: worker-secret
JIANMU_WORKER_ID: worker1
# 可同时并发的容器数量,默认为2
JIANMU_WORKER_CAPACITY: 5
volumes:
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- jianmu-mysql
- ci-server
web:
image: docker.jianmuhub.com/jianmu/jianmu-ui:v2.7.0
container_name: jianmu-web
ports:
- "8088:80"
# - "443:443"
restart: always
depends_on:
- jianmu-mysql
- ci-server
networks:
default:
ipam:
config:
- subnet: 10.1.0.0/16
启动
docker-compose up -d
访问 http://localhost
,默认用户名密码为 admin/123456
。
CentOS 7.9 安装注意事项
在 CentOS 7.9 安装过程需要替换自带的 docker。
以 root 权限登陆系统,更新系统并安装 docker。
更新操作系统,CentOS 7.9 最新版本:
yum -y update
移除 CentOS 默认的 docker 版本:
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
配置 docker 官方 yum 仓库:
yum install -y yum-utils
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
安装 docker 并启动:
yum install docker-ce docker-ce-cli containerd.io
systemctl enable docker
systemctl restart docker
安装 docker-compose:
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
配置 docker-compose 权限:
chmod +x /usr/local/bin/docker-compose
验证环境可用性如下:
[root@localhost ~]# docker version
Client: Docker Engine - Community
Version: 20.10.11
API version: 1.41
Go version: go1.16.9
Git commit: dea9396
Built: Thu Nov 18 00:38:53 2021
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.11
API version: 1.41 (minimum version 1.12)
Go version: go1.16.9
Git commit: 847da18
Built: Thu Nov 18 00:37:17 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.12
GitCommit: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
runc:
Version: 1.0.2
GitCommit: v1.0.2-0-g52b36a2
docker-init:
Version: 0.19.0
GitCommit: de40ad0
[root@localhost ~]# docker-compose version
docker-compose version 1.29.2, build 5becea4c
docker-py version: 5.0.0
CPython version: 3.7.10
OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
使用示例
平台部署
了解缓存
版本说明:v2.7.0 开始支持
注意:只在 docker worker 支持
可在 global
段落下定义 cache
,已定义的 cache
可以在节点中引用,用于解决项目级缓存问题。
- 同一项目中 cache 唯一
- 项目之间的 cache 相互隔离,避免资源冲突
- DSL 中删除某个 cache 配置时,该 cache 会被清除
- 项目删除时,会清除项目的所有 cache
语法:
global:
# 定义单个缓存
cache: m2
或
global:
# 定义多个缓存
cache:
- m1
- m2
pipiline:
maven_build:
type: maven_build:1.4.0-jdk11
# 在节点中引用缓存,可引用多个
cache:
# 表示容器中的 /.m1/repository 目录会挂载到缓存m1上
m1: /.m1/repository
m2: /.m2/repository
param:
mvn_action: test
workspace: ${git_clone.git_path}
shell:
image: alpine:3.13.6
# 可在shell节点中引用缓存
cache:
m2: /xxx
script:
- ls -l /xxx
了解 Docker 数据卷
数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
- 数据卷 可以在容器之间共享和重用
- 对 数据卷 的修改会立马生效
- 对 数据卷 的更新,不会影响镜像
- 数据卷 默认会一直存在,即使容器被删除
注意:数据卷 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会复制到数据卷中(仅数据卷为空时会复制)。
编译节点说明
- maven 节点在
1.4.0
版本开始支持修改local_repo_path
(本地仓库路径) 默认值为/.m2/repository
- nodejs 节点在
1.6.0
版本开始支持修改cache_path
(本地缓存目录) 默认值为/cache
建木 DSL 配置
name: 演示环境
description: 演示环境
# 每天早上6:00自动触发
trigger:
type: cron
schedule: 0 0 6 * * ?
global:
enabled:
value: true
mutable: true
param:
git_ref: master
demo_git_ref: dev
git_frame_url: http://192.168.0.2:10080/test/frame.git
git_demo_url: http://192.168.0.2:10080/test/demo.git
mvn_rep: http://192.168.0.125:9888/repository/maven-public/
img_name: 192.168.0.88/library/demo-api
img_tag: latest
cache: m2
pipeline:
# 同步git上的最新代码
frame:
type: git_clone:1.2.1
param:
remote_url: ${global.git_frame_url}
ref: ${global.demo_git_ref}
username: ((gogs.username))
password: ((gogs.password))
demo:
type: git_clone:1.2.1
param:
remote_url: ${global.git_demo_url}
ref: ${global.git_ref}
username: ((gogs.username))
password: ((gogs.password))
# maven编译打包
maven_frame_build:
type: maven_build:1.4.0-jdk8
cache:
m2: /home/jianmu/maven
param:
mvn_action: clean install -Dmaven.test.skip=true
workspace: ${frame.git_path}
maven_public_url: ${global.mvn_rep}
local_repo_path: /home/jianmu/maven
maven_demo_build:
type: maven_build:1.4.0-jdk8
cache:
m2: /home/jianmu/maven
param:
mvn_action: clean install -Dmaven.test.skip=true
workspace: ${demo.git_path}
maven_public_url: ${global.mvn_rep}
local_repo_path: /home/jianmu/maven
# 构建docker镜像并推送到私仓
docker_build:
type: docker_image_build:1.1.0
param:
registry_address: 192.168.0.88
docker_username: ((harbor.username))
docker_password: ((harbor.password))
image_name: ${global.img_name}
image_tag: ${global.img_tag}
docker_file: Dockerfile
docker_build_path: .
workspace: ${demo.git_path}/demo-api
# 连接81服务器,执行部署命令
deploy_demo:
type: ssh_cmd:1.0.1
param:
ssh_ip: 192.168.0.81
ssh_user: root
ssh_private_key: ((81_ssh.ssh_pk))
ssh_cmd: >-
cd /home/demo-api
&&
docker images
&&
docker-compose down
&&
docker pull ${global.img_name}:${global.img_tag}
&&
docker-compose up -d
&&
docker ps -a | grep demo
&&
echo done
关键说明:
-
在全局变量定义了一个 maven 缓存,变量名为
m2
global: cache: m2
-
新增一个 maven build 节点,使用缓存
m2
pipeline: # maven编译打包 maven_frame_build: type: maven_build:1.4.0-jdk8 cache: m2: /home/jianmu/maven param: local_repo_path: /home/jianmu/maven
注意:local_repo_path 默认路径为 /.m2/repository
-
上方完整示例执行时,将会把 jar 包下载在容器内部的
/home/jianmu/maven
目录下,宿主机路径为 docker 启动默认生成的数据卷(volume)可以使用以下命令查看:
docker volume ls
-
第二次执行时,建木将把宿主机上的数据卷(volume)重新挂载到容器内部的
/home/jianmu/maven
目录
文档自动更新
了解 Webhook
Webhook
可以接收外部事件来触发项目执行
定义语法:
trigger:
type: webhook
param:
- name: xxx
type: STRING
exp: $.xxx.xxx
auth:
token: ${trigger.xxx}
value: ((xxx.xxx))
only: (${trigger.xxx} == "xxx")
-
type:此处固定填
webhook
,必填 -
param:触发器参数,非必填
-
name:参数名称,必填
-
type:参数类型,支持类型:
STRING
、NUMBER
、BOOL
、SECRET
,必填 -
exp:提取参数表达式,必填
注意事项:
v2.2.4
开始,若type
为STRING
时,提取的值将被自动trim
处理,解决yml
语法带来的转义冲突
-
-
auth:认证鉴权,非必填
-
token:Webhook 请求携带的认证鉴权数据,如:请求头中的
Authorization
、Token
等,auth
存在时必填,支持运算表达式和字符串模版 -
value:用于校验
token
值,相同则验证成功,必须是密钥类型,auth
存在时必填 -
only:匹配规则,结果为
true
时触发流程,当前只可引用触发器参数,暂不支持引用全局参数,非必填。
示例:
trigger:
type: webhook
param:
- name: gitee_token
type: SECRET
exp: $.header.X-Gitee-Token
- name: pr_state
type: STRING
exp: $.body.json.pull_request.state
- name: pr_target_branch
type: STRING
exp: $.body.json.target_branch
auth:
token: ${trigger.gitee_token}
value: ((gitee.webhook_token))
only: ((${trigger.pr_target_branch} == "wap" || ${trigger.pr_target_branch} == "web") && ${trigger.pr_state} == "merged")
可使用 JsonPath
从 Webhook
请求中提取触发器参数,以供项目 DSL
中引用
根据提取的位置不同,提取规则如下:
-
Header:$.header.xxx,
http header
-
Query:$.query.xxx,
http querystring
-
Body:
- JSON:$.body.json.xxx,
http body,Content-Type为application/json
- Form 表单:$.body.form.xxx,
http body,Content-Type为application/x-www-form-urlencoded
- Text:$.body.text,
http body,Content-Type为text/plain
- JSON:$.body.json.xxx,
Webhook:
payload: {
"header": {
"content-length": "149",
"postman-token": "2ffe99d2-ff91-4546-a029-a9da8093c1ff",
"x-nginx-proxy": "true",
"connection": "close",
"content-type": "application/json",
"x-client-type": "jianmu",
"accept": "*/*"
},
"query": {
"phone": "10086"
},
"body": {
"json": {
"token": "yWi6XOJQ2VQ9BKSUnlK9jTiHY",
"user": [
{
"name": "Jerry",
"age": 3
},
{
"name": "Tom",
"age": 5
}
]
}
}
}
提取示例:
trigger:
type: webhook
param:
- name: type
type: STRING
exp: $.header.x-client-type
- name: phone
type: STRING
exp: $.query.phone
- name: token
type: STRING
exp: $.body.json.token
- name: name
type: STRIING
exp: $.body.json.user[0].name
- name: age
type: NUMBER
exp: $.body.json.user[0].age
- 表达式
$.header.x-client-type
的结果是jianmu
- 表达式
$.query.phone
的结果是10086
- 表达式
$.body.json.token
的结果是yWi6XOJQ2VQ9BKSUnlK9jTiHY
- 表达式
$.body.json.user[0].name
的结果是Jerry
- 表达式
$.body.json.user[0].age
的结果是3
在项目 DSL
中添加以上定义,保存后会自动生成 Webhook
链接。
Gogs Webhook 配置
建木 DSL 配置
name: 文档更新
description: 文档更新
# 生成webhook
trigger:
type: webhook
param:
- name: event
type: STRING
exp: $.header.X-Gogs-Event
only: (${trigger.event} === "push")
pipeline:
# 连接81服务器,调用同步frame-doc仓库数据
deploy_demo:
type: ssh_cmd:1.0.1
param:
ssh_ip: 192.168.0.81
ssh_user: root
ssh_private_key: ((81_ssh.ssh_pk))
ssh_cmd: >-
cd /home/frame-doc/docsify/frame-doc
&&
git pull
&&
echo done
执行结果
附录
机器间免密登录
ssh
命令用于远程登录上 Linux 主机。常用格式:
ssh [-l login_name] [-p port] [user@]hostname
环境信息
配置两台机器,操作系统都为 Centos7
,信息如下:
- Server A: 192.168.9.100
- Server B: 192.168.9.110
免密码登录原理
图解,server A 免登录到 server B:
- 在
A
上生成公钥私钥。 - 将公钥拷贝给
server B
,要重命名成authorized_keys
(从英文名就知道含义了) -
Server A
向Server B
发送一个连接请求。 -
Server B
得到Server A
的信息后,在authorized_key
中查找,如果有相应的用户名和IP
,则随机生成一个字符串,并用Server A
的公钥加密,发送给Server A
。 -
Server A
得到Server B
发来的消息后,使用私钥进行解密,然后将解密后的字符串发送给Server B
。Server B
进行和生成的对比,如果一致,则允许免登录。 - 得到
server B
发来的消息后,会使用私钥进行解析,然后将机密后的字符串发给server B
。 - 接收到机密后的字符串会跟先前生成的字符串进行对比,如果一致就允许免密登陆。
Linux 下生成密钥
查看 ssh-keygen 的命令手册。
man ssh-keygen
-
通过命令生成一对密钥,执行之后会在用户的根目录生成一个
.ssh
的文件夹。ssh-keygen -t rsa
-
用户的根目录查看生成的
.ssh
文件夹
-
查看
.ssh
文件下生成的文件
文件介绍:
- authorized_keys:存放远程免密登录的公钥,主要通过这个文件记录多台机器的公钥
- id_rsa:生成的私钥文件
- id_rsa.pub:生成的公钥文件
- know_hosts:已知的主机公钥清单
免密登陆设置
总之:A 要免密码登录到 B,B 首先要拥有 A 的公钥,然后 B 要做一次加密验证。对于非对称加密,公钥加密的密文不能公钥解开,只能私钥解开。
手工复制粘贴的方式
-
拷贝本地主机的公钥到远程主机
scp id_rsa.pub
-
将本地主机的公钥加到远程主机的授权列表
.ssh/authorized_keys
若不存在,手动创建
cat id_rsa.pub >> authorized_keys
-
.ssh
目录的权限必须是700
chmod 700 .ssh
-
授权列表
authorized_keys
的权限必须是600
chmod 600 authorized_keys
通过 ssh-copy-id 的方式
命令:
ssh-copy-id -i ~/.ssh/id_rsa.pub [romte_ip]
例如:
ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.9.110
结果如图:
ssh-copy-id
命令可以把本地主机的公钥复制到远程主机的 authorized_keys
文件上,ssh-copy-id
命令也会给远程主机的用户主目录(home)和 /.ssh
, 和 /.ssh/authorized_keys
设置合适的权限。
真诚点赞 诚不我欺~