Help us understand the problem. What is going on with this article?

Goで書いたサーバーをHerokuにDocker Deployする

More than 1 year has passed since last update.

Goで書いたサーバーをデプロイする先を探していて、Google App Engine(SE)Arukasなどを試してきたが、ふと気になって調べてみたらRailsアプリのホスティングで馴染みのあるHerokuもDocker Deployに対応していたので、試してみた。割と良さげなので、手順を残しておく。

前提: 必要なもの

Heroku CLI ログイン

heroku login
heroku container:login

HerokuへのデプロイはCLIを使ってシェルから行います。heroku loginをして、CLIからログインして起きましょう。Docker Deployの場合はheroku container:loginContainer Registryへのログインも必要となります。

プログラムの準備

まずはHerokuにDeployする、簡単なHTTPサーバーをGoで書いて、ローカル(+ローカルのDocker)で動作確認をします。

シンプルなHTTPサーバーをGoで書く

main.go
package main

import (
    "fmt"
    "net/http"
    "os"
    "strconv"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello world\n")
}

func main() {
    port, _ := strconv.Atoi(os.Args[1])
    fmt.Printf("Starting server at Port %d", port)
    http.HandleFunc("/", handler)
    http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}

HTTPリクエストがきたらHello world\nを返す、シンプルなHTTPサーバーです。

重要なのは、Listenに使うポート番号をコマンドライン引数(os.Args[1])で実行時に指定できるようにしていることです。これは、HerokuのDocker DeployでHTTPサーバーを動かしたい場合、Herokuから指定されたポート番号($PORT)でListenをする必要があるためです。

参考: Dockerfile commands and runtime

The web process must listen for HTTP traffic on $PORT, which is set by Heroku.

ローカルで実行して動作確認しましょう。

go run main.go 3000

curllocalhost:3000にアクセスして、Hello world\nが返ってきたらOKです。

Dockerfileを定義する

FROM golang:latest as builder

ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
WORKDIR /go/src/github.com/yokoe/go-server-example
COPY . .
RUN go build main.go

# runtime image
FROM alpine
COPY --from=builder /go/src/github.com/yokoe/go-server-example /app

CMD /app/main $PORT

最新のgolangでビルド、容量の小さいAlpine Linux上でサーバーを動かすDocker imageを作ります。HerokuではEXPOSEコマンドは無視されるので、記述する必要はありません。前述の通り、サーバーはHerokuから指定されるポート番号($PORT)でListenする必要があるので、起動時の引数に渡しています。

docker build -t herokuexp .
docker run -e "PORT=3000" -p 3000:3000 -t herokuexp

ローカルでビルドして試してみましょう。先ほどと同じくHello world\nが返ってきたらOKです。

Herokuにデプロイする

gitレポジトリの作成

git init

gitレポジトリを作成するのは必須ではありませんが、gitで管理しておくと以降のherokuコマンドでデプロイなどの作業をする際に--appnameを指定しなくてよくなるので楽です。

herokuアプリの作成

heroku create

新しいherokuアプリを作成します。

pushする

heroku container:push web

デプロイの作業はpushreleaseの二段階に分かれています。2018年5月まではpushをするだけでデプロイが完了していましたが、今は明示的にreleaseをするまでデプロイが完了しないので注意しましょう。

参考: https://devcenter.heroku.com/changelog-items/1426

まずは、Container RegistryにDocker imageをPushします。pushを実行するとローカルでDocker imageが作成され、Container Registryに登録されます。最後の引数はプロセスタイプです。今回はHTTPサーバーなのでwebを指定します。

なお、gitレポジトリを使用していない場合(gitのremoteにherokuが登録されていない状態)の場合は、コマンドを叩く際にappnameを明示的に指定してあげる必要があります。

unauthorized: authentication requiredが出る場合

Container Registryにログインしていない可能性があります。heroku container:loginでContainer Registryにログインしてから試しましょう。

releaseする

heroku container:release web

Container Registryにイメージをpushできたら、それをreleaseします。webプロセス1個のみを使う場合はpushreleaseを分けて叩くメリットがわからないかもしれませんが、複数のプロセスタイプのイメージを同時にデプロイしたい場合などに便利なようです。

pushにはDocker Image作成のために多少時間がかかりますが、releaseは一瞬で完了します。二つの作業合わせても、Google App Engineのデプロイに比べると圧倒的に速いので快適ですね。

pushreleaseをわける必要がない場合は、Taskで下記のようなタスクを追加すると楽です。

Taskfile.yml
version: '2'

tasks:
  release:
    cmds:
      - heroku container:push web
      - heroku container:release web
      - osascript -e 'display notification "Deploy Done" with title "Heroku Deploy" subtitle "My Go Server" sound name "Submarine"'

蛇足ですが、Macの場合は最後にosascriptでNotificationを出すようにしておくと、作業完了までの間他の作業に集中しやすいのでおすすめです。

動作確認

heroku open

デプロイに成功したら、サーバーにアクセスして確認します。サーバーのURLはheroku createした際などに表示されるので、それをcurlで叩いても良いですし、heroku openコマンドを叩くとそのURLをブラウザで起動してくれるので楽です。(APIサーバーの場合はcurlで確認したいですが)

まとめ

GoアプリのHerokuへのデプロイはかなり簡単で速い上、値段も明瞭なのでおすすめです。CircleCIと連携させればGitレポジトリへPushしたタイミングで自動デプロイすることも可能なので、気が向いたら追記or新しいポストで投稿しようと思います。

参考リンク

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした