I am trying to deploy an OpenPLC container on GNS3.
I have performed an initial test deployment outside of GNS3 to see that it works properly.
docker run --privileged --restart=always --publish 8080:8080 --publish 502:502 --ip 172.17.0.2 sflorenz05/open-plc:v0.1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0e8443707946 sflorenz05/open-plc:v0.1 "./start_openplc.sh" 3 seconds ago Up 2 seconds 0.0.0.0:502->502/tcp, :::502->502/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp goofy_poincare
Without including the "detach" option, we can see how the container is accessed from the web.
* Serving Flask app "webserver" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
172.31.88.200 - - [15/Nov/2022 16:00:53] "GET / HTTP/1.1" 302 -
172.31.88.200 - - [15/Nov/2022 16:00:53] "GET /login HTTP/1.1" 200 -
172.31.88.200 - - [15/Nov/2022 16:00:55] "GET /favicon.ico HTTP/1.1" 404 -
172.31.88.200 - - [15/Nov/2022 16:00:55] "GET /static/openplc_logo.gif HTTP/1.1" 200 -
In GNS3, I have properly added the container:
I have added the IP addresses from the GNS3 network configuration for the container.
# Static config for eth0
auto eth0
iface eth0 inet static
address 172.17.0.2
netmask 255.255.0.0
gateway 172.17.0.1
up echo nameserver 8.8.8.8 > /etc/resolv.conf
I have also directly added commands to expose the container ports:
In both cases, the container does not expose the ports, so it is not possible to access the container:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c8161f61bbfe sflorenz05/open-plc:v0.1 "/gns3/init.sh ./sta…" 7 seconds ago Up 3 seconds pensive_hermann
Any suggestion?
To resolve the issue, I have rebuilt the Dockerfile exposing the ports of interest:
FROM debian:bullseye-20211201
COPY . /workdir
WORKDIR /workdir
RUN ./install.sh docker
EXPOSE 502
EXPOSE 8080
ENTRYPOINT ["./start_openplc.sh"]
I then created the following testbed:
I have assigned neighboring IP addresses to the devices with respect to that of the bridge that GNS3 creates:
3: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 52:54:00:45:6a:2e brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
I have accessed the exposed web service on port 8080 and enabled the use of the exposed Modbus server on port 502.
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 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've moved my Mongodb from a container to a local service (it was really flaky when containerised). Problem is I cannot connect from a Node api into the locally running MongoDB service. I can get this working on my Mac, but not on Ubuntu. I've tried:
- DB_HOST=mongodb://172.17.0.1:27017/proto?authSource=admin
- DB_HOST=mongodb://localhost:27017/proto?authSource=admin
// this works locally, but not on my Ubuntu server
- DB_HOST=mongodb://host.docker.internal:27017/proto?authSource=admin
Tried adding this to my docker file:
ip -4 route list match 0/0 | awk '{print $3 "host.docker.internal"}' >> /etc/hosts && \
Also tried network bridge to no avail. Example docker compose
version: '3.3'
services:
search-api:
build: ../search-api
environment:
- PORT=3333
- DB_HOST=mongodb://host.docker.internal:27017/search?authSource=admin
- DB_USER=dbuser
- DB_PASS=password
ports:
- 3333:3333
restart: always
Problem can be caused by MongoDb not listening on the correct ip address and therefore blocking your access.
Either make sure you're listening to a specific ip or listening to all: 0.0.0.0
On linux the config file is per default installed here: /etc/mongod.conf
Configuration specific Ip address:
net:
bindIp: 172.17.0.1 #being your host's ip address
port: 27017
Configuration open to all connections:
net:
bindIp: 0.0.0.0
port: 27017
To get your hosts ip address (from within a container)
On docker-for-mac and docker-for-windows you can use host.docker.internal
While on linux you need to run ip route show in the container.
When running Docker natively on Linux, you can access host services using the IP address of the docker0 interface. From inside the container, this will be your default route.
For example, on my system:
$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link
valid_lft forever preferred_lft forever
And inside a container:
# ip route show
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 src 172.17.0.4
(copied from here: How to access host port from docker container)
I have a python unittest code inside a centos6.8 container. The unittest code needs to bind to 127.0.0.1.
This container is run with overlay network instead of host. The failure seems to go away if I switch docker run to --network host.
Inside the container I do see a loopback
[rtpbuild#bldrh6rtp89-rh6 /]$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
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
Any suggestion on why binding to 127.0.0.1 doesn't work when overlay network is used but works when host network is used? And how can I make it work under overlay network?
Should work, you need to elaborate a bit more how you run containers. As an example, docker swarm cluster, manager node, overlay network in swarm scope.
Command
docker run -it --rm --network ${network} -p 127.0.0.1:555:8080 caa06d9c/echo
Request
curl 127.0.0.1:555/
Reply
{
"method": "GET",
"path": "/",
"ip": "172.17.0.1"
}
Command
docker run -it --rm --network ${network} -p 127.0.0.1:555:8080 caa06d9c/echo --ip 127.0.0.1
Check
docker exec ${container} netstat -ptunl
Result
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 1/python3
So Docker correctly assign interfaces and ports
I have a swarm cluster in which I created a global service to run on all docker hosts in the cluster.
The goal is to have each container instance for this service connect to a port listening on the docker host.
For further information, I am following this Docker Daemon Metrics guide for exposing the new docker metrics API on all hosts and then proxying that host port into the overlay network so that Prometheus can scrape metrics from all swarm hosts.
I have read several docker github issues #8395 #32101 #32277 #1143 - from this my understanding is the same as outlined in the Docker Daemon Metrics. In order to connect to the host from within a swarm container, I should use the docker-gwbridge network which by default is 172.18.0.1.
Every container in my swarm has a network interface for the docker-gwbridge network:
326: eth0#if327: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
link/ether 02:42:0a:ff:00:06 brd ff:ff:ff:ff:ff:ff
inet 10.255.0.6/16 scope global eth0
valid_lft forever preferred_lft forever
inet 10.255.0.5/32 scope global eth0
valid_lft forever preferred_lft forever
333: eth1#if334: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.4/16 scope global eth1
valid_lft forever preferred_lft forever
Also, every container in the swarm has a default route that is via 172.0.0.1:
/prometheus # ip route show 0.0.0.0/0 | grep -Eo 'via \S+' | awk '{ print $2 }'
172.18.0.1
/prometheus # netstat -nr | grep '^0\.0\.0\.0' | awk '{print $2}'
172.18.0.1
/prometheus # ip route
default via 172.18.0.1 dev eth1
10.0.1.0/24 dev eth2 src 10.0.1.9
10.255.0.0/16 dev eth0 src 10.255.0.6
172.18.0.0/16 dev eth1 src 172.18.0.4
Despite this, I cannot communicate with 172.18.0.1 from within the container:
/ # wget -O- 172.18.0.1:4999
Connecting to 172.18.0.1:4999 (172.18.0.1:4999)
wget: can't connect to remote host (172.18.0.1): No route to host
On the host, I can access the docker metrics API on 172.18.0.1. I can ping and I can make a successful HTTP request.
Can anyone shed some light as to why this does not work from within the container as outlined in the Docker Daemon Metrics guide?
If the container has a network interface on the 172.18.0.1 network and has routes configured for 172.18.0.1 why do pings fail to 172.18.0.1 from within the container?
If this is not a valid approach for accessing a host port from within a swarm container, then how would one go about achieving this?
EDIT:
Just realized that I did not give all the information in the original post.
I am running docker swarm on a CentOS 7.2 host with docker version 17.04.0-ce, build 4845c56. My kernel is a build of 4.9.11 with vxlan and ipvs modules enabled.
After some further digging I have noted that this appears to be a firewall issue. I discovered that not only was I unable to ping 172.18.0.1 from within the containers - but I was not able to ping my host machine at all! I tried my domain name, the FQDN for the server and even its public IP address but the container could not ping the host (there is network access as I can ping google/etc).
I disabled firewalld on my host and then restarted the docker daemon. After this I was able to ping my host from within the containers (both domain name and 172.18.0.1). Unfortunately this is not a solution for me. I need to identify what firewall rules I need to put in place to allow container->host communication without requiring firewalld being disabled.
Firstly, I owe you a huge THANK YOU. Before I read your EDIT part, I'd spent literally day and night to solve a similar issue, and never realized that the devil is the firewall.
Without disabling the firewall, I have solved my problem on Ubunt 16.04, using
sudo ufw allow in on docker_gwbridge
sudo ufw allow out on docker_gwbridge
sudo ufw enable
I'm not much familiar with CentOS, but I do believe the following should help you, or at least serve as a hint
sudo firewall-cmd --permanent --zone=trusted --change-interface=docker_gwbridge
sudo systemctl restart firewalld
You might have to restart docker as well.