Drone CICD自动化部署指南

一、Drone核心优势与架构设计

1.1 为什么选择Drone

官方文档

Drone作为轻量级云原生CI/CD工具,相比Jenkins具有显著优势:

  • 资源占用低:基于Docker容器化运行,单个Pipeline平均内存消耗<100MB

  • 云原生支持:原生集成Kubernetes、Docker等云原生技术栈

  • 配置即代码:完全通过.drone.yml定义流程,版本可控

  • 高性能:测试显示并发构建能力比Jenkins高3-5倍16

1.2 企业级架构设计

[Gitee/GitHub] → [Drone Server] → [Docker Runner] (开发环境)
                          ↘ [K8s Runner] (生产环境)
                          ↘ [SSH Runner] (特殊场景)

二、 注册 OAuth 应用 (Gitee为例)

  • 登录 Gitee → 点击右上角头像 → 设置第三方应用创建应用

  • 填写应用信息:

    • 应用名称:Drone CI(自定义)
    • 应用描述:Drone CI/CD 工具(自定义)
    • 授权回调地址:http://你的服务器IP或域名/login(必须正确,否则无法登录)
    • 应用主页:http://你的服务器IP或域名
    • 权限选择:(最少权限原则)user_info,projects,pull_requests,hooks
  • 提交后,记录生成的 Client IDClient Secret(后续配置需要)

三、安装 Drone 服务器和 Runner

Drone 由两部分组成:

  • Drone Server:管理项目、接收仓库事件、协调任务
  • Drone Runner:执行流水线任务(编译、测试、部署等)

3.1 手动启动 Drone Server

docker run -d \
  --name drone-server \
  --restart always \
  -p 80:80 \  # 端口映射(生产环境建议加 HTTPS)
  -v /var/lib/drone:/data \  # 数据持久化
  -e DRONE_RPC_SECRET=your_agent_secret \  # 自定义密钥(与 Runner 保持一致)
  -e DRONE_GITEE_CLIENT_ID=你的Gitee Client ID \  # 替换为 Gitee 应用的 Client ID
  -e DRONE_GITEE_CLIENT_SECRET=你的Gitee Client Secret \  # 替换为 Gitee 应用的 Secret
  -e DRONE_GITEE_SERVER=https://gitee.com \  # Gitee 服务器地址(固定)
  -e DRONE_SERVER_HOST=你的服务器IP或域名 \  # Drone 访问地址(如 drone.example.com)
  -e DRONE_SERVER_PROTO=http \  # 协议(http 或 https)
  -e DRONE_USER_CREATE=username:你的Gitee用户名,admin:true \  # 设置 Gitee 用户名作为管理员
  drone/drone:2.16

DRONE_AGENT_SECRET 可以简单用命令生成openssl rand -hex 16 Drone Server 默认监听容器内的 80 端口(HTTP)和 443 端口(HTTPS,若配置证书),你可以通过 Docker 的端口映射映射(-p 参数)自定义宿主机的端口。

3.2 手动启动 Drone Runner

docker run -d \
  --name drone-runner \
  --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \  # 必须挂载,允许操作 Docker
  -e DRONE_RUNNER_NAME=my-gitee-runner \  # Runner 名称(自定义)
  -e DRONE_RUNNER_CAPACITY=2 \  # 最大并行任务数
  -e DRONE_RPC_SECRET=your_agent_secret \  # 与 Server 的密钥一致
  -e DRONE_RPC_HOST=你的服务器IP或域名 \
  -e DRONE_RPC_PROTO=http \
  drone/drone-runner-docker:1.8

3.3 验证安装

docker ps | grep drone
# 若 drone-server 和 drone-runner 状态为 Up,则启动成功。

访问控制台:

打开浏览器访问 http://你的服务器IP:端口,会出现Drone页面,点击CONTINUE。首次登录需授权 Drone 访问你的 Gitee 账号和仓库,授权后即可进入控制台。

四、 激活项目、配置项目秘钥

成功打开 Drone 控制台后,接下来的核心操作是激活项目、配置流水线和管理构建任务。以下是详细步骤:

4.1 激活代码仓库(首次使用)

Drone 需与你的 Gitee 仓库关联才能触发流水线,需先「激活」项目:

  1. 进入 Drone 控制台首页
    • 登录后,会显示你 Gitee 账号下的所有仓库列表(根据 OAuth 权限获取)。
  2. 激活目标项目
    • 找到你需要配置 CI/CD 的仓库(例如 my-app),点击仓库卡片右侧的 ACTIVATE 按钮并Trusted
    • 激活后,Drone 会自动为该仓库添加 Webhook(用于监听代码推送、PR 等事件),后续代码变动会自动触发流水线。

