😺

【失敗談】Apacheのコンテナが立ち上がらないエラー解決

2024/07/24に公開

EC2インスタンス内のhttpd.confをDocker環境でそのまま使おうとしてエラーになりました。
以下のようにローカルの./apache/conf.d/httpd.confをコンテナの/usr/local/apache2/conf/httpd.conf にボリュームマウントしました。

docker-compose.yaml
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を確認すると、指摘されたのは以下の箇所でした。

httpd.conf(Dcoker)
ServerRoot "/etc/httpd"

ServerRootには、apache関連ファイルの最上位のディレクトリ(要はApacheがある場所)を指定する必要があります。
EC2ではApacheは/etc/httpdにあったのですが、Dockerコンテナでは/usr/local/apache2にあります。

httpd.conf(Dcoker)
# 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.confInclude conf.modules.d/*.confがあり、モジュール設定ファイルの読み込みに失敗しています。
/usr/local/apache2/conf.modules.dを探しに行って「そんなファイルはないよ」と言われています。
実際確認してみると、確かにありませんでした。

Apacheコンテナ
root@434977c744b1:/usr/local/apache2/conf# ls
extra  httpd.conf  magic  mime.types  original

EC2のほうで確認するとありました。conf.modules.dの中には複数の設定ファイルがあり、そこでさまざまなモジュールがあります。

EC2
[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つです。

  1. モジュールを使えるようにする設定が間違っているのではないか?
  2. EC2の設定ファイルの内容を丸ごとボリュームマウントするから様々なエラーが出てしまうのではないか?

いったんボリュームマウントをコメントアウトしてdocker compose upしてみると、Apacheコンテナが正常に起動されました。

Apacheコンテナにログインして/usr/local/apache2/conf/httpd.confを確認してみると、ServerRootaccess_compat_moduleが正しく設定されていました。

httpd.conf(Docker)
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をリバースプロキシ化する設定を行いました。

httpd.conf(EC2)
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_moduleproxy_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で実行させました。

start-apache.sh
#!/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
docker-compose.yaml
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_moduleproxy_http_moduleが存在するのにエラーになるのだろう?と思ってhttpd.confをよく見ると、どっちもコメントアウトになっていました。

わざわざコマンドでコメントアウトを削除するのも面倒ですし、コメントアウトとはいえ存在するのに追加して重複になるのも避けるべきと考えました。

そのため、結局何もしないでdocker compose upで起動して、Apacheコンテナが起動した状態でhttpd.confcatコマンドで表示させて、それをローカルのhttpd.confにコピペして、そこにさっきの5行を追加しました。(コメントアウトの2行は削除して)

最終的にdocker-compose.yamlは以下となりました。
当初のボリュームマウントはEC2の内容をコンテナに反映していましたが、下のはリバースプロキシ部分を適用するためです。

docker-compose.yaml
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