はじめに
こんにちは、Google Cloudでオブザーバビリティを担当しているものです。Cloud Operations suiteをよろしくおねがいします。(宣伝終わり)
この記事はGo Advent Calendar 2021 その1の22日目の記事です。昨日は @sago35tk さんの「ESP32 向けに TinyGo をセットアップする」でした。TinyGoのコアな情報を日本語で教えてくれるtakasagoさんには本当にいつも感謝しています。
さて、今日はGo製のアプリケーションをdockerlessでコンテナ化できるkoの紹介をします。koは本当にイチオシのツールで、みんなに使ってもらいたいのでぜひ使ってください。
DockerによるGo製アプリのコンテナ化
まず最もポピュラーと思われるDockerを用いた場合のGo製アプリケーションのコンテナ化の方法についておさらいします。Go製のアプリケーションで最もシンプルな構成の場合、go build
をして特定のパスに置いた後、アプリケーションが使うポートを EXPOSE
して、CMD
もしくは ENTRYPOINT
でそのパスを指定してあげる、というような形になります。
具体的には、次のような簡単なGoのアプリケーションがあった場合
package main import ( "log" "net/http" ) const port = "8888" func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, world!")) }) log.Println("starting server on :" + port) if err := http.ListenAndServe(":"+port, nil); err != nil { log.Fatalf("error running server: %v", err) } }
Dockerfileとして次のようなものを用意する、ということです。
FROM golang:1.17.5-bullseye as builder WORKDIR /dist RUN go build -o server FROM gcr.io/distroless/base-debian11 WORKDIR /app COPY --from=builder /dist/server /app/server EXPOSE 8888 CMD ["/app/server"]
koを使った場合
しかしながら、これだけのためにわざわざDockerをいれたいかと言われたら、自分は入れたくありません!そこでkoを使います。
本日二回目の埋め込みリンクです。koはGo製アプリケーション専用のDockerlessコンテナビルドツールなのですが、たとえば上のアプリケーションの場合は、go build
を叩くかのように、設定ファイル等用意する必要なく、この ko publish
コマンド一発でコンテナが作れます。
$ ko publish --local --base-import-paths . 2021/12/22 01:08:18 Using base gcr.io/distroless/static:nonroot for test 2021/12/22 01:08:19 Building test for linux/amd64 2021/12/22 01:08:20 Loading ko.local/test:4a9444968723e9d5d24d25b07aaaa504c9ea8a1921273a3753028e5e6d9f5dc9 2021/12/22 01:08:20 Loaded ko.local/test:4a9444968723e9d5d24d25b07aaaa504c9ea8a1921273a3753028e5e6d9f5dc9 2021/12/22 01:08:20 Adding tag latest 2021/12/22 01:08:20 Added tag latest ko.local/test:4a9444968723e9d5d24d25b07aaaa504c9ea8a1921273a3753028e5e6d9f5dc9
いろいろオプションが付いていますが、これは気にしないことにして、このコマンドによって ko.local/test
というイメージができました。これは go.mod
でモジュール名を test
にしているからです。また ko.local
はレジストリ名が自動でprefixになっているということです。( --local
オプションをつけたことによる。)
たとえば KO_DOCKER_REPO
という環境変数で gcr.io/foo/bar
を指定して、アプリケーションのモジュール名を github.com/xxx/yyy
とした場合には、コンテナイメージ名は gcr.io/foo/bar/github.com/xxx/yyy
としてくれる、ということです。
koのコマンドがGo製のアプリケーションをビルドした後、よしなにそれをコンテナ内に配置し、エントリーポイントの設定をしてくれ、設定したコンテナレジストリ向けの名前でイメージを作成してくれます。簡単ですね!
ko のインストール
さて、koは簡単そうだ、という雰囲気がわかったところで、ko自体のインストール方法ですが、これも超簡単です。ko自体もただのGo製ツールですので、Goが手元にインストールされている人であれば
go install github.com/google/ko@latest
これでおしまいです。Dockerも必要ありません。macOSな環境では本当にこれは便利ですね!
当然バイナリ配布もされているので、手元にダウンロードしてくればそれで終わりです。各種方法は公式ドキュメントを見てください。
ko の挙動のカスタマイズ
とりあえず最低限動かせるコマンドを紹介したので、次に ko の挙動を変えたい場合にどうするかを紹介します。たとえば、koで作るコンテナのベースイメージを変更したい場合にはどうしたらいいでしょうか。(デフォルトは gcr.io/distroless/static:nonroot
)あるいはGoのビルドの際に必要な環境変数を渡したい場合にはどうしたらいいでしょうか。こうしたカスタマイズは .ko.yaml
というYAMLファイルで設定します。例えば次のような具合です。
defaultBaseImage: gcr.io/distroless/base-debian11 builds: - id: main dir: . main: . env: - CGO_ENABLED=0
ko とコンテナランタイムとの連携
さらに ko が便利なのはコンテナランタイムと連携する場合です。たとえば Kubernetes の deployment のYAML内でコンテナのイメージを指定しますが、そこを ko の記法を使ってコンテナを指定しておくことができます。
apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 3 ... template: spec: containers: - name: my-app image: ko://github.com/my-user/my-repo/cmd/app
これを ko resolve -f deployment.yaml
で渡してあげると、まず github.com/my-user/my-repo/cmd/app
にあるアプリケーションを ko でビルドして、環境変数 KO_DOCKER_REPO
で指定しているコンテナレジストリにプッシュして、さらに ko://...
の文字列をそのイメージのパスで置き換えるということをした deployment.yaml
の値を返してくれます。これを kubectl apply
にパイプで渡してあげたりするわけです。
apply
をするだけであれば ko apply
というショートカットも用意してくれています。とにかく雑にGo製アプリケーションをコンテナ化してどこかにデプロイするのがとても簡単になります。
Dockerに投げる場合でも
docker run --rm -p 8888:8888 $(ko publish --local .)
というようなワンライナーで上げられたり、Cloud Runに投げるときは
gcloud run deploy --image=$(ko publish --local .)
という具合にできます。
ko とツールの連携
さきほどちらりと kubectl
との連携させるための ko resolve
というコマンドを紹介しましたが、Kubernetesを扱う場合、たとえば自分は skaffold を使ってテスト環境を上げたりしています。
skaffoldでは最近 ko がサポートされたので、skaffold.yaml
にkoを指定するだけで一気通貫でコンテナのビルドからKubernetesクラスタへのデプロイまでいけます!
build: artifacts: - image: my-simple-go-app ko: fromImage: gcr.io/distroless/base-debian11 labels: org.opencontainers.image.licenses: Apache-2.0 ...
おわりに
大変雑にkoを紹介しましたが、これは概ね ko の公式ドキュメント(=README)に記載されているものです。
ただいかんせんぱっと見が分かりづらいと思われるので「本当に簡単に使えます!」ということだけにフォーカスして紹介しました。来月にはDocker Desktopの有料化も始まります。コンテナ化を行うだけであれば、いまや選択肢は数多くありますので、koもその一つとして知っておいて損はないと思います。ぜひ試してみてください。