How to read docker port mapping information? - mysql

I just started learning docker and I‘m a bit confused with port mapping in docker. I have container (which runs mysql service) running as below:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
59efytd163d3 myapp:mysql "docker-entrypoint.s…" 10 months ago Up 5 minutes 0.0.0.0:9991->3306/tcp
For the PORTS field, what does 0.0.0.0:9991->3306/tcp mean?
I checked the port number of mysql that's running outside the container:
john#MacBook-Pro:~/Documents$ lsof -n -P -i TCP | grep mysql
mysqld 1742 john 58u IPv4 0xd3c7de51ef6d2a49 0t0 TCP 127.0.0.1:3306 (LISTEN)
As you can see, the port is 3306, so I thought the port number for the mysql running inside the container must be 9991. However, after I got into the container and checked the mysql:
mysql> SHOW GLOBAL VARIABLES LIKE 'PORT'
-> ;
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| port | 3306 |
+---------------+-------+
1 row in set (0.00 sec)
It also shows 3306.
Both the mysql services running inside and outside the container has port number 3306. Where does the 0.0.0.0:9991->3306/tcp mean then? what does the 0.0.0.0:9991 refer to?

Docker runs containers on virtual networks:
docker network ls
NETWORK ID NAME DRIVER SCOPE
1234567890ab bridge bridge local
cdef01234567 deployment_default bridge local
890abcdef012 host host local
34567890abcd none null local
These port mappings bind ports on your host machine with containers running on these networks.
Think of each container as its own localhost with all ports available to it. In this case, your MySQL instance exposes port 3306 on its container. This is necessary because the binary in the container is also running on 3306. This explains why, within the container, you see 3306.
Very conveniently, when you run a container, Docker provides a mechanism for you to remap container ports (e.g. 3306) onto different ports (e.g. 9991) on your host machine.
This is more than just a convenience. If you wanted to run a second MySQL container image and it was also configured for 3306, you'd be unable to access both containers at the same time because they'd collide with the port 3306 on your host.
So, you define a port-mapping as you've done. In your example, from your local workstation (host), you can access the MySQL container instance on localhost:9991 and Docker remaps that port's traffic to the MySQL container's port 3306 and the container routes it to the MySQL binary (also on 3306).
So: 0.0.0.0:9991->3306/tcp means:
0.0.0.0 (an alias for any adaptor on localhost)
9991 port traffic maps to this container's port 3306
Using TCP (another protocol that you will see is UDP)
Three additional notes:
This image's Dockerfile may include e.g. EXPOSE 3306. This is purely documentary and in no way affects the docker run ... --publish=XXXX/3306.. command.
Container needs not publish ports to the localhost. This need only be done if the container image must be accessed from the host. If you name your containers and put them on user-defined networks or use Docker Compose, one container may access ports on another container without exposing ports to the host. Exposing ports like this should be (!) a security consideration.
When you run a container image, Docker uses a default network. The port-mapping resolution (0.0.0.0:XXXX/YYYY) is actually a combination of identifying which container (hostname resolution) and which port.

Related

Node RED on Docker writing on MYSQL database

I am running Node-RED on Docker, and I am trying to write data to MySQL on my localhost.
As host, I am using localhost (see picture)
I receive the error: connection refused.
Which Host address should I use here? I don't quite understand the communication between the container and the local host.
localhost always points to the TCP/IP stack that the program opening the connection is bound to.
Every Docker container has it's own TCP/IP stack so unless the database is running in the same container as Node-RED localhost will not be the correct hostname for the database.
You have 3 choices
If you are using docker-compose then you can use the container name as the hostname and it will connect to the right container.
You can use the docker inspect [container-instance-name] to find the IP address assigned to the database container and use that
If you have mapped the container port to your host machine (with the -p option) then you can use the IP address of the host which normally defaults to 172.17.0.1
Edit:
To connect to the host machine then you can use host.docker.internal on Docker for Windows and Docker for Mac (unfortunately the issue to fix this on Linux has been open for over 3 years).
You should also be able to use the IP address from point 3 above.

How to bind mysql port from host to docker container without port clash

I have a docker container running a Flask application that connects to a mySQL server. The mySQL server is hosted on the host machine at port 3308 on a windows 10 machine.
When executing
docker run -p 5000:5000 -p 3308:3308 -t webui
I receive the error
Ports are not available: listen tcp 0.0.0.0:3308: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.
due to the port being used by the mySQL server on the host machine
How do I map the port of the mySQL to the docker container such that the Flask application can access the database?
There are 2 ways to achieve this. The first approach is the recommended one.
The first is to add an entry to /etc/hosts inside the container:
docker run -p 5000:5000 -p 3308:3308 --add-host database:<HOST_IP> -t webui
You need to replace HOST_IP with the network IP of your host. Then you can reference the database inside your container using the name "database" (you can also customize this one).
The second is to bind your container to your host's interface:
docker run -p 5000:5000 -p 3308:3308 --bind 127.0.0.1 -t webui
Then you can refer to your database with 127.0.0.1 inside your container.
The issue was caused by the host name. The mySQL database port did not need to be bound to the container as it did not need to receive any inbound calls, only outbound to the database. Resolved by adding a new entry into the container's /etc/hosts file as described here.

Can't connect to db from docker container [duplicate]

