【失敗談】Apacheのコンテナが立ち上がらないエラー解決
EC2インスタンス内のhttpd.confをDocker環境でそのまま使おうとしてエラーになりました。
以下のようにローカルの./apache/conf.d/httpd.confをコンテナの/usr/local/apache2/conf/httpd.conf にボリュームマウントしました。
volumes:
- ./apache/conf.d/httpd.conf:/usr/local/apache2/conf/httpd.conf
ローカルのhttpd.confには、EC2のhttpd.confをそのままコピーして貼り付けました。
その状態でdocker compose up -d --buildを実行すると、以下のエラーが出ました。
httpd: Syntax error on line 34 of /usr/local/apache2/conf/httpd.conf: ServerRoot must be a valid directory
/usr/local/apache2/conf/httpd.confはコンテナ内のhttpd.confです。その34行目で間違いが指摘されています。
docker exec -it [コンテナID] bashでログインして見に行こうとしましたが、コンテナが動いていないので拒否されました。
Error response from daemon: Container 2e60e217d98bd88d7fa1b03d74229893b317f406fc1836a39282e59b1d9765a4 is not running
そんなときはdocker run --entrypointで、動いていないコンテナに入ることができます。
docker run -it --entrypoint /bin/bash -v $(pwd)/apache/conf.d/httpd.conf:/usr/local/apache2/conf/httpd.conf httpd:latest
エントリーポイントとは、Dockerが起動する際のメインのコマンドやプロセスのことです。
デフォルトの設定では、ApacheコンテナのエントリーポイントはCMD ["httpd-foreground"]です。
それをdocker run -it --entrypoint /bin/bashで一時的にbashに上書きしています。
Apacheコンテナに入って/usr/local/apache2/conf/httpd.confを確認すると、指摘されたのは以下の箇所でした。
ServerRoot "/etc/httpd"
ServerRootには、apache関連ファイルの最上位のディレクトリ(要はApacheがある場所)を指定する必要があります。
EC2ではApacheは/etc/httpdにあったのですが、Dockerコンテナでは/usr/local/apache2にあります。
# EC2
ServerRoot "/etc/httpd"
# Dockerコンテナ
ServerRoot "/usr/local/apache2"
httpd: Syntax error on line 61 of /usr/local/apache2/conf/httpd.conf: Include/IncludeOptional: Could not open directory /usr/local/apache2/conf.modules.d: No such file or directory
コンテナのhttpd.confにInclude conf.modules.d/*.confがあり、モジュール設定ファイルの読み込みに失敗しています。
/usr/local/apache2/conf.modules.dを探しに行って「そんなファイルはないよ」と言われています。
実際確認してみると、確かにありませんでした。
root@434977c744b1:/usr/local/apache2/conf# ls
extra httpd.conf magic mime.types original
EC2のほうで確認するとありました。conf.modules.dの中には複数の設定ファイルがあり、そこでさまざまなモジュールがあります。
[user@ip-10-0-0-13 httpd]$ ls
conf conf.d conf.modules.d logs modules run state
[user@ip-10-0-0-13 conf.modules.d]$ ls
00-base.conf 00-dav.conf 00-mpm.conf 00-proxy.conf 01-cgi.conf 10-proxy_h2.conf
00-brotli.conf 00-lua.conf 00-optional.conf 00-systemd.conf 10-h2.conf README
Dockerコンテナでは、/usr/local/apache2/modules下にモジュールがあります。
これらのモジュールを使えるようにするため、Include /usr/local/apache2/modulesとしてみます。
これによって次のエラーが生じました。
httpd: Syntax error on line 62 of /usr/local/apache2/conf/httpd.conf: Syntax error on line 453 of /usr/local/apache2/modules/mod_access_compat.so: /usr/local/apache2/modules/mod_access_compat.so:453: <\x14> was not closed.
mod_access_compat.soの中身を見てみると、人は読めないコードでした。
mod_access_compat.soのエラー解決だけでも難しく、これを解決したとしても他のモジュールでもエラーが生じ、キリがなくなりそうだと思いました。
ここで私が考えたことは以下2つです。
- モジュールを使えるようにする設定が間違っているのではないか?
- EC2の設定ファイルの内容を丸ごとボリュームマウントするから様々なエラーが出てしまうのではないか?
いったんボリュームマウントをコメントアウトしてdocker compose upしてみると、Apacheコンテナが正常に起動されました。
Apacheコンテナにログインして/usr/local/apache2/conf/httpd.confを確認してみると、ServerRootやaccess_compat_moduleが正しく設定されていました。
ServerRoot "/usr/local/apache2"
LoadModule access_compat_module modules/mod_access_compat.so
ここまでの確認で、1.はわかりませんが、2.の予想は正しそうです。
EC2のhttpd.confとDockerのhttpd.confは違いがあるので、EC2のhttpd.confでコンテナ内にボリュームマウントしないほうがよいですね。
そもそもなぜボリュームマウントしようとしたかというと、リバースプロキシの設定をするためでした。
EC2では、以下のようにApacheをリバースプロキシ化する設定を行いました。
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
ProxyRequests Off
ProxyPass / http://0.0.0.0:3000/
ProxyPassReverse / http://0.0.0.0:3000/
丸ごと上書きするのではなく、リバースプロキシの部分だけ追加すべきでした。
コンテナ内のhttpd.confを確認したところ、デフォルトでproxy_moduleとproxy_http_moduleがあったので、ProxyRequests ProxyPass ProxyPassReverseだけ追加すればよさそうです。
docker compose up -d --buildを実行する時に、apacheコンテナをhttpd-foregroundで実行する前に、/usr/local/apache2/conf/httpd.confに以下3行を追加します。(railsはdocker-composeのサービス名での指定です)
3行追加する用のシェルスクリプトを作成し、docker-compose.yamlのなかのApacheサービスのcommandで実行させました。
#!/bin/sh
echo 'ProxyRequests Off' >> /usr/local/apache2/conf/httpd.conf
echo 'ProxyPass / http://rails:3000/' >> /usr/local/apache2/conf/httpd.conf
echo 'ProxyPassReverse / http://rails:3000/' >> /usr/local/apache2/conf/httpd.conf
httpd-foreground
services:
apache:
image: httpd:latest
ports:
- :80:80
volumes:
- ./apache/conf.d/start-apache.sh:/usr/local/bin/start-apache.sh
depends_on:
- rails
command: /usr/local/bin/start-apache.sh
しかしこの方法はうまくいきませんでした。次のエラーが出ました。
AH00526: Syntax error on line 552 of /usr/local/apache2/conf/httpd.conf:Invalid command 'ProxyRequests', perhaps misspelled or defined by a module not included in the server configuration
なんでproxy_moduleとproxy_http_moduleが存在するのにエラーになるのだろう?と思ってhttpd.confをよく見ると、どっちもコメントアウトになっていました。
わざわざコマンドでコメントアウトを削除するのも面倒ですし、コメントアウトとはいえ存在するのに追加して重複になるのも避けるべきと考えました。
そのため、結局何もしないでdocker compose upで起動して、Apacheコンテナが起動した状態でhttpd.confをcatコマンドで表示させて、それをローカルのhttpd.confにコピペして、そこにさっきの5行を追加しました。(コメントアウトの2行は削除して)
最終的にdocker-compose.yamlは以下となりました。
当初のボリュームマウントはEC2の内容をコンテナに反映していましたが、下のはリバースプロキシ部分を適用するためです。
version: '3'
services:
apache:
image: httpd:latest
ports:
- :80:80
volumes:
- ./apache/conf.d/httpd.conf:/usr/local/apache2/conf/httpd.conf
depends_on:
- rails
command: httpd-foreground
rails:
build: .
command: rails s -b 0.0.0.0
ports:
- 3000:3000
volumes:
- .:/ocr_check_app
個人的にいちばんの学びはdocker run --entrypointで、動いてないコンテナに入ってファイルを確認できるところです。
Discussion