Posted at

Kubernetesでのローカルの開発をskaffoldで加速させる


前提とゴール


  • k8sでのデプロイはなんとなくわかる

    DeploymentとServiceのyaml用意して、kubectl applyすればいいんでしょ?くらい

  • しかし、k8sでのローカルってどうしたらいいか、なにもわからない


    • localのvolumeを、k8sでmountしてアプリを参照するの?

      これは一見シンプルに見えて、アプリビルド後に、podの再起動(=再適用)が必要になる


    • docker imageはproductionに(近い)registryに置けばいいの?

      いいけど、GCRとかに、いちいちpushしてpullするのはなんか無駄っぽい


    • docker imageはlocalでdocker buildしたimageを使えばいいの?

      これでいきます




  • localと各環境(production, ...)のyamlって絶対差分あるじゃん

    今回はkustomizeを使って解消しています

    kustomizeについてのサンプルはこちら

    Kubernetes+kustomizeでmasterをスマートにさっとデプロイする

    今回は利用しませんが、skaffoldはHelmにも対応しています


  • productionはskaffoldなしでデプロイまでできてるから、skaffoldいらないんだけど?

    これは自分が最初勘違いしていた話ですが、 全てをskaffoldに置き換える必要はありません

    ローカルの開発 だけ skaffoldを使います



skaffoldについて

ざっくり言うと、ファイルを監視して、変更があったらdocker buildして、kubectl applyまでやってくれるツールです、超快適です

ローカル専用ではないです が、今回はローカル専用として使います

細かくは公式を読みましょう

https://skaffold.dev/docs/

https://github.com/GoogleContainerTools/skaffold


skaffoldの準備


1. skaffoldコマンドをインストール

macであれば brew install skaffold


2. skaffold.yamlを書く

公式でサンプルコードをいくつも用意してくれています

https://github.com/GoogleContainerTools/skaffold/tree/master/examples

getting startやれば雰囲気は掴めます

https://skaffold.dev/docs/getting-started/

一番大切なのはskaffold.yamlのリファレンスで、これを確認しながら書くことになります

https://skaffold.dev/docs/references/yaml/


実際のディレクトリ構成

repository

├── ops
│   ├── app
│   │   ├── Dockerfile
│   │   └── app.jar
│   └── k8s
│     ├── base
│     │   ├── deployment.yaml
│     │   └── kustomization.yaml
│     ├── manifest
│     │   ├── local-k8s.yaml
│     │   └── prd-k8s.yaml
│     └── overlays
│     ├── local
│     │   ├── build.sh
│     │   └── kustomization.yaml
│     └── production
│     ├── build.sh
│     ├── deployment.yaml
│     └── kustomization.yaml
├── いろいろ
└── skaffold.yaml

kustomizeまわりの詳細についてはこちら

Kubernetes+kustomizeでmasterをスマートにさっとデプロイする

大切な要素は3つです


  • /skaffold.yaml

    skaffoldが参照するファイル


  • /ops/app/

    変更の監視をするフォルダ

    Dockerfileと、アプリのビルド後のファイルを配置している


  • /ops/k8s/overlays/local/

    kustomizeにて、ローカル環境の元になる設定



/skaffold.yaml

build.artifacts.contextで監視するフォルダを指定

useBuildkitはdockerのBuildKitという、buildが早くなる機能の有効可

docker v18.09以上で設定可


skaffold.yaml

apiVersion: skaffold/v1beta12

kind: Config
build:
artifacts:
- image: app-image-local
context: ops/app/
tagPolicy:
dateTime:
format: "20060102_150405"
timezone: "Local"
local:
useBuildkit: true
deploy:
kustomize:
path: ops/k8s/overlays/local


/ops/k8s/overlays/local/


kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1

kind: Kustomization
resources:
- ../../base
images:
- name: app-image
newName: app-image-local

../../base のファイル


base/deployment.yaml

---

apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-name
spec:
replicas: 1
template:
spec:
containers:
- name: container-name
image: app-image:latest


base/kustomization.yaml

commonLabels:

app: app-label
resources:
- deployment.yaml


(2019/07) skaffold v0.33.0 依存っぽい話

よくあるcontainersの設定である、

imagePullPolicy: Always は、ローカル環境ではあえて外しています

Alwaysつけると、下記のエラーが出るため

pull access denied for app-image-local, repository does not exist or may require 'docker login'

Back-off pulling image "app-image-local:hash"

また、skaffoldをググるとよく出てくる、ローカルのレジストリを参照するため、

docker imageにlocalhostつけて localhost:5000/hoge:fuga にする手順は不要でした

公式のリファレンスを探しましたが、localhostつける元ネタわからず、、


リポジトリ内にあるサンプルコードは、ソースファイルをDockerfileでコピーしてマルチステージビルドしてる件

元々ローカルでアプリをビルド後、Dockerfileでコピーする構成にしていたので、

どうすればいいのか悩んだポイントでしたが、

反映したいタイミングで自分でビルドし、 /ops/app に配置すれば、

再起動までskaffoldがやってくれるので、これはこれでいいかなという感じです


実行手順

個人的にMakefileでまとめています

make run-skaffold でskaffoldの実行しますが、監視しづづけているので、このコンソールはそのままにします

Ctrl+C で終了できますが、k8sも綺麗にしてくれます!

しかし docker images はいろいろ残ります、、

別のコンソールで make jar をすると、 /ops/app/app.jar が更新され、skaffoldが勝手に再起動します

Makefileのhelpについてはこちらから

Makefileを自己文書化する | POSTD


/Makefile

.PHONY: help

help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

jar: ## sbt assembly
sbt update clean scalafmt test assembly

run-sbt: ## sbt run
sbt update clean run

run-skaffold: ## run jar with skaffold (watch jar)
skaffold dev