用轻量级开源工具 Drone 完成小团队的 CI/CD
前言
持续集成和构建的工具有很多,除了著名的 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)
---
- 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:
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):
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)
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、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 文件
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 命令生成一个共享密钥:
openssl rand -hex 16
61379d57490fe37822267e7984acc934
下载镜像
Drone Server 以轻量级的 Docker 镜像的形式发布,镜像是自包含的,没有任何外部依赖。
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
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
$ 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、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):
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)
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 都有的头描述部分:
kind: pipeline # Pipeline 的类型,其他的还有 secret and signature。
type: docker # 定义了执行任务的类型,这里会使用 Docker 执行。
name: web # 定义 Pipline 的名字,一个 .drone.yml 可以有多个不同名字的 Pipeline。
然后是描述任务的每个步骤,steps 属性后描述此步骤的 name (名字) 和 image (镜像),每一步都会用到一个镜像,任务进行时会根据提供的镜像名字拉取镜像并生成一个临时 Docker 容器运行任务指令,步骤完成后自动删除。
steps:
- name: build-imaeg # 步骤名
image: docker # 步骤需要用到的镜像
下面是一个 vue 前端程序打包成 Docker 镜像并部署到服务器的例子。文中介绍的范例主要想覆盖常见的坑,对于新手可能会比较复杂,如果看不懂,没关系,可以直接跳过这一节,自己尝试动手安装 Drone CI 后回头再细品。
.drone.yml 文件
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 文件
# 设置基础镜像,如果本地没有该镜像,会从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 文件中我们可以定义
kind: pipeline
type: docker
name: default
steps:
- name: build
image: golang
commands:
- go build
- go test
node:
nodeA: runnerA
那么这个任务就只会在标签是 nodeA:runnerA 的 Runner 里运行。
如果想要在两个节点中运行,可以把这两个标签都加上,例如:
node:
nodeA: runnerA
nodeB: runnerB
因为 Runner 会主动心跳连接 Server 并在 Server 上注册自己,不需要固定的网络地址而且足够轻量, 因此这个 Runner 节点可以是你的 PC 机、笔记本,甚至是树莓派。