Heroku で Apache HTTP Server コンテナをそのまま動かそうとすると crash するのを解決したメモ


結論から言うと

  • Heroku ではコンテナに外部からのアクセスを受け付けるポートを動的に割り振っている
  • ので、httpd.conf に Listen するポート番号を固定で記述してしまうと疎通できない
  • Heroku が動的に割り振っているポート番号は環境変数 $PORT として取得できる
  • Dockerfile 内の ENTRYPOINT 実行タイミングで Listen ディレクティブを $PORT の値に編集するコマンドを実行してやるとなんとかなる

コンテナをpushしただけだとエラーになる

例えば Dockerfile はこんな感じ。

FROM httpd:alpine
MAINTAINER xsgk

ADD ./index.html /usr/local/apache2/htdocs

これのデプロイを行うと、

State changed from starting to crashed

とか

(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80
(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down

とか、もうエラーの大合唱。bind ができないってことは何かそもそも接続できてないね、と思ってるとこんなのを stackoverflow で見つけた。同じく Apache の httpd を使って接続できないという状況を以下のとおり解決したとのこと。

Deploy a Dockerized Laravel app using Apache on Heroku

I discovered I could insert a CMD statement at the end of my Dockerfile to sed replace the ports in my apache config files to the magical $PORT environment variable at run time.

(意訳)

Dockerfile の終わりに CMD ステートメントを挿入するかたちで、sed コマンドで Apache コンフィグファイル中のポート指定を、ランタイムの $PORT 環境変数の値に置換できることを発見したんだ

なるほど、やってみよう。

$PORT の値に書き換える処理を Dockerfile に追加した

今度の Dockerfile はこんな感じで、ENTRYPOINT が実行されるタイミングで http.conf 中の Listen ディレクティブを置換(sed)したのち、本来のコンテナ起動時のコマンド(httpd-foreground)を実行するよう記述。

FROM httpd:alpine
MAINTAINER xsgk

ADD ./index.html /usr/local/apache2/htdocs

ENTRYPOINT []
CMD sed -i -e "s/Listen 80/Listen $PORT/g" /usr/local/apache2/conf/httpd.conf && httpd-foreground

これをデプロイすると

出た。以上。

参考

Deploy a Dockerized Laravel app using Apache on Heroku