GitLab Auto DevOps を試してみた (その一)

# Auto DevOps を試してみた (その一)
これは [GitLab Advent Calender 2017](https://qiita.com/advent-calendar/2017/gitlab) の 13 日目の記事です。

(https://docs.gitlab.com/ee/topics/autodevops/) はとってもすごい機能なんですが、すごすぎてよくわかりません。[Auto DevOps: quick start guide](https://docs.gitlab.com/ee/topics/autodevops/quick_start_guide.html) を参考に試してみました!


## Auto DevOps とは?
GitLab は最近 DevOps Toolchain を目指しており、DevOps を支援する機能がたくさん実装されています。Auto DevOps はこれらの機能をまとめて一気に構築してくれる機能です。(多分)

以下の機能をまとめて扱えるようです。

* [Auto Build](https://docs.gitlab.com/ee/topics/autodevops/#auto-build)
* [Auto Test](https://docs.gitlab.com/ee/topics/autodevops/#auto-test)
* [Auto Code Quality](https://docs.gitlab.com/ee/topics/autodevops/#auto-code-quality)
* [Auto Review Apps](https://docs.gitlab.com/ee/topics/autodevops/#auto-review-apps)
* [Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/#auto-deploy)
* [Auto Monitoring](https://docs.gitlab.com/ee/topics/autodevops/#auto-monitoring)


## 試してみた
Auto DevOps 自体は Kubernetes 以外でもできるように見えるんですが、Quick Start が [GCP](https://console.cloud.google.com/) の [Kubernetes Engine](https://cloud.google.com/kubernetes-engine/docs/) を使っていますのでおとなしくそれを利用することにします。

Quick Start では Mac ですが、Ubuntu 16.04 LTS (WSL のですが) でやりました。GitLab は GitLab.com を使いました。

手順は大雑把に以下のようになります。

1. サンプルプロジェクトをフォークする
1. GCP の Kubernetes Engine でクラスターを組む
1. パソコンに `gcloud` と `kubectl` をインストールする
1. GitLab Project の Kubernetes 連携を設定する
1. Kubernetes クラスターに Helm を利用して NGINX Ingress Controller (リバースプロキシ) をインストールする
1. DNS にアプリの URL のベース名を設定する
1. GitLab Project の Auto DevOps を設定する
1. GitLab Project のパイプラインを実行させる

たったこれだけです! Auto ってついてるけど多いですね...

### サンプルプロジェクトのフォーク
Quick Start 用にプロジェクトが用意されています。それをフォークします。

[minimal-ruby-app](https://gitlab.com/auto-devops-examples/minimal-ruby-app) にアクセスし `Fork` ボタンをクリックしてこのプロジェクトをフォークしてください。

このプロジェクトは `Hello, world!` を表示するだけの簡単な Ruby ウェブアプリケーションです。

* `Hello, world!` を表示するための [server.rb](https://gitlab.com/auto-devops-examples/minimal-ruby-app/blob/master/server.rb)
* 単体テストの [test/app_spec.rb](https://gitlab.com/auto-devops-examples/minimal-ruby-app/blob/master/test/app_spec.rb)
* ウェブアプリケーションを Docker Image 化する [Dockerfile](https://gitlab.com/auto-devops-examples/minimal-ruby-app/blob/master/Dockerfile)

などから構成されています。


### GCP の Kubernetes Engine でクラスターを組む
GCP は[無料でお試し](https://cloud.google.com/free/)ができますのでそれを使いました。

また、本来なら GCP のプロジェクトを作成するのがいいんでしょうけど、初めて使いましたので気が付いたらもともとあったプロジェクトに追加してしまいました...

[Kubernetes Engine](https://console.cloud.google.com/kubernetes/list) にアクセスしたらしばらく待つように表示されました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/bef9e21b-dfcd-642f-8839-a95d467a8344.png)

しばらく待つと準備が完了しますので、`クラスタを作成`をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/be05f6f3-ff74-139c-cb5c-62c87d662bbd.png)

設定はデフォルトのままにしました。名前も `cluster-1` のままです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/057ec190-d0f5-3056-c229-c274d4abd112.png)

`作成`ボタンをクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/2752ae45-1e47-cead-c79f-2bff713c77c0.png)

しばらく待って緑色のチェックアイコンが表示されればクラスターの作成は完了です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/6886a423-a02d-a7cc-50c0-4a85da0d4945.png)


### `gcloud` と`kubetl` のインストール
`gcloud` は GCP を管理するためのコマンドで、`kubectl` は Kubernetes を管理するコマンドです。これらをインストールしていきます。

Quick Start では Mac でのインストール方法ですが、Ubuntu での手順となります。

#### `gcloud` のインストール
```
$ export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)"
$ echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
$ curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
$ sudo apt-get update && sudo apt-get install google-cloud-sdk
```


#### `kubectl` のインストール
```
$ sudo apt-get install kubectl
```


### Kubernetes 連携を設定する
Kubernetes クラスターと GitLab のプロジェクトを連携する設定をします。連携のための、Kubernetes の IP Address やトークンなどを取得します。

まずは、[Kubernetes Engine](https://console.cloud.google.com/kubernetes/list) にアクセスして、作成済みのクラスター `cluster-1` を選びます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/f60b0650-0eac-d0c3-6dcc-1863935ca677.png)

この中の`エンドポイント`と`マスターゾーン`をどこかにかコピっておいてください。

また、GCP のプロジェクトの一覧から Kbernetes Engine を構築したプロジェクトの ID を調べます。(名前ではなく ID です)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/4d71199c-2903-5b9d-3c98-e1cd134f53bf.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/7a091ab3-8f6a-0318-044d-310a7d2f353e.png)

`gcloud` でログインします。

```
$ gcloud auth login
```

ブラウザーが起動すると思いますので、ログインをして `verification code` を入力してください。

ログインが終わったら `kubectl` で Kubernetes を管理できるように資格情報を取得します。

```
$ gcloud container clusters get-credentials {クラスター名} --zone {マスターゾーン} --project {プロジェクト ID}
Fetching cluster endpoint and auth data.
kubeconfig entry generated for cluster-1.
```

`kubectl poxy` を起動して、Kuberntes の管理画面にブラウザーでアクセスできるようにします。

```
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
```

ブラウザーで [http://127.0.0.1:8001/ui](http://127.0.0.1:8001/ui) にアクセスします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/0be1c720-5a54-fe8f-572b-5051b98bc2c5.png)

一番左下の `Config and Storage` の`Secrets をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/e94eeea8-f7c4-93cc-cea3-29a32c72cc46.png)

表示されているトークンを選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/35ea08a6-e871-5ba0-99f9-c5568a0f77f5.png)

表示されている `ca.crt` と `token` を開いてください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/5c62419b-b3a4-e7ca-c2fe-a472da463b01.png)

フォークをした GitLab のプロジェクトの `Settings` -> `Integrations` -> `Project services` -> `Kubernetes` を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/1776f79e-3b00-c121-dcab-e9fe633dbb4b.png)

以下のように入力して `Save changes` ボタンをクリックします。

| 項目 | 値
| ---- | ----
| `Active` | チェックを入れる
| `API URL` | https://{エンドポイント}
| `CA Certificate` | `ca.crt` をコピって貼り付ける (BEGIN の行や END の行まですべて)
| `Project namespace` | そのままにします (自動で生成されるので不要?)
| `Token` | `token` をコピって貼り付けます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/ba341403-799b-0fd0-c1c2-f79ee69a6a19.png)


### NGINX Ingress Controller を使ってウェブアプリを公開できるようにする
NGINX Ingress Controller (リバースプロキシ) を Kubernetes クラスターで動作させます。[Helm](https://github.com/kubernetes/helm) を使いますので、Helm のインストールからです。

```
$ wget https://kubernetes-helm.storage.googleapis.com/helm-v2.7.2-linux-amd64.tar.gz
$ tar zxvf helm-v2.7.2-linux-amd64.tar.gz
$ sudo cp linux-amd64/helm /usr/local/bin/
```

インストールが終わったら Helm を初期化します。

```
$ helm init
```

`helm install` コマンドでリバースプロキシをセットアップします。

```
$ helm install --name ruby-app stable/nginx-ingress
```

`get svc` で起動したことを確かめられます。

```
$ kubectl get svc
NAME                                     TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
kubernetes                               ClusterIP      10.11.240.1     <none>        443/TCP                      1h
ruby-app-nginx-ingress-controller        LoadBalancer   10.11.255.100   <pending>     80:30224/TCP,443:30170/TCP   47s
ruby-app-nginx-ingress-default-backend   ClusterIP      10.11.241.248   <none>        80/TCP                       46s
```


### DNS のセットアップ
Auto DevOps ではワイルドカードドメインを利用します。管理している DNS に名前を登録します。

その前に、NGINX Ingress Controller の公開 IP Address を取得します。

```
$ kubectl get svc ruby-app-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
104.197.72.125
```

これを `*.{あなたのドメイン}` の A レコードに登録してください。もし自由になるドメインを持っていない方はこれを機会にゲットしてしまいましょう! 安いものなら年間 1,000 円もしません!

DNS の設定が終わったら、`host` コマンドで名前が引けるかどうかを確認します。

```
$ host minimal-ruby-app-staging.{あなたのドメイン}
minimal-ruby-app-staging.{あなたのドメイン} has address 104.197.72.125
```

余談ですが、ここまでが**準備**です。疲れました...


### Auto DevOps の設定
ようやく! ようやくです! Auto DevOps の設定に入ります。

フォーク下プロジェクトの `Settings` -> `CI/CD` -> `General pipeline settings` を開いてください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/2abc96bc-fcaa-d712-6816-8368c09b0207.png)

`Enable Auto DevOps` にチェックを入れ、ドメイン名にあなたのドメインを入れます。(`*` はつけないでください)

以上ですべての設定が終わりました!


### パイプラインを実行する
Auto DevOps の設定が完了したので、あとは CI/CD のパイプラインを実行するだけです。

方法は二つあります。

* リポジトリのファイルを何か書き換える
* 手動でパイプラインを実行する

今回は後者を選びました。

https://gitlab.com/{あなたの GitLab アカウント名}/minimal-ruby-app/pipelines/new

にアクセスして `Create pipline` ボタンをクリックします。(二回目以降は `CI/CD` -> `Pipelines` に `Run Pipeline` ボタンが表示されるのですが...)

そうすると、以下のように Auto DevOps のパイプラインが開始されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/adddefef-6a15-6ab9-4913-bc1ebbecbb03.png)

しばらく待つとすべてのジョブが終了します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/6b8d2dc5-7585-b461-69e9-7b58eaa2be22.png)

* `build` - ウェブアプリの Docker Image を作成して Container Registry に Push しています
* `codequality` - [Code Climate](https://codeclimate.com/) によるコード検査を行います
* `test` - 単体テストを実行します
* `production` - 本番 (Kubernetes Engine) にウェブアプリを設置して、公開します


### 見てみる!
`CI/CD` -> `Environments` を選択してください。`production` が追加されています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/cca8ef74-4362-e24d-0d90-c6db6912b745.png)

`Instance` のところに淡い緑の箱が一個だけありますが、これはウェブアプリを一つだけ起動していることを表しています。スケールアウト構成をとるとここにいっぱい四角が並ぶことになります。

`production` をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/ff1efff2-ce40-8ba3-c57c-db644bb446d1.png)

`View deployment` をクリックすることで、デプロイされたアプリにアクセスできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/79130d03-13df-93dc-cf6f-b3e12f315d5c.png)

キマシター!

同じく `production` ページの `>_` アイコンをクリックします。ターミナルにアクセスできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103982/27a87fe3-bd4d-6222-194e-9008fd217c9c.png)

`Monitoring` ボタンは残念ながら機能しませんでした。私の手順が悪かったのかどうかまではわかりません。

最後に、`get svc` を実行して、起動しているコンテナーを確認しましょう。さっきと比べてだいぶ増えましたね!

```
$ kubectl get svc --all-namespaces
NAMESPACE                  NAME                                     TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                      AGE
default                    kubernetes                               ClusterIP      10.11.240.1     <none>           443/TCP                      1h
default                    ruby-app-nginx-ingress-controller        LoadBalancer   10.11.255.100   104.197.72.125   80:30224/TCP,443:30170/TCP   24m
default                    ruby-app-nginx-ingress-default-backend   ClusterIP      10.11.241.248   <none>           80/TCP                       24m
kube-system                default-http-backend                     NodePort       10.11.248.101   <none>           80:30969/TCP                 1h
kube-system                heapster                                 ClusterIP      10.11.254.75    <none>           80/TCP                       1h
kube-system                kube-dns                                 ClusterIP      10.11.240.10    <none>           53/UDP,53/TCP                1h
kube-system                kubernetes-dashboard                     ClusterIP      10.11.247.106   <none>           80/TCP                       1h
kube-system                tiller-deploy                            ClusterIP      10.11.253.178   <none>           44134/TCP                    25m
minimal-ruby-app-4885600   production-auto-deploy                   ClusterIP      10.11.255.249   <none>           5000/TCP                     6m
minimal-ruby-app-4885600   production-postgres                      ClusterIP      10.11.253.171   <none>           5432/TCP                     6m
minimal-ruby-app-4885600   tiller-deploy                            ClusterIP      10.11.241.179   <none>           44134/TCP                    6m
```


## 終わりに
**Auto** DevOps なので、さくさくっといけると思いきや、結構大変ですね... まあ、まだベータですし、今後強化されていきますので苦労するのは今のうちだけだと思います。

NGINX Ingress Controller のイントールも、今回は Quick Start の手順に従いましたが、GitLab 10.2 で追加された [One-click install for Helm and Ingress on Kubernetes](https://about.gitlab.com/2017/11/22/gitlab-10-2-released/#one-click-install-for-helm-and-ingress-on-kubernetes) で簡単にできるようになっているはずです。

さて。

* ReviewApps は動く?
* ステージングをどうやって作るんだろう?
* モニタリング動かなかった
* テストやコード検査エラーの時にどうなるのか?

などなど、興味は尽きないのですが、今日は疲れたのでこれでおしまいです。