Trouble communicating between two docker container

2020-02-29 06:57发布

问题:

I’m new to docker and I’m trying to connect my spring boot app running into my boot-example docker container to a mysql server running into my mymysql docker container on port 6603, both running on the same phisical machine. The fact is: if I connect my spring-boot app to my mymysql docker container in order to communicate with the database, I get no errors and everything works fine.

When I move my spring boot application into my boot-example container and try to communicate (through Hibernate) to my mymysql container, then I get this error:

2018-02-05 09:58:38.912 ERROR 1 --- [           main] o.a.tomcat.jdbc.pool.ConnectionPool      : Unable to create initial connections of pool.

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_111]

My spring boot application.properties are:

server.port=8083
spring.jpa.hibernate.ddl-auto=create-drop
spring.datasource.url=jdbc:mysql://localhost:6603/mydockerdb
spring.datasource.username=root
spring.datasource.password=mypassword

It works fine until my spring boot app runs in a docker container on port 8082, (after the docker image is correctly built):

docker run -it -p 8082:8083 boot-example 

回答1:

As per above suggestion, Docker-compose is a way but if you don't want to go with compose/swarm mode.

  1. Simply create your own network using docker network create myNet
  2. Deploy your containers listening on a created network --network myNet
  3. Change your spring.datasource.url to jdbc:mysql://mymysql:6603/mydockerdb

By using DNS resolution of docker demon, containers can discover each other and hence can communicate. [DNS is not supported by default bridge. A user-defined network using bridge does.]

For more information: https://docs.docker.com/engine/userguide/networking/



回答2:

You cannot use localhost inside the container, it's the container itself. Hence, you will always get the connection refused error.

You can do below things -

  1. Add your host machine IP in application.properties file of your spring boot application. (Not recommended since it breaks docker portability logic)

  2. In case you want to use localhost, use --net=host while starting the container. (Not recommended for Production since no logical network layer exists)

  3. Use --links for container communication with a DNS name. (deprecated/legacy)

  4. Create a compose file & call your DB from spring boot app with the service name since they will be in same network & highly integrated with each other. (Recommended)

PS - Whenever you need to integrate multiple containers together, always go for docker-compose version 3+. Use docker run|build to understand the fundamentals & performing dry/test runs.



回答3:

As @vivekyad4v suggested - the easiest way to achieve your desire, is to use docker-compose which has better container communication integration.

Docker-compose is a tool for managing single or multiple docker container/s. It uses single configuration file called docker-compose.yml.

For better information about docker-compose, please take a look at documentation and compose file reference

In my experience, it is good practice to follow SRP (single responsibility principle), thus - creating one container for your database and one for your application. Both of them are communicating using network you specify in your configuration.

Following example of docker-compose.yml might help you:

version: '2'
 networks: 
 # your network name
  somename:
    driver: bridge

services:
   # PHP server
  php:
   image: dalten/php5.6-apache
   ports:
    - 80:80
   volumes:
    - .application_path:/some/application/path
   # your container network name defined at the beggining 
   networks: 
    - somename

   # Mysql server for backend
  mysql:
   image: dalten/mysql:dev
   ports:
    - 3306:3306
   # The /var/lib/mysql volume MUST be specified to achieve data persistence over container restart
   volumes:
    - ./mysql_data:/var/lib/mysql
   environment:
    MYSQL_ROOT_PASSWORD: root
    MYSQL_DATABASE: backend
   # your container network name defined at the beggining 
   networks: 
      - somename

Note: Communication between containers inside network can be achieved by calling the service name from inside container.

The connection parameters to MySQL container from PHP, would in this example be:

hostname: mysql
port: 3306
database: backend
user: root
password: root