Cloud Native Online #01に登壇した際のスライドもご覧ください。
Skaffoldとは
Skaffoldは継続的なKubernetesアプリケーション開発
を促進するツールで、
ソースコードの変更をトリガとして以下を自動で行ってくれることで、我々開発者はアプリケーションの開発に注力できるようになります。
- コンテナイメージのビルド
- コンテナレジストリへのpush
- k8sクラスタへのデプロイ
-
kubectl
の他、helm
やkustomize
も記述できる
-
画像はskaffold.dev/docsより引用
ソースコードの変更をトリガとしてk8sクラスタにデプロイされるまでの流れが示されています。
Forerver(Node)
やRails
やDjango
がソースコードの変更を検出してサーバを再起動する機能のKubernetes版と考えて良さそうです。
本エントリにはSkaffoldのGetting StartedをMinikubeで実施する場合に必要となる手順を記載します。
環境
Ubuntu 17.10
でMinikube v1.0.0
を使用しています。
$ uname -a
Linux mina 4.13.0-46-generic #51-Ubuntu SMP Tue Jun 12 12:36:29 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=17.10
DISTRIB_CODENAME=artful
DISTRIB_DESCRIPTION="Ubuntu 17.10"
$ minikube version
minikube version: v1.0.0
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.0", GitCommit:"641856db18352033a0d96dbc99153fa3b27298e5", GitTreeState:"clean", BuildDate:"2019-03-25T15:53:57Z", GoVersion:"go1.12.1", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.0", GitCommit:"641856db18352033a0d96dbc99153fa3b27298e5", GitTreeState:"clean", BuildDate:"2019-03-25T15:45:25Z", GoVersion:"go1.12.1", Compiler:"gc", Platform:"linux/amd64"}
$
Minikubeの準備
MinikubeとSkaffoldを組み合わせて使用する場合、留意事項があります。
Skaffoldは、k8sクラスタがMinikubeであると認識した場合、
docker build
は行いますが、docker push
は行いません。
これは、docker build
コマンドが、MinikubeのVM内でのdocker build
となるよう設定されていることが前提となっていると考えられます。
これには、minikubeのdocker-env
コマンドを活用できます。
このコマンドは以下のように、ローカルのdockerコマンドをMinikubeのVM内のdockerに接続するための環境変数設定を表示してくれます。
$ minikube docker-env
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/home/loft/.minikube/certs"
export DOCKER_API_VERSION="1.35"
# Run this command to configure your shell:
# eval $(minikube docker-env)
$
以下のようにevalで実行すると環境変数が設定されます。
$ eval $(minikube docker-env)
以降、dockerコマンドはMinikubeのVM内のdockerに対する操作になることに留意する必要はありますが、
この機構によりコンテナイメージをわざわざレジストリにpushしなくても
minikubeにアプリケーションをデプロイできるので素早い開発サイクルを回せるメリットがあります。
これを行なっていない場合、dockerイメージはMinikubeのVMの外のローカルでビルドされるため、当然PodのStatusはImagePullBackOff
となります。
Skaffoldのインストール
例) Linuxの場合
$ curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
$ chmod +x skaffold
$ sudo mv skaffold /usr/local/bin
Skaffold サンプルの入手
リポジトリをcloneし、examples/getting-started
ディレクトリに移動しましょう。
構成物については後述します。
$ git clone https://github.com/GoogleContainerTools/skaffold
$ cd examples/getting-started
$ ls -Fla
total 28
drwxrwxr-x 2 loft loft 4096 5月 7 21:00 ./
drwxrwxr-x 19 loft loft 4096 5月 7 21:00 ../
-rw-rw-r-- 1 loft loft 144 5月 7 21:00 Dockerfile
-rw-rw-r-- 1 loft loft 153 5月 7 21:00 k8s-pod.yaml
-rw-rw-r-- 1 loft loft 131 5月 7 21:00 main.go
-rw-rw-r-- 1 loft loft 734 5月 7 21:00 README.adoc
-rw-rw-r-- 1 loft loft 158 5月 7 21:00 skaffold.yaml
$
動作確認
ターミナルを2つ(terminal-1
とterminal-2
)用意し、以下を実行します。
terminal-1
skaffold dev
コマンドを実行します。
以下が行われる様子を確認できます。
- docker build ( MinikubeのVM内でbuild )
- docker push ( Minikubeの場合は行わない )
-
Found [minikube] context, using local docker daemon.
より、Minikubeを認識していることが分かる
-
- kubectl apply
- 標準出力ログの表示
- ソースコードの変更の監視
$ skaffold dev
Generating tags...
- gcr.io/k8s-skaffold/skaffold-example -> gcr.io/k8s-skaffold/skaffold-example:v0.28.0-89-gf25b09fa-dirty
Tags generated in 7.774075ms
Starting build...
Found [minikube] context, using local docker daemon.
Building [gcr.io/k8s-skaffold/skaffold-example]...
Sending build context to Docker daemon 3.072kB
Step 1/6 : FROM golang:1.10.1-alpine3.7 as builder
---> 52d894fca6d4
Step 2/6 : COPY main.go .
---> Using cache
---> 04e5f4a5d5e2
Step 3/6 : RUN go build -o /app main.go
---> Using cache
---> eb45bd0c0ce1
Step 4/6 : FROM alpine:3.7
---> 6d1ef012b567
Step 5/6 : CMD ["./app"]
---> Using cache
---> da76805ab2e2
Step 6/6 : COPY --from=builder /app .
---> Using cache
---> 9c5ffabae1d9
Successfully built 9c5ffabae1d9
Successfully tagged gcr.io/k8s-skaffold/skaffold-example:v0.28.0-89-gf25b09fa-dirty
Build complete in 72.162899ms
Starting test...
Test complete in 5.744µs
Starting deploy...
kubectl client version: 1.14
pod/getting-started created
Deploy complete in 301.514962ms
Watching for changes every 1s...
[getting-started] Hello world!
[getting-started] Hello world!
[getting-started] Hello world!
( 略 : )
terminal-2
アプリケーションのソースコードを書き換えてみましょう。
# 書き換え前
$ cat main.go
( 略 : )
fmt.Println("Hello world!")
( 略 : )
# 書き換え
$ vim main.go
# 書き換え後
$ cat main.go
( 略 : )
fmt.Println("Hello skaffold!")
( 略 : )
terminal-1
再びterminal-1
を確認してみると、ソースコードの変更をトリガとして以下が行われる様子を確認できます。
- docker build ( MinikubeのVM内でbuild )
- docker push ( Minikubeの場合は行わない )
- kubectl apply
- 標準出力ログの表示
- ソースコードの変更の監視
手作業でイメージをビルドし、レジストリにpushし、クラスタにデプロイする手間が省かれていますね。
( 略 : )
[getting-started] Hello world!
[getting-started] Hello world!
[getting-started] Hello world!
Generating tags...
- gcr.io/k8s-skaffold/skaffold-example -> gcr.io/k8s-skaffold/skaffold-example:v0.28.0-89-gf25b09fa-dirty
Tags generated in 21.094584ms
Starting build...
Found [minikube] context, using local docker daemon.
Building [gcr.io/k8s-skaffold/skaffold-example]...
Sending build context to Docker daemon 3.072kB
Step 1/6 : FROM golang:1.10.1-alpine3.7 as builder
---> 52d894fca6d4
Step 2/6 : COPY main.go .
---> 4a61f315455a
Step 3/6 : RUN go build -o /app main.go
---> Running in 30ee9d0e606f
Removing intermediate container 30ee9d0e606f
---> 6a9d5e79631a
Step 4/6 : FROM alpine:3.7
---> 6d1ef012b567
Step 5/6 : CMD ["./app"]
---> Using cache
---> da76805ab2e2
Step 6/6 : COPY --from=builder /app .
---> 16dbf70b67d6
Successfully built 16dbf70b67d6
Successfully tagged gcr.io/k8s-skaffold/skaffold-example:v0.28.0-89-gf25b09fa-dirty
Build complete in 1.75830858s
Starting test...
Test complete in 11.741µs
Starting deploy...
kubectl client version: 1.14
pod/getting-started configured
Deploy complete in 296.352796ms
Watching for changes every 1s...
[getting-started] Hello skaffold!
[getting-started] Hello skaffold!
( 略 : )
構成物の確認
main.go
アプリケーションのソースコード。
1sec毎に標準出力にHello world!
を表示する。
$ cat main.go
package main
import (
"fmt"
"time"
)
func main() {
for {
fmt.Println("Hello world!")
time.Sleep(time.Second * 1)
}
}
Dockerfile
main.goをビルドしコンテナ起動時のコマンドとしている。
$ cat Dockerfile
FROM golang:1.10.1-alpine3.7 as builder
COPY main.go .
RUN go build -o /app main.go
FROM alpine:3.7
CMD ["./app"]
COPY --from=builder /app .
$
k8s-pod.yaml
gcr.io/k8s-skaffold/skaffold-example
というイメージを使用するPodの定義。
$ cat k8s-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: getting-started
spec:
containers:
- name: getting-started
image: gcr.io/k8s-skaffold/skaffold-example
$
skaffold.yaml
Skaffoldの設定ファイル。
-
build
設定- ビルドするイメージ名として
gcr.io/k8s-skaffold/skaffold-example
を指定している
- ビルドするイメージ名として
-
deploy
設定-
kubectl
コマンドを使用している-
k8s-
で始まるマニフェストファイル(yaml)を指定している
-
-
$ cat skaffold.yaml
apiVersion: skaffold/v1beta9
kind: Config
build:
artifacts:
- image: gcr.io/k8s-skaffold/skaffold-example
deploy:
kubectl:
manifests:
- k8s-*
$
まとめ
いかがでしたか?
Skaffoldを使うと、クラスタにデプロイされるまでのルーチンが自動化されるので効率良く開発できそうですね。
特にMinikubeを開発環境として使用している場合は恩恵が大きそうです。
今回はSkaffoldのさわりであるGetting Startedを試してみましたが、Tutorialsも用意されています。
本記事がSkaffold導入の参考になりましたら幸いです。