本文介绍如何使用 Drone 持续构建与发布 Golang + node + kubernetes 应用。

Docker 部署 Drone

docker-compose.yaml示例, 其中配置项如下:

Key 说明
GITHUB_USER_NAME GitHub 的username
TOKEN API 或 Cli 连接 Drone 服务用的 token,可以随机生成:openssl rand -hex 16
GITHUB_CLIENT_ID 参考 Drone 文档 GitHub 引导 创建 OAuth Application,配置参考如下:
Homepage URLhttp://{SERVER_HOST},注意如果不是80端口需要带端口,如http://drone.hbchen.com:8000
Authorization callback URL{Homepage URL}/login,如http://drone.hbchen.com:8000/login
GITHUB_CLIENT_SECRET 同上
SERVER_HOST 绑定的域名,如drone.hbchen.com
RPC_SECRET Drone server 和 runner 通信用的 secret,可以随机生成:openssl rand -hex 16
RUNNER_DASHBOARD_USERNAME 可选,Runner 可以在3000端口提供一个 dashboard,如果需要可以配置用户名和密码
RUNNER_DASHBOARD_PASSWORD 同上
  • 如果外网使用的不是80端口(如此处使用8000),在激活一个 Repo 后需要修改 Repo Webhook 的地址,增加端口
  • 为用户添加 admin 权限,做 cache 挂载 volume 时需要将 Repo 的 Project settings 设置为 trusted,要 admin 才有此权限
version: '3'

services:
  drone-server:
    image: drone/drone:1.6
    restart: always
    ports:
      - 8000:80
    volumes:
      - /var/lib/drone:/data
    environment:
      - DRONE_USER_CREATE=username:{GITHUB_USER_NAME},machine:false,admin:true,token:{TOKEN}
      - DRONE_GITHUB_SERVER=https://github.com
      - DRONE_GITHUB_CLIENT_ID={GITHUB_CLIENT_ID}
      - DRONE_GITHUB_CLIENT_SECRET={GITHUB_CLIENT_SECRET}
      - DRONE_GITHUB_SKIP_VERIFY=true
      - DRONE_SERVER_HOST={SERVER_HOST}
      - DRONE_SERVER_PROTO=http
      - DRONE_RPC_SECRET={RPC_SECRET}

  drone-runner:
    image: drone/drone-runner-docker:1.2
    restart: always
    ports:
      - 3000:3000
    depends_on:
      - drone-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DRONE_RPC_HOST=drone-server
      - DRONE_RPC_PROTO=http
      - DRONE_RPC_SECRET={RPC_SECRET}
      - DRONE_RUNNER_NAME=drone-runner
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_UI_USERNAME={RUNNER_DASHBOARD_USERNAME}
      - DRONE_UI_PASSWORD={RUNNER_DASHBOARD_PASSWORD}

Drone Pipeline

Secret 配置

Pipeline 涉及到 Secret 配置与我们的目标相关,以micro-in-cn/starter-kit/.drone.yml为例:

  • Docker 镜像发布
    • push 镜像需要仓库用户名及密码
  • k8s 部署
    • kubectl 需要配置servercatoken

k8s 配置获取

1.取一个 Pod 的 Secret 或者单独创建一个 account

kubectl describe po {pod-name} | grep SecretName

2.取Secret的ca和token

kubectl get secret {secret-name} -o yaml | egrep 'ca.crt:|token:'

3.drone secret 配置

  • k8s_server
    • cat ~/.kube/config适用于minikube环境
  • k8s_ca
    • ca直接使用
  • k8s_token
    • token做base64解码后使用

kubectl部署需要对应的account有授权,根据自己的环境情况配置
测试可以将clusterrole=cluster-admin授权给serviceaccount

# Error from server (Forbidden): services is forbidden: User "system:serviceaccount:default:default" cannot list resource "services" in API group "" in the namespace "default"
kubectl create clusterrolebinding cluster-admin-role-bound --clusterrole=cluster-admin --serviceaccount={namespace}:{service-account}

使用 drone cli 工具连接 drone server

喜欢 web 操作可以选择在控制台配置 secret

