Heroku Container Registry & Runtime とは(Heroku Dev Center の私家訳)

この記事は、 Heroku Advent Calendar 2017 4日目の記事です
(dev center の記事を私訳します。 2017/11/23 最終更新の記事)


Heroku Container Registry では、Docker ベースのアプリケーションを Heroku にデプロイすることができます
Common RuntimePrivate Space もサポートされています

まずはじめに

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

ブラウザからアプリケーションを開きます

$ 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>

caution
プロセスタイプを指定するとしても、registry へのプッシュは、全てのプロセスをリスタートします
例えば、 もしあなたが web プロセスを指定したとしても、 worker プロセスもリスタートされます

既存の 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>

image のプッシュが成功した後、アプリケーションを開いてください:

$ heroku open -a <app>

複数の 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

ワンオフdyno

もし、アプリケーションが複数の Docker image で構成される場合、ワンオフdyno を作るときに、プロセスタイプを指定することができます:

$ heroku run bash --type=worker
Running bash on ⬢ multidockerfile... up, worker.5180

もし、プロセスタイプが指定されていなかった場合、 web image が使用されます

CI/CD を利用する

もしサードパーティの 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 をビルドしプッシュするためのドキュメントを用意しています:

Dockerfile コマンドとランタイム

アプリケーションのために Docker image を Container Registry へプッシュするとき、それら image は即座に Heroku app にリリースされます
Docker image はslugbuildpackでビルドすることと機能的に等価です
Docker image は dyno での実行において、slugが実行する方法と同じであり、また、同じ制約の下実行されます:

  • web プロセスはHerokuによって設定される$PORTにおいてHTTPトラフィックをリッスンしなければならなりません.Dockerfile 内の EXPOSE は優先されず、ローカルでのテスト時に使用することができます.HTTPリクエストのみがサポートされます
  • dyno同士のネットワークリンクはサポートされません
  • ファイルシステムはエフェメラルです
  • 実行時のディレクトリは/です.WORKDIRによって他のディレクトリを指定できます
  • 環境変数設定のための ENV はサポートされます
    • ENVは実行時変数(例: GEM_PATN)の使用や、クレデンシャルのための heroku config について使用することが推奨されます. そうすることで、センシティブなクレデンシャルが、偶然にソースコードに紛れないでしょう
  • ENTRYPOINT はオプションです. もし設定されない場合/bin/sh -c が使用されます
  • CMD は必須です. もしCMDが設定されていない場合、 registry はエラーを返します

ローカルでの image のテストにはroot以外のユーザでの実行を強く推奨します
container は Heroku 上では、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以外のユーザでの実行を強く推奨します
container は Heroku 上では、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の使い方はこちら

参考情報

images をスタックする

Cedar-14Heroku-16 の Docker image が利用可能です
しかしながら、いかなる base image も使用することができます
Heroku スタックイメージを使用する必要はありません
もし Heroku スタックイメージを使用することを選択するならば Heroku-16 (465.3 MB) をお勧めします
Cedar-14 に比べより小さいからです

heroku-16 を base image として使用する場合、 Dockerfile に次のように記述してください:

FROM heroku/heroku:16

デプロイ方法の変更

Container Registry へアプリケーションをデプロイしたならば、スタックは container にセットされます
これは、アプリケーションが、カスタム container を使用し、 Heroku-curated スタックをもはや使用しないということです
container に設定されると、git経由でアプリケーションをプッシュすることはできません
container registry 経由でアプリケーションをデプロイする必要が無く、代わりにgitを使用したい場合は、heroku stack:set heroku-16を実行してください

既知の制限とイシュー

  • Heroku は、ホスト側でのdocker ビルドサービスを提供しません; image はローカルや, Docker Hub や、そのほかの Docker build serviceでビルドされなければいけません. これは, Heroku Github integration and review apps の枠組みから外れると機能しない事を意味します
  • Docker image は(slugと違い)サイズ制限の対象ではありませんが,dyno の起動時間制限の対象です. レイヤ数/image サイズが大きくなると、dyno の起動時間も長くなります
  • 40以上のレイヤを持つ image は Common Runtime では起動に失敗するでしょう
  • Pipeline promotion はサポートされません
  • Release phase はサポートされません
  • このコマンドリストはサポートされません