2020/05/21

Drone CIをGKEで導入してGitlabと連携する

gkedronecigitlab

概要

Titleの通りですが、OSSのプロジェクト管理ツールであるDrone CIをkubernetes上にデプロイをして運用を開始しました。
これより前もDrone CIを使っていたのですが、versionが0.8.8と古く、最近新しいプロジェクトでv1.6.5を導入したところ、
runnerのk8sサポートやpipelineの書き方などが洗練されていたので、本プロジェクトもバージョンアップすることにしました。
また、このプロジェクトでは、gitlabをメインのgitリポジトリとして利用しているので、そのgitlabと連携しました。

実施事項

こちらの記事で作ったGKEクラスター上にDrone CIをdeployしました。

参考になったページ

k8sのデプロイ内容詳細

事前準備

  • drone serverが使うのpostgresql用のcompute diskを作成しておきます。
  • drone serverのweb server(nginx)のためのelastic ip addressを作成しておきます。
  • gitlabのAdmin Areaで、ApplicationsメニューからSystem OAuth applicationを作成しておきます。

k8sへのデプロイ設定ファイル及び順序

namespace

apiVersion: v1
kind: Namespace
metadata:
  name: drone

secrets

apiVersion: v1
kind: Secret
metadata:
  name: drone-server
  namespace: drone
type: Opaque
data:
  # 事前準備で作成した gitlab の application idをbase64エンコードします
  drone-gitlab-client-id: <base64-encoded-string-here>
  # 事前準備で作成した gitlab の application secretをbase64エンコードします
  drone-gitlab-client-secret: <base64-encoded-string-here>
  # openssl rand -hex 16 でランダム文字列を生成してbase64エンコードします
  drone-rpc-secret: <base64-encoded-string-here>
---
apiVersion: v1
kind: Secret
metadata:
  name: postgresql
  namespace: drone
type: Opaque
data:
  password: <base64-encoded-string-here>
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: internal-tls
  namespace: drone
data:
  # nginxで使うsslのcrtファイルの中身をbase64エンコードします
  tls_certificate_chain: <base64-encoded-string-here>
  # nginxで使うsslのkeyファイルの中身をbase64エンコードします
  tls_certificate_key: <base64-encoded-string-here>
  # you can generate tls_dhparam by `openssl dhparam 2048 -out tls_dhparam`
  tls_dhparam: <base64-encoded-string-here>

config map

apiVersion: v1
kind: ConfigMap
metadata:
  name: drone-server
  namespace: drone
data:
  drone-gitlab-server: "https://your-gitlab.com"
  drone-server-host: "your-drone-server.com"
  drone-server-proto: "https"
  drone-database-driver: "postgres"
  drone-database-datasource: "postgres://drone:<psqlpasswordhere>@postgresql:5432/drone?sslmode=disable"

postgresql

apiVersion: v1
kind: PersistentVolume
metadata:
  name: drone-postgresql
spec:
  storageClassName: drone-postgresql
  capacity:
    storage: 20Gi # <- 事前準備で作成した compute disk のサイズ
  accessModes:
    - ReadWriteOnce
  gcePersistentDisk:
    pdName: drone-postgresql # <- 事前準備で作成した compute disk の名前
    fsType: ext4
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgresql
  namespace: drone
spec:
  storageClassName: drone-postgresql
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgresql
  namespace: drone
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgresql
  template:
    metadata:
      name: postgresql
      labels:
        app: postgresql
    spec:
      containers:
        - name: postgresql
          image: postgres:9.6.17-alpine
          env:
            - name: POSTGRES_USER
              valueFrom:
                configMapKeyRef:
                  name: postgresql
                  key: user
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgresql
                  key: password
            - name: POSTGRES_DB
              valueFrom:
                configMapKeyRef:
                  name: postgresql
                  key: db-name
            - name: PGDATA
              value: /var/lib/postgresql/data/pgdata
          ports:
            - name: postgres
              containerPort: 5432
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: postgresql
      volumes:
        - name: postgresql
          persistentVolumeClaim:
            claimName: postgresql
---
apiVersion: v1
kind: Service
metadata:
  name: postgresql
  namespace: drone
