Heroku
docker
かしゆか
HerokuDay 23

Heroku で Docker を使う場合の諸注意

本日、かしゆかの誕生日です、どうぞみなさまお祝いください。

さて、本日の内容です。

Container Registry が GA になったよ!!

2017/9/5 の changelog で Container Registry GA - Deploy Docker images to Herokuと公開されたとおり、これまでβサービスとして提供されていた Docker 向けコンテナサービスが、本番向けにリリースされました。

これまで buildpack の制約や、docker でせっかく準備した開発サイクルのために、Herokuの利用を躊躇されていたみなさまには、朗報です。はやいところ、Heroku Pipelines 上で Heroku CI つかって、Docker のCI/CD まわしたいですね!! Heroku は世界を支配しますよ!!
(もしかすると、https://devcenter.heroku.com/articles/heroku-yml-build-manifest これ使うと、Pipelines も Review Apps もいけるかもしれないんですが、いまテスト中です。ややこい)

とは言え、Docker完全サポートではありません。Dockerで動きさえすればHeroku上でも動く、というわけでは残念ながらありません。Docker を Heroku上で動かすためには、いくつかの注意事項がありますので、そちらをご紹介します。

前提条件

Docker を Heroku上で動かすためには、最低限の条件が3点あります。

  1. Heroku アカウントを持っていること
  2. Heroku CLI コマンドを導入して、利用可能にしていること
  3. docker コマンドを導入して、利用可能なこと

現時点では、Dockerイメージを Heroku 上にデプロイするためには CLIが必須です。また、ローカルでdockerコマンドを実行して制御するため、Docker コマンドが必須です。Docker 使おうってんだから、みんな入ってるはずですけど。

デプロイの流れとコマンド

実際に、ローカルに準備した Dockerfile をHeroku上へデプロイする場合の流れは、次のとおりになります。すべて、コマンドで実行した場合です。一部、GUIでも実行可能な部分については、その旨を追記しています。

  1. heroku login で、Heroku アカウントへログインさせます。
  2. heroku container:login で、Heroku 上の Container Registry へログインします。
  3. heroku create で、Docker を動かすための Herokuアプリを作成します(GUIでも可)。
  4. heroku addons:create で、必要なアドオンを追加します(GUIでも可、アドオン不要なら実行不要)。
  5. heroku container:push <process-type> で、ローカルの Dockerfile もろもろをデプロイします。
  6. docker のイメージが作成され、Heroku 上で動作するように配置されます。
  7. heroku open で、デプロイされたアプリへ、ブラウザでアクセスします(GUIでも可)。

設定・デプロイ上の注意事項

とまぁ、コマンドがちょっとちがうものの、HerokuへのDockerデプロイは、それほど困難はありません。ただ、Heroku固有の制約があります。それらについて説明します。

  1. PORT 環境変数で Listen する Webアプリケーションであること
  2. Network link は未サポート
  3. Default working directory = '/'。変更するときは WORKDIR を指定する。
  4. CMDが必須。ENTRYPOINTはオプション。
  5. VOLUMEEXPOSESTOPSIGNALSHELLHEALTHCHECKは未サポート

Heroku は Webアプリケーションを動かすためのプラットフォームです。また、環境変数 PORT で指定されたポートで LISTENしていないと、「こりゃ不適合アプリだな」としてアプリをクラッシュさせて停止します。厳密には、PORT 変数で LISTENさえしていれば、Web応答をするかどうかに関係なく実行はできるようです(2017/12/18現在)

したがって、ポート番号を強制するようなEXPOSEも利用できませんし、そもそも外部のファイルデバイスを利用するという仕組みのないHerokuでは、VOLUME も利用できないということになります。

ENTRYPOINT はオプション指定ですが、何も指定していなければ自動的に /bin/sh -c が指定されます。

複数のイメージを push するには

ディレクトリごとにDockerfileを準備して、個別にも、いっぺんにでも、まとめてHerokuアプリへpushできます。例えば、次のようなディレクトリ構成だとします。

directory
web/
 +- Dockerfile.web

worker-dyno/
 +- Dockerfile.worker

worker-test/
 +- Dockerfile.test

heroku container:push--recursive を付与して実行します。

push
heroku container:push --recursive

この場合、web worker-dyno worker-test にある全ての Dockerfile のイメージが作成され、一つずつが Dyno として Heroku アプリ上に作られます。この場合では、3つの Dynoが作られるということですね。

ディレクトリ名はなんでもいいんですが、Dockerfile のあとは重要な識別子になります。これが Dyno のプロセスタイプになります。Heroku は Web Dyno が必要で、それが Webアプリとして実行される Dyno になります。その他のプロセスタイプの場合は、Worker Dynoとして定義され、バックエンドで実行させることができるようになります。

今回のケースだと、web 「Web Dyno」 一つと worker test という2つの「Worker Dyno」がデプロイされるということになります。このプロセスタイプを、Dockerfile のあとに「.」をつけて付与する必要があります。ただの「Dockerfile」では認識されませんので、お気をつけください。

また、push時にデプロイするプロセスタイプを指定できます。例えば、webtest だけデプロイしたい、ということであれば。

push
heroku container:push web test --recursive

と指定することになります。この場合でも --recursive は必要ですのでお忘れなく。

※ Herokuチームにはさんざんレビューいただいて、ホント感謝です。

参考

Container Registry & Runtime (Docker Deploys)