I know all of you have read my articles on Docker these days. They are not painful, but you still don’t feel the convenience of Docker. Yes, I think so too.

It is really boring to understand the concept in the early stage, please don’t worry about the exciting start. When you have some understanding of docker related concepts, I will give you a series of small examples combined with Spring Boot later, which will make you feel so cool to use Docker!

Today’s performance is directed by Docker-Compare of the Docker family, starring three big bowls of red and purple, Spring Boot, Nginx and Mysql. When the famous directors play together, they are always ready to make trouble. Next, another classic blockbuster is worth everyone’s expectation.

Spring Boot + Nginx + Mysql is the most commonly used combination in practical work. The most front-end uses Nginx proxy to forward requests to the Tomcat service embedded in the back-end Spring Boot. Mysql is responsible for data-related interactions in the business. So how did we navigate these environments before Docker?

  • 1. Install Nginx, configure Nginx information, and restart the system.
  • 2. Install Mysql, configure the character set and time zone, restart Mysql, and initialize the script.
  • 3. Start the Spring Boot project and conduct the overall joint commissioning test.

As you can see, I’ve only written three lines, but it takes a lot of work to set up these environments, but that’s not the end. When you use them for a period of time, you have to move to another environment. How do you do it again? Under normal circumstances, test environment, SIT environment, UAT environment, production environment! We need to repeat the setup four times. Some people say it’s not four times? It’s not a big deal, so I want to tell you,Too yong,Too Simple.

Let’s look at a few factors:

First, this is just the simplest case, if the project involves MongoDB, Redis, ES… What about a bunch of environments? Second, if you often build environments or debug programs, you know what environment problems are? Sometimes it’s exactly the same configuration, but it doesn’t work in another environment. You spend a lot of time looking it up, only to discover that there is a missing argument or comma, or that the kernel version of the system is inconsistent, or you don’t understand why! You can only change to another server, so using Docker can perfectly avoid these pits.

All right, let’s get started without further ado!

Spring Boot case

Let’s first prepare a small scenario with Spring Boot using Mysql. Let’s do this example. Use Spring Boot to make a Web application, providing a method to count the number of accesses by IP address. The statistics are stored in Mysql and displayed on the page on each request.

Configuration information

Depend on the 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>
Copy the code

Add Spring Boot Web support, use Jpa to operate database, add Myql driver package, etc.

The 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
Copy the code

The link information for the database is configured, and Jpa updates the table schema, dialect, and whether Sql is displayed

The core code

The core code is very simple, every time a request comes, determine whether the statistics have been counted, if not counted new data, if there is statistical data update 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."; }}Copy the code

The entity class and Repository layer code is relatively simple, so I won’t post it here. If you are interested, you can download the source code to view it.

When all is said and done, start the project and go to: http://localhost:8080/ and we should see something like this:

I have been seen ip 0:0:0:0:0:0:0:1 1 times.
Copy the code

If I visit it again, it will become

I have been seen ip 0:0:0:0:0:0:0:1 2 times.
Copy the code

Multiple visits have been superimposed, indicating that the demonstration project development is complete.

Docker reformed

First, let’s transform the directory into this structure

Let’s start with the outermost layer:

  • docker-compose.yamlDocker-compose: the core docker-compose file, which describes how to build the entire service
  • nginx: About nginx configuration
  • app: Address of the Spring Boot project

If we need to customize Mysql specifically, we can also create a Mysql folder on the outermost layer and configure it in this directory.

docker-compose.yamlFile,

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=dockerCopy the code
  • version: '3': indicates that the docker-comemage. yaml file is built using the third generation syntax.
  • services: is used to represent the service that compose needs to start. There are three services in this file: nginx, mysql, app.
  • container_name: Container name
  • environment: Information under this node is passed into the container as environment variables. In this example, the mysql service is configured with database, password, and permission information.
  • ports: indicates an open port
  • restart: alwaysIndicates that the service will continue to try if the service fails to start.
  • volumes: Loads the configuration file in the local directory to the container target address
  • depends_on: Indicates that a dependent service can be configured, indicating that the service must be started firstdepends_onStart the service after the following service.
  • command: mvn clean spring-boot:run -Dspring-boot.run.profiles=docker: indicates to start the project with this command,-Dspring-boot.run.profiles=dockerSaid the use ofapplication-docker.propertiesFile configuration information for startup.

Nginx file interpretation

Nginx has a file app.conf in the directory, which mainly configures the 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; }}Copy the code

This part is relatively simple. Configure request forwarding to forward requests from port 80 to port 8080 of the service app. The proxy_pass http://app:8080 configuration information needs to be explained. The reason for using app instead of localhost is that they are not in the same container, and the communication between the compose service needs to be accessed using the name of services.

Spring Boot project transformation

Add the Dockerfile file to the app directory at the same level as the pom.xm file.

The FROM maven: 3.5 JDK - 8Copy the code

Only one sentence, depending on the base image maven3.5 and JDK 1.8. Because the project startup command is set up in the docker-comemage. yaml file, there is no need to add the startup command.

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

  • application-dev.propertiesThe configuration information is the same as the preceding
  • application-docker.propertiesIn the configuration information to do a slight transformation, the database connection information byjdbc:mysql://localhost:3306/testInstead ofjdbc:mysql://mysql:3306/test

So we have all the configuration done.

The deployment of

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

  • Docker(1) : Docker introduction tutorial
  • Docker Compose (4) : Docker Compose

Copy the project to the server and go to CD dockercomposing -springboot-mysql-nginx

Start the 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 - [the main] O.S.B.W.E mbedded. Tomcat. TomcatWebServer: tomcat is started on the port (s) : 8080 (HTTP) with the context path 'app_1 | 2018-03-26 02:54:55. 660 INFO 1 - [the main] com.neo.Com poseApplication: Started ComposeApplication in 14.869 seconds (JVM running for 30.202)Copy the code

Tomcat started on port(s): 8080 Indicates that the service is successfully started. You can also use docker-compose up -d to start in the background

Access server address; http://58.87.69.230/, return: I have been seen IP 172.19.0.2 1 times. The overall service is successfully started

usedocker-compose psView 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; The Up 0.0.0.0:443 - > 443 / TCP, 0.0.0.0:80 - > 80 / TCPCopy the code

You can see the status, command, port, and other information of the service in the project.

Close the servicedocker-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
Copy the code

Docker – compose sequence

When docker-compose is used for startup, the project often reported Mysql connection exception. After tracking for a day, the problem was finally found. Docker-compose can use depends_on to define the order of service startup, but cannot determine whether the service has been started. Therefore, Mysql service startup is slow. When the Spring Boot project has been started, However, Mysql has not been initialized yet, so when the project connects to the Mysql database, it will have an exception to connect to the database.

There are two solutions to this problem:

1. Sufficient fault tolerance and retry mechanisms, such as connecting to a database. If the initial connection fails, the service consumer can retry again and again until the service is connected. That is, in the service definition: restart: always

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

conclusion

No comparison, no harm, before the use of Docker, we need to build such an environment, we need to install Nginx, Mysql, and then a series of configuration debugging, but also worry about various environmental problems; After using Docker, two simple commands can complete the online and offline service.

docker-compose up
docker-compose down
Copy the code

Swarm is the first batch of container technology to optimize deployment operations. Swarm is the first batch of container technology to optimize deployment operations. Swarm is the first batch of container technology to optimize deployment operations.

Example code – Github

Example code – code cloud

reference

Docker Compose with Spring Boot, MySQL and NGINX