golangをDockerでデプロイする

(golangでDocker上にデプロイする際に得られた知見を共有します。間違いやもっといい方法があればご指摘下さい)

golangはlibcなどに依存せず、さらにすべてstatic linkする、という特徴があります。これはどういうことかというと、golangで出力したバイナリが一つだけあれば動作する、ということです。

golangバイナリをDocker上で動かす

Dockerは異なる環境を動かすコンテナとして優れています。しかし、baseとなるイメージが巨大だったり、 docker pullは安全なの? だったりという問題も抱えています。

しかし、golangを使っている場合は、上記の特徴があるため、 出力したバイナリ + 必要なファイル だけで動作できます。(ただし、cgoなどを使っていない場合に限ります)

1. tar.gzを作成する

以下の様なディレクトリ構成だとします。

github.com/shirou/test
|-- main.go
|-- public
|   `-- css
|       `-- sample.css
`-- view
    `-- base.html

main.goはpublicとviewを適当に使うwebアプリだとします。(別になんでもいいです)

そのまま全部tar.gzで固め、dockerを動かすhostにscpします。

GOOS=linux GOARCH=amd64 go build
tar cvfz /tmp/image.tar.gz .
scp /tmp/image.tar.gz docker:/tmp/

別に全部固めなくても必要なファイルだけ固めれば大丈夫です。実際にはbuild用ディレクトリを作成し、その中に必要なファイルをcopyしていくことになるでしょう。

2. docker import

docker host側でtar.gzからdocker imageを作成します。

cat image.tar.gz | sudo docker import - test:latest

3. docker run

あとは普通に動かせます。

sudo docker run -p 8000:8000 test:latest /test

利点

この方式では、以下の利点が生まれます。

  1. docker pullやdocker hubが必要ない。private レポジトリも必要ない

  2. 必要なファイルだけなので、容量を消費しない

  3. 不必要なプロセスがまったく動いておらず、ファイルすら存在しないため、セキュリティ上問題が起こりえない(自分のプログラムに問題があった場合は別です)

  4. 構成管理をする必要がない(依存パッケージインストールなど必要ないし)

s3の利用

今回はtar.gzをscpで送っていますが、s3に置くことももちろんできます。 docker import はURLを引数に渡せます。

一つのファイルに固める

今回は必要なファイルをコピーする方式をとっていますが、 go-bindata などを使うと、一つのバイナリファイルにすべてを固められます。 kocha を使うのもいいでしょう。

その場合、tar.gzなどは必要なく、Dockerfileでそのファイルを単に ADD すれば動きます。

ハマりポイント

HTTPSで外部にアクセスする場合、 /etc/ssl/certs/ca-certificates.crt が必要な場合があります。

まとめ

golangで作成したバイナリをDockerで動かすといろいろな利点が生まれるよ、ということを説明しました。ansibleなんて要らなかったんや!(嘘です)

参考

Comments

comments powered by Disqus