[Docker] Port mapping. port numbers appear a lot, so I organized them.

This article can be read in about 19 minutes.

About Docker Port Mapping

Since several ports appear, it is messy and complicated, so we will organize them.

The above figure will be described as an example.

When Dockerizing and accessing services inside the container, the Docker container itself is an environment ((its own network interface, IP address, routing table, etc.) that is also independent of the host machine, so access is only possible through the container port.

Furthermore, if the flask application created in the container does not make a clear statement to allow access from the outside in the first place, there is a double restriction: even if the Docker container is accessible, the application cannot be launched.

External open in flask app: host='0.0.0.0'.

First, for the flask app, the host='0.0.0.0' setting must be added to the python file in which the app is run.

If the following is described, the Flask application will open a connection to the outside world on port 3000 and will listen for connections from outside (including host machines and all other non-hosts). Note that the default port is 5000, so there is no need to specify the port.

Python
if __name__ == '__main__':. 
    app.run(debug=True,  host='0.0.0.0', port=3000)

Two ways to configure Docker port mapping

In addition, docker containers also have ports, which can be accessed from the outside using a method called port mapping.

There are two main ways to perform port mapping.

When using thedocker run command

The -p option to the docker run command can be used to map the host’s port to the container’s port. The format is -p : .

For example, if the port 8080 of the host machine is mapped to port 3000 of the container, as shown in the figure above, the following would be used.

Zsh
docker run  -p  8080:3000 your-image-name

When using thedocker-compose.yml file

In the docker-compose.yml file, port mapping is defined in the services section. The format here is also : .

YAML
version: '3' 
 services: webapp:: webapp:: webapp:: webapp:: webapp:: webapp
   service s: webapp: 
     image: your-image-name 
     ports: 
       -  "8080:3000"

The result will look like the following. The above configuration will launch the image specified by the webapp service when the docker-compose up command is executed, mapping the host’s 8080 port to the container’s 3000 port.

It is time-consuming to execute the command docker run -p 8080:5001 your-image-name in the terminal every time, so I decided to define it in docker-compose.yml, and then use docker-compose up command to complete the mapping.

The EXPOSE instruction in the Dockerfile is not required.

In the Expose instruction in the Dockerfile, you may see the following description.

This indicates to Docker that the container will accept requests on port 3000. However, this is only for documentation purposes and does not actually expose the port to the outside world.

The EXPOSE instruction itself does not expose the port to the outside world, so when launching the container, the host machine’s port must be bound to the container’s port using the -p flag (e.g. docker run -p 8080:5001 image_name ) mentioned earlier.

YAML
# Use Python as a base image 
 FROM python:3.8-slim 
 
 # Set working directory 
 WORKDIR /app 
 
 # Copy necessary files to container 
 COPY . /app 
 
 # Install necessary packages 
 RUN pip install -r requirements.txt 
 
 # Open port 3000 
 EXPOSE 3000 
 
 # Command to run application 
 CMD ["python", "app.py"].

The Docker container port and the port number of the service running in the Docker container must match.

One question here is whether the port number of the docker container needs to match the port number specified in the flask application.

As it turns out, they must match. If they do not match, it is not possible to access the application in the container from the outside.

  • Port of Flask application in container: For example, suppose a Flask application is listening on port 5001 as app.run(host="0.0.0.0", port=5001).
  • Docker port mapping: In this case, the Docker command must be set to p 8080:5001. This will forward requests from port 8080 on the host machine to port 5001 on the container.
  • Access: With this setting, when accessing port 8080 on the host machine from the outside, the request is redirected to port 5001 in the container, where the Flask application receives processing.

If the container port does not match the port that the Flask application is listening on (e.g., Flask is listening on port 3100, but Docker maps it to 8080:5001), the Flask application cannot be accessed from the outside. Flask applications cannot be accessed from the outside. This is because requests from port 8080 on the host machine are forwarded to port 5001 on the container, but Flask is listening on a different port, in this case 3100.

There is currently no mechanism to configure the Docker container port and the Flask application port with different numbers and have them automatically bound together. It could be said that there is no need to have such a mechanism.

Regarding the port number listed in Running on

This is different between running the flask application directly without dockerization and with dockerization, and I was confused at first sight, so I leave this as a reminder.

To execute python files directly without Dockerization: port number of the executable

First, if you run without setting host='0.0.0.0', then

For understanding, we also dare to specify a port number, which is not usually set.

Python
if __name__ == "__main__":. 
    app.run(debug=True, port=3100)
Zsh
env   ~/dev/  python3 app/routes.py
 * Serving Flask app 'routes' 
  * Debug mode: on 
 WARNING: This is  a  development server. Do not use it in  a  production deployment. Use  a  production WSGI server instead. 
  * Running on http://127.0.0.1:3100 
 Press CTRL+C to quit 
  * Restarting with stat 
  * Debugger is active! 
  * Deb ugger   PIN :  801-553-609

The URL is http://127.0.0.1:3100, which is the only URL shown for access from the local host (localhost, i.e., own computer = 127.0.0.1). The IP address of the localhost: port number is listed.

127.0.0.1 is used as the IP address of localhost, which is determined by Internet protocol standards. It is called a loopback address. It is an address for a computer to communicate with itself, literally, a loopback address because the loop is backed up. It is such a convention, so we will break it down.

Next, if you run with host='0.0.0.0'

Python
python3app/routes.py 
  * Serving Flask app 'routes'. 
  * Debug mode: on 
  Do not use it in a production deployment. 
 * Running on all addresses (0.0.0.0) 
 * Running  onhttp://127.0.0.1:3100 
 * Running  onhttp://192.168.x.x:3100

The entry “Running on all addresses (0.0.0.0)” is added, and another address is shown in addition to the URL for access from the local host as shown earlier.

http://192.168.x.x:5000 is the URL for access from other devices in the local network (or external devices connected to the same network); this is the IP address that the machine the server is running on (the host machine) is using in the network.

However, the port is the same whether or not host='0.0.0.0.0' is added, and is the port number set in the flask application executable. Well, this is a matter of course. There are no other ports that can appear.

When Dockerizing and running a container: the port number is the host’s port number, but the log…

When you dockerize, a new independent environment called docker container is created, so the number of ports at the gateway increases dramatically.

If you docker run a dockerized flask application, it will look like this

Zsh
 $ docker-compose up 
  * Serving Flask app 'routes' 
  * Debug mode: on 
 WARNING: This is  a  development server. Do not use it in  a  production deployment. Use  a  production WSGI server instead. 
  * Running on all addresses (0.0.0.0 )
  * Run ning   on  http://127.0.0.1:3100 
  * Run ning   on  http://192.168.128.2:3100

Huh? The port number displayed here should be the host port, not the port number set in the flask application. Am I understanding this wrong? I tried to open the URL by clicking on it, but as I expected, I got an error.

When I retyped http://127.0.0.1:8080, it was displayed successfully.

  • 127.0.0.1: This is a local host address, valid only for the container itself.
  • 192.168.128.2: This is the IP address within the private network to which the Docker container is assigned and may be used to communicate with other containers.

Why did I get this log display?

Flask logs are generated in the context of container internals because they are based on the container’s internal network interface and IP address.

  • The address displayed in the log is: Address in the container’s internal network
  • Ports shown in the log: Ports that the flask application is actually listening on

reflects only whether it is inside Docker or in a normal host environment. For external access, the address (IP and port of the host machine) must be used according to Docker’s port mapping.

Is that why port bindings often list the same port number? I often see docker-compose.yml binding both host port and container port number as the same, which makes it possible to access the URL listed in the log when docker-compose is up by clicking on it.

YAML
version: '3' 
 services: webapp:: webapp:: webapp:: webapp:: webapp:: webapp
   service s: webapp: 
     image: your-image-name 
     ports: 
       -  "5000:5000"

However, it would be more convenient to set the same port number in the host machine = docker container = flask application executable, but on the other hand, since all the port numbers are the same, it would be difficult to understand how the site is accessed from the outside based on the principle of the same port number. On the other hand, since all the numbers are the same, it may be difficult to understand how the site is accessed from the outside.

In that case, the port number description would land on the default port number for each service for each image, since multiple services can be included in a docker container.

So in this case, the port binding number in docker-compose.yml and the port number in the flask app will all be 5000.

I am not sure if my understanding is correct.

If there are any errors in my understanding, I would appreciate your comments.

[Docker memorandum] Regarding DockerFile, docker-compose.yml, and Docker commands, click here.

Also, if multiple services with different functions are built in separate Docker containers, here is how to set up inter-container communication to allow inter-service coordination.

コメント

Copied title and URL