Edited at
HerokuDay 4

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

この記事は、 Heroku Advent Calendar 2017 4日目の記事です

(dev center の記事を私訳します。 2017/11/23 最終更新の記事)

(Last updated 02 May 2019 の記事に追従 (2019/05/30))


Heroku Container Registry では、Docker ベースのアプリケーションを Heroku にデプロイすることができます

Common RuntimePrivate 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 を利用してください




ローカルでの 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の使い方はこちら


参考情報


images をスタックする

Heroku-16Heroku-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 はサポートされません


  • このコマンドリストはサポートされません