1. 部署 MariaDB(MySQL)

    1) 部署环境

        IP 地址(本地测试环境):192.168.0.10
        操作系统:Linux CentOS 7.9     
        Docker 版本: 20.10.7

        注:CentOS 7.9 下不需要安装 Java 环境。

    2) 拉取 MariaDB 镜像

        $ sudo docker pull mariadb:10.4
        $ sudo docker images

            REPOSITORY         TAG        IMAGE ID          CREATED         SIZE
            mariadb                   10.4       0552982c09ae   7 days ago          404MB
            java                          8           d23bdf5b1b1b    5 years ago         643MB
            ...

        注:可以访问 Dockers Hub(https://hub.docker.com/_/mariadb?tab=tags)查询 MariaDB 镜像,本文使用 MariaDB 10.4。

    3) 配置 MariaDB

        在 Docker 主机上创建 /home/mysql/conf 目录。
        
        在 /home/mysql/conf 目录下创建 my_mariadb.cnf 文件,内容如下:

[mysqld]
    server-id=1
    port=3306
            
    #basedir=/usr/local/mysql
    #tmpdir=/tmp
    datadir=/var/lib/mysql
       
    # 查询日志,默认在 /var/lib/mysql 目录下
    #general_log=1
    #general_log_file=mysql_general.log

    # 二进制日志,默认在 /var/lib/mysql 目录下
    #log_bin=mysql_log_bin-1

    # 慢查询日志,默认在 /var/log/mysql 目录下
    #slow_query_log=1
    #long_query_time=1
    #slow_query_log_file=mysql_slow_query.log

    # 错误日志,指定到 /var/log/mysql 目录
    log_error=/var/log/mysql/mysql_err.log

    4) 运行 MariaDB 容器

  $ sudo docker run --name mariadb-10.4 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456\
          -v /home/mysql/conf:/etc/mysql/conf.d\
          -v /home/mysql/data:/var/lib/mysql\
          -v /home/mysql/log:/var/log/mysql\
          --privileged=true\
          -d mariadb:10.4

          参数说明:

      -p 3306:3306:映射容器服务的 3306 端口到宿主机的 3306 端口。外部可以直接通过宿主机 ip:3306 访问到 mariadb 的服务;
      MYSQL_ROOT_PASSWORD=123456:设置 mariadb 服务 root 用户的密码;
      -v:将本地文件夹与容器文件夹挂载;
      --privileged=true:使用该参数,容器内的 root 拥有真正的 root 权限。否则,容器内的 root 只是外部的一个普通用户权限。
      -d:设置容器在后台一直运行。
      mariadb:10.4: 镜像:tag。

     注:MariaDB (MySQL) 的默认配置文件是 /etc/mysql/my.cnf 文件。如果想要自定义配置,在 /etc/mysql/conf.d 目录中创建 *.cnf 文件。新建的文件可以任意起名,只要保证后缀名是 cnf 即可。新建的文件中的配置项可以覆盖 /etc/mysql/my.cnf 中的配置项。

       容器内的程序要在 /home/mysql/log 目录下创建 log 文件,需要确保 root/root 以外的用户也有 /home/mysql/log 目录的写权限,修改该目录的权限,命令如下:

        $ cd /home/mysql
        $ chmod a+w log

      修改后需要重启容器,命令如下:

        $ sudo docker restart mariadb-10.4

 

        $ sudo docker ps  # 查看运行的容器列表

            CONTAINER ID   IMAGE             COMMAND                   PORTS                         NAMES
            1a424e905075   mariadb:10.4  "docker-entrypoint.s…"   0.0.0.0:3306->3306/tcp  mariadb-10.4

            ...

        $ sudo docker exec -it mariadb-10.4 /bin/bash

