使用Docker CE for Windows构建基于Java、MySQL和Redis的Web应用程序开发环境
概括
这是关于在使用Java(使用Spring Boot框架)开发并运行使用MySQL和Redis的Web应用程序的环境,并在Docker CE for Windows中构建的笔记。
MySQL和Redis是使用官方镜像的容器,使用Spring Boot开发的Web应用程序将在使用CentOS 7官方镜像的容器中安装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文件放置在项目的根目录中。每个容器的信息都在各自的子目录中分离存放。
在项目根目录下,大致可以分为四个子目录。
名为demo-redis-spring的子目录是一个项目目录,需要在app-server上运行的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官方提供的映像。
- library/mysql – Docker Hub
Dockerfile => Docker文件
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
配置
/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脚本
将SQL脚本复制到容器的/docker-entrypoint-initdb.d目录下,将在数据库初始化时执行。
1_schema.sql 的中文同义句:1_模式.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 的中文释义为「2初始化备忘录数据.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的官方镜像。
- library/redis – Docker Hub
顺便提一下,如果要在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" ]
配置
以下是对/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
更改后的部分 de
# bind 127.0.0.1
logfile /var/log/redis.log
maxclients 100
requirepass foobared
appendonly yes
日志文件
在這個例子中,我們將日誌輸出更改為容器內的/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
需要密码
如果将`bind`注释掉,则在执行redis命令之前需要在`auth`中进行身份验证。此时,可以使用`requirepass`来设置验证密码。
应用服务器容器
在应用服务器上,我们通过Spring Boot开发的Web应用进行执行。
我们选择了CentOS7的官方镜像,而不是OpenJDK的官方镜像,并通过yum安装了OpenJDK 1.8。
- library/centos – Docker Hub
Dockerfile 的含义是什么?
正在更改地区设置,并添加名为app的用户作为Web应用程序的执行用户。
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
启动.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" ]
您可以通过docker-compose logs命令来查看Web应用程序的日志。
> 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 -> Docker 组合配置文件
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配置文件的问题。
当在app-server容器内执行Spring Boot应用程序时,需要设置环境变量SPRING_PROFILES_ACTIVE作为docker配置文件的指定。
app-server:
environment:
SPRING_PROFILES_ACTIVE: docker
使用指定的配置文件,在容器内切换MySQL服务器和Redis服务器的连接。以下是Spring Boot配置文件的相关部分摘录。当使用名为docker的配置文件时,将将MySQL服务器和Redis服务器的主机名设置为容器的主机名。
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
关于港口
在Windows上运行Web应用程序时,将mysql-server和redis-server容器的端口映射到外部,是为了能够访问容器中的Mysql服务器和Redis服务器。
MySQL服务器
ports:
- 3306:3306
Redis服务器
ports:
- 6379:6379
构建和运行容器,停止
建筑
> docker-compose build
如果不使用缓存
> docker-compose build --no-cache
启动
第一次启动时会创建一个音量。
> 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
下次开始将跳过创建卷。
> 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
目标目录的挂载
为了在app-server容器上执行使用Spring Boot开发的Web应用程序,需要将构建好的jar文件输出到目标目录target,并将其挂载到app-server容器的/var/target目录中。
app-server:
volumes:
- ./demo-redis-spring/target:/var/target
在中国境内运行网络应用程序
要执行Web应用程序,您需要使用exec命令进入app-server容器,并执行之前复制到容器中的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的数据持久化
使用命名卷。
volumes:
mysql-data:
driver: local
redis-data:
driver: local
如果想要进行数据初始化,可以使用docker volume命令进行删除。
音量的确认
> docker volume ls
DRIVER VOLUME NAME
local docker-demo-redis_mysql-data
local docker-demo-redis_redis-data
删除音量
> 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 cli连接到MySQL服务器。
如果想连接到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-cli从Redis服务器连接
如果想要连接到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)
应用服务器的扩容。
以下是在中国语言中对所提供的内容进行的概括:
可以通过指定的数量启动应用程序服务器的方法。
修改docker-compose.yml文件。
将端口(ports)配置为以下范围,以公开给外部。在此示例中,我们希望将最大扩展数设置为2,因此指定了端口范围为9000、9001。
app-server:
ports:
# - 9000:9000
- 9000-9001:9000
开始运行
在启动时使用–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服务器的数量。
这篇文章中的Java应用程序现在从一个实例同时连接两个连接。
从下面的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服务器的数量
目前我们可以看到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调整规模
docker-compose scale已被弃用,请改用up命令并使用–scale标志。
这个命令已被弃用。请改用带有 –scale 标志的 up 命令。请注意,使用带有 –scale 标志的 up 命令与 scale 命令有一些细微差别,因为它包含了 up 命令的行为。
增减执行的容器
最开始只运行一个app服务器。
> 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