神戸学院大学 経営学部 林坂ゼミ

Docker 入門トップページ

« 戻る 次へ »

Docker 入門

さまざまな Web サーバを Docker Compose で構築する

nginx のリバースプロキシ,および Apache のバーチャルホストの組合せで /site-a/ と /site-b/ を運用する

前のページまでは1個のサービスだけで Web サーバ環境を構築していました.ここでは複数のサービスを連携させる例を試します.具体的には http://localhost/site-a/ と http://localhost/site-b/ でそれぞれ独立した別のコンテンツを提供するサイトを構築します.また,それ以外の http://localhost/ でも別のコンテンツを提供します.これらのサイトは apache コンテナのバーチャルホストとして設定します.さらに apache コンテナに HTTP リクエストを転送するためのリバースプロキシを nginx で構築します.なお,このページのサンプルコードは GitHub の web04NginxApache フォルダで公開しています.

web-204

まず,例によって任意の新規ディレクトリを作成し,その中に次の構成でディレクトリとファイルを設置します.

% tree -a -F ⏎
./
├── apache/
│   └── conf/
│       └── httpd.conf
├── docker-compose.yml
├── nginx/
│   └── conf.d/
│       └── default.conf
├── Readme.md
└── web/
    ├── html7000/
    │   └── index.html
    ├── html8000/
    │   └── index.html
    ├── html9000/
    │   └── index.html
    └── logs/
        ├── apache/
        │   ├── .gitignore
        │   ├── access_log
        │   └── error_log
        └── nginx/
            ├── .gitignore
            ├── access.log
            └── error.log

12 directories, 13 files

まず,全体の設計図である docker-compose.yml を作成します.次の通り,apache と nginx の2個のサービスで構成されていることに注意してください.また,apache サービスについては5〜8行目では exporse を使って 7000,8000,9000 番ポートを Dokcer 内部ネットワークに公開しています.一方で,nginx に関する19〜20行目では port を使って 80 番ポートへの通信を受け付けるようにしています.つまり,80 番ポートは外部に公開し,7000, 8000, 9000 番ポートは外部には公開せず,Docker のコンテナ間通信でのみ利用されるということを意味しています.

docker-compose.yml
services:
  apache:
    image: httpd:latest
    container_name: apache4
    expose:
      - "7000:7000"
      - "8000:8000"
      - "9000:9000"
    volumes:
      - ./apache/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
      - ./web/html7000:/usr/local/apache2/htdocs7000/
      - ./web/html8000:/usr/local/apache2/htdocs8000/
      - ./web/html9000:/usr/local/apache2/htdocs9000/
      - ./web/logs/apache:/usr/local/apache2/logs/

  nginx:
    image: nginx:latest
    container_name: nginx4
    ports:
      - "80:80"
    depends_on:
      - apache
    volumes:
      - ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
      - ./web/logs/nginx:/var/log/nginx

次にリバースプロキシとして運用する nginx の設定を行います.次の通り nginx/conf.d/default.conf を作成します.2行目では 80 番ポートへの通信を受け付ける設定としています.5行目からのブロックでは,http://localhost/site-a/ 以下の HTTP リクエストを apache サービスの 8000 番ポートに転送する設定が記載されています.ここで,apache サービスの名称は docker-compose.yml の2行目で定義されたサービス名 apache と一致させていることに注意してください.同じように,13行目からのブロックでは http://localhost/site-b/ 以下の HTTP リクエストを apache サービスの 9000 番ポートに転送し,21行目からはそれ以外の HTTP リクエストを 7000 番ポートに転送する設定としています.