4.2 配置项目密钥(可选,用于部署等敏感操作)

如果你的流水线需要访问敏感信息(如服务器 SSH 密钥、数据库密码),需在 Drone 中配置「密钥」(Secrets),避免明文暴露:

  1. 进入项目设置:
    • 点击已激活的项目 → 右上角 Settings(齿轮图标)。
  2. 添加密钥:这些密钥可在流水线配置文件(.drone.yml)中通过 from_secret: 密钥名 引用。
    • 在 Secrets 区域,点击 Add Secret。
    • 填写 Name(如 server_ssh_key)和 Value(如实际的 SSH 私钥内容)。
    • 点击 Save 保存。

五、 编写流水线配置文件(核心)

在你的代码仓库根目录创建 .drone.yml 文件,定义自动化流程(如测试、编译、部署)。

示例(Golang 项目):

# 定义流水线类型和名称
kind: pipeline
type: docker
name: golang-enterprise-cd

# 触发条件:仅在 main 分支和 release/* 分支推送时执行
trigger:
  branch:
    - main
    - release/*
  event:
    - push
    - tag  # 支持标签触发(如发布版本时)

# 工作空间配置:缓存依赖,加速构建
workspace:
  path: /go/src/github.com/your-org/your-golang-project  # 项目路径(根据实际调整)

# 流水线步骤
steps:
  # 步骤1:代码质量检查(静态分析)
  - name: code-quality
    image: golangci/golangci-lint:v1.54-alpine  # 代码检查工具
    commands:
      - golangci-lint run ./...  # 运行所有代码检查规则
    depends_on: [ ]  # 无依赖,最先执行

  # 步骤2:下载依赖并缓存
  - name: fetch-dependencies
    image: golang:1.21-alpine
    commands:
      - go mod tidy  # 整理依赖
      - go mod vendor  # 导出依赖到vendor目录(便于缓存)
    volumes:
      - name: go-mod-cache  # 挂载缓存卷
        path: /go/pkg/mod
    depends_on: [ code-quality ]  # 依赖代码检查步骤

  # 步骤3:单元测试并生成覆盖率报告
  - name: unit-test
    image: golang:1.21-alpine
    commands:
      - go test -v -race -coverprofile=coverage.out ./...  # 运行测试(含数据竞争检测)
      - go tool cover -func=coverage.out  # 输出覆盖率摘要
    volumes:
      - name: go-mod-cache
        path: /go/pkg/mod
    depends_on: [ fetch-dependencies ]

  # 步骤4:编译(分环境构建)
  - name: build
    image: golang:1.21-alpine
    commands:
      # 编译Linux版本(生产环境)
      - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=${DRONE_TAG:-latest}" -o app-linux ./cmd/server
      # 编译Windows版本(可选,用于跨平台发布)
      - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.version=${DRONE_TAG:-latest}" -o app-windows.exe ./cmd/server
      # 查看编译产物
      - ls -lh app-linux app-windows.exe
    volumes:
      - name: go-mod-cache
        path: /go/pkg/mod
    depends_on: [ unit-test ]
    when:
      event: [ push, tag ]  # 推送和标签事件都执行

  # 步骤5:构建Docker镜像(生产环境)
  - name: build-docker
    image: docker:24.0.5
    commands:
      # 登录Docker仓库(如私有仓库或Docker Hub)
      - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
      # 构建镜像(标签包含Git commit和版本号)
      - docker build -t your-registry/your-golang-app:${DRONE_TAG:-$DRONE_COMMIT} -t your-registry/your-golang-app:latest .
      # 推送镜像
      - docker push your-registry/your-golang-app:${DRONE_TAG:-$DRONE_COMMIT}
      - docker push your-registry/your-golang-app:latest
    volumes:
      - name: docker-sock  # 挂载Docker套接字
        path: /var/run/docker.sock
    environment:
      DOCKER_USERNAME:
        from_secret: docker_username  # Docker仓库用户名(从密钥获取)
      DOCKER_PASSWORD:
        from_secret: docker_password  # Docker仓库密码(从密钥获取)
    depends_on: [ build ]
    when:
      branch: [ main ]  # 仅主分支构建Docker镜像

  # 步骤6:部署到生产环境(通过SSH)
  - name: deploy-production
    image: appleboy/drone-ssh
    settings:
      host:
        from_secret: prod_server_host  # 生产服务器地址
      username:
        from_secret: prod_server_user  # 服务器用户名
      key:
        from_secret: prod_server_ssh_key  # SSH私钥
      port: 22
      script:
        # 切换到部署目录
        - cd /opt/your-golang-app
        # 拉取最新镜像
        - docker pull your-registry/your-golang-app:${DRONE_TAG:-$DRONE_COMMIT}
        # 停止旧容器
        - docker-compose down || true
        # 启动新容器(使用docker-compose管理)
        - docker-compose up -d
        # 检查服务状态
        - docker-compose ps
    depends_on: [ build-docker ]
    when:
      branch: [ main ]  # 仅主分支部署到生产环境
      event: [ push, tag ]

  # 步骤7:发送构建结果通知(钉钉/企业微信)
  - name: send-notification
    image: appleboy/drone-webhook
    settings:
      urls:
        from_secret: notification_webhook  # 通知Webhook地址
      content_type: application/json
      body: |
        {
          "msgtype": "text",
          "text": {
            "content": "Golang项目构建结果:${DRONE_BUILD_STATUS}\n项目:${DRONE_REPO_NAME}\n分支:${DRONE_BRANCH}\n构建链接:${DRONE_BUILD_LINK}"
          }
        }        
    when:
      status: [ success, failure ]  # 成功或失败都通知
      depends_on: [ deploy-production ]

# 定义缓存卷(加速构建)
volumes:
  - name: go-mod-cache
    temp: { }  # 临时缓存(也可使用持久化卷)
  - name: docker-sock
    host:
      path: /var/run/docker.sock  # 挂载宿主机Docker套接字

示例 (PHP 项目):

# 定义流水线类型和名称
kind: pipeline
type: docker
name: php-enterprise-cd

# 触发条件:主分支、开发分支和标签事件
trigger:
  branch:
    - main
    - develop
    - feature/*
  event:
    - push
    - pull_request
    - tag

# 工作空间配置
workspace:
  path: /var/www/html  # PHP项目默认工作目录

# 流水线步骤
steps:
  # 步骤1:代码风格检查(PHP_CodeSniffer)
  - name: code-style
    image: php:8.2-cli-alpine
    commands:
      # 安装代码检查工具
      - curl -L https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar -o phpcs
      - chmod +x phpcs
      # 检查代码规范(使用PSR-12标准)
      - ./phpcs --standard=PSR12 src/ tests/
    depends_on: [ ]

  # 步骤2:安装PHP依赖(Composer)
  - name: install-dependencies
    image: composer:2.5-alpine
    commands:
      - composer install --no-dev --optimize-autoloader  # 生产环境依赖(无dev包)
      - composer dump-autoload -o  # 优化自动加载
    volumes:
      - name: composer-cache  # 缓存Composer依赖
        path: /tmp/composer-cache
    depends_on: [ code-style ]

  # 步骤3:单元测试(PHPUnit)
  - name: unit-test
    image: php:8.2-cli-alpine
    commands:
      # 安装PHP扩展和测试工具
      - docker-php-ext-install pdo_mysql
      - composer install  # 安装开发依赖(含PHPUnit)
      # 运行测试并生成报告
      - vendor/bin/phpunit --coverage-text --configuration phpunit.xml
    depends_on: [ install-dependencies ]
    when:
      event: [ pull_request, push ]  # PR和推送时执行测试

  # 步骤4:静态代码分析(PHPStan)
  - name: static-analysis
    image: php:8.2-cli-alpine
    commands:
      - composer require --dev phpstan/phpstan  # 安装分析工具
      - vendor/bin/phpstan analyse src/ --level=7  # 严格级别7(最高8)
    depends_on: [ install-dependencies ]

  # 步骤5:构建前端资源(若有Node.js依赖)
  - name: build-frontend
    image: node:18-alpine
    commands:
      - cd resources/assets  # 进入前端资源目录
      - npm install --production
      - npm run build  # 编译JS/CSS(如Webpack)
    depends_on: [ static-analysis ]
    when:
      branch: [ main, develop ]  # 仅主分支和开发分支构建前端

  # 步骤6:构建Docker镜像(含Nginx+PHP-FPM)
  - name: build-docker
    image: docker:24.0.5
    commands:
      - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
      # 构建镜像(区分环境标签)
      - |
        if [ "$DRONE_BRANCH" = "main" ]; then
          TAG="production-${DRONE_COMMIT:0:8}"
        elif [ "$DRONE_BRANCH" = "develop" ]; then
          TAG="staging-${DRONE_COMMIT:0:8}"
        else
          TAG="feature-${DRONE_BRANCH##*/}-${DRONE_COMMIT:0:8}"
        fi        
      - docker build -t your-registry/your-php-app:$TAG .
      - docker push your-registry/your-php-app:$TAG
    volumes:
      - name: docker-sock
        path: /var/run/docker.sock
    environment:
      DOCKER_USERNAME:
        from_secret: docker_username
      DOCKER_PASSWORD:
        from_secret: docker_password
    depends_on: [ build-frontend ]
    when:
      event: [ push, tag ]

  # 步骤7:部署到生产环境(使用Ansible自动化)
  - name: deploy-production
    image: williamyeh/ansible:alpine3
    commands:
      # 配置Ansible(连接生产服务器)
      - mkdir -p ~/.ssh
      - echo "$PROD_SSH_KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
      - ansible-playbook -i ansible/inventory/prod.yml ansible/deploy.yml -e "image_tag=${TAG}"
    environment:
      PROD_SSH_KEY:
        from_secret: prod_server_ssh_key
      TAG: production-${DRONE_COMMIT:0:8}
    depends_on: [ build-docker ]
    when:
      branch: [ main ]
      event: [ push, tag ]

  # 步骤8:部署到测试环境(开发分支)
  - name: deploy-staging
    image: appleboy/drone-ssh
    settings:
      host:
        from_secret: staging_server_host
      username:
        from_secret: staging_server_user
      key:
        from_secret: staging_server_ssh_key
      script:
        - cd /opt/your-php-app
        - docker-compose pull
        - docker-compose up -d
    depends_on: [ build-docker ]
    when:
      branch: [ develop ]  # 开发分支部署到测试环境

  # 步骤9:发送通知到企业微信
  - name: notify
    image: feiyu563/drone-wechat-work:latest
    settings:
      corp_id:
        from_secret: wechat_corp_id
      corp_secret:
        from_secret: wechat_corp_secret
      agent_id: 1000002
      to_user: "@all"
      message: "PHP项目构建${DRONE_BUILD_STATUS}\n仓库: ${DRONE_REPO}\n分支: ${DRONE_BRANCH}\n链接: ${DRONE_BUILD_LINK}"
    when:
      status: [ success, failure ]

