LoginSignup
8
3

More than 5 years have passed since last update.

kubernetesのホットリロード開発環境をvolumeMountsでシンプルに実現

Posted at

経緯

kubernetesのローカル開発環境といえば、skaffoldを使うのがポピュラーなのかと思います。まあ、あんまり他所の事情は知りませんが・・・
しかし、個人的にskaffold devを使うのってあんまり好きじゃないんですよね・・・例えば以下のような理由です。

  • 毎回build・Pod再起動するの時間がかかる
    • GoとかのImageならマシだが、Railsとかだと遅さが目立つ
  • DockerImageがどんどん増える
    • 自分はDocker for Mac使ってるので、ローカルのDocker環境が汚染されるのもイヤ
    • 当然容量も圧迫する。特にRailsとかだと顕著。

DockerImage増える問題に関しては、kanikoを利用すれば問題にならないかもしれませんが、build・再起動に時間かかる問題に関してはどうしようもありません。それに落ち着いて考えると、コード変更が入るたびにdocker buildするのってどうなのって感じですし・・・

代替法の検討

TelepresenceとかのOSSを利用することも考えましたが、今回はよりシンプルな方法を自作しました。

方法として、特に捻りも何もないですが単にローカルマシンのディレクトリをPodにVolumeMountするだけです。

前提環境

  • Goが使える環境
  • k8sに対応したDocker for Mac

今回使用するサンプル

今回は例として、Goの簡単なサーバーをサンプルとして用意しました。

main.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello k8s")
    })
    log.Fatal(http.ListenAndServe(":8080", nil))
}

これをGoが動く適当なディレクトリにmain.goというファイル名で置きます。
以降は、main.goを配置したディレクトリのパスを、PATHと表記します。

Docker for Macの設定

Docker for Macのkubernetesで、先ほどのディレクトリを共有できるように設定します。Preferences -> File Sharingから、先ほど配置したPATHを入力します。

スクリーンショット 2019-04-26 16.13.36.png

Dockerfileの作成

以下のDockerfileを作成し、PATHに配置します。

FROM golang:1.11-alpine as goapp
ENV APP_ROOT /go/src/app
WORKDIR $APP_ROOT
ADD main.go $APP_ROOT

CMD ["go", "run", "main.go"]

golangのDockerImageを作成する際は、マルチステージビルドを使って最終的に出来上がったバイナリだけを軽量なBaseImageに載せるみたいな工夫をすると思いますが、今回はあえてgo runを使います。

とりあえずbuildも済ませておきます。

docker build -t echo:v0.1 .

マニフェストファイルの作成

先ほどのDockerfileで作成したイメージを、deploymentリソースとしてデプロイします。
以下がdeploymentのマニフェストファイルになります。

deployment.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: echo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo
  template:
    spec:
      containers:
        - name: echo
          image: echo:v0.1
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: echo-volume
              mountPath: /go/src/app
      volumes:
        - name: echo-volume
          hostPath:
            path: PATH

先ほどDocker for MacでFile Sharingに登録したPATHをvolumsのhostPathに記述します。これでPATHのディレクトリと、Pod内の/go/src/appディレクトリが共有されます。

deploymentの定義はこれでOKなので、k8sクラスタにデプロイします。

kubectl apply -f deployment.yaml

ついでに、動作検証用のloadbalancerリソースも作成しておきます。

service.yaml
apiVersion: v1
kind: Service
metadata:
  name: echo-svc
spec:
  type: LoadBalancer
  selector:
    app: echo
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP

デプロイします

kubectl apply -f service.yaml

これでlocalhost:8080にアクセスすると、以下のように表示されます。

スクリーンショット 2019-04-26 16.31.05.png

ファイルを更新してみる

それでは、ファイルを更新してみます。main.goの11行目で"Hello k8s"としている部分を、"Updated hello k8s"に書き換えます。

fmt.Fprintf(w, "Updated hello k8s")

これで、Pod内のファイルも書き換わります。Rails等のアプリケーションならこれだけでもOKなのですが、今回はGoなのでコンパイルし直す必要があります。Dockerfileのentrypointをgo run main.goにしてあるので、Podを再起動すればOKです。再起動させるにはkubectlでPodを削除するのが手っ取り早いですが、毎回するのはしんどいので、このページの方法を参考にしてmakefileを作りました。

reload:
    @kubectl patch deployment echo -p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"reloaded-at\":\"`date +'%Y%m%d%H%M%S'`\"}}}}}"

echodeploymentのannotationsを書き換えて無理やりRollingUpdateさせる感じですね。以下のコマンドで再起動できるようになりました。

make reload

変更を監視して自動でリロードする

せっかくなのでファイル変更が入ったら自動でリロードできるようにしてみます。

今回、変更の監視にはCompileDaemonを利用しました。

go get github.com/githubnemo/CompileDaemon
go install github.com/githubnemo/CompileDaemon

先ほどのmakefileを書き換えます。

hot_reload:
    CompileDaemon -command="$(MAKE) reload"
reload:
    kubectl patch deployment echo -p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"reloaded-at\":\"`date +'%Y%m%d%H%M%S'`\"}}}}}"

以下のコマンドで、ファイル変更があった際には自動でreloadが実行されるようになりました。

make hot_reload

まとめ

今回はGoをアプリケーションを扱ったのでリロードの仕組みも作りましたが、Rails等のアプリケーションなら頻繁なリロードも必要ないのでもっと簡単ですね。
skaffoldを使う場合と比較して、良い点・悪い点いずれもあるかと思います。

良い点

  • 反映が早い。特にImageが大きいほど有利。
  • Docker Imageが毎回増えない

悪い点

  • 開発環境用のマニフェストファイルが本番用と乖離しやすい
  • 管理したいリソースが増えると、makefile等の自作設定ファイルの管理が必要

次はTelepresenceも試してみたいと思います。

8
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3