Kubernetesの開発環境で困っているならskaffoldを使え

この記事では[skaffold](https://github.com/GoogleCloudPlatform/skaffold)の紹介と、ローカル環境で試してみるまでの手順を書いていく。

# はじめに
コンテナを利用して開発で困るのが、少しの変更であってもビルドしてデプロイをしなければならないというストレス。変更を行って、そのimageをbuildして、deploymentを更新するのが面倒。

そのため、[以前記事に書いたとおり](https://qiita.com/tomoyamachi/items/6862cd8ffe220689f6c0)、localの開発ではdocker-composeを利用している。docker-composeではVolumeMountができるので、localでのファイル変更がそのままコンテナに反映できる。

しかし、本番環境をGKEに決めたので、それに合わせて開発環境もK8sにしなきゃな、というところへ、数日前にGoogle公式でちょうどいいツールが出た。
skaffoldだ。

# skaffoldについて

## できること
- 開発では、localでのファイル変更をトリガにbuild/push/deployまでの作業を自動でやってくれる。
- 本番では、CIに組み込んで自動デプロイが簡単になる
  - 面倒なtagの管理も色々やってくれる

ローカルでもリモートでも、簡単に組み込めるというのも売り。
![plugability.png](https://qiita-image-store.s3.amazonaws.com/0/14275/686b141a-595e-9e41-1d66-513affae8a10.png)


## Pros and Cons
- (Pros) Google公式なので自作ビルドツールより安心
- (Pros) 煩雑なimageのtag管理を自動でやってくれる
- (Pros) 導入が簡単
- (Cons) VolumeMountに比べると多少遅い
- (Cons) ビルドするファイルサイズが大きい場合、遅延が顕著になる

# ローカルで導入する

[minikube](https://github.com/kubernetes/minikube)とlocal repositoryを作って試すところまでやる。
事前にDockerは入っていることを前提とする。

## バージョン情報

- DockerCE Version 17.12.0-ce-mac55 (23011)
- minikube v0.25.0

## minikubeのインストール

基本は[minikube](https://github.com/kubernetes/minikube)の公式ドキュメントどおりに。
古いminikubeだと動かなかったので、インストール済みの人も最新版にして試す。

アップグレードする場合は、一回過去のイメージを消す。

```console
$ brew cask upgrade minikube
$ minikube delete
... 過去のISOファイルなどを消す
```

バージョン管理したい場合は、[asdf](http://brewformulas.org/Asdf)を使う。

## minikubeでclustersを作成

```console
$ minikube start


Starting local Kubernetes v1.9.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.
```

clusterができているか確認。

```console
$ kubectl config get-contexts
CURRENT   NAME                                                           CLUSTER                                                        AUTHINFO                                                       NAMESPACE
          gke_project_asia-east1-a_test08                        gke_project_asia-east1-a_test08                        gke_project_asia-east1-a_test08
*         minikube                                                       minikube                                                       minikube
```

利用するクラスタを選択

```console
$ kubectl config use context minikube
```

## ~~local repositoryを立てる~~ 不要な手順です

```console
$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
```

~~imageを利用してローカルにコンテナのレポジトリを立てる。~~

## skaffoldをcloneして、imageの向き先をlocal repositoryへ変更

```console
$ git clone https://github.com/GoogleCloudPlatform/skaffold
$ cd skaffold/examples/getting-started
$ vim skaffold.yaml
```

以下のように変更。

**※ 2018/9/8 追記**
**local repository不要なので、好きなコンテナ名にして大丈夫です。**

```diff
--- a/examples/getting-started/skaffold.yaml
+++ b/examples/getting-started/skaffold.yaml
@@ -2,7 +2,7 @@ apiVersion: skaffold/v1
 kind: Config
 build:
   artifacts:
-  - imageName: gcr.io/k8s-skaffold/skaffold-example
+  - imageName: localhost:5000/skaffold-example
     workspace: .
   local: {}
 deploy:
@@ -11,4 +11,4 @@ deploy:
     - paths:
       - k8s-*
       parameters:
-        IMAGE_NAME: gcr.io/k8s-skaffold/skaffold-example
+        IMAGE_NAME: localhost:5000/skaffold-example

```

## そのままskaffoldコマンドを実行

```console
$ skaffold dev
Starting build...
...
```

## もとのファイルを変更 → 自動更新

`main.go` を適当に変更する。
保存後、自動で更新される
だいたい5秒くらいで、体感的にはbabelのビルドと同じくらい。
すくなくとも、最小限の構成だと開発でストレスを感じるほどではない。

```
[getting-started getting-started] Hello world!
Sending build context to Docker daemon  18.94kB
Step 1/5 : FROM golang:1.9.4-alpine3.7
 ---> fb6e10bf973b
Step 2/5 : WORKDIR /go/src/github.com/GoogleCloudPlatform/skaffold/examples/getting-started
 ---> Using cache
 ---> 3610bc361941
Step 3/5 : CMD ./app
 ---> Using cache
 ---> 213af21552e9
Step 4/5 : COPY main.go .
 ---> eca894679662
Step 5/5 : RUN go build -o app main.go
 ---> Running in 0e0ef567d3dc
[getting-started getting-started] Hello world!
[getting-started getting-started] Hello world!
[getting-started getting-started] Hello world!
 ---> 88d8ca625d34
Successfully built 88d8ca625d34
Successfully tagged 1aaf6e85c5bb92f67740df5f4af5a6f6:latest
Successfully tagged localhost:5000/skaffold-example:88d8ca625d3450f89acd6e3d6b4028f075ab2645c019c8b65c4cf286ecde4313
Build complete.
Starting deploy...
Deploying k8s-pod.yaml...
[getting-started getting-started] Hello world!
Deploy complete.
[getting-started getting-started] Hello world!
[getting-started getting-started] Hello world!
[getting-started getting-started] Hello k8s!
[getting-started getting-started] Hello k8s!
```
## 補足

`skaffold dev` のところを `skaffold run -f skaffold.yaml` にすると一度だけビルドされる。 

## その他

CloudBuilderを利用して、簡単なコマンドを渡すこともできるらしい。
https://github.com/GoogleCloudPlatform/skaffold/blob/21116842e65c0c7ace293352fad2b1f4adb5c9b2/deploy/cloudbuild.yaml

# まとめ

自分がk8sで利用するサービスでは`docker build`部分の時間が長いため、変更から反映までのタイムラグが気になる。が、現状、ビルドツールをつくるよりは圧倒的に早いし、お手軽。

なお、責務を分けて、一つ一つのコンテナを軽量にしているところであれば、十分実用レベルの速さだと思うし、「遅いと感じるようであれば、ちゃんと設計しなおせ」というGoogleからのメッセージだと受け取っている。