Kubernetesでの開発を楽にするskaffoldを使ってみる

Kubernetesを開発環境で使っていると、 コードを修正して確認する度に、imageを作り直し、Kubernetesへデプロイしなければならないため、開発効率がよくありません。 hostPathをマウントする方法で解決できますが、Kubernetesでは、マウントパスを絶対パスで記述しなければならないため、manifestを共有しチームで開発しようとすると、各々の環境に合わせてパスを設定し直さなければなりません。

上記のような問題を解決するツールである skaffold というのを見つけたので試してみます。

どういったものか

  • ファイルの変更を検知して、イメージのビルド・プッシュ・デプロイを自動で行ってくれる
  • Google製(GoogleContainerTools)
  • Kubernetesサーバ側に何か設定する必要はない

参考

検証環境

環境は以下です。

  • PC: Ubuntu18.04
  • Kubernetes環境: minikube(virtualbox
  • 管理コマンド: kubectl
  • アプリケーション: 標準的なrailsアプリ

事前準備

skaffoldのインストール

以下の手順でインストールします。 https://skaffold.dev/docs/getting-started/

dockerの設定

minikubeのdockerを使います。

eval $(minikube docker-env)

設定する

skaffoldの設定ファイルである skaffold.yaml を設定します。 skaffold init というコマンドを実行すると、Kubernetesのmanifestを見て自動的に skaffold.yaml を生成してくれます。

apiVersion: skaffold/v1beta9
kind: Config
build:
  artifacts:
  - image: rails_app
deploy:
  kubectl:
    manifests:
    - rails-deployment.yaml
    - rails-service.yaml

ちなみに、manifest ファイルは以下のような感じです。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: rails
spec:
  replicas: 1
  template:
    metadata:
      labels:
        role: app
    spec:
      containers:
      - args:
        - bash
        - -c
        - bundle exec rake db:migrate && bundle exec rails s -b # 検証用なので、いちいちdb:migrateしています。
          0.0.0.0
        image: rails_app
        imagePullPolicy: Never # minikube上にimageができるのでpullする必要ありません。
        name: rails-app
        ports:
        - containerPort: 3000
        volumeMounts:
        - mountPath: /usr/local/bundle
          name: bundle
      volumes:
      - hostPath:
          path: /tmp/bundle
        name: bundle
apiVersion: v1
kind: Service
metadata:
  name: rails-app
spec:
  ports:
  - name: "3000"
    port: 3000
    targetPort: 3000
    nodePort: 30080
  selector:
    role: app
  type: NodePort

実行する

  • skaffold dev で実行する

フォアグラウンドで待ち受けられます。

-v debug で詳細に何をやっているのかが見られるので、気になる方はこちらのオプションをつけてみても良さそうです。

  • ファイルの変更をする

適当にファイルを編集して保存すると、ビルド、デプロイが実行されました! (ブラウザで確認し、ちゃんと反映されていることも確認)

Generating tags...
 - rails_app -> rails_app:3ec4d44-dirty
Tags generated in 26.202452ms
Starting build...
Found [minikube] context, using local docker daemon.
Building [rails_app]...
Sending build context to Docker daemon  40.27MB
・・・

podも新しくなっている様子

kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
rails-7b7c8bc85b-95ljp   1/1     Running   0          21s

この方法であれば、ビルド・デプロイの手間が省けるので、不自由なく開発ができそうです!

どういう仕組みなのか?

どうやら、Dockerfileの COPY(もしかしたらADDも) の内容からどのファイルをウォッチするかを判断しているようで、 DockerfileまたはCOPYしている範囲に変更があれば、ビルド->タグ付け->デプロイを自動で行ってくれるようです。

注意点

注意点としては、Dockerfileのキャッシュを上手く利用する書き方をしていないと、ビルドする度に時間がかかってしまいます。 ソースをコピーする記述はなるべく下のほうに書いておくと良さそうです。 また、DockerfileのCOPYは、ディレクトリをさかのぼる記述は書けないので、ウォッチしたいファイルがちゃんとCOPYできるようファイル構成を考える必要があります。

以上、今日のところはこんな感じです。