使用 Drone 构建项目的 CI/CD

使用 Drone 构建项目的 CI/CD。Drone是一个基于容器的持续交付平台,它使用Docker容器来执行构建和部署操作。分为 Server 和 Runner 两个部分,Server 用于接收远程仓库的回调,读取 .drone.yml 文

概要

Drone是一个基于容器的持续交付平台,它使用Docker容器来执行构建和部署操作。分为 Server 和 Runner 两个部分,Server 用于接收远程仓库的回调,读取 .drone.yml 文件,触发 CI/CD 流程,具体的流程部署交由 Runner 执行。它的工作流程如下:

  1. 代码库中添加一个 .drone.yml 文件,这个文件描述了你的 CI/CD 流程。
  2. 当你的代码库发生变化时,Drone 会检测到这个变化并触发一个构建;
  3. Drone 会拉取你的代码并在 Docker 容器中执行构建操作;
  4. 如果构建成功,Drone 会将构建产物推送到你的镜像仓库中;
  5. Drone 会触发一个部署操作,将你的应用程序部署到你的服务器上;

Server 的部署

本文中仅提供 Gitea 的部署及使用思路,Drone Server 还支持:

GitHubGitHub EnterpriseGiteaGiteeGitLabGogsBitbucket CloudBitbucket Server

针对 Gitea

授权应用

设置 - 应用 - 管理 OAuth2 应用程序 - 创建应用

1
2
3
4
5
6
7
8
9
# 客户端ID
6513cff2-d94d-482c-9643-71f5dd68b5a8
# 客户端密钥
gto_f772z4vz7elxrqt6ize5zjk5me6fozggu6mmirt6jdzab5pttvua

# 应用名称
test
# 重定向 URI
http://192.168.11.109/login

创建 Server

无公网IP时,不要使用 HTTPS

  • 生成 DRONE_RPC_SECRET
1
openssl rand -hex 16
  • docker-compose.yml 文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: '3.9'

services:
  drone-server:
    image: drone/drone:2
    container_name: drone-server
    ports:
      - 80:80
      - 443:443
    restart: always
    environment:
      # - DRONE_TLS_CERT=/etc/certs/drone.company.com/server.crt
      # - DRONE_TLS_KEY=/etc/certs/drone.company.com/server.key
      - DRONE_GITEA_SERVER=http://192.168.11.109:3100/
      - DRONE_GITEA_CLIENT_ID=39f1959f-ddef-49e7-85f7-1c650e4f1e24
      - DRONE_GITEA_CLIENT_SECRET=gto_mkluktyyr2bi6wvkkztdd7k5fvn6ogqo5fma24qv35uadec7oeua
      - DRONE_RPC_SECRET=68e4f56424e2cbf6e22e253da64f9600
      - DRONE_SERVER_HOST=192.168.11.109
      - DRONE_SERVER_PROTO=http
    volumes:
      - D:/Tools/drone/data:/data 
      # - D:/Tools/drone/certs/server.crt:/etc/certs/drone.company.com/server.crt
      # - D:/Tools/drone/certs/server.key:/etc/certs/drone.company.com/server.key
  • 运行
1
docker-compose up -d

访问 Server Web 端

1
http://192.168.11.109

Runner 的部署

类型 作用 备注
Docker Runner 容器中拉取仓库数据,执行 CI/CD 容器访问宿主机会存在局限性,但基本能满足常见需求
Exec Runner 安装二进制程序到系统中,直接在系统环境执行 CI/CD 服务器环境不好隔离
SSH Runner 通过远程命令执行 CI/CD 服务器环境不好隔离

Runner 需要配置:

1
2
3
4
5
6
7
8
9
environment:
  # Server 地址
  - DRONE_RPC_HOST=192.168.11.109
  # Secret
  - DRONE_RPC_SECRET=68e4f56424e2cbf6e22e253da64f9600
  # 并行的 pipline 构建数量
  - DRONE_RUNNER_CAPACITY=2
  # Runner 的名称
  - DRONE_RUNNER_NAME=runner109

部署 Docker Runner

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
version: '3.9'

services:
  drone-runner-docker:
    image: drone/drone-runner-docker:1
    container_name: drone-runner-docker
    ports:
      - 3000:3000
    restart: always
    environment:
      - DRONE_RPC_HOST=192.168.11.109
      - DRONE_RPC_SECRET=68e4f56424e2cbf6e22e253da64f9600
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_RUNNER_NAME=runner-109
    volumes:
      # Linux
      # - /var/run/docker.sock:/var/run/docker.sock
      # Windows
      # - //./pipe/docker_engine://./pipe/docker_engine
      - //var/run/docker.sock:/var/run/docker.sock
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
version: '3.9'

services:
  drone-runner-ssh:
    image: drone/drone-runner-ssh
    container_name: drone-runner-ssh
    ports:
      - 3001:3000
    restart: always
    environment:
      # 此处的 ip 能访问到 server即可,需加上 server 的端口号
      - DRONE_RPC_HOST=192.168.11.109
      - DRONE_RPC_SECRET=68e4f56424e2cbf6e22e253da64f9600
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_RUNNER_NAME=runner-ssh-109

测试 Runner

1
2
3
4
5
6
7
8
9
kind: pipeline
name: default

steps:
  - name: build
    image: node:18-alpine
    commands:
      - yarn install
      - yarn build

Piplines

Server 和 Runner 将根据 Piplines 配置的内容执行 CI/CD。

可以用 远程仓库的 webhook 先限制调用条件,再使用 pipline 配置触发条件。

示例:使用 docker 镜像部署 Springboot

 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
kind: pipeline
name: default

steps:
  - name: build
    image: maven:3.6.3-jdk-11
    commands:
      - mvn clean package

  - name: test
    image: maven:3.6.3-jdk-11
    commands:
      - mvn test

  - name: package
    image: plugins/docker
    volumes:
      - name: docker_socket
        path: /var/run/docker.sock
    commands:
      - docker build -t myapp .
      - docker tag myapp myusername/myapp
      - docker push myusername/myapp

  - name: deploy
    image: plugins/docker
    volumes:
      - name: docker_socket
        path: /var/run/docker.sock
    commands:
      - docker pull myusername/myapp
      - docker run -d -p 8080:8080 myusername/myapp

示例2:使用 ssh 镜像部署 Springboot

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
kind: pipeline
name: deploy

steps:
- name: deploy
  image: appleboy/drone-ssh
  settings:
    host: 192.168.11.xx
    username:
      from_secret: ssh_username
    password:
      from_secret: ssh_password
    port: 22
    script:
    - mkdir -p /data/application
    - cd /data/application
    - mvn clean package
    - java -jar target/myapp.jar

其他

自定义插件

Drone 能自定义插件,让整个流程极其容易定制化。上面 Piplines 中是用的镜像都被视为插件。

Secret

通过设置 Secret Name 和对应的 Secret Value,在 piplines 的定义中,就可以直接使用 Secret Name 替代,以避免密码泄露等安全问题。

  • Source environment variables - 构建过程中使用的变量

  • Source plugin settings - 插件内需要使用的变量

定时任务(cron)

可以在 pipline 中定义,也可以在 Server 的管理界面配置。

 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
kind: pipeline
name: deploy

steps:
- name: deploy
  image: maven:3.6.3-jdk-11
  commands:
  - cd /path/to/application
  - mvn clean package
  - java -jar target/myapp.jar

---
kind: pipeline
name: nightly

trigger:
  cron:
    # 每天晚上 10 点运行
    # 分钟 小时 日 月 周
    # 0 22 * * *
    schedule: "0 22 * * *"

steps:
- name: deploy
  image: maven:3.6.3-jdk-11
  commands:
  - cd /path/to/application
  - mvn clean package
  - java -jar target/myapp.jar

模板(template)

Yaml | Drone

针对大量配置类似或重复的仓库,可以先配置模板,通过填充变量的方式简化部署。

Webhooks

执行 CI/CD 的过程中,配置节点(主要包括:用户、仓库、构建过程)webhook,用其他服务进行接收调用。

 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
------ 此处只是字段介绍,实际环境中 repo、user、build 不能共存 ------
{
    "action": "created",
    "repo": {
        "id": 42,
        "uid": "16607898",
        "user_id": 2,
        "namespace": "octocat",
        "name": "octocat",
        ...
    },
    "user": {
        "id": 1,
        "login": "octocat",
        "email": "octocat@github.com",
        "active": true,
        "admin": false,
        ...
    },
    "build": {
        "id": 100207,
        "repo_id": 296163,
        "number": 42,
        "status": "pending",
        "event": "pull_request",
        "action": "sync",
        ...
    }
}

Docker 换成 Podman

podman 与 Docker 不同,它不需要一个守护进程来运行容器。

Server

1
podman run --volume=/var/lib/drone:/data --env=DRONE_GITHUB_CLIENT_ID=027934d76dc77a085a5e --env=DRONE_GITHUB_CLIENT_SECRET=ad448ca5f28b5c28b653fd0b17e425171fb03dcf --env=DRONE_RPC_SECRET=ad448ca5f28b5c28b653fd0b17e425171fb03dcf --env=DRONE_SERVER_HOST=192.168.22.111 --publish=80:80 --publish=443:443 --restart=always --detach=true --name=drone  drone/drone:2

Runner

1
systemctl --user enable --now podman.socket
命令部署示例
1
podman run --detach   --volume=/run/podman/podman.sock:/var/run/docker.sock  --env=DRONE_RPC_HOST=192.168.22.111   --env=DRONE_RPC_SECRET=ad448ca5f28b5c28b653fd0b17e425171fb03dcf   --env=DRONE_RUNNER_CAPACITY=2   --env=DRONE_RUNNER_NAME=my-first-runner   --publish=3000:3000   --restart=always   --name=runner   drone/drone-runner-docker:1
Podman Compose 部署示例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
version: '3.9'

services:
  drone-runner:
    image: drone/drone-runner-docker:1
    container_name: drone-runner
    ports:
      - 3000:3000
    restart: always
    environment:
      - DRONE_RPC_HOST=192.168.11.109
      - DRONE_RPC_SECRET=68e4f56424e2cbf6e22e253da64f9600
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_RUNNER_NAME=runner-109
    volumes:
      - /run/podman/podman.sock:/var/run/docker.sock

Plugin

使用 Buildah 构建镜像

Drone Plugins - Drone Buildah

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
kind: pipeline
name: build

steps:
- name: build
  image: docker.io/library/alpine:latest
  commands:
  - apk add buildah
  - buildah bud -t myimage .
  - buildah push myimage docker://myregistry/myimage
Gear(夕照)的博客。记录开发、生活,以及一些不足为道的思考……