# 缓存卷定义
volumes:
  - name: composer-cache
    host:
      path: /tmp/composer-cache  # 宿主机缓存目录(可持久化)
  - name: docker-sock
    host:
      path: /var/run/docker.sock

六、 提交代码触发流水线

  1. 将 .drone.yml 提交到 Gitee 仓库:
    git add .drone.yml
    git commit -m "Add Drone pipeline"
    git push origin main
    
  2. 在 Drone 控制台查看流水线执行:
    • 进入项目页面,会看到一条新的构建记录(状态为「running」),点击记录可查看实时日志:
    • 绿色步骤表示成功,红色表示失败。
    • 点击步骤名称可查看详细输出(如编译错误、测试结果)。

七、 管理构建任务

  1. 重新运行流水线:
    • 若构建失败,可在构建记录页面点击 RESTART 重新运行,无需再次提交代码。
  2. 取消正在运行的任务:
    • 点击构建记录页面的 STOP 按钮,终止当前流水线。
  3. 查看历史构建:
    • 项目首页会显示所有历史构建记录,可按时间、状态筛选。

八 、其他操作(可选)

  1. 关闭项目自动触发:
    • 若需临时禁用流水线,在项目 Settings 中关闭 Auto-cancel redundant builds 或直接 DEACTIVATE 项目(保留配置,不再监听事件)。
  2. 配置分支保护:
    • 结合 Gitee 的分支保护规则,要求流水线成功后才能合并 PR(需在 Gitee 仓库设置中配置)。
  3. 集成通知:
    • 在 .drone.yml 中添加邮件、钉钉、Slack 等通知步骤,例如构建失败时自动提醒:
      - name: notify
        image: appleboy/drone-telegram
        settings:
          token:
            from_secret: telegram_token
          to: your_chat_id
        when:
          status: [success, failure]  # 成功或失败都通知
      

通过以上步骤,即可利用 Drone 实现代码提交后的自动化测试、编译和部署。核心是通过 .drone.yml 定义流水线逻辑,Drone 会根据配置自动执行并反馈结果。