root@1a424e905075:/# mysql -u root -p
            Enter password:
            Welcome to the MariaDB monitor.  Commands end with ; or \g.
            Your MariaDB connection id is 8
            Server version: 10.4.26-MariaDB-1:10.4.26+maria~ubu2004 mariadb.org binary distribution

            Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

            Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

            MariaDB [(none)]> show databases;

                +--------------------+
                | Database           |
                +--------------------+
                | information_schema |
                | mysql              |
                | performance_schema |
                +--------------------+
                3 rows in set (0.001 sec)

            MariaDB [(none)]> show variables like '%log%';

                +---------------------------+--------------------------------------------+
                | Variable_name             | Value                                      |
                +---------------------------+--------------------------------------------+
                | general_log               | ON                                         |
                | general_log_file          | /var/log/mysql/mysql_general.log           |
                | log_bin                   | ON                                         |
                | log_bin_basename          | /var/lib/mysql/mysql_log_bin               |
                | log_bin_index             | /var/lib/mysql/mysql_log_bin.index         |
                | log_error                 | /var/log/mysql/mysql_err.log               |
                | slow_query_log_file       | /var/log/mysql/mysql_slow_query.log        |
                
                  ...

                +---------------------------+--------------------------------------------+
                80 rows in set (0.001 sec)

    注:MariaDB (MySQL) 命令的关键字,大小写不敏感,比如 show、like 可以写成 SHOW、LIKE。

    4) 创建数据库 testdb 和 user 表

   SQL 脚本如下:

