Heroku スターターガイド (Go)
はじめに
このチュートリアルでは、Go アプリをデプロイする方法を簡単に紹介します。
少し時間を取って仕組みを学び、Heroku を最大限に活用できるようにしましょう。
このチュートリアルでは、以下が用意されていることを前提としています。
- 無料の Heroku アカウント。
- インストール済みの Go 1.17+。
Windows 下では、環境変数は、「System」 (システム) コントロールパネルの **`Advanced`** (上級) タブにある 「Environment Variables」 (環境変数) ボタンから設定されます。環境変数の設定に関する詳細は、ここにあります。
設定する
Heroku CLI には、一般によく使われている Git というバージョン管理システムが必要です。Git がまだインストールされていない場合は、先に進む前に次の手順を完了してください。
このステップでは、Heroku Command Line Interface (CLI) をインストールします。CLI は、アプリケーションの管理やスケール、アドオンのプロビジョニング、アプリケーションログの表示、アプリケーションのローカル実行に使用します。
ご使用のプラットフォーム用のインストーラをダウンロードし、実行してください。
ターミナルで以下を実行します。
$ sudo snap install heroku --classic
インストールしたら、コマンドシェルで heroku
コマンドを使用できます。
heroku login
コマンドを使って Heroku CLI にログインします。
$ heroku login
heroku: Press any key to open up the browser to login or q to exit
› Warning: If browser does not open, visit
› https://cli-auth.heroku.com/auth/browser/***
heroku: Waiting for login...
Logging in... done
Logged in as me@example.com
このコマンドにより、Web ブラウザで Heroku ログインページが開きます。ブラウザですでに Heroku にログインしている場合は、ページに表示されているLog in
(ログイン) ボタンをクリックします。
この認証は、heroku
と git
コマンドが正常に動作するために必要な操作です。
外部の HTTP/HTTPS サービスへの接続にプロキシの使用が必要なファイアウォールを使っている場合は、heroku
コマンドを実行する前に、ローカルの開発環境で HTTP_PROXY
または HTTPS_PROXY
環境変数を設定できます。
アプリを準備する
このステップでは、Heroku にデプロイできるサンプルアプリケーションを準備します。
Heroku をはじめて使う場合は、 Heroku が提供するサンプルアプリケーションを使ってこのチュートリアルを行うことをお勧めします。
ただし、デプロイする既存のアプリケーションを用意してある場合は、 Heroku へのデプロイを準備する方法について、この記事を 参照してください。
Heroku にデプロイするコードのローカルバージョンを作成できるように、サンプルアプリケーションをクローンし、ローカルのコマンドシェルまたはターミナルで次のコマンドを実行します。
$ git clone https://github.com/heroku/go-getting-started.git
$ cd go-getting-started
これで、シンプルなアプリケーションと、Go のモジュール依存関係システムが使用する go.mod
ファイルを格納した、正常な Git リポジトリを準備できました。
アプリをデプロイする
このステップでは、アプリを Heroku にデプロイします。
Heroku でアプリを作成すると、Heroku でソースコードを受け取ることができるよう準備できます。
$ heroku create
Creating polar-inlet-4930... done, stack is heroku-18
https://polar-inlet-4930.herokuapp.com/ | https://git.heroku.com/polar-inlet-4930.git
Git remote heroku added
アプリを作成すると、heroku
という名前の Git リモートリポジトリも作成され、ローカルの Git リポジトリと関連付けられます。
Heroku によってランダムなアプリ名 (この場合は polar-inlet-4930
) が生成されます。パラメータを渡して独自のアプリ名を指定することもできます。
コードをデプロイします。
$ git push heroku main
Enumerating objects: 521, done.
Counting objects: 100% (521/521), done.
Delta compression using up to 8 threads
Compressing objects: 100% (309/309), done.
Writing objects: 100% (521/521), 226.26 KiB | 45.25 MiB/s, done.
Total 521 (delta 141), reused 501 (delta 134)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Go app detected
remote: -----> Fetching jq... done
remote:
remote: -----> Detected go modules - go.mod
remote:
remote: -----> Installing go1.17.2
remote: -----> Fetching go1.17.2.linux-amd64.tar.gz... done
remote: !! Installing package '.' (default)
remote: !!
remote: !! To install a different package spec add a comment in the following form to your `go.mod` file:
remote: !! // +heroku install ./cmd/...
remote: !!
remote: -----> Running: go install -v -tags heroku -mod=vendor .
remote: gopkg.in/bluesuncorp/validator.v5
remote: github.com/gin-gonic/gin/render
remote: github.com/manucorporat/sse
remote: github.com/mattn/go-colorable
remote: golang.org/x/net/context
remote: github.com/heroku/x/hmetrics
remote: github.com/heroku/x/hmetrics/onload
remote: github.com/gin-gonic/gin/binding
remote: github.com/gin-gonic/gin
remote: github.com/heroku/go-getting-started
remote:
remote: Compiled the following binaries:
remote: ./bin/go-getting-started
remote:
remote: -----> Discovering process types
remote: Procfile declares types -> web
remote:
remote: -----> Compressing...
remote: Done: 5.5M
remote: -----> Launching...
remote: Released v3
remote: https://go-on-heroku.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/go-on-heroku.git
* [new branch] main -> main
アプリケーションがデプロイされました。
アプリ名で生成された URL にあるアプリを開きます。
次のショートカットを使うと、簡単に Web サイトを開くことができます。
$ heroku open
ログを表示する
Heroku では、すべてのアプリと Heroku コンポーネントの出力ストリームを、時系列のイベントストリームに集約してログを作成するため、1 か所ですべてのイベントを確認できます。
実行中のアプリに関する情報を表示するには、ログコマンドの 1 つである、heroku logs --tail
を使います。
$ heroku logs --tail
2019-03-20T23:50:05.000000+00:00 app[api]: Build started by user edward@heroku.com
2019-03-20T23:50:16.285107+00:00 app[api]: Scaled to web@1:Free by user edward@heroku.com
2019-03-20T23:50:16.269238+00:00 app[api]: Release v3 created by user edward@heroku.com
2019-03-20T23:50:16.269238+00:00 app[api]: Deploy 89f8247e by user edward@heroku.com
2019-03-20T23:50:17.344246+00:00 heroku[web.1]: Starting process with command `go-getting-started`
2019-03-20T23:50:19.124843+00:00 app[web.1]: [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
2019-03-20T23:50:19.124866+00:00 app[web.1]: - using env: export GIN_MODE=release
2019-03-20T23:50:19.124868+00:00 app[web.1]: - using code: gin.SetMode(gin.ReleaseMode)
2019-03-20T23:50:19.124869+00:00 app[web.1]:
2019-03-20T23:50:19.124876+00:00 app[web.1]: [GIN-debug] GET /static/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (2 handlers)
2019-03-20T23:50:19.124878+00:00 app[web.1]: [GIN-debug] HEAD /static/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (2 handlers)
2019-03-20T23:50:19.124879+00:00 app[web.1]: [GIN-debug] GET / --> main.main.func1 (2 handlers)
2019-03-20T23:50:19.124881+00:00 app[web.1]: [GIN-debug] Listening and serving HTTP on :44768
2019-03-20T23:50:20.124893+00:00 heroku[web.1]: State changed from starting to up
2019-03-20T23:50:34.000000+00:00 app[api]: Build succeeded
2019-03-20T23:53:43.947356+00:00 app[web.1]: [GIN] 2019/03/20 - 23:53:43 | 200 | 1.974798ms | 204.14.239.105 | GET /
2019-03-20T23:53:44.159888+00:00 app[web.1]: [GIN] 2019/03/20 - 23:53:44 | 200 | 5.278921ms | 204.14.239.105 | GET /static/main.css
2019-03-20T23:53:44.160049+00:00 app[web.1]: [GIN] 2019/03/20 - 23:53:44 | 200 | 4.895772ms | 204.14.239.105 | GET /static/lang-logo.png
2019-03-20T23:53:43.948325+00:00 heroku[router]: at=info method=GET path="/" host=floating-caverns-97277.herokuapp.com request_id=d14eb124-9497-4605-b59f-eb072fa3e4de fwd="204.14.239.105" dyno=web.1 connect=0ms service=3ms status=200 bytes=6979 protocol=https
2019-03-20T23:53:44.161176+00:00 heroku[router]: at=info method=GET path="/static/lang-logo.png" host=floating-caverns-97277.herokuapp.com request_id=5e241f17-2e36-4154-8b9a-cb91a9234a3a fwd="204.14.239.105" dyno=web.1 connect=0ms service=6ms status=200 bytes=2057 protocol=https
2019-03-20T23:53:44.160488+00:00 heroku[router]: at=info method=GET path="/static/main.css" host=floating-caverns-97277.herokuapp.com request_id=a74cca0d-0792-48c7-9906-ec1d93c2a0a0 fwd="204.14.239.105" dyno=web.1 connect=0ms service=6ms status=200 bytes=823 protocol=https
2019-03-20T23:53:44.406484+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=floating-caverns-97277.herokuapp.com request_id=2a28a546-4d14-4161-8922-218066800060 fwd="204.14.239.105" dyno=web.1 connect=0ms service=0ms status=404 bytes=146 protocol=https
2019-03-20T23:53:44.405506+00:00 app[web.1]: [GIN] 2019/03/20 - 23:53:44 | 404 | 2.419µs | 204.14.239.105 | GET /favicon.ico
ブラウザで再びアプリケーションを表示すると、別のログメッセージが生成されます。
ログのストリーム出力を停止するには、Control+C
を押します。
Procfile を定義する
Procfile は、アプリケーションのルートディレクトリにあるテキストファイルです。このファイルを使って、アプリの起動時に実行するコマンドを明示的に宣言します。
先ほどデプロイしたサンプルアプリの Procfile
は、次のようになっています。
web: bin/go-getting-started
単一のプロセスタイプの web
と、その実行に必要なコマンドを宣言しています。 ここでは、web
という名前が重要です。 これは、このプロセスタイプを Heroku の HTTP ルーティングスタックにアタッチし、デプロイ後に Web トラフィックを受信することを宣言しています。 ここで使用するコマンド、bin/go-getting-started
は、開始したアプリのコンパイル済みバイナリです。ビルドプロセスにより、コンパイル済みバイナリが dyno の ~/bin
ディレクトリにインストールされます。
Procfile には追加のプロセスタイプを含めることができます。 たとえば、アイテムをキューから外す処理を実行するバックグラウンドプロセスを追加で宣言できます。
アプリをスケールする
現在、アプリは単一の Web dyno で実行されています。 dyno とは、Procfile
で指定されているコマンドを実行する軽量のコンテナのようなものです。
実行されている dyno の数を確認するには、ps
コマンドを使います。
$ heroku ps
=== web (Free): `go-getting-started`
web.1: up 2015/05/12 11:28:21 (~ 4m ago)
デフォルトでは、アプリは Free dyno でデプロイされます。Free dyno は、アイドル状態 (トラフィックを何も受信しない状態) が 30 分続くとスリープします。 スリープすると、スリープ解除するときの最初のリクエスト時に数秒の遅延が発生します。その後のリクエストは正常に処理されます。 Free dyno は、月ごとに割り当てられるアカウント別の Free dyno 時間を消費します。割り当て時間が残っている限り、無料のアプリはすべて稼働し続けます。
dyno がスリープしないようにするには、「dyno タイプ」の記事で紹介されている Hobby または Professional の dyno タイプにアップグレードできます。たとえば、アプリを Professional dyno に移行すると、Heroku に特定の数の dyno の実行を指示するコマンドを実行し、各 dyno で Web プロセスタイプを実行させて、アプリを簡単にスケールすることができます。
Heroku でアプリケーションをスケールするとは、実行する dyno の数を変更することを意味します。 Web dyno の数を 0 にスケールしてみます。
$ heroku ps:scale web=0
ブラウザのタブで更新ボタンを押してアプリにアクセスするか、heroku open
コマンドを使ってブラウザのタブで開きます。 リクエストに応答できる Web dyno がないので、エラーメッセージが表示されます。
もう一度スケールしてみましょう。
$ heroku ps:scale web=1
不正操作を防止するため、有料のアプリケーションを 2 つ以上の dyno にスケールするには、アカウントの確認が必要です。
アプリの依存関係を宣言する
Heroku では、アプリのルートディレクトリに go.mod
ファイルがあると、そのアプリを Go で記述されたものと認識します。
デプロイしたデモ用アプリには、事前に次のような go.mod
ファイルが用意されています。
$ cat go.mod
module github.com/heroku/go-getting-started
// +heroku goVersion go1.17
go 1.17
require (
github.com/gin-gonic/gin v0.0.0-20150626140855-4cc2de6207f4
github.com/heroku/x v0.0.0-20171004170240-705849e307dd
github.com/manucorporat/sse v0.0.0-20150604091100-c142f0f1baea // indirect
github.com/mattn/go-colorable v0.0.0-20150625154642-40e4aedc8fab // indirect
github.com/mattn/go-isatty v0.0.0-20150814002629-7fcbc72f853b // indirect
github.com/stretchr/testify v1.3.0 // indirect
golang.org/x/net v0.0.0-20150629084131-d9558e5c97f8 // indirect
gopkg.in/bluesuncorp/validator.v5 v5.9.1 // indirect
)
Windows では、コマンドプロンプトで、コマンドは `cat` ではなく `more go.mod` になります。
go.mod
ファイルは Go ツールで使用され、アプリケーションのビルドに必要な依存関係と、Heroku がアプリケーションのコンパイルに使用する必要のあるビルド設定の両方を指定します。この Go アプリはいくつかの依存関係があり、主に Gin (HTTP Web フレームワーク) に対するものです。
アプリをデプロイすると、Heroku はこのファイルを読み出し、go install .
を使って適切なバージョンの Go をインストールし、コードをコンパイルします。
アプリをローカルで実行する
ご使用の開発環境でアプリをローカル実行するには、若干の作業が必要です。Go はコンパイル済みの言語であり、最初にアプリケーションをコンパイルする必要があります。
$ go build -o bin/go-getting-started -v .
github.com/mattn/go-colorable
gopkg.in/bluesuncorp/validator.v5
golang.org/x/net/context
github.com/heroku/x/hmetrics
github.com/gin-gonic/gin/render
github.com/manucorporat/sse
github.com/heroku/x/hmetrics/onload
github.com/gin-gonic/gin/binding
github.com/gin-gonic/gin
github.com/heroku/go-getting-started
heroku local
コマンドを使ってアプリケーションをローカルで起動します。このコマンドは、Heroku CLI の一部としてインストールされています。
$ heroku local web
forego | starting web.1 on port 5000
...
web.1 | [GIN-debug] Listening and serving HTTP on :5000
Windows では、`heroku local` を実行する前に、次の 2 つの作業を行う必要があります。
- 上記に一覧表示したコマンドの代わりに `go build -o bin/go-getting-started.exe -v` を実行します。
- 内容がチェックアウトのものではなく `web: bin\go-getting-started.exe` になるように Procfileを変更します。Procfile への変更はコミットしないでください。コミットした場合、アプリケーションの Web プロセスが Heroku 上で開始できなくなります。
Heroku と同じように、heroku local
も Procfile
を確認して実行する内容を判断します。
Web ブラウザで「http://localhost:5000」を開きます。ローカルで実行されているアプリが表示されます。
アプリのローカルでの実行を停止するには、ターミナルウィンドウに戻り、Ctrl
+ C
を押して終了します。
ローカルの変更をプッシュする
このステップでは、アプリケーションへのローカルでの変更を Heroku に反映させる方法を学びます。 例として、アプリケーションを変更して依存関係を追加し、それを使用するコードも追加します。
依存関係は、Go ツールで管理されます。
Blackfriday Markdown パーサーを使用するようにアプリを変更しましょう。この依存関係はまだアプリケーションで使用されていないので、依存関係のコピーをフェッチしに行くように指示する必要があります。
$ go get github.com/russross/blackfriday@v2
go: downloading github.com/russross/blackfriday v2.0.0+incompatible
go: extracting github.com/russross/blackfriday v2.0.0+incompatible
go: downloading github.com/shurcooL/sanitized_anchor_name v1.0.0
go: extracting github.com/shurcooL/sanitized_anchor_name v1.0.0
これは次の 3 つの作業を行います。
v2
の Blackfriday モジュールとそのすべての依存関係を モジュールキャッシュにダウンロードします。- Blackfriday 依存関係とその依存関係を
go.mod
に記録します。 - Blackfriday とその依存関係の暗号和を
go.sum
に記録します。
その後で、新しいルートである /mark
を導入しましょう。これは、パーサーによってレンダリングされる HTML を示します。"github.com/russross/blackfriday"
をインポートのリストに追加することで Blackfriday を使用するように main.go
を変更します。その結果、次のようになります。
import (
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
_ "github.com/heroku/x/hmetrics/onload"
"github.com/russross/blackfriday"
)
次に、blackfriday を使用する新しいルートを導入するように、main()
関数を変更します。 既存の router.GET()
呼び出した後、次を追加します。
router.GET("/mark", func(c *gin.Context) {
c.String(http.StatusOK, string(blackfriday.Run([]byte("**hi!**"))))
})
最後に、ローカルでプログラムを再コンパイルして開始し、新しいエンドポイントを手動でテストしましょう。
$ go build -o bin/go-getting-started -v .
$ heroku local
新しい /mark
ルート (http://localhost:5000/mark) でアプリケーションにアクセスします。 これで、Markdown から生成された HTML のテキスト表現が表示されます (<p><strong>hi!</strong></p>
)。
完成させるため、Heroku にローカルの変更をデプロイしましょう。
Heroku への Go アプリケーションのデプロイは、ほとんどの場合、同じパターンで行います。
まず、未使用のすべてのモジュールがアプリケーションから削除されていることを確認します。
$ go mod tidy
次に、新しい依存関係をベンダー化することによって、ビルドが繰り返し可能で崩壊に耐性があることを確認します。
$ go mod vendor
次に、変更した、または新しいファイルを、Git リポジトリに追加し、それらをコミットします。
$ git add -A .
$ git commit -m "Markdown demo dependency"
[blackFriday fc791f7] Markdown demo dependency
21 files changed, 5962 insertions(+)
create mode 100644 vendor/github.com/russross/blackfriday/.gitignore
create mode 100644 vendor/github.com/russross/blackfriday/.travis.yml
create mode 100644 vendor/github.com/russross/blackfriday/LICENSE.txt
create mode 100644 vendor/github.com/russross/blackfriday/README.md
create mode 100644 vendor/github.com/russross/blackfriday/block.go
create mode 100644 vendor/github.com/russross/blackfriday/doc.go
create mode 100644 vendor/github.com/russross/blackfriday/esc.go
create mode 100644 vendor/github.com/russross/blackfriday/html.go
create mode 100644 vendor/github.com/russross/blackfriday/inline.go
create mode 100644 vendor/github.com/russross/blackfriday/markdown.go
create mode 100644 vendor/github.com/russross/blackfriday/node.go
create mode 100644 vendor/github.com/russross/blackfriday/smartypants.go
create mode 100644 vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml
create mode 100644 vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE
create mode 100644 vendor/github.com/shurcooL/sanitized_anchor_name/README.md
create mode 100644 vendor/github.com/shurcooL/sanitized_anchor_name/go.mod
create mode 100644 vendor/github.com/shurcooL/sanitized_anchor_name/main.go
前と同じ方法でデプロイします。
$ git push heroku main
最後に、新しいコードが機能していることを確認します。
$ heroku open mark
アドオンをプロビジョニングする
アドオンは、アプリケーションですぐに使える追加サービスを提供するサードパーティのクラウドサービスです。永続性、ログ記録、モニタリングなど、さまざまなアドオンがあります。
Heroku では、デフォルトで 1500 行のアプリケーションログが記録されますが、 完全なログストリームもサービスとして提供しています。複数のアドオンプロバイダーがこのサービスを利用し、ログの永続化、検索、メールや SMS 通知などの機能を実現するログサービスを提供しています。
このステップでは、このようなログに関するアドオンの 1 つである、Papertrail をプロビジョニングします。
Papertrail ログ記録アドオンをプロビジョニングします。
このアドオンのプロビジョニングには、アカウントの確認が必要です。
$ heroku addons:create papertrail
Creating giggling-carefully-3978... done
Adding giggling-carefully-3978 to polar-inlet-4930... done
Setting PAPERTRAIL_API_TOKEN and restarting polar-inlet-4930... done, v5
Welcome to Papertrail. Questions and ideas are welcome (support@papertrailapp.com). Happy logging!
不正操作を防止するため、アドオンのプロビジョニングにはアカウントの確認が必要です。アカウントが未確認の場合は、確認用ページに転送されます。
アドオンがデプロイされ、アプリケーション用に設定されました。 アプリのアドオンは、次のように一覧表示できます。
$ heroku addons
このアドオンが動作していることを確認するため、アプリケーションの Heroku URL に数回アクセスします。アクセスする度にログメッセージが生成され、Papertrail のアドオンに送られるようになります。 Papertrail のコンソールにアクセスし、ログメッセージを確認します。
$ heroku addons:open papertrail
ログが Papertrail の UI に表示されるまで数分待機する必要があります。
ブラウザで Papertrail の Web コンソールが開き、最新のログイベントが表示されます。 このインターフェースでは、検索したり通知を設定したりできます。
One-off dyno を起動する
One-off dyno で、heroku run
コマンドを使ってコマンド (通常はアプリの一部を構成するスクリプトやアプリケーション) を実行できます。 dyno の仕組みに慣れるため、この dyno でシェルを開く bash
コマンドを実行する One-off dyno を作成してみましょう。 シェルが開いたら、そこでコマンドを実行できます。 dyno にはそれぞれ固有の一時的なファイル領域が割り当てられ、アプリとその依存関係がそこに格納されます。コマンド (この場合は bash
) が完了すると、dyno は削除されます。
$ heroku run bash
Running bash on ⬢ go-getting-started... up, run.9087
~ $ ls
Dockerfile Makefile Procfile README.md app.json bin go.mod go.sum heroku.yml main.go static templates vendor
~ $ exit
exit
必ず exit
と入力してシェルを閉じ、dyno を終了してください。
Error connecting to process
というエラーが表示された場合は、ファイアウォールの設定が必要な可能性があります。
環境設定を定義する
Heroku では、設定を外部に置き、暗号鍵や外部リソースのアドレスなどのデータを環境設定に保存できます。
環境設定は、ランタイムに環境変数としてアプリケーションに提供されます。アプリケーションはすでに、1 つの環境設定、$PORT
環境設定を読み込んでいます。$PORT
は、Heroku によって web
dyno に自動的に設定されます。ユーザーが設定した環境設定を Go アプリケーションで使用する方法を調べてみましょう。
main.go
を変更し、REPEAT
環境変数の値で指定した回数だけ Hello From Go!
を返す repeatHandler
関数を追加します。 ファイルを次に示すように変更します。
package main
import (
"bytes"
"log"
"net/http"
"os"
"strconv"
"github.com/gin-gonic/gin"
_ "github.com/heroku/x/hmetrics/onload"
"github.com/russross/blackfriday"
)
func repeatHandler(r int) gin.HandlerFunc {
return func(c *gin.Context) {
var buffer bytes.Buffer
for i := 0; i < r; i++ {
buffer.WriteString("Hello from Go!\n")
}
c.String(http.StatusOK, buffer.String())
}
}
func main() {
port := os.Getenv("PORT")
if port == "" {
log.Fatal("$PORT must be set")
}
tStr := os.Getenv("REPEAT")
repeat, err := strconv.Atoi(tStr)
if err != nil {
log.Printf("Error converting $REPEAT to an int: %q - Using default\n", err)
repeat = 5
}
router := gin.New()
router.Use(gin.Logger())
router.LoadHTMLGlob("templates/*.tmpl.html")
router.Static("/static", "static")
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl.html", nil)
})
router.GET("/mark", func(c *gin.Context) {
c.String(http.StatusOK, string(blackfriday.Run([]byte("**hi!**"))))
})
router.GET("/repeat", repeatHandler(repeat))
router.Run(":" + port)
}
heroku local
は、ローカルディレクトリにある .env
ファイルの内容に応じて、環境を自動的に設定します。 プロジェクトのトップレベルディレクトリにはすでに .env
ファイルがあり、以下の行が含まれています。
REPEAT=10
アプリを再コンパイルし、実行します。
$ go build -o bin/go-getting-started -v .
$ heroku local
http://localhost:5000/repeat でアプリ上の /repeat
ルートにアクセスすると、「Hello From Go!」が 10 回表示されます。
Heroku で環境設定を設定するには、次のコマンドを実行します。
$ heroku config:set REPEAT=10
Setting config vars and restarting polar-inlet-4930... done, v6
REPEAT: 10
heroku config
を使って設定した環境設定を表示します。
$ heroku config
== polar-inlet-4930 Config Vars
PAPERTRAIL_API_TOKEN: erdKhPeeeehIcdfY7ne
REPEAT: 10
「ローカルの変更をプッシュする」セクションで学習した内容を使用して変更を Heroku にデプロイし、アプリケーションの /repeat
ハンドラにアクセすることにより試してみます。
$ heroku open repeat
データベースを使う
add-on marketplace には、Redis や MongoDB、Postgres、MySQL など、多数のデータストアが揃っています。 このステップでは、無料の Heroku Postgres Starter Tier dev データベースをアプリに追加します。
データベースを追加します。
$ heroku addons:create heroku-postgresql:hobby-dev
Creating heroku-postgresql:hobby-dev on ⬢ go-getting-started... free
Created postgresql-curved-22223 as DATABASE_URL
Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pg:copy
Use heroku addons:docs heroku-postgresql to view documentation
これによりデータベースが作成され、$DATABASE_URL
環境変数が設定されます。アプリの環境設定を一覧表示すると、$DATABASE_URL
の値が表示されます。
$ heroku config
=== polar-inlet-4930 Config Vars
DATABASE_URL: postgres://xx:yyy@host:5432/d8slm9t7b5mjnd
Heroku には、さらに詳細を表示する pg
コマンドもあります。
$ heroku pg
=== DATABASE_URL
Plan: Hobby-dev
Status: Available
Connections: 0/20
PG Version: 11.2
Created: 2019-03-21 00:59 UTC
Data Size: 7.7 MB
Tables: 0
Rows: 0/10000 (In compliance)
Fork/Follow: Unsupported
Rollback: Unsupported
Continuous Protection: Off
Add-on: postgresql-vertical-31536
表示内容から、Hobby のデータベース (無料) を使っており、実行している Postgres のバージョンは 11.2 で、テーブルもデータ行もないことがわかります。
このデータベースを使用するアプリケーションにルートを追加しましょう。
Blackfriday モジュールとまったく同様に、使用する前に、Go の PostgreSQL モジュール (github.com/lib/pq
) に対して go get
を行う必要があります。
$ go get github.com/lib/pq@v1
go: finding github.com/lib/pq v1.0.0
go: downloading github.com/lib/pq v1.0.0
go: extracting github.com/lib/pq v1.0.0
dbFunc
関数をアプリに追加し、/db
ルートを登録します。
package main
import (
"bytes"
"database/sql"
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"
"github.com/gin-gonic/gin"
_ "github.com/heroku/x/hmetrics/onload"
_ "github.com/lib/pq"
"github.com/russross/blackfriday"
)
func repeatHandler(r int) gin.HandlerFunc {
return func(c *gin.Context) {
var buffer bytes.Buffer
for i := 0; i < r; i++ {
buffer.WriteString("Hello from Go!\n")
}
c.String(http.StatusOK, buffer.String())
}
}
func dbFunc(db *sql.DB) gin.HandlerFunc {
return func(c *gin.Context) {
if _, err := db.Exec("CREATE TABLE IF NOT EXISTS ticks (tick timestamp)"); err != nil {
c.String(http.StatusInternalServerError,
fmt.Sprintf("Error creating database table: %q", err))
return
}
if _, err := db.Exec("INSERT INTO ticks VALUES (now())"); err != nil {
c.String(http.StatusInternalServerError,
fmt.Sprintf("Error incrementing tick: %q", err))
return
}
rows, err := db.Query("SELECT tick FROM ticks")
if err != nil {
c.String(http.StatusInternalServerError,
fmt.Sprintf("Error reading ticks: %q", err))
return
}
defer rows.Close()
for rows.Next() {
var tick time.Time
if err := rows.Scan(&tick); err != nil {
c.String(http.StatusInternalServerError,
fmt.Sprintf("Error scanning ticks: %q", err))
return
}
c.String(http.StatusOK, fmt.Sprintf("Read from DB: %s\n", tick.String()))
}
}
}
func main() {
port := os.Getenv("PORT")
if port == "" {
log.Fatal("$PORT must be set")
}
tStr := os.Getenv("REPEAT")
repeat, err := strconv.Atoi(tStr)
if err != nil {
log.Printf("Error converting $REPEAT to an int: %q - Using default\n", err)
repeat = 5
}
db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatalf("Error opening database: %q", err)
}
router := gin.New()
router.Use(gin.Logger())
router.LoadHTMLGlob("templates/*.tmpl.html")
router.Static("/static", "static")
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl.html", nil)
})
router.GET("/mark", func(c *gin.Context) {
c.String(http.StatusOK, string(blackfriday.Run([]byte("**hi!**"))))
})
router.GET("/repeat", repeatHandler(repeat))
router.GET("/db", dbFunc(db))
router.Run(":" + port)
}
依存関係を更新し、新しいコードをコミットし、Heroku に変更をデプロイします。
$ go mod tidy
$ go mod vendor
$ git add -A .
$ git commit -m "/db"
$ git push heroku main
$ heroku open db
ページを数回リロードすると、次のような内容が表示されます。
Read from DB: 2019-03-21 01:08:21.671103 +0000 +0000
Read from DB: 2019-03-21 01:08:22.988895 +0000 +0000
Read from DB: 2019-03-21 01:08:23.606315 +0000 +0000
Read from DB: 2019-03-21 01:08:24.111442 +0000 +0000
Read from DB: 2019-03-21 01:08:24.287767 +0000 +0000
Read from DB: 2019-03-21 01:08:24.434537 +0000 +0000
Read from DB: 2019-03-21 01:08:24.582809 +0000 +0000
ローカル環境に Postgres がインストールされている場合、heroku pg:psql
コマンドを使ってリモートデータベースに接続し、すべての行を表示できます。
$ heroku pg:psql
--> Connecting to postgresql-vertical-31536
psql (11.2)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
floating-caverns-97277::DATABASE=> SELECT * FROM ticks;
tick
----------------------------
2019-03-21 01:08:21.671103
2019-03-21 01:08:22.988895
2019-03-21 01:08:23.606315
2019-03-21 01:08:24.111442
2019-03-21 01:08:24.287767
2019-03-21 01:08:24.434537
2019-03-21 01:08:24.582809
...
詳細は、「Heroku PostgreSQL」を参照してください。
MongoDB や Redis のアドオンをインストールするときも、同様のテクニックを利用できます。
次のステップ
ここまで、Go アプリケーションのデプロイ、アプリの設定変更、ログの表示、スケール、アドオンのアタッチおよび使用を行う方法を説明しました。
次にお勧めするリソースを紹介します。
- 「Heroku の仕組み」では、アプリケーションの作成、設定、デプロイ、および実行時に必要な技術的な概念の概要を紹介しています。
- Go カテゴリでは、Go アプリケーションの開発とデプロイに関する詳細を確認できます。
- Heroku の開発者としての体験および CI/CD 機能の詳細は、「Heroku Enterprise Developer Learning Journey」を参照してください。