- はじめに
- Nginx でロードバランサを構成する
- ロードバランサとWebサーバの起動
- Web アプリケーションの準備
- Docker でアプリケーションをビルドする
- DBサーバの準備
- ロードバランサとアプリケーションサーバの起動
- まとめ
はじめに
前回は Docker のインストールからイメージビルド・コンテナ起動・Compose までの流れをみてきました。
今回は以下のような、一般的な Web アプリケーションの開発環境を構築していきます。
前回の記事とあわせて、Docker の活用方法を理解いただければと思います。
Nginx でロードバランサを構成する
最初に、単純な Web サーバを Nginx でロードバランシングする環境を作成して動作を見てみます。
このような構成となります。
作業フォルダを作成しましょう。
$ mkdir web-app $ cd web-app
最初に Nginx でバランシングする Webサーバを準備します。
Webサーバ1号機の作成
以下のように簡単なページを準備します。
$ mkdir -p nginx1 $ cat <<EOF > nginx1/index.html <!DOCTYPE html> <html><body><h1>Hello nginx1</h1></body></html> EOF
docker-compose.yml
では以下のような指定になるでしょう(後ほど作成するためここでは記載例のみ示します)。
nginx2: container_name: "nginx1" image: nginx volumes: - ./nginx1:/usr/share/nginx/html
Webサーバ2号機の作成
同じように2号機を作成します。
$ mkdir -p nginx2 $ cat <<EOF > nginx2/index.html <!DOCTYPE html> <html><body><h1>Hello nginx2</h1></body></html> EOF
docker-compose.yml
では以下のような指定になるでしょう。
nginx1: container_name: "nginx2" image: nginx volumes: - ./nginx2:/usr/share/nginx/html
ロードバランサの作成
HAProxy などでも良いですが、今回は Nginx でロードバランサを作成していきます。
proxy
ディレクトリを作成し、Nginx の設定ファイルである default.conf
を作成します。
$ mkdir proxy $ touch default.conf
default.conf
は以下のように編集します。
upstream backend { server nginx1; server nginx2; } server { listen 80; server_name localhost; location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for; proxy_pass http://backend; } }
ロードバランサとして利用するためupstream
ディレクティブに backend
という名前を付けて内側のWebサーバを指定します。先ほど作成した Web サーバのサービス名を指定します。
compose で起動した場合は同じネットワークに属するため、サービス名での参照が可能となります。
server
ディレクティブでは proxy_pass
にbackend
を指定して、/
でのアクセスをバックエンドサーバへ転送する設定とします。
また、proxy_set_header
で X-
系のヘッダを付与するようにしています。
default.conf
について少し補足しておきます。
nginxの設定ファイルは、/etc/nginx/nginx.conf
にあり、以下のようになっています(大部分を省略しています)。
http { ... include /etc/nginx/conf.d/*.conf; server { ... include /etc/nginx/default.d/*.conf; } }
http
ディレクティブで /etc/nginx/conf.d/*.conf
というパスで設定がインクルードされています。
上記で作成した default.conf
はここからインクルードされるため、http
ディレクティブの要素として定義されることになります。
ロードバランサとWebサーバの起動
web-app
ディレクトリ配下に以下の内容で docker-compose.yml
を作成します。
$ touch docker-compose.yml
以下のように編集します。
version: '3' services: proxy: container_name: "proxy" image: nginx ports: - "80:80" volumes: - ./proxy/default.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - nginx1 - nginx2 nginx1: container_name: "nginx1" image: nginx volumes: - ./nginx1:/usr/share/nginx/html nginx2: container_name: "nginx2" image: nginx volumes: - ./nginx2:/usr/share/nginx/html
proxy
と各 Web サーバを起動しているだけです。
ここまででのディレクトリ構成は以下のようになりました。
では早速実行してみましょう。
$ docker-compose up
各サービスが起動したら http://localhost
でアクセスします。
リロードを行うことで、ラウンドロビンでバランシングされていることが分かります。
ここでは nginx
イメージからロードバランサを作成していますが、jwilder/nginx-proxy
というロードバランサ用のイメージを利用することで、Nginx の設定を行うことなくロードバランサを構築することもできます。
詳しくは触れませんが jwilder/nginx-proxy
を利用した場合の docker-compose.yml
のサンプルは以下のようになります。
version: '3' services: nginx-proxy: image: jwilder/nginx-proxy ports: - "80:80" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro whoami: image: jwilder/whoami environment: - VIRTUAL_HOST=whoami.local
VIRTUAL_HOST
を設定しておけば、自動で(docker-genで設定ファイルが自動生成される)バランシングしてくれます。
Web アプリケーションの準備
Nginx で簡単なWebページの作成ができたので、次は Web アプリケーションを動かしてみましょう。
以下のような構成となります。
アプリケーションは Spring Boot のサンプルアプリケーショである Spring Petclinic を利用しましょう。
app
ディレクトリを作成し、git clone
でソースを取得します。
$ mkdir app $ cd app $ git clone https://github.com/spring-projects/spring-petclinic.git
今回は、Docker でDBサーバを作るため、取得したソースの MySql の接続設定を編集します。
spring-petclinic/src/main/resources/application-mysql.properties
を以下のように変更します。
# database init, supports mysql too database=mysql spring.datasource.url=jdbc:mysql://mysql/petclinic spring.datasource.username=root spring.datasource.password=petclinic # Uncomment this the first time the app runs spring.datasource.initialization-mode=always
データソースURLを、後ほど作成するサービス名のmysql
に変更しています。
Docker でアプリケーションをビルドする
プロジェクトのビルドも Docker でやりましょう。
maven
イメージが公開されているので、Maven がインストールされていなくても、以下のコマンドでビルドできます。
ビルドは以下のコマンドで行えます。
$ docker run -it --rm --name my-maven-project -v "$(pwd)/spring-petclinic":/usr/src/mymaven -w /usr/src/mymaven maven:3.6.2-jdk-8 mvn package
とは言っても Maven の依存のダウンロードで時間がかかります(手元の環境で10分程)。
上記コマンドでビルドした場合、ビルド時にダウンロードした依存ファイルは再利用できません。ビルドを繰り返す場合は、データボリュームを使うと便利です。
以下で maven-repo
という名前でデータボリュームを作成します。
$ docker volume create --name maven-repo
maven-repo
を /root/.m2
にマウントして実行します。
$ docker run -it --rm --name my-maven-project -v maven-repo:/root/.m2 -v "$(pwd)/spring-petclinic":/usr/src/mymaven -w /usr/src/mymaven maven:3.6.2-jdk-8 mvn package
初回は依存のダウンロードで少し時間がかかりますが、次回からは maven-repo
にダウンロードした依存ファイルが使われるためすぐにビルドが完了します。
... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 58.010 s [INFO] Finished at: 2019-00-00T00:00:00Z [INFO] ------------------------------------------------------------------------
以上のようにビルドが完了しました。
ビルドした成果物は /app/spring-petclinic/target
に jar ファイルが作成されるので、アプリケーションの実行は以下のように行えます。
app: container_name: app image: openjdk:8 volumes: - ./app/spring-petclinic/target:/usr/src/app command: bash -c "cd /usr/src/app && java -Dspring.profiles.active=mysql -jar *.jar"
openjdk:8
というイメージで Java8 の実行環境が手に入るため、あとは java
コマンドで起動するだけです。
java
コマンドの引数で -Dspring.profiles.active=mysql
としてプロファイルを指定します。
実際の docker-compose.yml
は後述します。
DBサーバの準備
先ほど編集した application-mysql.properties
で定義した接続先のDBサーバを準備します。
といっても、application-mysql.properties
で spring.datasource.initialization-mode=always
と指定しているため、データベースの準備や初期データ登録は自動的に行われるため、コンテナを起動するだけです。
docker-compose.yml
の指定は以下のようになるでしょう。
mysql: container_name: mysql image: mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=petclinic - MYSQL_DATABASE=petclinic
ロードバランサとアプリケーションサーバの起動
web-app
ディレクトリ直下の docker-compose.yml
を以下のように編集します(先ほど作成した Web サーバの設定は削除します)。
version: '3' services: proxy: container_name: "proxy" image: nginx ports: - "80:80" volumes: - ./proxy/default.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - app1 - app2 app1: container_name: app1 image: openjdk:8 depends_on: - mysql volumes: - ./app/spring-petclinic/target:/usr/src/app command: bash -c "cd /usr/src/app && java -Dspring.profiles.active=mysql -jar *.jar" app2: container_name: app2 image: openjdk:8 depends_on: - mysql volumes: - ./app/spring-petclinic/target:/usr/src/app command: bash -c "cd /usr/src/app && java -Dspring.profiles.active=mysql -jar *.jar" mysql: container_name: mysql image: mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=petclinic - MYSQL_DATABASE=petclinic
内容は、今まで見てきたものを組み合わせただけなので、特に説明は不要でしょう。
ここまでのディレクトリ構成は以下のようになっています。
では早速実行してみましょう。
$ docker-compose up
各サービスが起動したら http://localhost
でアクセスします。
アプリケーションが動いていますね。 動画だけだと分かりませんが、この間もラウンドロビンでアプリケーションサバーに対するバランシングが行われています。
まとめ
前回に続き、Docker の利用方法を見てきました。
主に開発環境構築を視野に、ロードバランサ・アプリケーションサーバ・DBサーバを使った環境構築を行いました。
流れを理解すれば、オプションなど調べつつ活用が広がるかと思います。
最後に、停止しているコンテナを一括で削除しておきましょう(ローカルの停止コンテナを全て消すので注意してください)。
$ docker container prune
コンテナが削除されました。なお、イメージの一括削除は docker image prune
を使います。
- 作者:山田 明憲
- 出版社/メーカー: 技術評論社
- 発売日: 2018/08/25
- メディア: 単行本(ソフトカバー)
プログラマのためのDocker教科書 第2版 インフラの基礎知識&コードによる環境構築の自動化
- 作者:WINGSプロジェクト阿佐 志保
- 出版社/メーカー: 翔泳社
- 発売日: 2018/04/11
- メディア: Kindle版