Spring Boot 2.0 (V): Docker Compose + Spring Boot + Nginx + Mysql Practice

Keywords: Docker MySQL Nginx Spring

I know you have read several articles I wrote about docker during this period. It's not painful or itchy, and you still don't feel the convenience of docker. Yes, I know your felling.

It's really boring to know what the concept is in the early stage. Please don't rush to start at once. When you know something about docker, I'll give you a series of small examples with Spring Boot, which will make you feel that using Docker is so cool.

Today's director is Docker family's docker-comparison, starring Spring Boot, Nginx, Mysql three red and purple bowls. When famous directors are together, they are often ready to do something. The next classic blockbuster is worth looking forward to.

Spring Boot + Nginx + Mysql is the most commonly used combination in practical work. The front end uses Nginx proxy to forward requests to Tomcat service embedded in the back end Spring Boot. Mysql is responsible for data-related interaction in business. So how can we solve these environments without docker?

  • 1. Install Nginx, configure Nginx-related information, and restart.
  • 2. Install Mysql, configure character set time zone and other information, restart, and finally initialize the script.
  • 3. Start Spring Boot project and conduct debugging test as a whole.

You see, I only wrote three lines, but in fact, it's very difficult to build these environments, but this is not the end. It takes a while to migrate to another environment. What should we do again? Normally, test environment, SIT environment, UAT environment, production environment! We need to build it four times. Didn't someone say that it was built four times? It's no big deal, so I want to tell you, Too yong, Too Simple.

Let's look at the following factors:

First, this is only the simplest case, if the project involves MongoDB, Redis, ES... What about some of the environments?
Second, if you build environments or debug programs regularly, you will know what environmental problems are. Sometimes it's exactly the same configuration, but in another environment it's impossible to run. So you spend a lot of time looking for it, only to find that there is a missing parameter or comma problem, or that the kernel version of the system is inconsistent, or that you don't understand why in the end! Only one server can be replaced, so using Docker can avoid these pits perfectly.

Well, let's start without much nonsense.

Spring Boot case

First, we will prepare a small scenario of Spring Boot using Mysql. Let's give an example of a Web application using Spring Boot, which provides a method of counting the number of visits according to IP address. Each time we request, we store the statistics in Mysql and display them on the page.

configuration information

Dependency package

<dependencies>
     <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Spring Boot Web support is added, Jpa is used to operate database, Myql driver package is added, etc.

configuration file

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true

Configured database link information, Jpa update table schema, dialect, and whether Sql is displayed

Core code

The core code is very simple. Every time a request comes, it determines whether it has been counted, if there is no new data, if there is statistical data to update the data.

@RestController
public class VisitorController {

    @Autowired
    private VisitorRepository repository;

    @RequestMapping("/")
    public String index(HttpServletRequest request) {
        String ip=request.getRemoteAddr();
        Visitor visitor=repository.findByIp(ip);
        if(visitor==null){
            visitor=new Visitor();
            visitor.setIp(ip);
            visitor.setTimes(1);
        }else {
            visitor.setTimes(visitor.getTimes()+1);
        }
        repository.save(visitor);
        return "I have been seen ip "+visitor.getIp()+" "+visitor.getTimes()+" times.";
    }
}

Entity class and Repository layer code is relatively simple, not posted here, you are interested in downloading the source code to view.

When all of the above is completed, start the project and visit http://localhost:8080/we can see the return result as follows:

I have been seen ip 0:0:0:0:0:0:0:1 1 times.

A second visit will become

I have been seen ip 0:0:0:0:0:0:0:1 2 times.

Multiple visits have been superimposed to illustrate the completion of the demonstration project development.

Docker ization Reform

First, we'll transform the directory into such a structure.

Let's start with the outermost layer:

  • docker-compose.yaml: docker-compose core file that describes how to build the entire service
  • Nginx: Configuration of nginx
  • app: Spring Book Project Address

If we need to customize Mysql, we can also create a MySQL folder at the outermost level and configure it in this directory.

Doker-compose.yaml file details

version: '3'
services:
  nginx:
   container_name: v-nginx
   image: nginx:1.13
   restart: always
   ports:
   - 80:80
   - 443:443
   volumes:
   - ./nginx/conf.d:/etc/nginx/conf.d

  mysql:
   container_name: v-mysql
   image: mysql/mysql-server:5.7
   environment:
    MYSQL_DATABASE: test
    MYSQL_ROOT_PASSWORD: root
    MYSQL_ROOT_HOST: '%'
   ports:
   - "3306:3306"
   restart: always

  app:
    restart: always
    build: ./app
    working_dir: /app
    volumes:
      - ./app:/app
      - ~/.m2:/root/.m2
    expose:
      - "8080"
    depends_on:
      - nginx
      - mysql
    command: mvn clean spring-boot:run -Dspring-boot.run.profiles=docker
  • Version:'3': Represents the use of third-generation grammar to build docker-compose.yaml files.
  • Services: Used to represent the services compose needs to start, we can see that there are three services in this file: nginx, mysql, app.
  • container_name: Container name
  • Environment: The information under this node is passed into the container as an environment variable. In this example, the mysql service configures database, password, and privilege information.
  • ports: ports that are open to the outside world
  • restart: always indicates that if the service starts unsuccessfully, it will try all the time.
  • volumes: Load the configuration file in the local directory to the container destination address
  • Dependent_on: Dependent services can be configured to indicate that the services under dependent_on need to be started before starting this service.
  • Command: MVN clean spring-boot: run-Dspring-boot.run.profiles=docker: means to start a project with this command, and - Dspring-boot.run.profiles=docker means to start with application-docker.properties file configuration information.