spec:
  ports:
    - name: postgres
      port: 5432
      targetPort: postgres
  selector:
    app: postgresql

drone server

apiVersion: apps/v1
kind: Deployment
metadata:
  name: drone-server
  namespace: drone
spec:
  replicas: 1
  selector:
    matchLabels:
      app: drone-server
  template:
    metadata:
      name: drone-server
      labels:
        app: drone-server
    spec:
      containers:
        - name: drone-server
          image: drone/drone:1.6.5
          env:
            - name: DRONE_GITLAB_SERVER
              valueFrom:
                configMapKeyRef:
                  name: drone-server
                  key: drone-gitlab-server
            - name: DRONE_GITLAB_CLIENT_ID
              valueFrom:
                secretKeyRef:
                  name: drone-server
                  key: drone-gitlab-client-id
            - name: DRONE_GITLAB_CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: drone-server
                  key: drone-gitlab-client-secret
            - name: DRONE_RPC_SECRET
              valueFrom:
                secretKeyRef:
                  name: drone-server
                  key: drone-rpc-secret
            - name: DRONE_SERVER_HOST
              valueFrom:
                configMapKeyRef:
                  name: drone-server
                  key: drone-server-host
            # see https://discourse.drone.io/t/drone-server-changing-ports-protocol/4144/3
            - name: DRONE_SERVER_PORT
              value: ":80"
            - name: DRONE_SERVER_PROTO
              valueFrom:
                configMapKeyRef:
                  name: drone-server
                  key: drone-server-proto
            - name: DRONE_DATABASE_DRIVER
              valueFrom:
                configMapKeyRef:
                  name: drone-server
                  key: drone-database-driver
            - name: DRONE_DATABASE_DATASOURCE
              valueFrom:
                configMapKeyRef:
                  name: drone-server
                  key: drone-database-datasource
            - name: DRONE_USER_CREATE
              value: "username:<your-gitlab-username>,admin:true"
          ports:
            - name: http
              containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: drone-server
  namespace: drone
spec:
  ports:
    - name: drone-server
      port: 80
      targetPort: http
  selector:
    app: drone-server

drone runner

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: drone
  namespace: drone
rules:
  - apiGroups:
      - ""
    resources:
      - secrets
    verbs:
      - create
      - delete
  - apiGroups:
      - ""
    resources:
      - pods
      - pods/log
    verbs:
      - get
      - create
      - delete
      - list
      - watch
      - update
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: drone
  namespace: drone
subjects:
  - kind: ServiceAccount
    name: default
    namespace: drone
roleRef:
  kind: Role
  name: drone
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: drone-runner
  namespace: drone
spec:
  replicas: 1
  selector:
    matchLabels:
      app: drone-runner
  template:
    metadata:
      name: drone-runner
      labels:
        app: drone-runner
    spec:
      containers:
        - name: drone-runner
          image: drone/drone-runner-kube:1.0.0-beta.2
          ports:
            - containerPort: 3000
          env:
            - name: DRONE_RPC_HOST
              value: drone-server
            - name: DRONE_RPC_PROTO
              value: http
            - name: DRONE_RPC_SECRET
              valueFrom:
                secretKeyRef:
                  name: drone-server
                  key: drone-rpc-secret
            - name: DRONE_NAMESPACE_DEFAULT
              value: drone
          volumeMounts:
            # Enables Docker in Docker
            - name: docker-socket
              mountPath: /var/run/docker.sock
      volumes:
        - name: docker-socket
          hostPath:
            path: /var/run/docker.sock

nginx

deploymentは割愛しますが、 drone-server serviceに対してproxyするnginxのDockerを作成して、デプロイします。
secretでデプロイしたtlsの設定ファイルを使用してSSLを有効にします。

apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: drone
spec:
  type: LoadBalancer
  loadBalancerIP: <XXX.XXX.XXX.XXX> # <- 事前準備で作成した外部IPアドレスの値
  ports:
    - name: http
      port: 80
      targetPort: http
    - name: https
      port: 443
      targetPort: https
  selector:
    app: nginx

これらのdeploy後に、内部DNSにAレコードを追加して対応完了です。