10分で作るCI環境：HelmでDroneを立ててGithub Enterpriseと連携する方法

こんにちは。
[CET](https://qiita.com/_stakaya/items/21d6e8b9c1f7c8529e2f#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)という[チーム](https://engineer.recruit-lifestyle.co.jp/techblog/2018-02-21-rls-meetup-7/)に所属している@mihirat です。


- OSSのCI/CDとして有名なDroneを
- Helmを使ってGKE上に構築し、
- cloudSQLをバックエンドとして使い、
- Github Enterpriseと連携する
やり方をまとめます。

最後までこの記事を読むと、Helmも、Droneもわかってしまう美味しい記事となっているはずです。

なお先に白状すると、10分というのはGithubの場合(頑張ればそれくらいいけるんじゃないだろうか…？)で、
Github Enterpriseだと多分ネットワーク周りで作業が多いのでもっとかかります。ご容赦ください。


## 導入編
### Droneって？
[公式サイト](https://drone.io/)
無料で使える、Go製のCI/CDツールです。
Github/Github Enterpriseなどと連携でき、リポジトリに簡単な `.drone.yml` を含めることでPRなどがhookされ、自動ビルドや自動デプロイを行うことができます。

### Helmって？
Kubernetesを簡単に使うためのテンプレートファイルとそのコマンド群、みたいなイメージです。
k8sを使おうとすると大量のymlを書く必要がありますが、これはそれなりに苦痛です。
いわゆるベストな構成をみんなで共有できるように、コマンド一つで必要なPodやServiceなどのリソースを全て作成できるテンプレートファイル群にまとめられていて、それに自分の好みのパラメータなどを注入して使います。
[Githubにあるテンプレートたち](https://github.com/kubernetes/charts)
今回は、この中のDroneを作るテンプレートを使います。

### Kubernetesって？
[拙著ですがこちらなどご参考ください](https://qiita.com/mihirat/items/ebb0833d50c882398b0f)
# 作り方
主に参考にしたのは、[こちらのサイト](https://akomljen.com/set-up-a-drone-ci-cd-pipeline-with-kubernetes/)。
とはいえDroneの最新版だとけっこう違う & Github Enterpriseだと更にちょっと工夫が必要だったので、その点を主に説明します。

## 構築編
### 1. 周辺リソースを準備する
GKE上に構築する場合は、
- CloudSQL(HelmのDroneはデフォルトだとsqliteを使いますが、MySQLが必要ならば)
- GKE
あとは必要な権限を付与したサービスアカウントなどを発行しましょう。
Drone用のエンドポイントとなるFQDNを作るために、ドメインの取得やDNSレコードの設定などをします。グローバルIPも必要ですね。
Github Enterpriseと連携する場合はさらに、NATインスタンスの構築や、internal通信を許可するfirewallルールなどが必要になります。

### 2. Github EnterpriseでOauth application登録をする
Droneで使うのに必要なGithubのClientとSecretを発行するために、DroneのエンドポイントとなるFQDNなどを登録します。
Githubだと[このページ](https://github.com/settings/applications/new)
Github Enterpiseは[こちら](http://ashphy.hateblo.jp/entry/drone-github-enterprise-setup)
### 2. Droneの設定をymlに書いていく
Helmでは、デフォルトではvalues.ymlを用いてデプロイが行われます。
カスタムする場合は、values.ymlに自分ができる設定とその説明が全て書いてあるので、そのファイルをコピーするなどして自分のファイルを作成します。

以下、CloudSQLと連携する場合のymlのサンプルになります。

```yaml
service:
 httpPort: 80
 nodePort: 32015
 type: NodePort

ingress:
 enabled: true

 name: drone
 annotations:
   # GCP上で取得したglobal ipなどを指定します。https通信にするためにSSL証明書も追加してあります。
   kubernetes.io/ingress.class: “gce”
   kubernetes.io/ingress.global-static-ip-name: “drone”
   kubernetes.io/ingress.allow-http: “false”
   ingress.gcp.kubernetes.io/pre-shared-cert: “my-cert"

 hosts:
   - my-drone.com

server:
 host: https://my-drone.com

 env:
   DRONE_DEBUG: “false”
   DRONE_DATABASE_DRIVER: “mysql”
   DRONE_DATABASE_DATASOURCE: “drone-db-user:drone-db-pass@tcp(127.0.0.1:3306)/drone-db-name?parseTime=true”

   ## 環境変数
   DRONE_PROVIDER: “github”
   DRONE_OPEN: “true”
   DRONE_GITHUB: “true”
   DRONE_ORGS: “my-org”
   DRONE_ADMIN: “hiroshi,takashi,mike”
   DRONE_GITHUB_CLIENT: “my-client”
   DRONE_GITHUB_SECRET: “my-secret”
   DRONE_GITHUB_PRIVATE_MODE: “true”
   DRONE_GITHUB_URL: “github enterprise endpoint”

 extraContainers: |
   - name: cloudsql-proxy
     image: gcr.io/cloudsql-docker/gce-proxy:1.11
     imagePullPolicy: Always
     command:
       - /cloud_sql_proxy
       - --dir=/cloudsql
       - -instances=“my-google-project”:“cloudsql-region”:“cloudsql-instancename”=tcp:3306
       - -credential_file=/secrets/cloudsql/credentials
     volumeMounts:
       - name: cloudsql-instance-creds
         mountPath: /secrets/cloudsql
         readOnly: true

 extraVolumes: |
   # secretは事前に作成して、同じnamespaceにデプロイしておく
   - name: cloudsql-instance-creds
     secret:
       secretName: my-credential

agent:
 env:
   # 同じpod内で複数Jobを何個まで走らせるかのパラメータ。1つのpodが使えるリソースが多くない場合、ここは1にしておかないとリソース不足になる。
   DRONE_MAX_PROCS: 1
 # 逆に、ここでpod数を増やせるので、大人数で共有する場合にはここを大きくする。DRONE_MAX_PROCS × replicas = totalの最大並列実行数
 replicas: 3

persistence:
 enabled: false
```

extraContainersで、GKEでCloud SQLを使うためにコンテナを追加します。
参考サイト：
[Google公式](https://cloud.google.com/sql/docs/mysql/connect-container-engine?hl=ja)

extraVolumesでは、CloudSQLに接続できる権限を持ったサービスアカウントを発行して、それをk8sのsecretとしてデプロイしておき、drone-serverにマウントします。
[GKEでのサービスアカウントの扱いについて](https://github.com/kelseyhightower/gke-service-accounts-tutorial)

#### ちなみに
この機能、執筆時点で昨日マージされた[自分のPR](https://github.com/kubernetes/charts/pull/6016)でできるようになりました :tada:
Linux FoundationへのPRの出し方は[こちら](https://blog.whywrite.it/2018/06/15/how-to-submit-pr-to-kubernetes/)によくまとまってます。
PR作るまでがけっこう大変でした。

DRONEの環境変数系は0.7と0.8でかなり違うのでご注意を。
##### 参考：
drone 0.7
https://medium.com/magnetis-backstage/how-to-deploy-drone-ci-to-kubernetes-205cd401595c
drone 0.8
http://docs.drone.io/release-0.8.0
http://docs.drone.io/database-settings/

### 3. Helmの初期化
Helmのインストールは `brew install helm` とかでシュッと入ります。
ただ、Helmを実行する権限をk8s内部で付与する必要があるので、下記のようなリソースを先にk8s内部に作成する必要があります。[Helm公式](https://github.com/kubernetes/helm/blob/master/docs/rbac.md)

```yaml

apiVersion: v1
kind: ServiceAccount
metadata:
 name: tiller
 namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
 name: tiller
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: cluster-admin
subjects:
 - kind: ServiceAccount
   name: tiller
   namespace: kube-system
```

で、リソース作成。
```
$ kubectl apply -f rbac_config.yml --record
$ helm init --service-account tiller --upgrade
```
これでhelmを利用する準備が整いました。

### 4.Helmでデプロイ
デプロイ時には `helm upgrade -i <release name> -n <namespace> -f my_values.yml stable/drone` などとコマンドを打つことになります。
releaseというのは、そのアプリを構成するservice, deploymentなどのk8sのリソースの１セットのバージョン管理の単位で、Helmでは名前をつけて管理します。
`ver1` とか自分でわかるものを使いましょう。

無事に作成できていれば、Droneのコンソールにたどり着くはず！
Drone自体の使い方は[このあたりの記事](https://www.rco.recruit.co.jp/career/engineer/blog/drone_io/)をご参考に。



この記事は[元記事](http://techeten.xyz/1201)の転載です。