前言
持续集成和构建的工具有很多,除了著名的 Jenkins,Travis,CircleCI,还有最近比较热门的 Github Action 和 Gitlab CI/CD。但是这些工具面对私人项目不是要收费就是占用大量服务器资源,作为个人开发者的私人项目如果想要使用并不友好。那么开源免费的 Drone CI 是个不错选择,它不但非常轻量,而且十分强大。并可以结合私有代码仓库自动编译、构建服务,几行脚本即可实现自动化部署。本文讲述 Drone CI 的具体实践,结合Gitea,怎么在 VPS 里从零开始搭建一个基于 Gitea + Drone CI 的持续集成系统。
Gitea 简介
Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证
Gitea的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。采用Go作为后端语言,只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了x86,amd64,还包括 ARM 和 PowerPC.
Gitea 功能特性
- 支持活动时间线
- 支持 SSH 以及 HTTP/HTTPS 协议
- 支持 SMTP、LDAP 和反向代理的用户认证
- 支持反向代理子路径
- 支持用户、组织和仓库管理系统
- 支持添加和删除仓库协作者
- 支持仓库和组织级别 Web 钩子(包括 Slack 集成)
- 支持仓库 Git 钩子和部署密钥
- 支持仓库工单(Issue)、合并请求(Pull Request)以及 Wiki
- 支持迁移和镜像仓库以及它的 Wiki
- 支持在线编辑仓库文件和 Wiki
- 支持自定义源的 Gravatar 和 Federated Avatar
- 支持邮件服务
- 支持后台管理面板
- 支持 MySQL、PostgreSQL、SQLite3、MSSQL 和 TiDB(MySQL) 数据库
- 支持多语言本地化(21 种语言)
Drone 简介
Drone 是一款基于 Docker 的 CI/CD 工具,所有编译、测试、发布的流程都在 Docker 容器中进行.
开发者只需在项目中包含 .drone.yml 文件,将代码推送到 git 仓库,Drone 就能够自动化的进行编译、测试、发布。
为什么使用 Drone 作为CI/CD 工具
- 功能灵活强大:构建、测试、发布、部署,你想干什么都可以,一套系统全搞定
- 兼容性好:支持所有SCM、所有平台、所有语言
- 环境部署简单:原生支持Docker容器,启动两个容器就完成了部署,其它构建、测试、部署工具在使用时会自动从docker仓库拉取
- 扩展性强:强大的插件系统,丰富的插件可以免费使用,也可以自定义
- 配置简单:正如官方宣传的那样,“configuration as a code”,所有功能、步骤、工具、命令,一个yaml配置文件全搞定
- 维护简单:直接复用SCM的账号体系和权限管理,无需注册用户、分配权限
安装前准备
docker环境安装
1、首先到各大公有云厂商提供的云平台上购买对应的机器,配置可以选择1核2g,或者2核2g,不需要购买太大的配置。
2、机器开通完成后,部署docker环境,可以选择手动部署,或者使用Ansible脚本部署,本次使用Ansible部署,部署脚本如下:(docker-install.yaml)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
---
- name: Remove Docker system
yum:
name:
- docker-client
- docker-client-latest
- docker-common
- docker-latest
- docker-latest-logrotate
- docker-logrotate
- docker-selinux
- docker-engine-selinux
- docker-engine
state: absent
tags:
- cicd
- docker_remove
- name: Remove Docker files
shell: |
rm -rf /etc/systemd/system/docker.service.d
rm -rf /var/lib/docker
rm -rf /var/run/docke
rm -rf /etc/docker
tags:
- cicd
- docker_remove
- name: Install Docker yum
yum:
name:
- yum-utils
- device-mapper-persistent-data
- lvm2
state: present
tags:
- cicd
- docker_install
- name: Install yum manager
shell: |
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
tags:
- cicd
- docker_install
- name: Install Docker
yum:
name: docker-ce
state: present
tags:
- cicd
- docker_install
- name: Configure Docker for files
file:
path: "{{ item }}"
state: directory
with_items:
- /etc/docker
- /etc/systemd/system/docker.service.d
tags:
- cicd
- docker_install
- name: Configure Docker for config
template:
src: "{{ item.name }}"
dest: "{{ item.dest }}"
loop:
- { name: "daemon.json.j2", dest: "/etc/docker/daemon.json" }
- { name: "docker.service.j2", dest: "/usr/lib/systemd/system/docker.service" }
tags:
- cicd
- docker_install
- name: Started Docker
systemd:
name: docker
enabled: yes
state: started
tags:
- cicd
- docker_install
- name: Install Docker-Compose
environment:
DOCKER_COMPOSE_VERSION: 1.25.0-rc2
shell: |
curl -L https://get.daocloud.io/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
tags:
- cicd
- docker_install
- name: Install Docker Swarm
shell:
docker swarm init --advertise-addr {{ groups['pankuibo'][0] }}
tags:
- cicd
- docker_install
|
3、安装docker环境,由于本次Ansible为剧本形式,所以执行如下命令来安装docker:
1
|
ansible-playbook --inventory-file='./../inventory/inventory.ini' ./deploy.yml -e target='test' --tags='docker_remove,docker_install,docker_compose' --forks=5 --user='root'
|
这里说明一下:
1、由于定义了不同的tags,来执行不同的操作
2、部署文件、主机文件、角色文件单独分开,更加灵活方便
Gitea安装及配置
安装
Gitea 在其 Docker Hub 组织内提供自动更新的 Docker 镜像。可以始终使用最新的稳定标签或使用其他服务来更新 Docker 镜像,安装的配置文件如下(docker-compose-gitea.yaml):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
version: "3.8"
services:
gitea:
image: gitea/gitea:1.16.5
environment:
- USER_UID=1000
- USER_GID=1000
- DB_TYPE=mysql
- DB_HOST=localhost:3306
- DB_NAME=gitea
- DB_USER=gitea
- SSH_PORT=2224
volumes:
- /data/gitea:/data
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2224:2224"
networks:
- "default"
deploy:
mode: replicated
replicas: 1
labels:
- "traefik.enable=true"
- "traefik.docker.network=default"
- "traefik.http.services.gitea_gitea.loadbalancer.server.port=3000"
# http 80
- "traefik.http.routers.gitea.rule=Host(`gitea.localhost.com`)"
- "traefik.http.routers.gitea.entrypoints=web"
placement:
constraints: [node.role == manager]
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
networks:
default:
external:
name: traefik_default
|
由于依赖于数据库,所以需要先安装Mysql服务到环境中,使用Mysql的安装配置文件如下(docker-compose-mysql.yaml)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
version: "3.8"
services:
mysql:
image: mysql:5.7.37
environment:
- MYSQL_ROOT_PASSWORD=PWD
command: --default-authentication-plugin=mysql_native_password
volumes:
- /data/mysql:/var/lib/mysql
- /etc/localtime:/etc/localtime:ro
ports:
- "3306:3306"
networks:
- "default"
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
networks:
default:
external:
name: traefik_default
|
要基于 docker-compose 启动gitea,请执行 docker-compose up -d,以在后台启动 Gitea。使用 docker-compose ps 将显示 Gitea 是否正确启动。可以使用 docker-compose logs 查看日志。
要停止gitea,请执行 docker-compose down。这将停止并杀死容器。这些卷将仍然存在。
本次使用如下命令来安装Gitea,目前环境中使用Docker Swarm集群,所以使用如下命令安装即可,关于Docker Swarm的使用说明可以参照Docker Swarm使用说明
1
2
|
1、docker stack deploy -c docker-compose-mysql.yaml mysql
2、docker stack deploy -c docker-compose-gitea.yaml gitea
|
以上设置中 Gitea 的端口号为 3000,因此本地环境浏览器进入localhost:3000即可访问页面,建议配置域名和 Nginx 或 Caddy 反向代理访问。本次使用的代理组件是traefik代理,更多关于traefik的使用说明请参考traefik使用说明
关于上面的配置说明
数据库
要将 Gitea 与 MySQL 数据库结合使用,请将这些更改应用于上面创建的 docker-compose-gitea.yaml 文件
1
2
3
4
5
6
7
8
9
10
|
version: "3.8"
services:
gitea:
image: gitea/gitea:1.16.5
environment:
+ - DB_TYPE=mysql
+ - DB_HOST=localhost:3306
+ - DB_NAME=gitea
+ - DB_USER=gitea
|
环境变量
- APP_NAME:“Gitea: Git with a cup of tea”:应用程序名称,在页面标题中使用。
- RUN_MODE:prod:应用程序运行模式,会影响性能和调试。“dev”,“prod"或"test”。
- DOMAIN:localhost:此服务器的域名,用于 Gitea UI 中显示的 http 克隆 URL。
- SSH_DOMAIN:localhost:该服务器的域名,用于 Gitea UI 中显示的 ssh 克隆 URL。如果启用了安装页面,则 SSH 域服务器将采用以下形式的 DOMAIN 值(保存时将覆盖此设置)。
- SSH_PORT:22:克隆 URL 中显示的 SSH 端口。
- SSH_LISTEN_PORT:%(SSH_PORT)s:内置 SSH 服务器的端口。
- DISABLE_SSH:false:如果不可用,请禁用 SSH 功能。如果要禁用 SSH 功能,则在安装 Gitea 时应将 - SSH 端口设置为 0。
- HTTP_PORT:3000:HTTP 监听端口。
- ROOT_URL:"":覆盖自动生成的公共 URL。如果内部 URL 和外部 URL 不匹配(例如在 Docker 中),这很有用。
- LFS_START_SERVER:false:启用 git-lfs 支持。
- DB_TYPE:sqlite3:正在使用的数据库类型[mysql,postgres,mssql,sqlite3]。
- DB_HOST:localhost:3306:数据库主机地址和端口。
- DB_NAME:gitea:数据库名称。
- DB_USER:root:数据库用户名。
- DB_PASSWD:"” :数据库用户密码。如果您在密码中使用特殊字符,请使用“您的密码”进行引用。
- INSTALL_LOCK:false:禁止访问安装页面。
- SECRET_KEY:"" :全局密钥。这应该更改。如果它具有一个值并且 INSTALL_LOCK 为空,则 INSTALL_LOCK 将自动设置为 true。
- DISABLE_REGISTRATION:false:禁用注册,之后只有管理员才能为用户创建帐户。
- REQUIRE_SIGNIN_VIEW:false:启用此选项可强制用户登录以查看任何页面。
- USER_UID:1000:在容器内运行 Gitea 的用户的 UID(Unix 用户 ID)。如果使用主机卷,则将其与 /data - 卷的所有者的 UID 匹配(对于命名卷,则不需要这样做)。
- USER_GID:1000:在容器内运行 Gitea 的用户的 GID(Unix 组 ID)。如果使用主机卷,则将其与 /data 卷的所有者的 GID 匹配(对于命名卷,则不需要这样做)
创建新的 OAuth2 应用程序
创建一个Gitea的 OAuth2 应用程序,“客户端ID”和“客户端密钥”用于授权访问Gitea的资源。
重定向 URI配置必须按照下面示例的格式和路径,并且必须是真实存在的
- 应用名称-Drone CI
- 重定向URI-指向Drone的登陆URI
- 客户端ID
- 客户端密钥
Drone安装及配置
创建新的共享密钥
创建一个新的共享密钥,用于授权Runners和Drone Server之间进行通信。
可以使用openssl命令生成一个共享密钥:
1
2
|
openssl rand -hex 16
61379d57490fe37822267e7984acc934
|
下载镜像
Drone Server 以轻量级的Docker镜像的形式发布,镜像是自包含的,没有任何外部依赖。
1
|
docker pull drone/drone
|
配置
Drone 服务器使用环境变量进行配置。本文引用了配置选项的子集,定义如下。有关配置选项的完整列表,请参阅配置
Drone Server 部分
- DRONE_GITEA_CLIENT_ID
必需的字符串值提供您的 Gitea oauth 客户端 ID
- DRONE_GITEA_CLIENT_SECRET
必需的字符串值提供您的 Gitea oauth 客户端密码
- DRONE_GITEA_SERVER
必需的字符串值提供您的 Gitea 服务器地址。例如https://gitea.company.com,请注意,http(s)否则您将看到来自 Gitea 的“不支持的协议方案”错误
- DRONE_RPC_SECRET
必需的字符串值提供在上一步中生成的共享密钥。这用于验证服务器和运行器之间的 rpc 连接。必须为服务器和运行器提供相同的秘密值
- DRONE_SERVER_HOST
必需的字符串值提供您的外部主机名或 IP 地址。如果使用 IP 地址,您可以包括端口。例如drone.company.com
- DRONE_SERVER_PROTO
必需的字符串值提供您的外部协议方案。此值应设置为 http 或 https。如果您配置 ssl 或 acme,此字段默认为 https
- DRONE_DATABASE_DATASOURCE
1
|
DRONE_DATABASE_DATASOURCE=root:password@tcp(1.2.3.4:3306)/drone?parseTime=true
|
可选的字符串值。配置数据库连接字符串。默认值为嵌入的 sqlite 数据库文件的路径
- DRONE_DATABASE_DRIVER
可选字符串值。配置数据库驱动程序名称。默认值为 sqlite3 驱动程序。替代驱动程序是 postgres 和 mysql
- DRONE_GITEA_SKIP_VERIFY
布尔值在建立与远程 Gitea 服务器的连接时禁用 tls 验证。默认值为假
- DRONE_RUNNER_CAPACITY
可选数字值。限制运行器可以执行的并发管道的数量。这并不限制可以在单个远程实例上执行的并发管道的数量
- DRONE_USER_CREATE
1
2
3
|
$ openssl rand -hex 16
55f24eb3d61ef6ac5e83d550178638dc
DRONE_USER_CREATE=username:octocat,machine:false,admin:true,token:55f24eb3d61ef6ac5e83d550178638dc
|
在启动时创建的可选用户帐户。这应该用于使用管理帐户为系统播种。它可以是真实账户(即真实的 GitHub 用户),也可以是机器账户
- DRONE_USER_FILTER
可选的以逗号分隔的帐户列表。注册仅限于此列表中的用户,或属于此列表中组织成员的用户
Drone Runner 部分
- DRONE_RPC_HOST
提供 Drone Server 的网络地址(可以带上端口号),Drone Runner 会根据地址连接到 Drone Server 以接收来自 Server 的 piplines 任务
- DRONE_RPC_SECRET
提供在上一步中生成的共享密钥。这用于验证服务器和运行器之间的 rpc 连接。必须为服务器和运行器提供相同的秘密值
- DRONE_RPC_PROTO
填http或者https。 取决于访问 Drone Server 的地址是否使用 https
- DRONE_RUNNER_CAPACITY
一次可以执行几个job,不可为0
- DRONE_RUNNER_NAME
可选的字符串值。设置Runnner的名字。Runner名称存储在服务器中,可用于将构建追溯到特定Runner
- DRONE_RUNNER_LABELS
可选的字符串映射。提供一组标签,用于将管道路由到特定机器或一组机器
- DRONE_LOGS_DEBUG
启用调试日志记录。此配置参数是布尔类型,是可选的
- DRONE_LOGS_PRETTY
启用日志作为默认 json 格式的替代。此配置参数是布尔类型,是可选的
- DRONE_LOGS_NOCOLOR
启用日志的颜色格式;与漂亮的打印日志一起使用。此配置参数是布尔类型,是可选的
安装Drone server 和 Drone Runner
Drone Runner 说明
一旦Drone服务已启动并运行,可以安装runners来执行构建流水线(pipeline).
Drone runners 轮询服务器以查找要执行的工作任务,这里提供了几种不同的runners针对不同用户场景和运行时环境进行了优化,可以根据情况安装一个或多个,一种或多种。
1
2
3
4
5
6
|
1、Docker Runner
2、kubernetes Runner
3、Exec Runner
4、SSH Runner
5、Digital Ocean Runner
6、Macstadium Runner
|
Docker runner 是一个守护进程,它在一个短生命周期容器中执行流水线(pipeline)任务。可以安装一个单独的 Docker runner,或者在多台机器上安装来创建一个构建集群。
Docker runner 是一个通用的 runner,针对可以在无状态容器中运行测试和编译代码的项目进行了优化。
Docker runner 不太适合不能在容器内运行测试或编译代码的项目,包括以 Docker 不支持的操作系统或体系结构为目标的项目,如macOS
启动 Drone Server 和 Drone Runnner
安装的配置文件如下(docker-compose-drone.yaml):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
version: "3.8"
services:
drone:
image: drone/drone:2.0.0 #不要用latest,latest并非稳定版本
ports:
- "7000:80"
networks:
- "drone"
volumes:
- /data/drone/:/var/lib/drone/:rw
- /var/run/docker.sock:/var/run/docker.sock:rw
environment:
#- "DB_PASSWD_FILE=/run/secrets/db_passwd"
- DRONE_DEBUG=true
- DRONE_DATABASE_DATASOURCE=drone:123456@tcp(localhost:3306)/drone?parseTime=true #mysql配置,要与上边mysql容器中的配置一致
- DRONE_DATABASE_DRIVER=mysql
- DRONE_GITEA_SKIP_VERIFY=false
- DRONE_GITEA_CLIENT_ID=xxxxxx
- DRONE_GITEA_CLIENT_SECRET=xxxxxx
- DRONE_GITEA_SERVER=http://localhost:3000/
- DRONE_TLS_AUTOCERT=false
- DRONE_RUNNER_CAPACITY=2
- DRONE_RPC_SECRET=48f11fe546a25099cde4a05ce35a4815 #RPC秘钥
- DRONE_SERVER_PROTO=http #这个配置决定了你激活时仓库中的webhook地址的proto
- DRONE_SERVER_HOST=localhost:7000
- DRONE_USER_CREATE=username:root,admin:true #管理员账号,是你想要作为管理员的Gitea用户名
- DRONE_USER_FILTER=root
- DRONE_DATADOG_ENABLE=false
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
drone-runner:
image: drone/drone-runner-docker:1.6.3
networks:
- "drone"
depends_on:
- drone
volumes:
- /var/run/docker.sock:/var/run/docker.sock:rw
environment:
- DRONE_RPC_HOST=localhost:7000
- DRONE_RPC_SECRET=48f11fe546a25099cde4a05ce35a4815
- DRONE_RPC_PROTO=http
- DRONE_RUNNER_CAPACITY=4
- DRONE_RUNNER_NAME=runner
- DRONE_RUNNER_LABELS=machine1:runner1
- DRONE_DEBUG=true
- DRONE_LOGS_DEBUG=true
- DRONE_LOGS_PRETTY=true
- DRONE_LOGS_NOCOLOR=false
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
networks:
drone:
external: true
name: traefik_default
|
如果是使用docker-compose方式启动,只需要在docker-compose-drone.yaml的目录下输入docker-compose up -d
即可
本次通过以下命令可以启动Drone服务,容器通过环境变量配置,如果想要查看完整的配置参数,请查看配置参考(https://docs.drone.io/server/reference)
1
|
docker stack deploy -c docker-compose-drone.yaml drone
|
以上设置中 Server 的端口号为 7000,因此本地环境浏览器进入localhost:7000即可访问管理页面,建议配置域名和 Nginx 或 Caddy 反向代理访问。本次使用的代理组件是traefik代理,更多关于traefik的使用说明请参考traefik使用说明
Drone 的登录账号默认是绑定 Gitea 账号的,因此只要登录了 Gitea,Drone 也会自动登录。
在打开并登录 Drone 后,你的 Repositories 应该是空的,因为没有同步 Gitea 的代码仓库到 Drone CI 里,只要在首页里的右上角点击SYNC按钮,Drone 便会自动开始同步 Gitea 的代码仓库。同步完成后需要激活仓库,配置完成后,会自动到对应的私有仓库中创建Webhook构建钩子。
如果 Steps 需要挂载宿主机的文件夹,需要在 Drone 对应项目中的 SETTINGS 里的 Project settings 里需要勾选Trusted,这意味着开启容器的特权模式去挂载宿主机的文件夹。开启这个设置用户的权限必须是 admin ,其他用户没有权限开启。
Drone CI 自动部署的实例
在项目代码的根目录新建一个.drone.yml文件,一旦代码上传到代码仓库( github, gitlab, gitea 等),git 仓库会通过 Drone 预先埋好的 Webhoot 钩子发送事件请求给 Drone,Drone 接收到事件请求后会找到仓库项目根目录中的.drone.yml文件进行解析并根据文件的描述执行任务。
Drone CI 构建的每个 step 都会根据镜像产生一个 Docker 容器,并在容器里运行指定任务。
首先每个 Pipline 都有的头描述部分:
1
2
3
|
kind: pipeline # Pipeline 的类型,其他的还有 secret and signature。
type: docker # 定义了执行任务的类型,这里会使用 Docker 执行。
name: web # 定义 Pipline 的名字,一个 .drone.yml 可以有多个不同名字的 Pipeline。
|
然后是描述任务的每个步骤,steps 属性后描述此步骤的 name (名字) 和 image (镜像),每一步都会用到一个镜像,任务进行时会根据提供的镜像名字拉取镜像并生成一个临时 Docker 容器运行任务指令,步骤完成后自动删除。
1
2
3
|
steps:
- name: build-imaeg # 步骤名
image: docker # 步骤需要用到的镜像
|
下面是一个 vue 前端程序打包成 Docker 镜像并部署到服务器的例子。文中介绍的范例主要想覆盖常见的坑,对于新手可能会比较复杂,如果看不懂,没关系,可以直接跳过这一节,自己尝试动手安装 Drone CI 后回头再细品。
.drone.yml 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
kind: pipeline
type: docker #在docker runner中运行
name: web
#定义setups,每个setup有属于自己的name,最后会显示在Drone CI管理页面的侧边栏
steps:
- name: restore-cache # 把之前缓存好的数据取出
image: drillster/drone-volume-cache
settings:
restore: true
mount: # 缓存挂载的文件夹
- ./.npm-cache
- ./node_modules
volumes:
- name: cache
path: /cache
- name: compile #编译
image: node:12
commands:
- yarn config set registry https://registry.npm.taobao.org -g
- yarn config set cache ./.npm-cache --global
- yarn install
- yarn run build
- name: build image #打成docker镜像
image: docker
failure: ignore
volumes:
- name: sock
path: /var/run/docker.sock
commands:
- docker build -t localhost:v1.0 -f Dockerfile .
- docker image prune -f --filter "dangling=true" # 清理无用镜像
- name: rebuild-cache # 把依赖和 npm 缓存放到缓存里
image: drillster/drone-volume-cache
settings:
rebuild: true
mount:
- ./.npm-cache
- ./node_modules
volumes:
- name: cache
path: /cache
- name: deploy #部署到服务器上
image: docker
failure: ignore
volumes:
- name: sock
path: /var/run/docker.sock
commands:
- docker service ls|grep test || export SERVICE=down #先检查服务是否存在,存在更新,不存在创建
- |
if [ "$SERVICE" != "down" ]
then
docker service update --image test:v1.0 test_test
else
docker stack deploy -c deploy.yaml autocd-web
fi
# 循环检测服务是否启动成功
- |
while true
do
docker service ps test_test|awk '{print $6}'|awk 'NR==2'|grep 'Running' || export SERVICE=down
if [ "$SERVICE" == "down" ]
then
echo -e "\033[5;35;40m 正在启动中请稍后 ... \033[0m"
export SERVICE=up
continue
else
docker service logs -n 200 test_test
sleep 3
break
fi
done
# 挂载宿主机文件到docker容器中
volumes:
- name: sock
host:
path: /var/run/docker.sock
- name: cache
host:
path: /tmp/cache
# 创建触发器,绑定分支及事件及上一次成功时才运行
trigger:
branch:
- master
event:
- pull_request
- push
status:
- success
- failure
node:
machine1:runner1
|
Dockerfile 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 设置基础镜像,如果本地没有该镜像,会从Docker.io服务器pull镜像
# 这里会直接调用宿主机的密钥登录私有仓库。
FROM nginx:1.19.2-alpine
# 编译项目,使用npm安装程序的所有依赖,利用taobao的npm安装,并打包编译成静态文件
# 这两步在drone里已经完成
# 复制所有静态文件到 /usr/share/nginx/html下。
# 拷贝配置文件到nginx配置目录中
COPY dist/ /usr/share/nginx/html/
ADD nginx.conf /etc/nginx/nginx.conf
ADD default.conf /etc/nginx/conf.d/default.conf
# 暴露container的端口
EXPOSE 80
# 运行命令
CMD ["nginx", "-g", "daemon off;"]
|
流水线说明
上面的范例有5个Steps
- restore-cache
- compile
- build image
- rebuild-cache
- deploy
简单整理一下每一步(详细的上面注释都有解释)
1、clone克隆私有仓库代码(默认自动添加);
2、restore-cache 步骤会把之前缓存的文件从宿主机中取出;
3、compile 步骤时 yarn或npm 跳过已经安装过的依赖;
4、build 步骤会时根据仓库中的 dockerfile 打成本地镜像包,由于不需要推送到docker私有镜像仓库即并没有使用plugins/docker插件;
5、rebuild-cache 步骤把缓存通过挂载文件放到宿主机中;
6、deploy 步骤使用 将应用部署到容器中;
优化
因为一次构建每一个 steps 都会新生成一个容器并在容器里运行构建,沙盒环境里没有缓存数据。通过restore-cache和rebuild-cache这两个 steps 建立宿主机与容器的缓存,把 vue 的依赖 node_modules 目录和 yran 缓存通过 volumes 映射到宿主机上,在下一次构建并安装依赖时 yarn 会自动跳过没有变化的依赖包,从而加快构建速度。
实际在构建过程中,Drone CI会默认在所有setup最前面添加一个克隆代码的setup(clone), 使用自建的 Gitea 服务内网拉取可以极致地加快构建速度,等代码克隆完成后才会开始执行预定义的一些setup,如果中途报错,即会直接报错退出整个pipeline流水线流程。
多节点运行
在 docker-compose-drone.yaml 文件中定义 Runner 的DRONE_RUNNER_LABELS环境变量可以为 Runner 加上标签,在定义 .drone.yml 时通过这个标签让 pipeline 路由到不同的 Runner 执行任务。
例如我有两个不同的机器放在不同的地方,在这两台机器上运行 Runner 并使用DRONE_RUNNER_LABELS环境变量分别定义这两个 Runner 的标签,例如在第一个 Runner 里DRONE_RUNNER_LABELS=nodeA:runnerA,另一个 Runner 里DRONE_RUNNER_LABELS=nodeB:runnerB,那么在.drone.yml文件中我们可以定义
1
2
3
4
5
6
7
8
9
10
11
12
13
|
kind: pipeline
type: docker
name: default
steps:
- name: build
image: golang
commands:
- go build
- go test
node:
nodeA: runnerA
|
那么这个任务就只会在标签是nodeA:runnerA的 Runner 里运行。
如果想要在两个节点中运行,可以把这两个标签都加上,例如:
1
2
3
|
node:
nodeA: runnerA
nodeB: runnerB
|
因为 Runner 会主动心跳连接 Server 并在 Server 上注册自己,不需要固定的网络地址而且足够轻量, 因此这个 Runner 节点可以是你的 PC 机、笔记本,甚至是树莓派。