Container Registry および Runtime (Docker デプロイ)
この記事の英語版に更新があります。ご覧の翻訳には含まれていない変更点があるかもしれません。
最終更新日 2024年04月30日(火)
Table of Contents
Heroku Container Registry を使用すると、Docker イメージを Heroku にデプロイできます。Common Runtime と Private Space の両方がサポートされています。
Heroku で Docker イメージをビルドさせる場合は、レビューアプリを活用するだけでなく、heroku.yml で Docker イメージのビルドを確認します。
Heroku container
スタックは、高度なユースケースのみを想定しています。カスタム Docker イメージが特に必要な場合を除き、
Heroku のデフォルト buildpack を利用したビルドシステムを代わりに使用することをお勧めします。これにより、
ベースイメージの自動セキュリティ更新、言語固有の最適化が提供され、Dockerfile
を保守する必要がなくなります。
はじめに
作業用 Docker インストールがあることを確認し (docker ps
など)、Heroku にログインしていることを確認します (heroku login
)。
Container Registr にログインします。
$ heroku container:login
Alpine ベースの python 例を複製することによりサンプルコードを取得します。
$ git clone https://github.com/heroku/alpinehelloworld.git
アプリのディレクトリに移動して、Heroku アプリを作成します。
$ cd alpinehelloworld
$ heroku create
Creating salty-fortress-4191... done, stack is heroku-20
https://salty-fortress-4191.herokuapp.com/ | https://git.heroku.com/salty-fortress-4191.git
イメージをビルドし、Container Registry にプッシュします。
$ heroku container:push web
続いてイメージをアプリにリリースします。
$ heroku container:release web
次に、アプリをブラウザで開きます。
$ heroku open
レジストリへのログイン
Heroku は、registry.heroku.com
でコンテナレジストリを実行します。
Heroku CLI を使用している場合、次のように指定してログインできます。
$ heroku container:login
または直接 Docker CLI を使用します。
$ docker login --username=_ --password=$(heroku auth:token) registry.heroku.com
イメージのビルドとプッシュ
イメージのビルドとプッシュ
イメージをビルドして Container Registry にプッシュするには、ディレクトリに Dockerfile が含まれていることを確認し、次のように実行します。
$ heroku container:push <process-type>
既存のイメージのプッシュ
Docker Hub からプルしたものなどのイメージを Heroku にプッシュするには、次の命名テンプレートに従って、そのイメージにタグを付けプッシュします。
$ docker tag <image> registry.heroku.com/<app>/<process-type>
$ docker push registry.heroku.com/<app>/<process-type>
タグでプロセスタイプを指定することにより、CLI を使用してイメージをリリースできます。タグでプロセスタイプを指定しない場合は、image_id
を使用する API を介してリリースする必要があります。
複数のイメージのプッシュ
複数のイメージをプッシュするには、Dockerfile.<process-type>
を使用して 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 つのイメージすべてをビルドしてプッシュします。特定のイメージだけをプッシュする場合は、プロセスタイプを指定できます。
$ heroku container:push web worker --recursive
=== Building web
=== Building worker
=== Pushing web
=== Pushing worker
イメージのリリース
CLI
Container Registry に正常にイメージをプッシュした後、次のコマンドを使用して新しいリリースを作成できます。
$ heroku container:release web
複数のイメージがある場合は、それらを一覧表示します。
$ heroku container:release web worker
複数のプロセスタイプを持つアプリでは、1 つのプロセスタイプ (heroku container:release web
など) だけをリリースする場合、すべてのプロセスタイプが再起動されます。
API
curl --netrc -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"
curl --netrc
オプションが機能するようにするには、heroku login
を事前に実行して .netrc
ファイルの API トークンを設定する必要があります。
Docker イメージ ID の取得
プラットフォーム API を介してイメージをリリースするときに使用される docker イメージの値は、algorithm:hex
形式である必要があります。次に例を示します。
sha256:4d2647aab0e8fbe92cb0fc88c500eb51661c5907f4f14e79efe8bfbda1f7d159
イメージのためにこの ID を取得するには、次のコマンドを実行します。
$ docker inspect my_image --format={{.Id}}
sha256:4d2647aab0e8fbe92cb0fc88c500eb51661c5907f4f14e79efe8bfbda1f7d159
One-off dyno
アプリが複数の Docker イメージから構成されている場合、One-off dyno を作成するときにプロセスタイプを対象にすることができます
$ heroku run bash --type=worker
Running bash on ⬢ multidockerfile... up, worker.5180
$
タイプが指定されていない場合、web
イメージが使用されます。
CI/CD プラットフォームの使用
現在、Heroku CI を使用してコンテナビルドをテストすることはできません。
サードパーティ製の CI/CD プラットフォームを使用している場合は、レジストリにイメージをプッシュできます。最初に次の情報で認証します。
- レジストリ URL:
registry.heroku.com
- ユーザー名:
your Heroku email address
- メール:
your Heroku email address
- パスワード:
your Heroku API key
多くの CI/CD プロバイダーは、イメージをビルドして Docker レジストリにプッシュする方法に関するドキュメントを用意しています。
Release Phase
Release Phase を使用するには、release
という名前の Docker イメージをプッシュします。
$ heroku container:push release
Docker イメージをリリースすると、heroku container:release
を実行することにより、Release Phase プロセスタイプを指定する必要があります。
$ heroku container:release web release
Releasing images web,release to your-app-name... done
Running release command...
Migrating database.
Release Phase が実行するときにストリーミングログを確認する場合は、Docker イメージに curl
が必要です。Docker イメージに curl
が含まれていない場合、アプリケーションログでのみ Release Phase ログを使用できます。
Dockerfile コマンドとランタイム
Docker イメージは、dyno において、slugs が行う方法と同じように同じ制約のもと実行します。
- Web プロセスは、Heroku により設定された
$PORT
上で HTTP トラフィックをリスンする必要があります。Dockerfile
内のEXPOSE
は考慮されませんが、ローカルテストに使用できます。HTTP リクエストだけがサポートされています。 - dyno のネットワークリンクはサポートされていません。
- ファイルシステムは一時的です。
- 作業用ディレクトリは
/
です。WORKDIR
を使用して、別のディレクトリを設定できます。 - 環境変数を設定するための
ENV
がサポートされています。- ランタイム変数 (
GEM_PATH
など) にENV
を、資格情報にheroku config
を使用することをお勧めします。そうすれば、機密性のある資格情報が誤ってソースコード制御にチェックインされることがなくなります。
- ランタイム変数 (
ENTRYPOINT
はオプションです。設定されていない場合、/bin/sh -c
が使用されます。CMD
は常にシェルにより実行されるので、環境設定はプロセスで使用可能になります。単一のバイナリを実行したり、シェルなしでイメージを使用するには、ENTRYPOINT
を使用してください。
コンテナは、Heroku のルート権限で実行されていないので、非ルートユーザーとしてローカルでイメージをテストすることを強くお勧めします。
未サポートの Dockerfile コマンド
VOLUME
- ボリュームマウンティングはサポートされていません。dyno のファイルシステムは一時的です。EXPOSE
-EXPOSE
はローカルテストに使用できますが、Heroku のコンテナランタイムではサポートされていません。代わりに、Web プロセス/コードで $PORT 環境変数を取得する必要があります。STOPSIGNAL
- dyno マネージャーは、SIGTERM 信号とそれに続く SIGKILL 信号を送信することにより、プロセスがグレースフルシャットダウンを行うように要求します。STOPSIGNAL
は考慮されません。SHELL
- Docker イメージのデフォルトのシェルは/bin/sh
であり、必要に応じてENTRYPOINT
で上書きできます。HEALTHCHECK
-HEALTHCHECK
は現在サポートされていませんが、Heroku Dyno マネージャーが自動的に、実行中のコンテナのヘルスを確認します。
ローカルでのイメージのテスト
ローカルでイメージをテストするときに、多数のベストプラクティスがあります。これらのベストプラクティスは、この Dockerfile 例に実装されています。
非ルートユーザーとしてのイメージの実行
コンテナは、Heroku のルート権限で実行されていないので、非ルートユーザーとしてローカルでイメージをテストすることを強くお勧めします。CMD
の直前に、次のコマンドを Dockerfile に追加できます。
Alpine を使用している場合:
RUN adduser -D myuser
USER myuser
Ubuntu を使用している場合:
RUN useradd -m myuser
USER myuser
コンテナが非ルートユーザーとして実行していることを確認するには、実行中のコンテナにアタッチしてから、whoami
コマンドを実行します。
$ docker exec <container-id> bash
$ whoami
myuser
Heroku にデプロイすると、非ルートユーザーとしてもコンテナを実行します (ただし、Dockerfile で指定された USER
は使用しません)。
$ heroku run bash
$ whoami
U7729
環境変数からのポートの取得
テストのために、たとえば次のように、Dockerfile
またはコードが $PORT 環境変数から読み取ることをお勧めします。
CMD gunicorn --bind 0.0.0.0:$PORT wsgi
Docker コンテナをローカルで実行している場合、-e フラグを使用して環境変数を設定できます。
$ docker run -p 5000:5000 -e PORT=5000 <image-name>
複数の環境変数の設定
ローカルで Heroku を使用する場合、.env ファイルで環境設定を設定できます。heroku local
が実行されると、.env が読み取られ、各 name/value のペアが環境で設定されます。Docker を使用するときに、この同じ .env ファイルを使用できます。
$ docker run -p 5000:5000 --env-file .env <image-name>
.env ファイルを .dockerignore ファイルに追加することをお勧めします。
マルチコンテナアプリケーションに対する Docker Compose の利用
マルチコンテナアプリケーションを作成した場合、Docker Compose を使用して、ローカルの開発環境を定義できます。ローカル開発に Docker Compose を使用する方法について説明します。
追加情報
- ローカルでの Docker イメージの実行に関する詳細は、Docker の公式ドキュメントに記述されています。
- ローカル開発に Docker Compose を使用する方法について説明します。
- Docker イメージのビルドパフォーマンスおよびサイズを最適化する方法のヒントについては、Dockerfile を書き込むためのベストプラクティスのガイドを参照してください。
Heroku ベースイメージ
Heroku のスタックは、利便性を向上させるため Docker ベースイメージとして利用できます (Docker イメージの名前とタグについては、各スタックの詳細ページを参照してください)。ただし、ビルドおよび起動時間を最短にするには、アプリの言語についていずれかの公式の Docker イメージなど、より小さい汎用性の低いベースイメージを代わりに使用することを強くお勧めします。
デプロイ方法の変更
Container Registry を介してアプリケーションをデプロイすると、スタックは container
に設定されます。これは、アプリケーションが Heroku-curated スタックを使用しなくなったが、代わりに自身のカスタムコンテナを使用していることを意味します。
アプリに対して Docker イメージを使用する必要がなくなり、Heroku-curated スタックを使用した buildpack ベースのデプロイに切り替えて戻す場合、heroku stack:set
コマンドを使用して、使用可能な heroku-*
スタックの 1 つに切り替えます。詳細は、「新規スタックへの移行」を参照してください。
既知の問題と制限事項
- コンテナスタックを使用しているアプリで、基礎となるベース Docker イメージに対するセキュリティ更新およびバグ修正を取得するためには、アプリを再構築/再デプロイする必要があります。対照的に、Heroku buildpack/slug ベースのデプロイは、基礎となるスタックのベースイメージへの自動更新を受信するため、アプリを再構築/再デプロイする必要はありません。
- Heroku は、
x86_64
イメージのみサポートしています。他のアーキテクチャで実行するように構築されたイメージをアップロードしようとすると、unsupported architecture
エラーが返されます。また、コンテナランタイムで ARM64 などの他のアーキテクチャを使用しようとすると、Exec format
エラーが発生します。コンテナビルダーがx86_64
個のイメージを出力するようにする必要があります。ビルドされたイメージが Heroku 用に正しくビルドされていることを確認するには、Docker ビルドコマンドにプラットフォームフラグを渡します: docker build --platform linux/amd64
。 - Docker イメージをローカルでビルドして、Heroku Container Registry にプッシュするとき、レビューアプリはサポートされません。レビューアプリで Docker を使用するには、Heroku に Docker イメージをビルドできるようにする heroku.yml マニフェストでアプリを定義する必要があります。
- パイプラインのプロモートはサポートされていません。
- Docker イメージは、サイズの制限に従いませんが (slugs) と異なる)、dyno 起動時間の制限に従います。レイヤ数/イメージサイズが大きくなると、dyno 起動時間が長くなります。そのため、40 レイヤを超えるイメージは、Common Runtime での起動時にエラーになる可能性があります。Docker イメージサイズを減らす推奨の方法については、Dockerfile の書き込みのベストプラクティスガイドを参照してください。
- こちらの一覧に記載されている
Dockerfile
コマンドはサポートされていません。 - Private または Shield Space のコンテナアプリでは、dyno を起動するときに
.profile
や.profile.d/*
スクリプトが実行されません。 - 実行時に Docker イメージが抽出される仕組みが原因で、(以前の Docker イメージレイヤのファイルが後のレイヤーで削除されたときに作成される) ホワイトアウトファイルは受け入れられません。Common Runtime でのみ、
heroku labs:enable runtime-new-layer-extract
を使用して、これを解決する新しい抽出方法に切り替えることができます。現在、Private Space での回避策はありません。 - 回避策を適用しない限り、
heroku run
の--exit-code
引数はサポートされていません。 - 既存のアプリをコンテナスタックに移行し、移行と同時にアプリのプロセス名を変更した場合、手動でクリーンアップするまで古いプロセスの dyno が残り続ける可能性があります。これを避けるには、(移行と同時にではなく) コンテナスタックの移行の前後にプロセス名を変更するか、移行中に古いプロセスをスケールダウンします。
- コンテナスタックを使用しているアプリが (ローカルではなく) Heroku のビルドシステムを使用してビルドされる場合、heroku.yml コンテナビルドの既知の問題と制限も適用されます。