I have an app whose only dependency is flask, which runs fine outside docker and binds to the default port 5000. Here is the full source:
from flask import Flask
app = Flask(__name__)
app.debug = True
#app.route('/')
def main():
return 'hi'
if __name__ == '__main__':
app.run()
The problem is that when I deploy this in docker, the server is running but is unreachable from outside the container.
Below is my Dockerfile. The image is ubuntu with flask installed. The tar just contains the index.py listed above;
# Dockerfile
FROM dreen/flask
MAINTAINER dreen
WORKDIR /srv
# Get source
RUN mkdir -p /srv
COPY perfektimprezy.tar.gz /srv/perfektimprezy.tar.gz
RUN tar x -f perfektimprezy.tar.gz
RUN rm perfektimprezy.tar.gz
# Run server
EXPOSE 5000
CMD ["python", "index.py"]
Here are the steps I am doing to deploy
$> sudo docker build -t perfektimprezy .
As far as I know the above runs fine, the image has the contents of the tar in /srv. Now, let's start the server in a container:
$> sudo docker run -i -p 5000:5000 -d perfektimprezy
1c50b67d45b1a4feade72276394811c8399b1b95692e0914ee72b103ff54c769
Is it actually running?
$> sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c50b67d45b1 perfektimprezy:latest "python index.py" 5 seconds ago Up 5 seconds 0.0.0.0:5000->5000/tcp loving_wozniak
$> sudo docker logs 1c50b67d45b1
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
Yep, seems like the flask server is running. Here is where it gets weird. Lets make a request to the server:
$> curl 127.0.0.1:5000 -v
* Rebuilt URL to: 127.0.0.1:5000/
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:5000
> Accept: */*
>
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact
curl: (52) Empty reply from server
Empty reply... But is the process running?
$> sudo docker top 1c50b67d45b1
UID PID PPID C STIME TTY TIME CMD
root 2084 812 0 10:26 ? 00:00:00 python index.py
root 2117 2084 0 10:26 ? 00:00:00 /usr/bin/python index.py
Now let's ssh into the server and check...
$> sudo docker exec -it 1c50b67d45b1 bash
root#1c50b67d45b1:/srv# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:47677 127.0.0.1:5000 TIME_WAIT
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
root#1c50b67d45b1:/srv# curl -I 127.0.0.1:5000
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 5447
Server: Werkzeug/0.10.4 Python/2.7.6
Date: Tue, 19 May 2015 12:18:14 GMT
It's fine... But not from the outside.
What am I doing wrong?
The problem is you are only binding to the localhost interface, you should be binding to 0.0.0.0 if you want the container to be accessible from outside. If you change:
if __name__ == '__main__':
app.run()
to
if __name__ == '__main__':
app.run(host='0.0.0.0')
It should work.
Note that this will bind to all interfaces on the host, which may in some circumstances be a security risk - see https://stackoverflow.com/a/58138250/4332 for more information on binding to a specific interface.
When using the flask command instead of app.run, you can pass the --host option to change the host. The line in Docker would be:
CMD ["flask", "run", "--host", "0.0.0.0"]
or
CMD flask run --host 0.0.0.0
Your Docker container has more than one network interface. For example, my container has the following:
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
32: eth0#if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
if you run docker network inspect bridge, you can see that your container is connected to that bridge with the second interface in the above output. This default bridge is also connected to the Docker process on your host.
Therefore you would have to run the command:
CMD flask run --host 172.17.0.2
To access your Flask app running in a Docker container from your host machine. Replace 172.17.0.2 with whatever the particular IP address is of your container.
You need to modify the host to 0.0.0.0 in the docker file. This is a minimal example
# Example of Dockerfile
FROM python:3.8.5-alpine3.12
WORKDIR /app
EXPOSE 5000
ENV FLASK_APP=app.py
COPY . /app
RUN pip install -r requirements.txt
ENTRYPOINT [ "flask"]
CMD [ "run", "--host", "0.0.0.0" ]
and the file app.py is
# app.py
from flask import Flask
app = Flask(__name__)
#app.route("/")
def home():
return "Hello world"
if __name__ == "__main__":
app.run()
Then compile with
docker build . -t deploy_flask
and run with
docker run -p 5000:5000 -t -i deploy_flask:latest
You can check the response with curl http://127.0.0.1:5000/ -v
First of all in your python script you need to change code from
app.run()
to
app.run(host="0.0.0.0")
Second, In your docker file, last line should be like
CMD ["flask", "run", "-h", "0.0.0.0", "-p", "5000"]
And on host machine if 0.0.0.0:5000 doesn't work then you should try with localhost:5000
Note - The CMD command has to be proper. Because CMD command provide defaults for executing container.
To build on other answers:
Imagine you have two computers. Each computer has a network interface (WiFi, say), which is its public IP. Each computer has a loopback/localhost interface, at 127.0.0.1. This means "just this computer."
If you listed on 127.0.0.1 on computer A, you would not expect to be able to connect to that via 127.0.0.1 when running on computer B. After all, you asked to listen on computer A's local, private address.
Docker is similar setup; technically it's the same computer, but the Linux kernel is allowing each container to run with its own isolated network stack. So 127.0.0.1 in a container is the same as 127.0.0.1 on a different computer than your host—you can't connect to it.
Longer version, with diagrams: https://pythonspeed.com/articles/docker-connection-refused/
For fast readers, three quick things to check:
Make sure you have exposed the port in the Dockerfile.
Running the command in container using flask run --host=0.0.0.0
Specifying the port in your docker run command docker run -it -p5000:5000 yourImageName
In my case, binding the host to 0.0.0.0 only worked on my local environment, and it failed when deploying on a server.
Then it's working when I replaced the port with --network=host:
Before:
docker run -d -p 5000:5000 <docker_image>
After:
docker run -d --network=host <docker_image>
ps. I still used the 0.0.0.0:5000 inside the container when running the flask app.
Related
I have an app whose only dependency is flask, which runs fine outside docker and binds to the default port 5000. Here is the full source:
from flask import Flask
app = Flask(__name__)
app.debug = True
#app.route('/')
def main():
return 'hi'
if __name__ == '__main__':
app.run()
The problem is that when I deploy this in docker, the server is running but is unreachable from outside the container.
Below is my Dockerfile. The image is ubuntu with flask installed. The tar just contains the index.py listed above;
# Dockerfile
FROM dreen/flask
MAINTAINER dreen
WORKDIR /srv
# Get source
RUN mkdir -p /srv
COPY perfektimprezy.tar.gz /srv/perfektimprezy.tar.gz
RUN tar x -f perfektimprezy.tar.gz
RUN rm perfektimprezy.tar.gz
# Run server
EXPOSE 5000
CMD ["python", "index.py"]
Here are the steps I am doing to deploy
$> sudo docker build -t perfektimprezy .
As far as I know the above runs fine, the image has the contents of the tar in /srv. Now, let's start the server in a container:
$> sudo docker run -i -p 5000:5000 -d perfektimprezy
1c50b67d45b1a4feade72276394811c8399b1b95692e0914ee72b103ff54c769
Is it actually running?
$> sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c50b67d45b1 perfektimprezy:latest "python index.py" 5 seconds ago Up 5 seconds 0.0.0.0:5000->5000/tcp loving_wozniak
$> sudo docker logs 1c50b67d45b1
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
Yep, seems like the flask server is running. Here is where it gets weird. Lets make a request to the server:
$> curl 127.0.0.1:5000 -v
* Rebuilt URL to: 127.0.0.1:5000/
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:5000
> Accept: */*
>
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact
curl: (52) Empty reply from server
Empty reply... But is the process running?
$> sudo docker top 1c50b67d45b1
UID PID PPID C STIME TTY TIME CMD
root 2084 812 0 10:26 ? 00:00:00 python index.py
root 2117 2084 0 10:26 ? 00:00:00 /usr/bin/python index.py
Now let's ssh into the server and check...
$> sudo docker exec -it 1c50b67d45b1 bash
root#1c50b67d45b1:/srv# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:47677 127.0.0.1:5000 TIME_WAIT
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
root#1c50b67d45b1:/srv# curl -I 127.0.0.1:5000
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 5447
Server: Werkzeug/0.10.4 Python/2.7.6
Date: Tue, 19 May 2015 12:18:14 GMT
It's fine... But not from the outside.
What am I doing wrong?
The problem is you are only binding to the localhost interface, you should be binding to 0.0.0.0 if you want the container to be accessible from outside. If you change:
if __name__ == '__main__':
app.run()
to
if __name__ == '__main__':
app.run(host='0.0.0.0')
It should work.
Note that this will bind to all interfaces on the host, which may in some circumstances be a security risk - see https://stackoverflow.com/a/58138250/4332 for more information on binding to a specific interface.
When using the flask command instead of app.run, you can pass the --host option to change the host. The line in Docker would be:
CMD ["flask", "run", "--host", "0.0.0.0"]
or
CMD flask run --host 0.0.0.0
Your Docker container has more than one network interface. For example, my container has the following:
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
32: eth0#if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
if you run docker network inspect bridge, you can see that your container is connected to that bridge with the second interface in the above output. This default bridge is also connected to the Docker process on your host.
Therefore you would have to run the command:
CMD flask run --host 172.17.0.2
To access your Flask app running in a Docker container from your host machine. Replace 172.17.0.2 with whatever the particular IP address is of your container.
You need to modify the host to 0.0.0.0 in the docker file. This is a minimal example
# Example of Dockerfile
FROM python:3.8.5-alpine3.12
WORKDIR /app
EXPOSE 5000
ENV FLASK_APP=app.py
COPY . /app
RUN pip install -r requirements.txt
ENTRYPOINT [ "flask"]
CMD [ "run", "--host", "0.0.0.0" ]
and the file app.py is
# app.py
from flask import Flask
app = Flask(__name__)
#app.route("/")
def home():
return "Hello world"
if __name__ == "__main__":
app.run()
Then compile with
docker build . -t deploy_flask
and run with
docker run -p 5000:5000 -t -i deploy_flask:latest
You can check the response with curl http://127.0.0.1:5000/ -v
First of all in your python script you need to change code from
app.run()
to
app.run(host="0.0.0.0")
Second, In your docker file, last line should be like
CMD ["flask", "run", "-h", "0.0.0.0", "-p", "5000"]
And on host machine if 0.0.0.0:5000 doesn't work then you should try with localhost:5000
Note - The CMD command has to be proper. Because CMD command provide defaults for executing container.
To build on other answers:
Imagine you have two computers. Each computer has a network interface (WiFi, say), which is its public IP. Each computer has a loopback/localhost interface, at 127.0.0.1. This means "just this computer."
If you listed on 127.0.0.1 on computer A, you would not expect to be able to connect to that via 127.0.0.1 when running on computer B. After all, you asked to listen on computer A's local, private address.
Docker is similar setup; technically it's the same computer, but the Linux kernel is allowing each container to run with its own isolated network stack. So 127.0.0.1 in a container is the same as 127.0.0.1 on a different computer than your host—you can't connect to it.
Longer version, with diagrams: https://pythonspeed.com/articles/docker-connection-refused/
For fast readers, three quick things to check:
Make sure you have exposed the port in the Dockerfile.
Running the command in container using flask run --host=0.0.0.0
Specifying the port in your docker run command docker run -it -p5000:5000 yourImageName
In my case, binding the host to 0.0.0.0 only worked on my local environment, and it failed when deploying on a server.
Then it's working when I replaced the port with --network=host:
Before:
docker run -d -p 5000:5000 <docker_image>
After:
docker run -d --network=host <docker_image>
ps. I still used the 0.0.0.0:5000 inside the container when running the flask app.
I want to use scrapinghub/splash container on Azure App Service (Web App for Containers) on Linux.
But docker run command on deploy randomly changes the binding port of container side (see the log below, port 8961 is automatically assigned. this number varies every deploy)
2020-01-21 08:56:47.494 INFO - docker run -d -p 8961:8050 --name b2scraper-splash_3_d89ce1f2 -e WEBSITES_ENABLE_APP_SERVICE_STORAGE=false -e WEBSITES_PORT=8050 -e WEBSITE_SITE_NAME=b2scraper-splash -e WEBSITE_AUTH_ENABLED=False -e PORT=8050 -e WEBSITE_ROLE_INSTANCE_ID=0 -e WEBSITE_HOSTNAME=b2scraper-splash.azurewebsites.net -e WEBSITE_INSTANCE_ID=5446f93a2cbcb25300f091395c54ce738773ce47489c2818322ffabbc23e3413 scrapinghub/splash:latest python3 /app/bin/splash --proxy-profiles-path /etc/splash/proxy-profiles --js-profiles-path /etc/splash/js-profiles --filters-path /etc/splash/filters --lua-package-path "/etc/splash/lua_modules/?.lua" --disable-private-mode --port 8050
Changing host port binding is possible using WEBSITES_PORT, but seems no way to change container side.
Is there way to fix container-side port binding like -p 8050:80 or -p 8050:443 of docker run command?
e.g. Using the container on Azure Container Instances is possible, without changing service port 8050.
--publish in the docker run command creates a firewall rule which maps a container port to a port on the Docker host.
https://docs.docker.com/config/containers/container-networking/
For the command: docker run -d -p 8961:8050 imagename, TCP port 8050 in the container is mapped to 8961 on the Docker Host. On App Services, this docker run command cannot be changed. The container port (8050 in this case) can be set to a specific value using WEBSITES_PORT application setting.
That doesn´t work. you get 443 as port with HTTPS.
Neither EXPOSE XXXX, nor WEBSITES_PORT or PORT as configuration parameters...
You do see "docker run -d -p 8961:8050" in the logs, but it doesn´t matter to Azure when it comes to exposing the app...
I am having the same problem like here and here
I am Trying to run a flask app inside docker container.It works fine with '0.0.0.0' but it throws error with my ip address
I am behind a corporate proxy. When i checked my ip address with ipconfig, it showed IP Address as : 10.***.**.** And I am using docker toolbox where my container ip is 172.17.0.2 and VM IP Address is 192.168.99.100.
I have a flask app running inside this docker with host
if __name__ == "__main__":
app.run(host= '0.0.0.0')
works fine. But when i change it to my ip address
if __name__ == "__main__":
app.run(host= '10.***.**')
throws error :
socket.error:[errno 99] cannot assign requested address
I checked again the ip address with a simple flask application which is running on local (i.e without docker)
if __name__ == "__main__":
app.run(host= '10.***.**')
It worked fine.
So the problem is coming only when running inside the docker. And that's because i am behind a router running NAT with internal ip address. And how do i find this internal ip address with NAT? I have already done port forwarding for flask application with port 5000.
> iptables -t nat -A DOCKER -p tcp --dport 5000 -j DNAT --to-destination 172.17.0.2:5000
> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https
> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https
To let other computers on the LAN connect to your service just use 0.0.0.0 address in app.run() function and expose desired port from your docker container to your host PC.
To expose port you need to
1) specify EXPOSE directive in Dockerfile
2) run container with -p <port_on_host>:<port_in_container> parameter.
For example:
Dockerfile:
FROM ubuntu:17.10
RUN apt-get update && apt-get install -y apache2
EXPOSE 80
ENTRYPOINT ["/usr/sbin/apache2ctl"]
CMD ["-D", "FOREGROUND"]
Build:
docker build -t image_name .
Run:
docker run -d -p 80:80 image_name
Check:
curl http://localhost
P.S. make sure that 80 port is not used by another app on your host PC before running container. If this port is already in use - specify another port, for example 8080:
docker run -d -p 8080:80 image_name
And then check:
curl http://localhost:8080
Docs are here.
The answer of OSError [Errno 99] - python applies here also.
If it works using the ip address but not using hostname.
Removing double localhost in /etc/hosts should be solution. hosts file should look something like this (mapping ip to hostname)
127.0.0.1 localhost
127.0.1.1 your_hostname_here
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Answer by #'Artsiom Praneuski' is only concerned with Docker configuration, which is all relevant in docker container setup but does not point to Python environment fix(both container and normal setup).
I have an app whose only dependency is flask, which runs fine outside docker and binds to the default port 5000. Here is the full source:
from flask import Flask
app = Flask(__name__)
app.debug = True
#app.route('/')
def main():
return 'hi'
if __name__ == '__main__':
app.run()
The problem is that when I deploy this in docker, the server is running but is unreachable from outside the container.
Below is my Dockerfile. The image is ubuntu with flask installed. The tar just contains the index.py listed above;
# Dockerfile
FROM dreen/flask
MAINTAINER dreen
WORKDIR /srv
# Get source
RUN mkdir -p /srv
COPY perfektimprezy.tar.gz /srv/perfektimprezy.tar.gz
RUN tar x -f perfektimprezy.tar.gz
RUN rm perfektimprezy.tar.gz
# Run server
EXPOSE 5000
CMD ["python", "index.py"]
Here are the steps I am doing to deploy
$> sudo docker build -t perfektimprezy .
As far as I know the above runs fine, the image has the contents of the tar in /srv. Now, let's start the server in a container:
$> sudo docker run -i -p 5000:5000 -d perfektimprezy
1c50b67d45b1a4feade72276394811c8399b1b95692e0914ee72b103ff54c769
Is it actually running?
$> sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c50b67d45b1 perfektimprezy:latest "python index.py" 5 seconds ago Up 5 seconds 0.0.0.0:5000->5000/tcp loving_wozniak
$> sudo docker logs 1c50b67d45b1
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
Yep, seems like the flask server is running. Here is where it gets weird. Lets make a request to the server:
$> curl 127.0.0.1:5000 -v
* Rebuilt URL to: 127.0.0.1:5000/
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:5000
> Accept: */*
>
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact
curl: (52) Empty reply from server
Empty reply... But is the process running?
$> sudo docker top 1c50b67d45b1
UID PID PPID C STIME TTY TIME CMD
root 2084 812 0 10:26 ? 00:00:00 python index.py
root 2117 2084 0 10:26 ? 00:00:00 /usr/bin/python index.py
Now let's ssh into the server and check...
$> sudo docker exec -it 1c50b67d45b1 bash
root#1c50b67d45b1:/srv# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:47677 127.0.0.1:5000 TIME_WAIT
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
root#1c50b67d45b1:/srv# curl -I 127.0.0.1:5000
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 5447
Server: Werkzeug/0.10.4 Python/2.7.6
Date: Tue, 19 May 2015 12:18:14 GMT
It's fine... But not from the outside.
What am I doing wrong?
The problem is you are only binding to the localhost interface, you should be binding to 0.0.0.0 if you want the container to be accessible from outside. If you change:
if __name__ == '__main__':
app.run()
to
if __name__ == '__main__':
app.run(host='0.0.0.0')
It should work.
Note that this will bind to all interfaces on the host, which may in some circumstances be a security risk - see https://stackoverflow.com/a/58138250/4332 for more information on binding to a specific interface.
When using the flask command instead of app.run, you can pass the --host option to change the host. The line in Docker would be:
CMD ["flask", "run", "--host", "0.0.0.0"]
or
CMD flask run --host 0.0.0.0
Your Docker container has more than one network interface. For example, my container has the following:
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
32: eth0#if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
if you run docker network inspect bridge, you can see that your container is connected to that bridge with the second interface in the above output. This default bridge is also connected to the Docker process on your host.
Therefore you would have to run the command:
CMD flask run --host 172.17.0.2
To access your Flask app running in a Docker container from your host machine. Replace 172.17.0.2 with whatever the particular IP address is of your container.
You need to modify the host to 0.0.0.0 in the docker file. This is a minimal example
# Example of Dockerfile
FROM python:3.8.5-alpine3.12
WORKDIR /app
EXPOSE 5000
ENV FLASK_APP=app.py
COPY . /app
RUN pip install -r requirements.txt
ENTRYPOINT [ "flask"]
CMD [ "run", "--host", "0.0.0.0" ]
and the file app.py is
# app.py
from flask import Flask
app = Flask(__name__)
#app.route("/")
def home():
return "Hello world"
if __name__ == "__main__":
app.run()
Then compile with
docker build . -t deploy_flask
and run with
docker run -p 5000:5000 -t -i deploy_flask:latest
You can check the response with curl http://127.0.0.1:5000/ -v
First of all in your python script you need to change code from
app.run()
to
app.run(host="0.0.0.0")
Second, In your docker file, last line should be like
CMD ["flask", "run", "-h", "0.0.0.0", "-p", "5000"]
And on host machine if 0.0.0.0:5000 doesn't work then you should try with localhost:5000
Note - The CMD command has to be proper. Because CMD command provide defaults for executing container.
To build on other answers:
Imagine you have two computers. Each computer has a network interface (WiFi, say), which is its public IP. Each computer has a loopback/localhost interface, at 127.0.0.1. This means "just this computer."
If you listed on 127.0.0.1 on computer A, you would not expect to be able to connect to that via 127.0.0.1 when running on computer B. After all, you asked to listen on computer A's local, private address.
Docker is similar setup; technically it's the same computer, but the Linux kernel is allowing each container to run with its own isolated network stack. So 127.0.0.1 in a container is the same as 127.0.0.1 on a different computer than your host—you can't connect to it.
Longer version, with diagrams: https://pythonspeed.com/articles/docker-connection-refused/
For fast readers, three quick things to check:
Make sure you have exposed the port in the Dockerfile.
Running the command in container using flask run --host=0.0.0.0
Specifying the port in your docker run command docker run -it -p5000:5000 yourImageName
In my case, binding the host to 0.0.0.0 only worked on my local environment, and it failed when deploying on a server.
Then it's working when I replaced the port with --network=host:
Before:
docker run -d -p 5000:5000 <docker_image>
After:
docker run -d --network=host <docker_image>
ps. I still used the 0.0.0.0:5000 inside the container when running the flask app.
This question already has answers here:
Deploying a minimal flask app in docker - server connection issues
(8 answers)
Closed 5 years ago.
I have a flask script which I try to execute it via docker run command. Following command i am doing
docker run -dit -v /media/sf_MY_WINDOWS/GitRepo/:/ext/GitRepo -p 5000:5000 "isbhatt/prefixman:v1" /ext/docker/vm_scripts/db_loader.sh
and db_loader.sh file contains
/usr/local/bin/python2.7 /ext/SDSNG/src/prefix_manager/manage.py runserver --host 0.0.0.0 &
but when I do curl localhost:5000 Connection refused.
If I go into container and run the stuff and do curl localhost:5000 it works in container..
What is wrong here?
Output of netstat -tln on container
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN
If inside your container your script is binding to 127.0.0.1, then the port forwarding normally provided using -p will not work. Ensure that inside the container your service is listening on 0.0.0.0.
You can check on what address your service is listening by running netstat -tln inside the container:
container# netstat -tln
If you see this:
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN
Then that's your problem. You want to see:
tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN
Resolved it. By removing & at the end of manage.py runserver --host 0.0.0.0
That & kept the process in the background and if no process is running in foreground the container would stop even if you have provided -d option.
And #Iarsks , Yup the --host has to be 0.0.0.0 .