使用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应用程序,而不是在容器中。

sub directorydescriptionapp-serverWebアプリケーションを実行するコンテナのDockerfileと関連ファイルを格納するディレクトリです。mysql-servermysql-serverを実行するコンテナのDockerfileと関連ファイルを格納するディレクトリですredis-serverredis-serverを実行するコンテナのDockerfileと関連ファイルを格納するディレクトリです。demo-redis-springSpring 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官方提供的映像。

    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
广告
将在 10 秒后关闭
bannerAds