概要
MySQL、Redisを利用するWebアプリケーションをJava(フレームワークにSpring Bootを使用)で開発、実行する環境をDocker CE for Windowsで構築したときのメモです。
MySQLおよびRedisはオフィシャルイメージを利用したコンテナで、Spring Bootで開発したWebアプリケーションはCentOS7のオフィシャルイメージを利用したコンテナにOpenJDKをインストールして実行します。
ソースコードはrubytomato/docker-demo-redisにあります。
環境
- Windows 10 Professional
- Docker CE for Windows 18.06.0
- Redis 4.0.11
- MySQL 8.0.12
- CentOS 7
- OpenJDK 1.8.0_181
- Spring Boot 2.0.4
MySQL,Redis,Webアプリケーションの実行環境を構築
プロジェクトディレクトリの構成
コンテナの管理、実行はdocker-composeで行うので、プロジェクトのルートディレクトリにdocker-compose.ymlを配置しています。それぞれのコンテナの情報はサブディレクトリ毎に分離しています。
project-root以下には大きく分けて4つのサブディレクトリがあります。
demo-redis-springというサブディレクトリは、コンテナではなくapp-serverで実行するWebアプリケーションのプロジェクトディレクトリです。
sub directory | description |
---|---|
app-server | Webアプリケーションを実行するコンテナのDockerfileと関連ファイルを格納するディレクトリです。 |
mysql-server | mysql-serverを実行するコンテナのDockerfileと関連ファイルを格納するディレクトリです |
redis-server | redis-serverを実行するコンテナのDockerfileと関連ファイルを格納するディレクトリです。 |
demo-redis-spring | Spring Bootを利用したWebアプリケーションのプロジェクトディレクトリです。 |
ディレクトリ構成
/project-root
|
+--- docker-compose.yml
+--- README.md
|
+--- /demo-redis-spring
| |
| +--- pom.xml
| |
| +--- /src
| | |
| | +--- /main
| | +--- /test
| |
| +--- /target
| |
| +--- demo.jar
|
+--- /app-server
| |
| +--- Dockerfile
| |
| +--- start.sh
|
+--- /mysql-server
| |
| +--- Dockerfile
| |
| +--- /conf
| | |
| | +--- mysqld.cnf
| |
| +--- /sql
| |
| +--- 1_schema.sql
| +--- 2_init_memo_data.sql
|
+--- /redis-server
|
+--- Dockerfile
|
+--- /conf
|
+--- redis.conf
MySQLサーバー用コンテナ
イメージはMySQLのオフィシャルを利用します。
Dockerfile
FROM mysql:8.0.12
COPY ./conf/mysqld.cnf /etc/mysql/conf.d
COPY ./sql/1_schema.sql /docker-entrypoint-initdb.d
COPY ./sql/2_init_memo_data.sql /docker-entrypoint-initdb.d
Configuration
/conf/mysqld.cnfの内容は以下の通りです。このファイルをコンテナの/etc/mysql/conf.dへコピーするとMySQL起動時に読み取られて反映されます。
[mysqld]
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci
log_output = FILE
general_log = 1
log_queries_not_using_indexes = 1
log_slow_admin_statements = 1
log_syslog = 0
log_timestamps = SYSTEM
long_query_time = 3
slow_query_log = 1
general_log_file = general_query_all.log
log_error = error.log
slow_query_log_file = slow_query.log
log_bin_trust_function_creators = 1
[mysql]
show-warnings
prompt = "\u@\h [\d] > "
SQL Script
SQL Scriptをコンテナの/docker-entrypoint-initdb.dへコピーすると、データベースの初期化時に実行されます。
1_schema.sql
CREATE DATABASE sample_db DEFAULT CHARACTER SET = utf8mb4;
CREATE USER 'test_user'@'%' IDENTIFIED BY 'test_user' PASSWORD EXPIRE NEVER;
GRANT ALL ON sample_db.* TO 'test_user'@'%';
USE sample_db;
CREATE TABLE IF NOT EXISTS memo (
id BIGINT AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
description TEXT NOT NULL,
done BOOLEAN DEFAULT FALSE NOT NULL,
updated TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL,
PRIMARY KEY (id)
)
CHARACTER SET = utf8mb4,
COLLATE utf8mb4_general_ci;
2_init_memo_data.sql
USE sample_db;
START TRANSACTION;
INSERT INTO memo (title, description, done, updated) VALUES ('title A', 'description A', false, '2018-08-01');
INSERT INTO memo (title, description, done, updated) VALUES ('title B', 'description B', false, '2018-08-02');
COMMIT;
Redisサーバー用コンテナ
イメージはRedisのオフィシャルを利用します。
ちなみに、Windows上でRedisサーバーを稼働させる場合、Redis 3.0まではMicrosoftArchive/redisからビルドファイルが入手できましたが、4.0以上は提供されていない為、実質的にDockerなどの仮想環境を利用することになります。
Dockerfile
FROM redis:4.0.11
COPY ./conf/redis.conf /usr/local/etc/redis/redis.conf
RUN set -x && \
touch /var/log/redis.log && \
chown redis:root /var/log/redis.log && \
chmod 664 /var/log/redis.log
CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
Configuration
/conf/redis.confは、https://raw.githubusercontent.com/antirez/redis/4.0/redis.confをベースに下記の部分を変更しました。
このファイルをコンテナの/usr/local/etc/redis/redis.confへコピーし、redis-server起動時に引数として与えます。
変更前の箇所
bind 127.0.0.1
logfile ""
# maxclients 10000
# requirepass foobared
appendonly no
変更後の箇所
# bind 127.0.0.1
logfile /var/log/redis.log
maxclients 100
requirepass foobared
appendonly yes
logfile
この例では、ログをコンテナ内の/var/log/redis.logへ出力するように変えていますが、logfileの設定をデフォルトにしておくと標準出力(stdout)へ出力されます。標準出力に出力されるログはdocker-compose logsで確認することができます。
> docker-compose logs -f redis-server
redis-cliのコマンドを監視したい場合
他のクライアントから実行されたコマンドを監視したい場合はredis-cli monitorを使用します。
> docker-compose exec redis-server redis-cli
127.0.0.1:6379> auth foobared
OK
127.0.0.1:6379> monitor
OK
requirepass
bindをコメントアウトすると、redisコマンドを実行する前にauthで認証する必要があります。
このときのauthで指定するパスワードをrequirepassで設定します。
Applicationサーバー用コンテナ
ApplicationサーバーではSpring Bootで開発したWebアプリケーションを実行します。
利用するイメージはOpenJDKのオフィシャルイメージではなくCentOS7のオフィシャルイメージで、それにyumでOpenJDK 1.8をインストールしました。
Dockerfile
ロケールの変更とWebアプリケーションの実行ユーザーとしてappというユーザーを追加しています。
FROM centos:7
RUN set -x && \
yum update -y && \
yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel && \
yum reinstall -y glibc-common && \
yum -y clean all
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk
# locale settings
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
RUN set -x && \
localedef -i ja_JP -c -f UTF-8 ja_JP.UTF-8 && \
unlink /etc/localtime && \
ln -s /usr/share/zoneinfo/Japan /etc/localtime
# application user settings
ENV HOME /home/app
RUN set -x && \
groupadd app && \
useradd -g app -d /home/app -s /bin/bash app
WORKDIR $HOME
USER app
COPY start.sh .
EXPOSE 9000
start.sh
Webアプリケーションを簡単に実行するためのshellです。
コンテナの/var/targetは、Windows上の/project-root/demo-redis-spring/targetをマウントしたディレクトリです。
このマウントはdocker-compose.ymlの方で記述しています。
#!/bin/bash
set -x
java -Xmx512m -Xms512m -XX:MaxMetaspaceSize=256m -verbose:gc -Xloggc:app-gc.log -jar /var/target/demo.jar
app-serverコンテナ起動時にwebアプリケーションを実行する
この記事では、app-serverコンテナの起動とそのコンテナ内で実行するwebアプリケーションの実行はタイミングを分けていますが、app-serverコンテナ起動とともにwebアプリケーションを実行するには、Dockerfileの最後に下記の行を追加します。
CMD [ "./start.sh" ]
webアプリケーションのログは、docker-compose logsコマンドで確認できます。
> docker-compose logs -f --tail=all app-server
Attaching to app-server
app-server | + java -Xmx512m -Xms512m -XX:MaxMetaspaceSize=256m -verbose:gc -Xloggc:app-gc.log -jar /var/target/demo.jar
app-server |
app-server | . ____ _ __ _ _
app-server | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
app-server | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
app-server | \\/ ___)| |_)| | | | | || (_| | ) ) ) )
app-server | ' |____| .__|_| |_|_| |_\__, | / / / /
app-server | =========|_|==============|___/=/_/_/_/
app-server | :: Spring Boot :: (v2.0.4.RELEASE)
// ...省略...
docker-compose.yml
version: "3.6"
services:
mysql-server:
container_name: mysql-server
build:
context: ./mysql-server
volumes:
- mysql-data:/var/lib/mysql
environment:
TZ: Asia/Tokyo
MYSQL_ROOT_PASSWORD: password
ports:
- 3306:3306
networks:
- redis-network
restart: always
tty: true
redis-server:
container_name: redis-server
build:
context: ./redis-server
environment:
TZ: Asia/Tokyo
volumes:
- redis-data:/data
ports:
- 6379:6379
networks:
- redis-network
restart: always
tty: true
app-server:
build:
context: ./app-server
environment:
TZ: Asia/Tokyo
SPRING_PROFILES_ACTIVE: docker
volumes:
- ./demo-redis-spring/target:/var/target
depends_on:
- mysql-server
- redis-server
ports:
- 9000:9000
networks:
- redis-network
restart: always
stdin_open: true
tty: true
networks:
redis-network:
driver: bridge
volumes:
mysql-data:
driver: local
redis-data:
driver: local
Spring Profileについて
app-serverコンテナ内からSpring Bootアプリケーションを実行するときに、dockerというプロファイルを指定するためにSPRING_PROFILES_ACTIVEという環境変数を設定します。
app-server:
environment:
SPRING_PROFILES_ACTIVE: docker
指定されたプロファイルでMySQL serverとRedis serverの接続先をコンテナ内へ切り替えます。
下記はSpring Bootの設定ファイルの関係部分の抜粋です。dockerというプロファイルのときに、MySQL serverとRedis serverのホスト名をコンテナのホスト名にしています。
spring:
profiles:
active: dev
datasource:
url: jdbc:mysql://localhost:3306/sample_db?useSSL=false&allowPublicKeyRetrieval=true
username: test_user
password: test_user
redis:
host: localhost
port: 6379
ssl: false
database: 0
password: foobared
server:
port: 9001
---
spring:
profiles: docker
datasource:
url: jdbc:mysql://mysql-server:3306/sample_db?useSSL=false&allowPublicKeyRetrieval=true
redis:
host: redis-server
server:
port: 9000
portsについて
下記のようにmysql-server、redis-serverコンテナのポートを外部に公開しているのは、Windows上でWebアプリケーションを実行するときに、コンテナのMysql server、Redis serverへアクセスできるようにするためです。
mysql-server
ports:
- 3306:3306
redis-server
ports:
- 6379:6379
コンテナのビルドと起動,停止
ビルド
> docker-compose build
キャッシュを利用しない場合
> docker-compose build --no-cache
起動
初回起動時はvolumeが作成されます。
> docker-compose up -d
Creating network "docker-demo-redis_redis-network" with driver "bridge"
Creating volume "docker-demo-redis_mysql-data" with local driver
Creating volume "docker-demo-redis_redis-data" with local driver
Creating mysql-server ... done
Creating redis-server ... done
Creating app-server ... done
次回以降はvolumeの作成はスキップされます。
> docker-compose up -d
Creating network "docker-demo-redis_redis-network" with driver "bridge"
Creating mysql-server ... done
Creating redis-server ... done
Creating app-server ... done
再起動
> docker-compose restart
Restarting app-server ... done
Restarting redis-server ... done
Restarting mysql-server ... done
停止
> docker-compose down
Stopping app-server ... done
Stopping mysql-server ... done
Stopping redis-server ... done
Removing app-server ... done
Removing mysql-server ... done
Removing redis-server ... done
Removing network docker-demo-redis_redis-network
targetディレクトリのマウント
Spring Bootで開発したWebアプリケーションをapp-serverコンテナ上で実行するために、ビルドされたjarファイルが出力されるtargetディレクトリをapp-serverコンテナの/var/targetへマウントします。
app-server:
volumes:
- ./demo-redis-spring/target:/var/target
Webアプリケーションの実行
Webアプリケーションを実行するにはexecコマンドでapp-serverコンテナに入り、コンテナへcopyしておいたstart.shを実行します。
> docker-compose exec app-server bash --login
[app@72e38b38c6ca ~]$ ./start.sh
+ java -Xmx512m -Xms512m -XX:MaxMetaspaceSize=256m -verbose:gc -Xloggc:app-gc.log -jar /var/target/demo.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.4.RELEASE)
2018-08-08 22:09:10.248 INFO 46 --- [ main] com.example.demo.Application : Starting Application v0.0.1-SNAPSHOT on 72e38b38c6ca with PID 46 (/var/target/demo.jar started by app in /home/app)
2018-08-08 22:09:10.253 DEBUG 46 --- [ main] com.example.demo.Application : Running with Spring Boot v2.0.4.RELEASE, Spring v5.0.8.RELEASE
2018-08-08 22:09:10.256 INFO 46 --- [ main] com.example.demo.Application : The following profiles are active: docker
// ...以下省略...
app-serverコンテナのポート9000が外部に公開されているので、ブラウザからhttp://localhost:9000/
にアクセスしてページが表示されることを確認します。
MySQL,Redisのデータ永続化
named volumeを利用します。
volumes:
mysql-data:
driver: local
redis-data:
driver: local
データの初期化を行いたい場合は、docker volumeコマンドで削除します。
volumeの確認
> docker volume ls
DRIVER VOLUME NAME
local docker-demo-redis_mysql-data
local docker-demo-redis_redis-data
volumeの削除
> docker volume rm docker-demo-redis_redis-data
docker-demo-redis_redis-data
削除すると次回起動時に、自動的に作成されます。
> docker-compose up -d
Creating network "docker-demo-redis_redis-network" with driver "bridge"
Creating volume "docker-demo-redis_redis-data" with local driver
Creating mysql-server ... done
Creating redis-server ... done
Creating app-server ... done
MySQLサーバーへmysql cliから接続する
MySQLサーバーに接続して作業を行いたい場合は、mysql-serverコンテナからmysqlコマンドで接続します。
> docker-compose exec mysql-server mysql -u test_user -p --database=sample_db
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.12 MySQL Community Server - GPL
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
test_user@localhost [sample_db] >
Redisサーバーへredis-cliから接続する
Redisサーバーに接続して作業を行いたい場合は、redis-serverコンテナからredis-cliコマンドで接続します。
> docker-compose exec redis-server redis-cli
127.0.0.1:6379> auth foobared
OK
127.0.0.1:6379> keys *
(empty list or set)
Applicationサーバーのスケールアウト
任意の指定する数だけApplicationサーバーを起動する方法です。
docker-compose.ymlの修正
portsを下記のように、外部に公開する側のportを範囲で設定します。
この例ではスケールアウトする最大数を2としたいのでportの範囲は9000,9001を指定しました。
app-server:
ports:
# - 9000:9000
- 9000-9001:9000
起動
up時に--scale app-server=num
で、起動するapp-serverの数をnumに指定します。
> docker-compose up -d --scale app-server=2
Creating network "docker-demo-redis_redis-network" with driver "bridge"
Creating mysql-server ... done
Creating redis-server ... done
WARNING: The "app-server" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Creating docker-demo-redis_app-server_1 ... done
Creating docker-demo-redis_app-server_2 ... done
app-serverコンテナで任意のコマンドを実行するには--index=num
で、どのコンテナで実行するかnumで指定します。
> docker-compose exec --index=1 app-server bash --login
MySQL serverへの接続数を確認する
この記事のJavaアプリケーションは1インスタンスから同時に2つのコネクションを張るようになっています。
下記のshow processlistの結果から、Id #8,#9が172.22.0.4から、Id #10,#11が172.22.0.5から接続されていることがわかります。
> show processlist;
+----+-----------------+------------------+-----------+---------+------+------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-----------------+------------------+-----------+---------+------+------------------------+------------------+
| 4 | event_scheduler | localhost | NULL | Daemon | 843 | Waiting on empty queue | NULL |
| 8 | test_user | 172.22.0.4:48354 | sample_db | Sleep | 674 | | NULL |
| 9 | test_user | 172.22.0.4:48356 | sample_db | Sleep | 676 | | NULL |
| 10 | test_user | 172.22.0.5:40842 | sample_db | Sleep | 263 | | NULL |
| 11 | test_user | 172.22.0.5:40844 | sample_db | Sleep | 265 | | NULL |
| 13 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+-----------------+------------------+-----------+---------+------+------------------------+------------------+
6 rows in set (0.00 sec)
Redis serverへの接続数を確認する
client id #3が172.22.0.4から、id #4が172.22.0.5から接続されていることがわかります。
127.0.0.1:6379> client list
id=3 addr=172.22.0.4:37174 fd=9 name= age=1621 idle=1621 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
id=4 addr=172.22.0.5:44918 fd=10 name= age=1051 idle=1051 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
id=5 addr=127.0.0.1:41110 fd=11 name= age=79 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
docker-compose scale
docker-compose scale
はdeprecatedです。代わりにupコマンドで--scaleフラグを使用します。
This command is deprecated. Use the up command with the --scale flag instead. Beware that using up with --scale flag has some subtle differences with the scale command as it incorporates the behaviour of up command.
実行するコンテナを増減させる
最初にapp-severを1つだけ実行します。
> docker-compose up -d
Creating network "docker-demo-redis_redis-network" with driver "bridge"
Creating mysql-server ... done
Creating redis-server ... done
Creating docker-demo-redis_app-server_1 ... done
指定した数までコンテナをスケールアウトする
> docker-compose up -d --scale app-server=2
redis-server is up-to-date
mysql-server is up-to-date
WARNING: The "app-server" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Starting docker-demo-redis_app-server_1 ... done
Creating docker-demo-redis_app-server_2 ... done
指定した数までコンテナを減らす
> docker-compose up -d --scale app-server=1
redis-server is up-to-date
mysql-server is up-to-date
Stopping and removing docker-demo-redis_app-server_2 ... done
Starting docker-demo-redis_app-server_1 ... done