nginx/conf.d/default.conf
server {
    listen 80;
    server_name localhost;

    location /site-a/ {
        proxy_pass http://apache:8000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /site-b/ {
        proxy_pass http://apache:9000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
        proxy_pass http://apache:7000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

続いて apache の設定を行います.nginx からは内部ネットワークを通じて apache の 7000, 8000, 9000 番ポートへ転送されることから,4〜6行目でそれらのポートへの通信を受け付けるようにします.加えて,115行目以降でそれぞれのポートへの処理を担当するバーチャルホストの設定を行います.さらに,ログファイルにポート番号も出力される設定を 69〜70 行目で行います.

apache/conf/httpd.conf
ServerRoot "/usr/local/apache2"

#Listen 12.34.56.78:80
Listen 7000
Listen 8000
Listen 9000

LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so

<IfModule unixd_module>
User www-data
Group www-data
</IfModule>

# 'Main' server configuration

ServerAdmin you@example.com

#ServerName www.example.com:80


<Directory />
    AllowOverride none
    Require all denied
</Directory>


# DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>

<Files ".ht*">
    Require all denied
</Files>

ErrorLog "logs/error_log"

LogLevel warn

<IfModule log_config_module>
    # LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %{local}p" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>

    CustomLog "logs/access_log" combined
</IfModule>

<IfModule alias_module>
    ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
</IfModule>

<IfModule cgid_module>
    #Scriptsock cgisock
</IfModule>

<Directory "/usr/local/apache2/cgi-bin">
    AllowOverride None
    Options None
    Require all granted
</Directory>

<IfModule headers_module>
    RequestHeader unset Proxy early
</IfModule>

<IfModule mime_module>
    TypesConfig conf/mime.types

    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
</IfModule>


<IfModule proxy_html_module>
Include conf/extra/proxy-html.conf
</IfModule>

<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>

<VirtualHost *:7000>
    DocumentRoot "/usr/local/apache2/htdocs7000"
    <Directory "/usr/local/apache2/htdocs7000">
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:8000>
    DocumentRoot "/usr/local/apache2/htdocs8000"
    <Directory "/usr/local/apache2/htdocs8000">
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>


<VirtualHost *:9000>
    DocumentRoot "/usr/local/apache2/htdocs9000"
    <Directory "/usr/local/apache2/htdocs9000">
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

引き続いて Web サイトのコンテンツを準備します.まず,web/html7000/index.html にはトップページ http://localhost/ のコンテンツを作成します.

web/html7000/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Apache</title>
</head>
<body>
  <h1>Hello Apache</h1>
  <p>
    Hello Apache
  </p>
  <p>
    このサイトはNginxのリバースプロキシとApacheのバーチャルホストを使って,3つの異なるサイトとしてサービスを提供しています.
  </p>
  <h2>リンク</h2>
  <ul>
    <li><a href="/">トップページ</a>(このページ)</li>
    <li><a href="/site-a/">Site-A</a></li>
    <li><a href="/site-b/">Site-B</a></li>
  </ul>
</body>
</html>

さらに http://localhost/site-a/ で提供するコンテンツを web/html8000/index.html に設置します.

web/html8000/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Apache</title>
</head>
<body>
  <h1>Hello Apache</h1>
  <p>
    Hello Apache Site-A
  </p>
  <p>
    このサイトはNginxのリバースプロキシとApacheのバーチャルホストを使って,3つの異なるサイトとしてサービスを提供しています.
  </p>
  <h2>リンク</h2>
  <ul>
    <li><a href="/">トップページ</a></li>
    <li><a href="/site-a/">Site-A</a>(このページ)</li>
    <li><a href="/site-b/">Site-B</a></li>
  </ul>
</body>
</html>

Site-B http://localhost/site-b/ のコンテンツは web/html9000/index.html に設置します.

web/html9000/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Apache</title>
</head>
<body>
  <h1>Hello Apache</h1>
  <p>
    Hello Apache Site-B
  </p>
  <p>
    このサイトはNginxのリバースプロキシとApacheのバーチャルホストを使って,3つの異なるサイトとしてサービスを提供しています.
  </p>
  <h2>リンク</h2>
  <ul>
    <li><a href="/">トップページ</a></li>
    <li><a href="/site-a/">Site-A</a></li>
    <li><a href="/site-b/">Site-B</a>(このページ)</li>
  </ul>
</body>
</html>

アクセスログは nginx と apache で独立して取得することになります.いずれもディレクトリを作成したうえで docker-compose.yml でボリュームとして設定しているので,ログファイルは自動的に作成されます.しかしながら,ログファイルが Git のリポジトリに登録されないように web/logs/apache/.gitignore および web/logs/nginx/.gitignore を作成します.

web/logs/apache/.gitignore および web/logs/nginx/.gitignore
*

すべてのファイルの準備ができたら Docker イメージを確認しておきます.これまでの作業で nginx と httpd (apache) のイメージがダウンロードされていることが分かります.(イメージが存在しなくても構いません.)

% docker image ls ⏎
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    17848b7d08d1   5 weeks ago   198MB
httpd        latest    8875809932eb   6 weeks ago   147MB
%

次のコマンドでコンテナを起動します.ここで2つのコンテナをまとめて起動できたことに注意してください.

% docker compose up -d ⏎
[+] Running 3/3
 ✔ Network web04nginxapache_default  Created                      0.0s
 ✔ Container apache4                 Started                      0.1s
 ✔ Container nginx4                  Started                      0.2s
%

コンテナの起動状態を確認します.コンテナ名 nginx4 が TCP 80 番ポートを受け付けていることに注意してください.

% docker container ls ⏎
CONTAINER ID   IMAGE          COMMAND                   CREATED          STATUS          PORTS                                 NAMES
b3f1f0a7b3e4   nginx:latest   "/docker-entrypoint.…"   15 seconds ago   Up 15 seconds   0.0.0.0:80->80/tcp, [::]:80->80/tcp   nginx4
d02d1a83d777   httpd:latest   "httpd-foreground"        15 seconds ago   Up 15 seconds   0/tcp, 80/tcp                         apache4
%

コンテナが起動できたので,Web ブラウザで http://localhost/ にアクセスします.ブラウザからのリクエストは nginx のリバースプロキシを経由して apache のバーチャルホストへ転送されていることに注意してください.

docker-2025-web-06

次に,http://localhost/site-a/ や http://localhost/site-b/ にアクセスします.

docker-2025-web-07
docker-2025-web-08

動作確認が終わればコンテナを終了させ同時に廃棄します.このときも1つのコマンドだけで複数のコンテナをまとめて操作できていることに注意してください.

% docker compose down ⏎
[+] Running 3/3
 ✔ Container nginx4                  Removed                           0.2s
 ✔ Container apache4                 Removed                           1.1s
 ✔ Network web04nginxapache_default  Removed                           0.2s
% docker container ls -a ⏎
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
%

このページでは1個の apache コンテナ上で複数のバーチャルホストを構築しました.このため,例えば site-a のバーチャルホストにおいてトラブルが起こったり設定を変更するなどしてコンテナが停止したり再起動している間は,site-b やトップページも Web サービスが停止することに注意してください.次のページでは apache のバーチャルホストではなく,複数の apache コンテナを起動して全体としては同様のサービスを設定します.