Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

python - Docker cannot connect application to MySQL

I am trying to run integration tests (in python) which depend on mysql. Currently they depend on SQL running locally, but I want them to depend on a MySQL running in docker.

Contents of Dockerfile:

FROM continuumio/anaconda3:4.3.1
WORKDIR /opt/workdir
ADD . /opt/workdir
RUN python setup.py install

Contents of Docker Compose:

version: '2'

services:
   mysql:
     image: mysql:5.6
     container_name: test_mysql_container
     environment:
       - MYSQL_ROOT_PASSWORD=test
       - MYSQL_DATABASE=My_Database
       - MYSQL_USER=my_user
       - MYSQL_PASSWORD=my_password
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     expose:
       - "3306"

   my_common_package:
     image: my_common_package
     depends_on:
       - mysql
     restart: always
     links:
       - mysql

volumes:
  db_data:

Now, I try to run the tests in my package using:

docker-compose run my_common_package python testsql.py

and I receive the error

pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'localhost' ([Errno 99] Cannot assign requested address)")

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

docker-compose will by default create virtual network were all the containers/services in the compose file can reach each other by an IP address. By using links, depends_on or network aliases they can reach each other by host name. In your case the host name is the service name, but this can be overridden. (see: docs)

Your script in my_common_package container/service should then connect to mysql on port 3306 according to your setup. (not localhost on port 3306)

Also note that using expose is only necessary if the Dockerfile for the service don't have an EXPOSE statement. The standard mysql image already does this.

If you want to map a container port to localhost you need to use ports, but only do this if it's necessary.

services:
   mysql:
     image: mysql:5.6
     container_name: test_mysql_container
     environment:
       - MYSQL_ROOT_PASSWORD=test
       - MYSQL_DATABASE=My_Database
       - MYSQL_USER=my_user
       - MYSQL_PASSWORD=my_password
     volumes:
       - db_data:/var/lib/mysql
     ports:
       - "3306:3306"

Here we are saying that port 3306 in the mysql container should be mapped to localhost on port 3306.

Now you can connect to mysql using localhost:3306 outside of docker. For example you can try to run your testsql.py locally (NOT in a container).

Container to container communication will always happen using the host name of each container. Think of containers as virtual machines.

You can even find the network docker-compose created using docker network list:

1b1a54630639        myproject_default             bridge              local
82498fd930bb        bridge                        bridge              local

.. then use docker network inspect <id> to look at the details.

Assigned IP addresses to containers can be pretty random, so the only viable way for container to container communication is using hostnames.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...