export DRONE_SERVER=http://drone.hbchen.com:8000
export DRONE_TOKEN={前面配置的TOKEN}
drone info
drone secret add --repository=micro-in-cn/starter-kit --name=ali_registry_username --data={xxx}
drone secret add --repository=micro-in-cn/starter-kit --name=ali_registry_password --data={xxx}
drone secret add --repository=micro-in-cn/starter-kit --name=k8s_server --data={xxx}
drone secret add --repository=micro-in-cn/starter-kit --name=k8s_ca --data={xxx}
drone secret add --repository=micro-in-cn/starter-kit --name=k8s_token --data={xxx}

编译&缓存

在项目编译时都会有大量的依赖下载,这些对编译速度影响很大,并且容易导致失败,所以需要使用缓存,避免每次都要重新拉取依赖,以micro-in-cn/starter-kit/console/web为例,有 Golang 和 node 的编译,使用 drone 社区drillster/drone-volume-cache插件对 Golang 和 node 依赖进行缓存。基本过程就是在编译前将cache加载到相应目录,编译后重新将cache写回volume,编译时 Golang 需要指定GOPATH,node 指定global cache

# 挂载 host 缓存目录
volumes:
  - name: cache
    host:
      path: /tmp/drone_cache

steps:
  - name: restore-cache
    image: drillster/drone-volume-cache
    settings:
      restore: true
      mount:
        - ./.npm-cache
        - ./console/web/vue/node_modules
        - ./_gopath
    volumes:
      - name: cache
        path: /cache
    when:
      event:
        - push
  - name: build-vue
    image: node:10.16.3-alpine
    commands:
      - cd console/web/vue
      - npm config set cache ./.npm-cache --global
      - npm install
      - export VUE_APP_BASE_API=
      - npm run build:prod
    when:
      event:
        - push
  - name: build-golang
    image: golang:1.13-alpine
    environment:
      GOPATH: /drone/src/github.com/micro-in-cn/starter-kit/_gopath
      GOOS: linux
      GOARCH: amd64
      CGO_ENABLED: 0
      GOPROXY: https://mirrors.aliyun.com/goproxy/,direct
      GOSUMDB: off
    commands:
      - cd console/web
      - go version
      - go build -o ./bin/linux_amd64/console-web main.go plugin.go
    when:
      event:
        - push
  - name: rebuild-cache
    image: drillster/drone-volume-cache
    settings:
      rebuild: true
      mount:
        - ./.npm-cache
        - ./console/web/vue/node_modules
        - ./_gopath
    volumes:
      - name: cache
        path: /cache
    when:
      event:
        - push

发布镜像&部署

  • docker username 和 password 通过 secret 获取
  • k8s 先用 secret 配置环境变量,使用时再从环境变量去取
  - name: publish-xxx
    image: plugins/docker
    settings:
      tags: latest
      dockerfile: ./console/api/Dockerfile
      context: ./console/web
      repo: registry.cn-hangzhou.aliyuncs.com/hb-chen/starter-kit-console-api
      registry: registry.cn-hangzhou.aliyuncs.com
      username:
        from_secret: ali_registry_username
      password:
        from_secret: ali_registry_password
    when:
      event:
        - push
  - name: deploy-xxx
    image: dtzar/helm-kubectl:3.1.1
    environment:
      SERVER:
        from_secret: k8s_server
      CERTIFICATE_AUTHORITY_DATA:
        from_secret: k8s_ca
      USER_TOKEN:
        from_secret: k8s_token
    commands:
      - kubectl config set-cluster k8s --server="$${SERVER}"
      - kubectl config set clusters.k8s.certificate-authority-data "$${CERTIFICATE_AUTHORITY_DATA}"
      - kubectl config set-credentials k8s-admin --token="$${USER_TOKEN}"
      - kubectl config set-context default --cluster=k8s --user=k8s-admin
      - kubectl config use-context default
      - helm template micro ./deploy/k8s/helm/starter-kit/charts/service --namespace starter-kit --set nameOverride=console-api --set micro.command=/console-api --set image.repository=registry.cn-hangzhou.aliyuncs.com/hb-chen/starter-kit-console-api --set image.tag=${DRONE_TAG=latest} --set image.pullPolicy=Always --set serviceAccount.create=true --set serviceAccount.name=micro-services | kubectl apply -f -
    when:
      event:
        - push