This question already has answers here:
From inside of a Docker container, how do I connect to the localhost of the machine?
(41 answers)
Closed 3 years ago.
I have MySQL server installed on a server and dockerized project, The DB is not publicly accessible, only from inside the server. It's used by local non dockerized apps too.
I want to connect to it from inside the docker with it remaining not publicly accessible, I tried 172.17.0.1 but I get connection refused.
the current bind_address is 127.0.0.1, What do you suggest the bind_address would be ??
You can run the application through the host network mode which will make the container able to connect to the localhost of your main server (the docker host) while keeping the bind-address points to 127.0.0.1.
So you need to run your application like this if you are using docker cli:
docker run --network=host myappimage
In case of docker-compose you will use is in your service:
network_mode: host
Trying to describe a bit better what I understand from your question at first:
You have a host with mysql installed (not dockerized, but directly
on your host)
You have some client apps connecting to that MySQL in your host
using your localhost IP and the mysql port (let's say:
127.0.0.1:3306 by default)
Now you created a docker container with another app (inside the
container) that you want to have connected with your MySQL server,
which is still running in your host, accessible locally, but out
of your new container (or any other container)
You want your dockerized service to remain isolated, with no other contact with anything else outside your container (but the MySQL server, of course)
⚠️ Well, I'm going to start by ruling out the option of using --net=host (even when it could work in similar cases to allow your services to "live" in your host's network) since you don't want your container to be available from your other host's processes nor having access to anything else (which would happen with host networking)
Connecting to [non-dockerized] services in your host
✔️ In this case, what you actually need to do (from your app inside your container) is to connect to your Docker Host's IP
But not to the IP in your regular local network (e.g.: 192.168.1.5) nor in your public/wlan network, but to the IP that docker assigns to your host within your docker network itself (the network that docker creates to comunicate with and between your containers)
By default (if you don't specify any other network settings for your container) your container should be using the docker's bridge network, which is setup in the host (not inside the container) and commonly named docker0
So, it's as simple as finding the IP corresponding to your Host, and using that one as your mysql client's bind_address (e.g.: jdbc:mysql://172.X.XX.XX:3306 or $dbhost = "172.X.XX.XX"; etc.)
What is my Docker Host IP address?
Ok... and how can I find the IP that docker assigns to my host (the one for the docker's bridge network)?
Manually
You can just list all of your current assigned IP addresses, to find the one corresponding to that docker0 network:
ip -4 addr
or even better by directly filtering the one that you want:
ip -4 addr show docker0
You'll get an output similar to this:
3: docker0: mtu 1500 qdisc noqueue
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
And copy the ip that appears there after inet
Automatically
I like using this script to directly grab my current docker's host IP (especially useful when testing across many hosts):
ip -4 addr show docker0 | awk '$1=="inet" {print $2}' | cut -d/ -f1
Just put it in some handly place (e.g. in your /.bashrc) assigned to some environment variable:
export DOCKER_HOST_IP="$(ip -4 addr show docker0 | awk '$1=="inet" {print $2}' | cut -d/ -f1 )"
Hope it could be useful!

Runing multiple mysql containers with different port using host network

I have a Mysql server running on the host using default port 3306. I Want to run a MySQL docker container using network host but with a different port.
My configuration is defined in a docker-compose file. After building the image and tried running the container, it starts and shutdown with port conflict notice.
Is there a way to dynamically change the container port before starting up? I don't want to use the network bridge.
If using host networking is a hard requirement, then nothing in Docker space will be able to control or limit what ports the service does or doesn't use. You need to change a service-specific configuration file, environment variable, or command-line argument to make it listen somewhere else.
Particularly for servers that listen on a single TCP port (like most database and HTTP-based servers) the default Docker bridge/NAT setup should work fine; alternate setups like host networking and macvlan are unnecessary. If you're willing to use the standard setup, this is trivial:
version: '3'
services:
mysql:
image: mysql
ports: ['9999:3306'] # listen on host port 9999 instead
docker run --name 'dockername' -e MYSQL_ROOT_PASSWORD='password' -p 1000:3306 -d mysql
docker exec -it 'dockername' mysql -uroot -p
ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'password'
flush privileges;
here 1000 is the port at which you want to run your mysql docker container.

Port forwarding with docker for wordpress

I'm a newbie to docker. I followed the tutorials here https://www.youtube.com/watch?v=Pe6a8Jbvi9E to create a WordPress site with docker. He is explaining about port forwarding with the following command,
docker run --link=my_mysql:mysql -p 80:80 -d wordpress
As of my understanding, this will redirect all the requests in the port 80 of host to the port 80 of container. But how this will communicate with the port 3306 of mysql? And also in that tutorial database details not set anywhere for wordpress , than from where the db config values are taken from? Can someone explain? Sorry if this are very basic questions.
But how this will communicate with the port 3306 of mysql?
The wordpress container will communicate with the mysql container, because that is what a link allows: (see Linking Containers Together)
Links allow containers to discover each other and securely transfer information about one container to another container. When you set up a link, you create a conduit between a source container and a recipient container.
So the port 3306 is not exposed to the host (like the 80 port is), but it is visible to wordpress container.
Docker creates a secure tunnel between the containers that doesn't need to expose any ports externally on the container; you'll note when we started the db container we did not use either the -P or -p flags.
That's a big benefit of linking: we don't need to expose the source container, here the mysql database, to the network.
Docker defines a set of environment variables for each port exposed by the source container.
Each variable has a unique prefix in the form:
<name>_PORT_<port>_<protocol>
The components in this prefix are:
the alias <name> specified in the --link parameter (for example, mysql)
the <port> number exposed
a <protocol> which is either TCP or UDP