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 フォルダで公開しています.
まず,例によって任意の新規ディレクトリを作成し,その中に次の構成でディレクトリとファイルを設置します.
% 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 のバーチャルホストへ転送されていることに注意してください.
次に,http://localhost/site-a/ や http://localhost/site-b/ にアクセスします.
動作確認が終わればコンテナを終了させ同時に廃棄します.このときも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 コンテナを起動して全体としては同様のサービスを設定します.