【Skaffold】Kubernetesネイティブなローカル開発環境を試す

![image.png](https://qiita-image-store.s3.amazonaws.com/0/243014/34d1f376-d8d0-d13b-e1aa-2100b2fa0e71.png)

## Skaffoldとは
SkaffoldはKubernetesに乗せるアプリケーション開発作業を省力化してくれるコマンドラインツールで、Googleエンジニアの方々が中心となって開発されているOSS。
■Github
https://github.com/GoogleContainerTools/skaffold

Kubernetesに乗せるアプリケーションの開発では、下記1〜4を繰り返す事になり動作確認するのにも手間がかかる。

1.アプリケーションのコード編集
↓
2.コンテナイメージBuild
↓
3.コンテナレジストリへPush
↓
4.kubernetesへDeploy

SkaffoldのPiplineでは2〜4の作業を順次実行してくれる為、開発に集中することができそうです（※3は省略可)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/243014/32555a7d-cc3a-0394-1a4b-895f4aa66956.png)

## Skaffoldインストール

```
$ brew install skaffold
```

```
$ skaffold version
v0.26.0
```

## Skaffoldを利用するための事前準備
準備する必要があるのは下記。

1. アプリケーションのソースコード (今回はmain.goのみ)
2. Dockerfile
3. Kubernetesマニフェスト
4. Skaffold設定ファイル (skaffold.yaml)

### 最終的な構成

```
└── skaffold
    ├── Dockerfile
    ├── main.go
    ├── k8s-deployment.yaml
    └── k8s-service.yaml
    └── skaffold.yaml
```

### 1. アプリケーションソースコードの準備
`Hello Skaffold!`を返すだけのコードを使用

```main.go
package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, Skaffold!")
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

```

### 2. Dockerfileの準備

マルチステージビルドを用いて、1段目でGolangアプリケーションをコンパイルして、2段目で軽量なイメージを用いてビルドを行い、コンパイルされたバイナリをコピーしています。

``` Dockerfile
FROM golang:1.12-alpine3.9 as builder
COPY main.go .
RUN go build -o /go-app main.go

FROM alpine:3.9  
EXPOSE 8080
COPY --from=builder /go-app .
ENTRYPOINT ["./go-app"]
```

### 3. Kubernetesマニフェストの準備
DeploymentとServiceを用意

```k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: skaffold-deployment
spec:
  selector:
    matchLabels:
      app: skaffold-sample
  template:
    metadata:
      labels:
        app: skaffold-sample
    spec:
      containers:
      - name: skaffold-container
        image: {DOCKERHUB-USERNAME}/skaffold-sample
        ports:
        - containerPort: 8080

```

あとでアクセスして確かめたいのでLoadBalancerで公開しておく。

```k8s-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: skaffold-service
spec:
  type: LoadBalancer
  selector:
    app: skaffold-sample
  ports:
  - port: 80
    targetPort: 8080
```

### 4. skaffold設定ファイル作成

```skaffold.yaml
apiVersion: skaffold/v1beta7
kind: Config
build:
  artifacts:
  - image: {DOCKERHUB-USERNAME}/skaffold-sample
    context: .
  local:
    push: false
deploy:
  kubectl:
    manifests:
      - k8s-*
```

pushなしでkubernetesにデプロイできる為、ローカル開発でとても便利！


## Dockerイメージホスティング
今回はDockerHubにホスティングしました（GCPでもどこでも構いません）
`{DOCKERHUB-USERNAME}/skaffold-sample`
というリポジトリを作成しておきましょう（docker loginを忘れずに）

## 実行
```
$ skaffold dev
```

ログを見るとイメージがビルドされ、リポジトリにPushされているのが分かります。

```
Watching for changes every 1s...
```
監視してくれている模様👀


curlでアクセスしてみると

```
Hello, Skaffold!
```

## ソースコードを変更してみる
main.goを変更してみる

```main.go
fmt.Fprintf(w, "Hello, kubernetes!")
```

開発モードでは、ソースコード変更を検知すると自動的にDockerイメージのビルドから処理が再実行されます（変更後にterminal見ると動いているのがわかります）

動作確認してみるとkubernetesに乗っているアプリケーションが差し代わっているのが分かります。

```
Hello, kubernetes!
```

## 所感
- Kubernetesアプリケーションのローカル開発に非常に便利そう！
- Helmと組み合わせればとても良い感じに使えそう！
- Skaffoldに限った事ではないが、Kubernetes周辺のエコシステムはめちゃくちゃ活発でアップデートサイクルが早い（良い事ではある）ので、キャッチアップをしっかりせねばと感じた（ただ、これ系で躊躇してたら遅いと思われ）
- 英語力大事…