Interpretation of Nginx Files

nginx has a file app.conf in the directory, which mainly configures service forwarding information.

server {
    listen 80;
    charset utf-8;
    access_log off;

    location / {
        proxy_pass http://app:8080;
        proxy_set_header Host $host:$server_port;
        proxy_set_header X-Forwarded-Host $server_name;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /static {
        access_log   off;
        expires      30d;

        alias /app/static;
    }
}

This piece of content is relatively simple, configuring request forwarding, forwarding the request of port 80 to port 8080 of service app. The configuration information of proxy_pass http://app:8080 needs to be explained. App is used here instead of localhost, because they are not in a container, and the service communication of a group of compose needs to be accessed by the name of services.

Spring Boot Project Renovation

In the app directory, the Dockerfile file is added at the same level as the pom.xm file. The contents of the file are as follows:

FROM maven:3.5-jdk-8

Only one sentence, depending on the base mirror Maven 3.5 and jdk 1.8. Because the project startup command is set in the docker-compose.yaml file, there is no need to add the startup command here.

Create application-dev.properties and application-docker.properties files under the resources directory of the project

  • Configuration information in application-dev.properties is consistent with the above
  • The configuration information in application-docker.properties is slightly modified, and the connection information of the database is changed from jdbc:mysql://localhost:3306/test to jdbc:mysql://mysql:3306/test.

So all our configurations have been completed.

deploy

We will copy the project to the server for testing. The server needs to install the Docker and Docker Compos environment first. If you don't know anything about it, you can see my two previous articles:

Copy the project to the server and enter the directory CD docker compose-spring boot-mysql-nginx

Start service: docker-compose up

[root@VM_73_217_centos dockercompose-springboot-mysql-nginx]# docker-compose up
Creating network "dockercomposespringbootmysqlnginx_default" with the default driver
Creating v-nginx ... done
Creating v-mysql ... done
Creating dockercomposespringbootmysqlnginx_app_1 ... done
Attaching to v-nginx, v-mysql, dockercomposespringbootmysqlnginx_app_1
v-mysql  | [Entrypoint] MySQL Docker Image 5.7.21-1.1.4
v-mysql  | [Entrypoint] Initializing database
app_1    | [INFO] Scanning for projects...
... 
app_1    | 2018-03-26 02:54:55.658  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
app_1    | 2018-03-26 02:54:55.660  INFO 1 --- [           main] com.neo.ComposeApplication               : Started ComposeApplication in 14.869 seconds (JVM running for 30.202)

See the information Tomcat started on port(s): 8080 indicates that the service started successfully. You can also use docker-compose up-d background boot

Access the server address; http://58.87.69.230/, return: I have seen IP 172.19.0.21 times. Represents that the overall service started successfully.

Use docker-compose ps to view all current containers in the project

[root@VM_73_217_centos dockercompose-springboot-mysql-nginx]# docker-compose ps
                 Name                                Command                  State                        Ports                  
----------------------------------------------------------------------------------------------------------------------------------
dockercomposespringbootmysqlnginx_app_1   /usr/local/bin/mvn-entrypo ...   Up             8080/tcp                                
v-mysql                                   /entrypoint.sh mysqld            Up (healthy)   0.0.0.0:3306->3306/tcp, 33060/tcp       
v-nginx                                   nginx -g daemon off;             Up             0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

You can see the status, commands, ports and other information of the services in the project.

Close the service docker-compose down

[root@VM_73_217_centos dockercompose-springboot-mysql-nginx]# docker-compose down
Stopping dockercomposespringbootmysqlnginx_app_1 ... done
Stopping visitor-nginx                           ... done
Stopping visitor-mysql                           ... done
Removing dockercomposespringbootmysqlnginx_app_1 ... done
Removing visitor-nginx                           ... done
Removing visitor-mysql                           ... done

docker-compose order

When using docker-compose startup, Mysql connection anomalies often occur in the project report. After a day of tracking, the problem is finally found. Although docker-compose can define the order of service startup by depend_on, it can not determine whether the service is started or not, so there will be a phenomenon that Mysql service startup is slow. When Spring Book project has been started, but Mysql has not been initialized, so when the project connects to Mysql database, there will be a connection to the database. Abnormal.

There are two solutions to this problem:

1. Adequate fault-tolerant and retrial mechanisms, such as connecting to databases, can be retried by service consumers until the first connection fails. That is to say, in services: restart: always

2. Wait synchronously and use wait-for-it.sh or other shell scripts to block the current service startup until the dependent service is loaded. This scheme can be tried later.

summary

Without comparison, there is no harm. Before using Docker, we need to build such an environment. We need to install Nginx and Mysql, debug a series of configurations, and worry about various environmental problems. After using Docker, we can finish the service online and offline with two simple commands.

docker-compose up
docker-compose down

In fact, container technology is still a lot of optimization of deployment operation and maintenance, which is just the beginning, after the use of Swarm will really feel its convenience and strength.

Sample code - github

Sample Code - Code Cloud

Reference resources

Docker Compose with Spring Boot, MySQL and NGINX

Posted by ciaran on Wed, 02 Jan 2019 13:09:09 -0800