概要
今まではスクリプトにk8sのデプロイ処理を書いていましたが、Skaffoldが発表されたのでDraftと一緒に試してみます!

環境
- Skaffold: v0.3.x
- Draft: v0.12.x
- Helm: v2.8.x
- Kubernetes(以後k8s): v1.9.x
- DockerRegistry: Google Container Registry(以後GCR)
ソースコード
前提
- helmを使う
- 必須ではないため、適宜
kubectl applyなどに読み替えてください
- 必須ではないため、適宜
- k8sのセットアップが完了している
- asia.gcr.ioへのログイン(認証)が完了している
検証してみる内容
実際の運用環境に近い内容で検証していきます。
想定環境
- デプロイ先の環境は
localを含め、stageの2種類- 実際は
prodなどの環境もあると思うので、増えても対応が可能な設定にする
- 実際は
- 全ての環境は別々のClusterとなる
- Namespaceで環境を分ける場合はちょっとコマンドが変わりますが実現は可能
-
local環境はminikubeかDocker For (Windows|MAC)で構築- 記事中は
Docker For MACを使用
- 記事中は
-
stageはGKE(k8s)を使用 - サンプルアプリケーションはGolang
実現したいこと
- helmを利用したい(必須ではない)
-
localから未コミットのソースをコンパイルしてデプロイしたい - 複数のClusterにデプロイしたい
- 生成するDockerイメージのタグを指定をしたい
- プライベートなDocker Registryを使用したい
デプロイするソースコードの一部
全部入りソースはこちら
- サンプルアプリは
Hello worldを繰り返し表示します
package main
import (
"fmt"
"time"
)
func main() {
for {
fmt.Println("Hello world")
time.Sleep(time.Second * 1)
}
}
- Dockerファイルの内容はビルド環境と実行環境を兼ねています。
FROM golang:1.9.4-alpine3.7
WORKDIR /go/src
COPY main.go .
RUN go build -o app
CMD ["./app"]
- helmはよくある
DeploymentとServiceの設定です-
Draft用に同じような設定がcharts/appに配置されています
-
apiVersion: v1
name: foo-app
version: 0.1.0
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: foo-app
labels:
app: foo-app
spec:
replicas: {{ .Values.replicas }}
template:
metadata:
labels:
app: foo-app
spec:
containers:
- name: foo-app
image: {{ .Values.image }}
apiVersion: v1
kind: Service
metadata:
name: foo-app
labels:
app: foo-app
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: foo-app
selector:
app: foo-app
replicas: 1
image: asia.gcr.io/{gcp_project}/test/foo-app
local環境へのデプロイ
local環境へのデプロイを通じて基本的な操作を見ていきます。
どのツールも開発途中の状態(未コミット)でデプロイできますが、Gitコミットのハッシュ値を使用するのでGit管理されている必要があります。
スクリプト(Makefile)でデプロイ
まずはスクリプトだけでデプロイする方法を試します。
処理内容は以下です。
- Dockerファイルを元にコンテナイメージを作成
- helmを使ってコンテナイメージの差し替え(デプロイ)
# Const
# ===============================================================
gcp_project := {gcp_project}
image_repo := asia.gcr.io/$(gcp_project)/test/foo-app
tag := $(shell date +'%Y-%m-%dT%H%M%S')
# Task
# ===============================================================
plain-deploy: docker-build helm-apply
helm-apply:
helm upgrade --install \
--set image.tag=$(tag) \
foo-app charts/app
docker-build:
docker build -t $(image_repo):$(tag) .
docker tag $(image_repo):$(tag) $(image_repo):latest
-
local環境へデプロイ
$ make plain-deploy
Skaffoldでデプロイ
Skaffoldを使えば設定ファイルの設置だけでデプロイ可能です。
処理内容は以下です。
- Dockerファイルを元にコンテナイメージを作成
- helmを使ってコンテナイメージの差し替え(デプロイ)
apiVersion: skaffold/v1alpha2
kind: Config
build:
tagPolicy:
sha256: {}
artifacts:
- imageName: asia.gcr.io/{gcp_project}/test/foo-app
workspace: .
local: {}
deploy:
helm:
releases:
- name: skaffold-app
chartPath: helm
namespace: default
values:
image: asia.gcr.io/{gcp_project}/test/foo-app
-
local環境へデプロイ
$ skaffold run
Draftでデプロイ
Draftも設定ファイルの設置だけでデプロイ可能です。
処理内容は以下です。
- Dockerファイルを元にコンテナイメージを作成
- DockerRegistryへコンテナイメージをpush
- helmを使ってコンテナイメージの差し替え(デプロイ)
他のツールと違う点はDockerRegistryへのプッシュが強制されます。
local環境の場合、DockerRegistryへのプッシュは不要な作業となってしまいます。
コンテナイメージのサイズが大きいと、このデメリットは大きなストレスになりそうです。
draft createでも作成可能ですが、内容をシンプルにしたいため今回は手動で作成します。
[environments]
[environments.local]
name = "foo-app"
namespace = "default"
wait = false
watch = false
auto-connect = false
registry = "asia.gcr.io/{gcp_project}/test"
-
local環境へデプロイ-
environments.localをenvironments.developmentに変更すると-eオプションが不要になります。通常はenvironments.developmentを利用するほうが楽できます。
-
$ draft up -e local
複数環境の対応
次はGKEに構築されているstage環境にデプロイする方法を見ていきます。
GKEの場合、以下のコマンドでコンテキストファイルを作成できます。
$ gcloud container clusters get-credentials {cluster_name} --project {gcp_project} --zone {gcp_zone}
以後のコンテキストの切り替えは、以下のコマンドで実施します。
# コンテキストの一覧取得
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* docker-for-desktop docker-for-desktop-cluster docker-for-desktop
gke_{project-name}_{zone}_{cluster-name} gke_{project-name}_{zone}_{cluster-name} gke_{project-name}_{zone}_{cluster-name}
# `local`環境に切り替え
$ kubectl config use-context docker-for-desktop
# `stage`環境に切り替え
$ kubectl config use-context gke_{project-name}_{zone}_{cluster-name}
スクリプト(Makefile)
複数環境への対応は、helmオプションの--kube-contextを追加するだけで対応できます。
--- MakefileV1.mk 2018-04-09 18:41:24.000000000 +0900
+++ MakefileV2.mk 2018-04-09 18:40:50.000000000 +0900
@@ -1,9 +1,18 @@
+# Option
+#===============================================================
+ENV := local
+
# Const
#===============================================================
gcp_project := {gcp_project}
image_repo := asia.gcr.io/$(gcp_project)/test/foo-app
+context := docker-for-desktop
tag := $(shell date +'%Y-%m-%dT%H%M%S')
+ifeq ($(ENV),stage)
+ context := gke_{gcp_project}-{gcp_zone}_{custer_name}
+endif
+
# Task
#===============================================================
plain-deploy: docker-build docker-push helm-apply
@@ -11,6 +20,7 @@ plain-deploy: docker-build docker-push h
helm-apply:
helm upgrade --install \
--set image.tag=$(tag) \
+ --kube-context $(context) \
foo-app charts/app
docker-build:
以下コマンドでstage環境にデプロイできます。
$ make ENV=stage plain-deploy
環境ごとにパラメータを変えたいは場合、さらに以下のパッチを当てます。
--- MakefileV2.mk 2018-04-09 18:40:50.000000000 +0900
+++ MakefileV2-2.mk 2018-04-09 18:29:17.000000000 +0900
@@ -21,6 +21,7 @@ helm-apply:
helm upgrade --install \
--set image.tag=$(tag) \
--kube-context $(context) \
+ --values charts/app/env/$(ENV).yaml \
foo-app charts/app
docker-build:
以下コマンドで環境ごとの設定ファイルを作成します。
# 環境用に上書きファイルを追加
$ mkdir -p charts/app/env
# localは空ファイルで作成
$ touch charts/app/env/local.yaml
# stageではreplicasを2に変更
$ echo 'replicas: 2' >> charts/app/env/stage.yaml
以下コマンドでstage用パラメーターを使い、stage環境にデプロイできます。
$ make ENV=stage plain-deploy
Skaffold
残念ながらSkaffoldは、コンテキストの指定ができないのでスクリプトで対応する必要があります。
またkubectl config use-contextでコンテキストを切り替えると、その後の操作(session)も切り替わった状態になるので注意してください。
--- MakefileV2-2.mk 2018-04-09 18:29:17.000000000 +0900
+++ MakefileV3.mk 2018-04-09 18:30:22.000000000 +0900
@@ -15,6 +15,10 @@ endif
# Task
#===============================================================
+skaffold-deploy:
+ kubectl config use-context $(context)
+ skaffold run
+
plain-deploy: docker-build docker-push helm-apply
helm-apply:
以下コマンドでstage環境にデプロイできます。
$ make ENV=stage skaffold-deploy
環境ごとにパラメータを変えたい場合は、設定ファイルを複数用意する必要があります。
# local用にサフィクスを追加
$ mv skaffold.yaml skaffold-local.yaml
# workaround for skaffold
# 指定ありでもskaffold.yamlの空ファイルが必要
$ touch skaffold.yaml
# stage用の設定ファイルを作成
$ cat > skaffold-stage.yaml
apiVersion: skaffold/v1alpha2
kind: Config
build:
tagPolicy:
sha256: {}
artifacts:
- imageName: asia.gcr.io/{gcp_project}/test/foo-app
workspace: .
local: {}
deploy:
helm:
releases:
- name: foo-app
chartPath: helm
namespace: default
valuesFilePath: helm/env/stage.yaml
values:
image: asia.gcr.io/{gcp_project}/test/foo-app
# 環境用に上書きファイルを追加
$ mkdir -p helm/env
# localは空ファイルで作成
$ touch helm/env/local.yaml
# stageではreplicasを2に変更
$ echo 'replicas: 2' >> helm/env/stage.yaml
作成した設定ファイルを使用できるようにタスクも書き換えます。
--- MakefileV3.mk 2018-04-09 18:30:22.000000000 +0900
+++ MakefileV3-2.mk 2018-04-09 18:32:41.000000000 +0900
@@ -8,16 +8,18 @@
gcp_project := {gcp_project}
image_repo := asia.gcr.io/$(gcp_project)/test/foo-app
context := docker-for-desktop
tag := $(shell date +'%Y-%m-%dT%H%M%S')
+skaffold_yaml := skaffold-local.yaml
ifeq ($(ENV),stage)
context := gke_{gcp_project}_asia-northeast1-a_stage-cluster
+ skaffold_yaml := skaffold-stage.yaml
endif
# Task
#===============================================================
skaffold-deploy:
kubectl config use-context $(context)
- skaffold run
+ skaffold run -f $(skaffold_yaml)
plain-deploy: docker-build docker-push helm-apply
以下コマンドでstage用パラメーターを使い、stage環境にデプロイできます。
$ make ENV=stage skaffold-deploy
Draft
DraftはHelmと同じ開発元だけあって--kube-contextオプションを指定すればコンテキストの切り替えができます。
とはいえ、コンテキストの名前が長いので他のツールと同じくMakefileにタスクを作成します。
--- MakefileV3-2.mk 2018-04-09 18:32:41.000000000 +0900
+++ MakefileV4.mk 2018-04-09 18:35:56.000000000 +0900
@@ -17,6 +17,9 @@ endif
# Task
#===============================================================
+draft-deploy:
+ draft --kube-context $(context) up --environment $(ENV)
+
skaffold-deploy:
kubectl config use-context $(context)
skaffold run -f $(skaffold_yaml)
また環境ごとにパラメータを変えたい場合は、環境ごとの設定をdraft.tomlに追加します。
... // 追加
[environments.stage]
name = "foo-app"
namespace = "default"
wait = false
watch = false
auto-connect = false
registry = "asia.gcr.io/{gcp_project}/test"
set = ["replicas=2"]
以下コマンドでstageにデプロイできます。
$ make ENV=stage draft-deploy
タグの指定
CI/CDのパイプラインでは、Gitで発行したタグをDockerイメージのタグとして使用したいケースが多いと思います。
通常はhelmの設定ファイルや、各ツールの設定ファイルを書き換えれば実現できす。
ただしそれでは、パイプラインやワークフローが複雑になるので動的にコマンドラインから変更する方法を確認していきます。
スクリプト(Makefile)
タグの対応くらいはスクリプトでも複雑な処理は不要ですね。
--- MakefileV4.mk 2018-04-09 18:35:56.000000000 +0900
+++ MakefileV5.mk 2018-04-09 18:36:26.000000000 +0900
@@ -1,13 +1,13 @@
# Option
#===============================================================
ENV := local
+TAG :=
# Const
#===============================================================
gcp_project := {gcp_project}
image_repo := asia.gcr.io/$(gcp_project)/test/foo-app
context := docker-for-desktop
-tag := $(shell date +'%Y-%m-%dT%H%M%S')
skaffold_yaml := skaffold-local.yaml
ifeq ($(ENV),stage)
@@ -15,6 +15,12 @@ ifeq ($(ENV),stage)
skaffold_yaml := skaffold-stage.yaml
endif
+ifeq ($(TAG),)
+ tag := $(shell date +'%Y-%m-%dT%H%M%S')
+else
+ tag := $(TAG)
+endif
+
# Task
#===============================================================
draft-deploy:
以下コマンドでタグを指定してデプロイできます。
$ make ENV=stage TAG=0.3.0 plain-deploy
Skaffold
--tagオプションを使うことで実現できます。
--- MakefileV5.mk 2018-04-09 18:36:26.000000000 +0900
+++ MakefileV6.mk 2018-04-09 18:37:40.000000000 +0900
@@ -17,10 +17,14 @@ endif
ifeq ($(TAG),)
tag := $(shell date +'%Y-%m-%dT%H%M%S')
+ skaffold_option :=
else
tag := $(TAG)
+ skaffold_option := --tag $(tag)
endif
+
+
# Task
#===============================================================
draft-deploy:
@@ -28,7 +32,7 @@ draft-deploy:
skaffold-deploy:
kubectl config use-context $(context)
- skaffold run -f $(skaffold_yaml)
+ skaffold run -f $(skaffold_yaml) $(skaffold_option)
plain-deploy: docker-build docker-push helm-apply
以下コマンドでタグを指定してデプロイできます。
$ make ENV=stage TAG=0.3.0 skaffold-deploy
Draft
残念ながら対応していないようで、関連するIssueがありますが実装はされていないようです。
- Improve cycle time on Minikube by eliminating push step
draft upshould tag and release a ":latest" tag
Draftは開発時のツールとして使い、本番環境へのデプロイなどは別の方法を検討したほうが良いかもしれません。
Conclusion
SkaffoldとDraftを比べてみましたが、現状でも十分便利だと感じました。
ただSkaffoldはhelmのtemplate構成に制限があったりするので使用するにはWorkaroundな対応が必要です。
同様にDraftもまだstableではなく、experimentalな状態のため、(draftdの削除などの)大きな変更も入るでしょう。
それでも秘伝のスクリプトがないチームには検討の価値があると思います。
また、すでに秘伝のスクリプトがあるチームでは物足りなさがあると思うので、スクリプトと合わせて使う方法が良さそうです。
| スクリプト | Skaffold | Draft | |
|---|---|---|---|
| 導入の容易さ | × | ○ | ○ |
| デプロイ | ○ | ◎ | ◎ |
| 複数環境へのデプロイ | ◎ | △ | ◎ |
| 環境ごとのカスタムパラメータ | ○ | △ | ◎ |
| タグの指定 | ○ | ◎ | × |
また今回の記事にはないですが、keelも良い選択肢ですので、合わせて検討してみてください!
気が向いてたらこの記事にも追記します。