前回の記事で、Herokuで動くようになったGolangプロジェクト(フレームワークはEcho)を今回Dockerコンテナで動くようにしてみました。 simple-minds-think-alike.hatenablog.com
- 前提
- Dockerfileの作成
- ローカルで動作確認
- Heroku container registoryにイメージをpush
- リリース
- イメージビルド、Heroku container registoryへのpush、リリースの手間を無くす
- Procfile削除
- サンプル
- 2020/12/20追記
- 参考
前提
- Herokuアカウント作成済
- ローカル環境にHeroku CLIインストール済
- ローカル環境にDockerインストール済
Dockerfileの作成
こんな感じで動くDockerfileを作ってみます。
以下のようなDockerfileをプロジェクトに追加しました。一つづつ解説していきます。
# Herokuで実行するGoのバイナリを作る FROM golang:latest as builder ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 WORKDIR /app COPY . . RUN go build main.go # 作ったGoのバイナリを実行する FROM alpine:latest COPY --from=builder /app /app CMD /app/main $PORT
実行バイナリファイルを作るイメージ
FROM golang:latest as builder
実行バイナリを作るためにgo build
を使いたいので、golang:latest
イメージを使っています。
変数ENV_CGO_ENABLED
ENV CGO_ENABLED=0
net
パッケージを使う場合には、CGO_ENABLEDを無効にしないと複数のバイナリができてしまう(Dynamic link)ので無効にしておきます。
参考にしたStackoverflowのリンクを貼っておきます。 stackoverflow.com
Golangのドキュメントにも書いてありました。
Go 1.2 Release Notes - The Go Programming Language
The net package requires cgo by default because the host operating system must in general mediate network call setup. On some systems, though, it is possible to use the network without cgo, and useful to do so, for instance to avoid dynamic linking. The new build tag netgo (off by default) allows the construction of a net package in pure Go on those systems where it is possible.
変数GOOS, GOARCH
ENV GOOS=linux ENV GOARCH=amd64
以下のHerokuのドキュメントに
Container Registry & Runtime (Docker Deploys) | Heroku Dev Center
Docker images run in dynos the same way that slugs do, and under the same constraints:
と書いてあり、Docker使わない場合とホストOS自体は同じになるようなので、OSはUbuntu 18.04ベース(2020年5月時点で最新のHerokuスタック)ということになります。
実行環境であるalpineはマルチアーキテクチャイメージで、ホストOSと同じlinux、アーキテクチャのイメージになるので、Ubuntu 18.04と同じになるように
ENV GOOS=linux
ENV GOARCH=amd64
を指定します。
バイナリを実行するイメージ
バイナリを実行するコンテナにシンプルなalpineイメージを使います。
FROM alpine:latest
ビルドしたバイナリをコピー
COPY --from=builder /app /app
バイナリ実行
CMD /app/main $PORT
前回の記事でも書きましたが、HerokuではWeb worker processに紐付けられるPORT番号は環境変数PORTから取れます。 Herokuの以下のドキュメントに記載があります。
Runtime Principles | Heroku Dev Center
ローカルで動作確認
$ docker build -t golang-sample . $ docker run -e "PORT=3000" -p 3000:3000 -t golang-sample
以下のURLにアクセスして、動作確認します。
Heroku container registoryにイメージをpush
Heroku container registoryにログイン
$ heroku container:login
イメージビルドして、Heroku container registoryにイメージをpushします
$ heroku container:push web moritamorie:~/go/src/github.com/golang-sample$ heroku container:push web › Warning: heroku update available from 7.39.0 to 7.39.3. === Building web (/home/moritamorie/go/src/github.com/golang-sample/Dockerfile) Sending build context to Docker daemon 11.7MB Step 1/10 : FROM golang:latest as builder ---> 7e5e8028e8ec 〜〜〜 Step 10/10 : CMD /app/main $PORT ---> Using cache ---> 4f60b0d6aaa9 Successfully built 4f60b0d6aaa9 Successfully tagged registry.heroku.com/golang-sample/web:latest === Pushing web (/home/moritamorie/go/src/github.com/golang-sample/Dockerfile) The push refers to repository [registry.heroku.com/golang-sample/web] Your image has been successfully pushed. You can now release it with the 'container:release' command
リリース
Heroku container registoryにpushしたイメージをリリースします
$ heroku container:release web
イメージビルド、Heroku container registoryへのpush、リリースの手間を無くす
以下の heroku.yml
ファイルを追加すると、buildプロセスをHeroku側に移すことができるので、Dockerを使わないときと同様の手順( git push heroku master
)で済みます。
build: docker: web: Dockerfile
Procfile削除
コンテナ側でバイナリの実行までやってくれるので、Docker対応が済んだらProcfileは削除してしまってOKです。
サンプル
今回のサンプルのコードも置いておくのでよかったら参考にしてみてください! github.com
2020/12/20追記
以下の記事で、Github Actionsを設定することでPRがmaster
ブランチにマージされた時に自動的にHeroku環境にデプロイ(Container Registryにpush、web dynoに反映)できるようにしてみました。もしよろしければこちらの記事も参考にしてみて下さい!
simple-minds-think-alike.hatenablog.com