CREATE TABLE `user` (
                `id` int(11) NOT NULL AUTO_INCREMENT,
                `username` varchar(50) NOT NULL,
                `password` varchar(255) DEFAULT NULL,
                `age` int(11) DEFAULT NULL,
                `createtime` timestamp NULL DEFAULT NULL,
                PRIMARY KEY (`id`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    可以在容器内的 MariaDB [(none)]> 命令行下创建,操作命令如下:

MariaDB [(none)]> CREATE DATABASE IF NOT EXISTS testdb;
            Query OK, 1 row affected (0.000 sec)

            MariaDB [(none)]> USE testdb;
            Database changed

            MariaDB [testdb]> CREATE TABLE `user` (
                -> `id` int(11) NOT NULL AUTO_INCREMENT,
                -> `username` varchar(50) NOT NULL,
                -> `password` varchar(255) DEFAULT NULL,
                -> `age` int(11) DEFAULT NULL,
                -> `createtime` timestamp NULL DEFAULT NULL,
                -> PRIMARY KEY (`id`)
                -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
            Query OK, 0 rows affected (0.010 sec)

            MariaDB [testdb]> show tables;

                +------------------+
                | Tables_in_testdb |
                +------------------+
                | user             |
                +------------------+
                1 row in set (0.000 sec)

              MariaDB [testdb]> select * from user;
              Empty set (0.000 sec)

 

2. 修改 SpringbootWebDocker 项目

    1) 导入 JDBC、MariaDB、MyBatis 等相关依赖包

        访问 http://www.mvnrepository.com/ 查询依赖包。

        修改 pom.xml:

1             <project ... >
 2                 ...
 3 
 4                 <dependencies>
 5                     ...
 6 
 7                     <dependency>
 8                         <groupId>org.mariadb.jdbc</groupId>
 9                         <artifactId>mariadb-java-client</artifactId>
10                     </dependency>
11                     <dependency>
12                         <groupId>org.springframework.boot</groupId>
13                         <artifactId>spring-boot-starter-data-jdbc</artifactId>
14                     </dependency>
15                     <dependency>
16                         <groupId>org.mybatis.spring.boot</groupId>
17                         <artifactId>mybatis-spring-boot-starter</artifactId>
18                         <version>2.2.0</version>
19                     </dependency>
20 
21                     <dependency>
22                         <groupId>org.projectlombok</groupId>
23                         <artifactId>lombok</artifactId>
24                         <version>1.18.8</version>
25                     </dependency>
26 
27                     ...
28                 </dependencies>
29             
30                 ...    
31             </project>

            注:lombok 提供了一些简化实体类定义的注解。要使用 lombok,IDEA 需要安装 lombok 插件,这里以 Windows 版的 IDEA 为例,安装步骤如下:

                菜单 File -> Settings -> 选中左侧 Plugin ->  搜索 "lombok" -> Install lombok plugin -> Restart IDEA

        在 IDE 中项目列表 -> SpringbootWebDocker -> 点击鼠标右键 -> Maven -> Reload Project

    2) 修改 src/main/resources/application.properties 文件

spring.main.banner-mode=off

        # Web server
        server.display-name=SpringBootWebDocker-Test
        #server.address=localhost
        server.port=9090   

        # Data source
        spring.datasource.username=root
        spring.datasource.password=123456
        spring.datasource.url=jdbc:mysql://192.168.0.10:3306/testdb
        spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
        
        mybatis.mapper-locations=classpath:mapper/*.xml

        注:不要设置 server.address。

    3) 实体类、配置 MyBatis

        (1) 创建 src/main/java/com/example/entity/User.java 文件

1             package com.example.entity;
 2 
 3             import java.util.Date;
 4             import java.io.Serializable;
 5 
 6             import lombok.Data;
 7             import lombok.NoArgsConstructor;
 8             import lombok.experimental.Accessors;
 9 
10             @NoArgsConstructor // 无参构造函数
11             @Data // 提供类的 get、set、equals、hashCode、canEqual、toString 方法
12             @Accessors(chain = true)
13             public class User implements Serializable {
14                 private Integer id;
15                 private String username;
16                 private String password;
17                 private Integer age;
18                 private Date createtime;
19 
20             }

        (2) 创建 src/main/java/com/example/mapper/UserMapper.java 文件

1             package com.example.mapper;
 2 
 3             import org.apache.ibatis.annotations.Mapper;
 4             
 5             import com.example.entity.User;
 6 
 7             @Mapper
 8             public interface UserMapper {
 9                 int insert(User user);
10                 User selectByUsername(String username);
11             }

            当 mapper 接口较多时,可以在 Spring Boot 主启动类上使用 @MapperScan 注解扫描指定包下的 mapper 接口,而不再需要在每个 mapper 接口上都标注 @Mapper 注解。
        
        (3) 创建 src/main/resources/mapper/UserMapper.xml 文件

1            <?xml version="1.0" encoding="UTF-8"?>
 2             <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 3                                     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 4             <mapper namespace="com.example.mapper.UserMapper">
 5                 <resultMap id="BaseResultMap" type="com.example.entity.User">
 6                     <id column="id" jdbcType="BIGINT" property="id"/>
 7                     <result column="username" jdbcType="VARCHAR" property="username"/>
 8                     <result column="password" jdbcType="VARCHAR" property="password"/>
 9                     <result column="age" jdbcType="INTEGER" property="age"/>
10                     <result column="createtime" jdbcType="DATE" property="createtime"/>
11                 </resultMap>
12                 <sql id="Base_Column_List">
13                     id, username, password, age, createtime
14                 </sql>
15                 <insert id="insert" parameterType="com.example.entity.User">
16                     INSERT INTO user (id, username, password, age, createtime)
17                     VALUES (#{id,jdbcType=BIGINT}, #{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR},
18                     #{age,jdbcType=INTEGER}, #{createtime,jdbcType=DATE})
19                 </insert>
20                 <select id="selectByUsername" parameterType="java.lang.String" resultMap="BaseResultMap">
21                     SELECT
22                     <include refid="Base_Column_List"/>
23                     FROM user
24                     WHERE username = #{username,jdbcType=VARCHAR}
25                 </select>            
26             </mapper>

    4) 服务和控制

        (1) 创建 src/main/java/com/example/service/UserService.java 文件

1             package com.example.service;
 2 
 3             import com.example.entity.User;
 4 
 5             public interface UserService {
 6 
 7                 int insert(User user);
 8                 User selectByUsername(String username);
 9 
10             }

        (2) 创建 src/main/java/com/example/service/UserServiceImpl.java 文件

1             package com.example.service;
 2 
 3             import org.springframework.beans.factory.annotation.Autowired;
 4             import org.springframework.stereotype.Service;
 5 
 6             import com.example.entity.User;
 7             import com.example.mapper.UserMapper;
 8 
 9             @Service("userService")
10             public class UserServiceImpl implements UserService {
11                 @Autowired
12                 UserMapper UserMapper;
13 
14                 @Override
15                 public int insert(User user) {
16                     return UserMapper.insert(user);
17                 }
18     
19                 @Override
20                 public User selectByUsername(String username) {
21                     return UserMapper.selectByUsername(username);
22                 }
23     
24             }

        (3) 创建 src/main/java/com/example/controller/UserController.java 文件

1             package com.example.controller;
 2 
 3             import org.springframework.beans.factory.annotation.Autowired;
 4             import org.springframework.web.bind.annotation.RestController;
 5             import org.springframework.web.bind.annotation.RequestParam;
 6             import org.springframework.web.bind.annotation.RequestMapping;
 7 
 8             import com.example.entity.User;
 9             import com.example.service.UserService;
10 
11             @RestController
12             public class UserController {
13                 @Autowired
14                 UserService userService;
15 
16                 @RequestMapping("/hello")
17                 public String hello() {
18                     return "Hello Page - SpringBoot Web Docker";
19                 }
20 
21                 @RequestMapping("/create")
22                 public String create(String username, String password, Integer age) {
23 
24                     if ("".equals(username) || "".equals(password)) {
25                         return "Invalid username or password.";
26                     }
27 
28                     User user = userService.selectByUsername(username);
29                     System.out.println("user = " + user);
30                     if (user != null) {
31                         return "'" + username + "' exists, please enter a new username.";
32                     }
33 
34                     user = new User();
35                     user.setUsername(username);
36                     user.setPassword(password);
37                     user.setAge(age);
38                     user.setCreatetime(new Date());
39                     Integer ret = userService.insert(user);
40                     if (ret <= 0) {
41                         return "Failed to create '" + username + "'.";
42                     }
43 
44                     return "Create '" + username + "' successfully.";
45                 }
46 
47             }

    5) Jar 打包

        菜单 View -> Tool Windows -> Maven -> SpringbootWebDocker -> Lifecycle -> Clean & Package

            jar 包生成在目录 target/ 里

                SpringbootWebDocker.jar
                SpringbootWebDocker.jar.original  

        点击 IDEA 底部 Terminal 标签页,执行如下命令。

           java -jar target/SpringbootWebDocker.jar

               ...

                Spring boot web project     

        浏览器访问 http://localhost:9090/create?username=admin&password=123456&age=20,页面显示:

            Create 'admin' successfully.

       查看数据库 testdb 里 user 表,内容如下:

            id  username    password    age     createtime
            1   admin       123456      20      2022-09-02 00:00:00

3. 部署 SpringbootWebDocker 项目 Jar 包

    1) 部署环境

        IP 地址(本地测试环境):192.168.0.10
        操作系统:Linux CentOS 7.9     
        Docker 版本: 20.10.7

        注:CentOS 7.9 下不需要安装 Java 环境。

    2) 创建 Dockerfile

        创建 /home/docker 目录,把 SpringbootWebDocker.jar 和 application.properties 上传到该目录。

        创建 /home/docker/logs 文件夹存放日志文件,该路径与 SpringBoot 项目中 logging.file.path 设置的一致。
        
        创建 home/docker/Dockerfile 文件,内容如下:

# 指定基础镜像
            FROM java:8
            # 维护者
            MAINTAINER Tester
            # 将文件添加到容器中,并更名为 webdocker.jar
            ADD SpringbootWebDocker.jar /home/docker/webdocker.jar
            ADD application.properties /home/docker/application.properties
            # 指定端口,与 SpringBoot 项目配置文件中的端口一致
            EXPOSE 9090
            # 容器启动时,运行该程序
            ENTRYPOINT ["java", "-jar", "/home/docker/webdocker.jar", "--spring.config.location=/home/docker/application.properties"]

         注:这里使用 Java 8 基础镜像来演示,建议实际应用中使用较新的 Java 版本,可以访问 https://hub.docker.com/_/openjdk/tags 查询。

    3) 构建镜像

        $ cd /home/docker
        $ sudo docker build -t webdocker .  
        $ sudo docker images

REPOSITORY                TAG        IMAGE ID       CREATED          SIZE
            webdocker                 latest     8b1cd7959abf    14 seconds ago   668MB
            mariadb                    10.4        0552982c09ae   8 days ago        404MB
            java                           8           d23bdf5b1b1b    5 years ago       643MB
            ...

    4) 创建并启动容器

        $ sudo docker run -p 9090:9090 --name webdocker\
                    -v /home/docker/logs:/home/docker/logs\
                    -v /home/docker/application.properties:/home/docker/application.properties\
                    -d webdocker

            dde73d87638c8516847c68ead5a9de5ff624fb2534f3ef675b5ab9b354c4f56a
        
        $ sudo docker ps    # 查看容器

            CONTAINER ID   IMAGE       COMMAND         ...        PORTS                               NAMES
            dde73d87638c   webdocker "java -jar /home/doc…"    0.0.0.0:9090->9090/tcp     webdocker
            
            ...

         $ sudo docker exec -it webdocker /bin/bash   # 进入容器

    5) 页面访问

        浏览器访问 http://192.168.0.10:9090/create?username=user&password=333666&age=30,页面显示:

            Create 'user' successfully.

        查看数据库 testdb 里 user 表,内容如下:

            id  username    password    age     createtime
            1   admin         123456        20      2022-09-02 00:00:00
            2   user            333666        30      2022-09-02 00:00:00