Skaffoldを使う

k8s環境でのProd,Stg,Feature,DevなどへのデプロイにSkaffoldを利用しています。
おそらくJenkinsやCIツールなどからこいつを利用してデプロイするのが今のところのベストプラクティスかと思われるので、メモっておきます。

Skaffold: docker buildやkubectl apply を自動でやってくれる便利ツール、dockerのtag管理などもやってくれるのでとってもらくちん。
https://skaffold.dev/
https://github.com/GoogleContainerTools/skaffold

# インストール

コマンドなのでPATHの通ったところに配置します。インストールは簡単。公式の通りにするだけ。

https://skaffold.dev/docs/install/

```
murata:~ $ skaffold
A tool that facilitates continuous development for Kubernetes applications.

  Find more information at: https://skaffold.dev/docs/getting-started/

End-to-end pipelines:
  run               Run a pipeline
  dev               Run a pipeline in development mode
  debug             [beta] Run a pipeline in debug mode

Pipeline building blocks for CI/CD:
  build             Build the artifacts
  deploy            Deploy pre-built artifacts
  delete            Delete the deployed application
  render            [alpha] Perform all image builds, and output rendered Kubernetes manifests

Getting started with a new project:
  init              [alpha] Generate configuration for deploying an application
  fix               Update old configuration to newest schema version

Other Commands:
  completion        Output shell completion for the given shell (bash or zsh)
  config            Interact with the Skaffold configuration
  credits           Export third party notices to given path (./skaffold-credits by default)
  diagnose          Run a diagnostic on Skaffold
  schema            List and print json schemas used to validate skaffold.yaml configuration
  version           Print the version information

Usage:
  skaffold [flags] [options]

Use "skaffold <command> --help" for more information about a given command.
Use "skaffold options" for a list of global command-line options (applies to all commands).
```

# ファイル作成

こんな感じでk8sのマニフェスト(yaml), Dockerfile, Skaffoldファイルの3つを、各ステージ環境ごとに用意しています。

```
murata:~/workspace/tmp/ttt/back $ ll
total 12
-rw-rw-r-- 1 murata murata    0 Dec 23 12:52 Dockerfile.dev
-rw-rw-r-- 1 murata murata    0 Dec 23 12:52 Dockerfile.feature
-rw-rw-r-- 1 murata murata    0 Dec 23 12:52 Dockerfile.prod
-rw-rw-r-- 1 murata murata  200 Dec 23 12:52 go.mod
-rw-rw-r-- 1 murata murata 2925 Dec 23 12:52 go.sum
-rw-rw-r-- 1 murata murata    0 Dec 23 12:54 k8s.dev.yaml
-rw-rw-r-- 1 murata murata    0 Dec 23 12:54 k8s.prod.yaml
-rw-rw-r-- 1 murata murata    0 Dec 23 12:54 k8s.feature.yaml
-rw-rw-r-- 1 murata murata  228 Dec 23 12:51 main.go
-rw-rw-r-- 1 murata murata    0 Dec 23 12:52 skaffold.dev.yaml
-rw-rw-r-- 1 murata murata    0 Dec 23 12:52 skaffold.prod.yaml
-rw-rw-r-- 1 murata murata    0 Dec 23 12:52 skaffold.feature.yaml
```

Dockerfileは普通に作るだけ。k8sファイルもいつも通り作るだけ。
skaffold.dev.yamlではDockerfileとk8sファイルの場所を指定してあげる。Dockerのリポジトリがサーバと同居しているのであればlocal.pushはfalseでおｋ。その辺のオプションは公式を参照してください。


```:skaffold.dev.yaml
apiVersion: skaffold/v1
kind: Config
build:
  artifacts:
  - image: dev/xxxxx.dev
    context: ./
    docker:
      dockerfile: ./Dockerfile.dev
  local:
    push: false
    useBuildkit: true
deploy:
  kubectl:
    manifests:
    - ./k8s.dev.yaml
```



# コマンド

`skaffold run -f ./skaffold.dev.yaml` するだけでkubectl apply までやってくれちゃう優れもの。

skaffold runで1回だけビルド、--tailを付けるとログの出力がされます。(kubectl logsがそのまま出てくる)

skaffold devで実行するとファイルに変更があった場合にビルドしなおしてくれます。

```
murata:~/workspace/tmp/ttt/back $ skaffold run -f ./skaffold.dev.yaml --tail
Generating tags...
 - dev/ttt -> WARN[0000] Unable to find git commit: Running [git describe --tags --always]
 - stdout:
 - stderr: fatal: not a git repository (or any parent up to mount point /)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
: exit status 128
dev/ttt:dirty
Checking cache...
 - dev/ttt: Not found. Building
Building [dev/ttt]...
[+] Building 6.6s (10/10) FINISHED
 => [internal] load build definition from Dockerfile.dev                                                
 => => transferring dockerfile: 181B                                                                    
 => [internal] load .dockerignore                                                                       
 => => transferring context: 2B                                                                         
 => [internal] load metadata for docker.io/library/golang:1.13.4                                        
 => CACHED [1/5] FROM docker.io/library/golang:1.13.4                                                   
 => [internal] load build context                                                                       
 => => transferring context: 550B                                                                       
 => [2/5] WORKDIR /app                                                                                  
 => [3/5] ADD . /app                                                                                    
 => [4/5] RUN go mod download                                                                           
 => [5/5] RUN go build                                                                                  
 => exporting to image                                                                                  
 => => exporting layers                                                                                 
 => => writing image sha256:6a87aa5a540a1910371f352abfbd4efa0045df9d34032fa183e75397b5e7e185            
 => => naming to docker.io/dev/ttt:dirty                                                                
Tags used in deployment:
 - dev/ttt -> dev/ttt:6a87aa5a540a1910371f352abfbd4efa0045df9d34032fa183e75397b5e7e185
   local images can't be referenced by digest. They are tagged and referenced by a unique ID instead
Starting deploy...
 - deployment.apps/ttt created
 - service/ttt created

```

手元でがりがり開発している場合には、VolumeMountしてskaffold runのほうが早いです。(DockerのBuildがされないので)


こいつは本番やステージング環境でも使えるので手プロイしている人にとってはオペミスも減るのでとってもよろしいかと思います。