この記事は、 Heroku Advent Calendar 2017 4日目の記事です
(dev center の記事を私訳します。 2017/11/23 最終更新の記事)
(Last updated 02 May 2019 の記事に追従 (2019/05/30))
Heroku Container Registry では、Docker ベースのアプリケーションを Heroku にデプロイすることができます
Common Runtime も Private Space もサポートされています
もし、Heroku 上で Docker image をビルドする場合、Review app を利用することもできます
building Docker images with heroku.yml を確認してください
まずはじめに
Docker がインストールされ、動作する環境を用意します(例: docker ps
)。heroku へコマンドラインからログインしておきます(heroku login
)
Container Registry へログインします:
$ heroku container:login
Alpine ベースの python サンプル image を入手します
$ git clone https://github.com/heroku/alpinehelloworld.git
アプリケーションのディレクトリに移動し、 heroku app を create します
$ heroku create
Creating salty-fortress-4191... done, stack is cedar-14
https://salty-fortress-4191.herokuapp.com/ | https://git.heroku.com/salty-fortress-4191.git
image をビルドし、 Container Registry へプッシュします
$ heroku container:push web
そして、release 操作を行います
$ heroku container:release web
ブラウザからアプリケーションを開きます
$ heroku open
registry へのログイン
Heroku は Container Registry を、 registry.heroku.com
上で実行しています
HerokuCLI を利用している場合、次のようにしてログインすることが可能です:
$ heroku container:login
もしくは、Docker コマンドから直接ログインすることもできます:
$ docker login --username=_ --password=$(heroku auth:token) registry.heroku.com
image(s) のプッシュ
image のビルドとプッシュ
image をビルドし、registry.heroku.com へプッシュするには、アプリケーションのディレクトリに Dockerfile
が存在することが必要です. 以下を実行します:
$ heroku container:push <process-type>
既存の image をプッシュする
Heroku へ image をプッシュするために、 Docker Hub から pull されたものであっても、 tag 付けを行い、 naming template に従ってプッシュしてください:
$ docker tag <image> registry.heroku.com/<app>/<process-type>
$ docker push registry.heroku.com/<app>/<process-type>
tag にプロセスタイプを指定することで、CLI を使用して image をリリースできます(release the image using the CLI)
もし、tag にプロセスタイプを指定したくない場合は、image_id
を使った API 経由のリリースが可能です(release via the API)
複数の image をプッシュする
複数 image をプッシュするために、Dockerfile を Dockerfile. のようにリネームしてください:
$ ls -R
./webapp:
Dockerfile.web
./worker:
Dockerfile.worker
./image-processor:
Dockerfile.image
それから、プロジェクトのルートディレクトリから、実行します:
$ heroku container:push --recursive
=== Building web
=== Building worker
=== Building image
=== Pushing web
=== Pushing worker
=== Pushing image
3つの image をビルドし、プッシュします
もし、特定の image のみをプッシュしたい場合は、プロセスタイプを指定することができます:
$ heroku container:push web worker --recursive
=== Building web
=== Building worker
=== Pushing web
=== Pushing worker
image のリリース
CLI
container registry への push が成功したあと、新しい release を作ることができます
$ heroku container:release web
もし、複数の image がある場合は、リストとして渡します
$ heroku container:release web worker
caution
多数のプロセスタイプをもつ app の場合で、ひとつのプロセスタイプのみを release した場合、
(e.g.,heroku container:relase web
)
すべてのプロセスタイプがリスタートされます
API
$ curl -n -X PATCH https://api.heroku.com/apps/$APP_ID_OR_NAME/formation \
-d '{
"updates": [
{
"type": "web",
"docker_image": "$WEB_DOCKER_IMAGE_ID"
},
{
"type": "worker",
"docker_image": "$WORKER_DOCKER_IMAGE_ID"
},
]
}' \
-H "Content-Type: application/json" \
-H "Accept: application/vnd.heroku+json; version=3.docker-releases"
Docker image ID を取得する
$ docker build -t my_image .
...
Successfully built acf835bc07f5
Successfully tagged my_image:latest
docker inspect my_image --format={{.Id}}
acf835bc07f5
ワンオフdyno
もし、アプリケーションが複数の Docker image で構成される場合、ワンオフdyno を作るときに、プロセスタイプを指定することができます:
$ heroku run bash --type=worker
Running bash on ⬢ multidockerfile... up, worker.5180
プロセスタイプが指定されていなかった場合、 web
image が使用されます
CI/CD を利用する
caution
現時点では、コンテナビルドのテストに Heroku CI は使えません
もしサードパーティの CI/CD プラットフォームを使用している場合、registry に image をプッシュできます
初回の認証は、下記の情報が必要です:
- Registry URL:
registry.heroku.com
- Username:
your Heroku email address
- Email:
your Heroku email address
- Password:
your Heroku API key
多くの CI/CD プロバイダが、Docker registry へ image をビルドしプッシュするためのドキュメントを用意しています:
Release フェイズ
Release フェイズ を使用するためには、Docker image の名前を release
とします
$ heroku container:push release
heroku container:release
によって Docker image をリリースする場合、プロセスタイプの指定が必要です
$ heroku container:release web release
Releasing images web,release to your-app-name... done
Running release command...
Migrating database.
release フェイズ実行中の、ストリーミングログを見たい場合、Docker image 内に
curl
が必要です
Docker image 内にcurl
がない場合、release フェイズのログはアプリケーションログ内で利用可能です
Heroku-16 もしくは Heroku-18 スタックをベースイメージとして使用している場合、curl
はイメージ内に含まれています
Dockerfile コマンドとランタイム
Docker image の dyno 上での実行において、slug が実行する方法と同じであり、また、同じ制約の下実行されます:
-
web
プロセスはHerokuによって設定される$PORT
においてHTTPトラフィックをリッスンしなければならなりません. Dockerfile 内のEXPOSE
は優先されませんが、ローカルでのテスト時に使用することができます. また、HTTPリクエストのみがサポートされます - dyno 同士のネットワークリンクはサポートされません
- ファイルシステムはエフェメラルです
- 実行時のディレクトリは
/
です.WORKDIR
によって他のディレクトリを指定できます - 環境変数設定のための
ENV
がサポートされています- センシティブなクレデンシャルが、偶発的にソースコードに紛れることがなくすために、
ENV
は実行時変数(例:GEM_PATH
)の使用や、クレデンシャル用にheroku config
を使用することが推奨されます
- センシティブなクレデンシャルが、偶発的にソースコードに紛れることがなくすために、
-
ENTRYPOINT
はオプションです. もし設定されない場合/bin/sh -c
が使用されます-
config varsがプロセスで使用可能になるために、
CMD
は shell によって常に実行されます - シングルバイナリの実行や、shell 無しでの image 実行には
ENTRYPOINT
を利用してください
-
config varsがプロセスで使用可能になるために、
ローカルでの image のテストにはroot以外のユーザでの実行を強く推奨します
Heroku 上では、container は root 権限では実行されません
サポートされない Dockerfile コマンド
-
VOLUME
- ボリュームマウントはサポートされません. dyno のファイルシステムはエフェメラルです -
EXPOSE
-EXPOSE
はローカルでのテスト時には使用することができます. しかし、 Heroku container runtime ではさぽーとされません. かわりに web プロセスなどで、環境変数の$PORT
を取得するようにしてください -
STOPSIGNAL
- dyno マネージャは、プロセスが SIGLILL シグナルに準拠したSIGTERM signalを送られる事によるグレースフルシャットダウンを要求します.STOPSIGNAL
は推奨されません -
SHELL
- Docker image のデフォルトのシェルは/bin/sh
です. 必要であれば、ENTRYPOINT
によって上書きすることができます -
HEALTHCHECK
-HEALTHCHEK
は現在サポートされていませんが、 Heroku Dyno マネージャは実行中コンテナのherth check を自動的に行っています
ローカルで image をテストする
ローカルで image をテストするとき、いくつかのベストプラクティスがあります
このベストプラクティスは Dockerfile 例 で使用されています
非root として実行する
ローカルでの image のテストにはroot以外のユーザでの実行を強く推奨します
Heroku 上では、container は root 権限では実行されないためです
Dockerfile のCMD
行の直前に下記のコマンドを追加することができます:
Alpine 使用の場合:
RUN adduser -D myuser
USER myuser
Ubuntu 使用の場合:
RUN useradd -m myuser
USER myuser
自身の containar が非ルートユーザで実行されていることを確認し、実行中の container に attach し、 whoami
コマンドを実行します:
$ docker exec <container-id> bash
$ whoami
myuser
Heroku へのデプロイ時、非ルートユーザで container も実行します
(Dockerfile に USER
が指定されていたとしても使用しません)
$ heroku run bash
$ whoami
U7729
環境変数からのポート番号の取得
テスト実行のために、Dockerfile やコード上で、環境変数から $PORT
を読み込むようにすることを提案します
例えば:
CMD gunicorn --bind 0.0.0.0:$PORT wsgi
Docker container をローカルで実行するとき、-e
フラグによって環境変数を設定することができます:
docker run -p 5000:5000 -e PORT=5000 <image-name>
複数の環境変数を設定する
もしheroku local
で実行しているならば、config var を .env
ファイルに設定することができます
heroku local
が実行されているとき、 .env
は読み込まれ、name/value ペアが環境変数に設定されます
同じ.env
ファイルを Docker を使用するときにも使用することができます:
docker run -p 5000:5000 --env-file .env <image-name>
.env
ファイルは、.dockerignore
ファイルに追加することを提案します
マルチコンデナアプリケーション用のdocker-composeの活用
マルチコンテナアプリケーションを作ったならば、ローカル開発環境を定義するdocker-composeを使用することができます
ローカル開発のためのdocker-composeの使い方はこちら
参考情報
- Docker image をローカルで実行するための情報は、Docker社のオフィシャルドキュメントにあります
- ローカル開発環境でのdocker-composeの使用法はこちらです
images をスタックする
Heroku-16 と Heroku-18 の Docker image が利用可能です
しかしながら、いかなる base image も使用することができます
Heroku スタックイメージを使用する必要はありません
もし Heroku スタックイメージを使用することを選択するならば Heroku-18 (406 MB) をお勧めします
Heroku-18 を base image として使用する場合、 Dockerfile に次のように記述してください:
FROM heroku/heroku:18
latest image を取得する
すでにアプリケーションで Heroku-18 を使用していて、latest version に更新したい場合は、下記を実行します
$ docker pull heroku/heroku:18
そして、再度アプリケーションの deply を実行してください
デプロイ方法の変更
Container Registry へアプリケーションをデプロイしたならば、スタックは container
にセットされます
これは、アプリケーションが、カスタム container を使用し、 Heroku-curated スタックをもはや使用しないということです
container
に設定されると、git
経由でアプリケーションをプッシュすることはできません
container registry 経由でアプリケーションをデプロイする必要が無く、代わりにgit
を使用したい場合は、heroku stack:set heroku-18
を実行してください
既知の制限とイシュー
- Review apps はサポートされません. Docker を Review apps とともに利用する場合、Docker image を Heroku 上でビルドするために heroku.yml manifest とともにアプリケーションを定義してください
- Docker image は(slugと違い)サイズ制限の対象ではありませんが,dyno の起動時間制限の対象です. レイヤ数/image サイズが大きくなると、dyno の起動時間も長くなります
- 40以上のレイヤを持つ image は Common Runtime では起動に失敗するでしょう
- Pipeline promotion はサポートされません
- このコマンドリストはサポートされません