おひとり

できる限りひとりで楽しむための情報やプログラミング情報など。

【Kubernetes】SkaffoldとHelmを使った開発環境の構築

この記事ではKubernetesな環境を想定してSkaffoldとHelmで開発環境を構築する方法を解説します。
もっとも、この記事でお伝えする方法が「最善」かと言われるとかなり怪しいですが、一応ある程度実用的な開発環境を考えました。

この記事を読むことで、ローカルに以下の要件を満たす開発環境を構築できます。

  • ソースコードを変更したら自動でDockerfileに記載した内容でコンテナをビルド(ホットリロード)
  • ソースコードを変更し、ビルドが完了したらそれをKubernetesクラスタにデプロイ(Helm利用)
  • docker composeのように、関連するサービスをコマンド1つで起動してすぐに開発をスタートできる。

後で見ますが、これらはSkaffoldが実現します。

背景

開発中のWebサービスをKubernetesに移行するにあたり、開発環境をどうするかが問題となりました。
現状、ローカルでの開発はdocker composeを利用していますが、本番環境をKubernetesに移行するにあたり、ローカルの開発環境もそれに合わせる方向で考えました。

そこで、今回は以下のツールを使ってローカルの開発環境を整備します。

  • Kubernetes
  • minikube
  • Helm
  • Skaffold

なお、この記事のソースコードは以下にあります。

https://github.com/SRsawaguchi/kubernetes-hanson

こちらのリポジトリのREADME.mdからより詳細な手順に飛べます。

前提

kubectl, minikubeの環境が整っていること。
追加で、以下のソフトウェアをインストールします。

Helm

helm.sh

Skaffold

skaffold.dev

プロジェクトの構造

今回はシンプルなWebサービスを前提とします。
APIサーバがHTTP通信を受け付け、Backendサーバに処理を依頼、処理結果をクライアントに返すというシンプルなものです。
今回のサンプルプロジェクトは以下のようになっています。
※各ファイルの中身はリポジトリを参照してください。

.
├── api
├── backend
├── chart

apiにはAPIサーバのソースコード(Go)が、backendにはバックエンドサーバのソースコード(Go)が入っています。
※今回はBackendサーバについては触れません。

chartディレクトリにはHelmチャートが入っています。
※Helmチャートの作成手順や中身について詳しく知りたい方は、こちらの2. Helm3. Helmハンズオンをご覧ください。

そして、apiディレクトリには以下のコンテンツが入っています。

.
├── Dockerfile
├── Makefile
├── go.mod
├── main.go
└── skaffold.yaml

重要なファイルのみ取り上げます。

  • DockerfileはこのAPIサーバのイメージを生成するDockerfileです。
  • main.goのソースコード変更すると、このDockerfileを元にイメージをビルドするようにします。
  • skaffold.yamlはSkaffoldの設定ファイルです。

後ほど見ていきます。

HelmチャートをSkaffoldに対応させる

Skaffoldはソースコードを監視し、変更を検出したらDockerfileを元にイメージを再生成し、自動でHelmにデプロイしてくれます。
デプロイのため、新しく作成したイメージにはタグを自動で付与します。
そのため、HelmチャートのKubetetesリソースのテンプレートにおいて、イメージの指定を変数化(variables.yamlに外だし)する必要があります。

今回のプロジェクトで関連するファイルを見てみましょう。

./chart/templates/api-deploy.yaml

https://github.com/SRsawaguchi/kubernetes-hanson/blob/main/chart/templates/api-deploy.yaml

省略...
    spec:
      containers:
      - image: {{ .Values.images.api }}. <--------イメージの指定を変数化
        imagePullPolicy: {{ .Values.imageConfig.pullPolicy }}
        name: msvcapi
省略...

そして、values.yamlでは以下のように記述しています。

https://github.com/SRsawaguchi/kubernetes-hanson/blob/main/chart/values.yaml

images:
  api: msvcapi:1.0.0
  backend: msvcbackend:0.0.1

Skaffoldでは、helm installする際に--setで値を指定するのと同じく、デプロイのたびにこれらの変数を介して新しいイメージの情報をtemplates/配下のファイルに反映させます。

続いて、Skaffoldの設定ファイルskaffold.yamlを作成しましょう。

skaffold.yamlを準備

続いてskaffold.yamlを準備していきましょう。
今回はapiディレクトリの中に作成します。(アプリと同じディレクトリに作成します。)

./api/skaffold.yaml

https://github.com/SRsawaguchi/kubernetes-hanson/blob/main/api/skaffold.yaml

apiVersion: skaffold/v2beta16
kind: Config
metadata:
  name: hanson-api-skaffold
build:
  artifacts:
  - image: skaffold-api
    docker:
      dockerfile: Dockerfile
deploy:
  helm:
    releases:
      - name: hanson
        chartPath: ../chart
        setValues:
          api:
            message: "This is a message from skaffold!!"
          imageConfig:
            pullPolicy: IfNotPresent
        artifactOverrides:
          images.api: skaffold-api
        recreatePods: false
        skipBuildDependencies: false
        useHelmSecrets: false
        wait: false

この中で重要なのはartifactOverridesです。

        artifactOverrides:
          images.api: skaffold-api

artifactOverridesは、Skaffoldが作成したイメージの情報をhelmに渡すために使います。
もう一度先ほどのvalues.yamlを見てみましょう。

images:
  api: msvcapi:1.0.0
  backend: msvcbackend:0.0.1

ご覧の通り、今回のvalues.yamlでは、images.apiでAPIサーバ向けのイメージを指定しています。
そのため、artifactOverridesでは、images.apiの値をoverrideするように設定します。

f:id:hitoridehitode:20210619161527p:plain
適切にimageの指定を置き換えられるように設定する

なお、skaffold.yamlでは、環境変数などの開発用のパラメータを与える便利な機能があります。
一例は。。。

  • setValues: helm install--setと同じ要領で定義した値を渡す
  • setValueTemplates: ホストの開発変数の値を--setと同じ容量で渡す

全ての設定項目はこちらにまとまっています。

skaffold.dev

実行

これで必要な設定は全て完了です。
早速実行してみましょう。

cd api
skaffold dev

この状態で./api/main.goを書き換えると、イメージが再生成され、そのままデプロイされます。

このような環境を構築することで、複数のサービスで構成されるアプリであっても、docker compose upと同じように一度に全て立ち上げ、コードを書いて結果をチェックするlことができます。

まとめ

今回はSkaffoldとHelmをつかって、ローカルの開発環境を整えました。
Skaffoldはkubectlを使ったデプロイが最もお手軽ですが、複数のサービスにより動作しているアプリの場合はやや手間です。
そこでSkaffoldのデプロイ先をHelmにすることで、docker composeと同じようにコマンド一つで手軽に開発をはじめられ、終わったらまるごとuninstallできます。

効率的な開発環境は生産性向上に欠かせませんね!!

参考リンク

f:id:hitoridehitode:20210619153558p:plain:w250