[英]Why I am unable to access service created by docker-compose?
I am building a micro-service based web app with Flask
and Docker
. 我正在用Flask
和Docker
构建一个基于微服务的Web应用程序。 Currently, I have 2 services running by docker-compose
under the same default network. 目前,我有2个服务在相同的默认网络下由docker-compose
运行。
docker-compose.yml file is -- docker-compose.yml文件是-
version: '3'
services:
mysql:
image: mysql
environment:
MYSQL_USER: "mysqluser"
MYSQL_PASSWORD: "mysqlpassword"
MYSQL_ROOT_PASSWORD: "root"
MYSQL_DATABASE: "gadgetfreeiot"
container_name: mysql
ports:
- 3306:3306
restart: always
entrypoint: ['docker-entrypoint.sh', '--default-authentication-plugin=mysql_native_password']
product_api:
build: ./${SERVICE_ROOT:-src/services/product/api}
image: product_api:v1
container_name: product_api
volumes:
- ./${SERVICE_ROOT:-src/services/product/api}:${PROJECT_ROOT:-/usr/projects/gadgetfreeiot}/${SERVICE_ROOT:-src/services/product/api}
ports:
- 5000:5000
depends_on:
- mysql
environment:
username: "mysqluser"
password: "mysqlpassword"
host: "mysql"
port: "3306"
database: "gadgetfreeiot"
command: ["./wait-for-mysql.sh", "--", "python", "./run.py"]
docker ps
output gives me -- docker ps
输出给我-
johir@ubuntu:gadgetfreeiot$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e10329e26e5c product_api:v1 "./wait-for-mysql.sh…" 18 minutes ago Up 18 minutes 0.0.0.0:5000->5000/tcp product_api
7fed5a136123 mysql "docker-entrypoint.s…" 18 minutes ago Up 18 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp mysql
Both services are running under gadgetfreeiot_default
network. 两种服务都在gadgetfreeiot_default
网络下运行。 docker inspect gadgetfreeiot_default
shows that both are under the same network -- docker inspect gadgetfreeiot_default
显示两者都在同一网络下-
johir@ubuntu:gadgetfreeiot$ docker inspect gadgetfreeiot_default
[
{
"Name": "gadgetfreeiot_default",
"Id": "67e09ae3a33c0ff4203eefe4fee6ba421d3f68564c6e32c7d1cd04e866ac6850",
"Created": "2018-10-18T14:56:05.86215576+03:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "192.168.0.0/20",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"14ffb8eaa0c17de0122de142dbcf7aa5455b41b47eadb197e8be200c2375fbb3": {
"Name": "mysql",
"EndpointID": "38ed4140ed728271194ee82f12b3d937c53166f6159ab4e6fcf2d8087039ed06",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/20",
"IPv6Address": ""
},
"e013059b510e42933d33f7c3fb7e141a19a6c78a0e34d031e5fce5e104aa8697": {
"Name": "product_api",
"EndpointID": "fdbe0ed92d0e53d6fc1040a50b1898e2bb87b34384f80b98e638a3a89a57c4e1",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/20",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.docker.compose.network": "default",
"com.docker.compose.project": "gadgetfreeiot",
"com.docker.compose.version": "1.22.0"
}
}
]
Now I am trying to access the product_api
as well as mysql
services from my host OS. 现在,我正在尝试从主机操作系统访问product_api
以及mysql
服务。 In the meantime, I am also trying to access from one container to another (from product_api
to mysql
and from mysql
to product_api
). 同时,我还尝试从一个容器访问另一个容器(从product_api
到mysql
,从mysql
到product_api
)。 mysql
is accessible from all 3 that is my host OS, product_api and mysql itself by -- mysql
是所有3个是我的主机操作系统,product_api和MySQL本身的访问-
mysql -h172.19.0.2 -P3306 -umysqluser -p
product_api
is also able to access by -- product_api
也可以通过-访问
mysql -hmysql -P3306 -umysqluser -p
Luckily I am able to access curl http://localhost:5000
shows from product_api -- 幸运的是,我能够从product_api中访问curl http://localhost:5000
节目-
johir@ubuntu:gadgetfreeiot$ docker exec -it product_api bash
root@e013059b510e:/usr/projects/gadgetfreeiot/src/services/product/api# curl http://localhost:5000
{
"message": "Endpoint not found",
"status": "failed"
}
Where curl http://172.19.0.3:5000
shows -- 如果curl http://172.19.0.3:5000
显示-
curl: (7) Failed to connect to 172.19.0.3 port 5000: Connection refused
That means product_api
is up & running and only accessible by localhost
or 127.0.0.1
from inside the product_api container not by IP or by service name from outside product_api container that is neither from my host OS nor from mysql
container. 这意味着product_api
已启动并正在运行,并且只能通过localhost
或127.0.0.1
从product_api容器内部进行访问,而不能通过IP或通过product_api外部容器中的服务名称进行访问,而这既不是我的主机操作系统也不是mysql
容器。
Finally, I checked -- active networks among 3 by netstat -tln
-- 最后,我通过netstat -tln
检查了3个活动网络-
# product_api container
root@e10329e26e5c:/usr/projects/gadgetfreeiot/src/services/product/api# netstat -tln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.11:40071 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:5000 0.0.0.0:* LISTEN
# mysql container
root@7fed5a136123:/# netstat -tln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.11:35507 0.0.0.0:* LISTEN
tcp6 0 0 :::33060 :::* LISTEN
tcp6 0 0 :::3306 :::* LISTEN
# host OS
johir@ubuntu:gadgetfreeiot$ netstat -tln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
tcp6 0 0 ::1:631 :::* LISTEN
tcp6 0 0 :::5000 :::* LISTEN
tcp6 0 0 :::3306 :::* LISTEN
Note: port 5000 is not open by tcp6 in product_api
container. 注意: tcp6无法在product_api
容器中打开端口5000。 On the other hand port 3306 is open by tcp6 on mysql
container. 另一方面,端口3306由mysql
容器上的tcp6打开。
Question: Why I am unable to access product_api
service from my host OS or even from mysql (in constraint, why tcp6 is not exposing port 5000 for product_api service)? 问题:为什么我无法从主机操作系统甚至从mysql访问product_api
服务(因此,为什么tcp6不会为product_api服务公开端口5000)?
The short answer is, you aren't unable to access, as you showed with curl http://localhost:5000
. 简而言之,就是您无法访问,如curl http://localhost:5000
。 It just seems to be a bit confusing who (host vs containers) can access which IPs and resolve which hostnames. 谁(主机与容器)可以访问哪些IP并解析哪些主机名似乎有些令人困惑。
In your docker-compose.yml
you mapped the ports 3306
and 5000
to your respective containers. 在docker-compose.yml
,将端口3306
和5000
映射到各自的容器。 So docker added a port forward from any interface on your host (w/o the interfaces of the docker networks) to your containers (have a look at the output of sudo iptables-save | grep 5000
if you are interested in how it's done under the hood, it will look something like this: 因此,docker从主机上的任何接口(不带docker网络的接口)向您的容器添加了端口转发(如果您对sudo iptables-save | grep 5000
的输出感兴趣,请查看输出)引擎盖,它将看起来像这样:
-A DOCKER -d 192.168.0.2/20 ! -i br-e013059b510e -o br-e013059b510e -p tcp -m tcp --dport 5000 -j ACCEPT
So from your host, you can reach your service via 因此,您可以从主机上通过以下方式获得服务
curl http://localhost:5000
From another computer (assuming firewall settings allow) via 从另一台计算机(假设允许防火墙设置)通过
curl http://your.hostname:5000
From a container on the same docker network 从同一docker网络上的容器
curl http://product_api:5000 # or
curl http://product_api.gadgetfreeiot_default:5000 # or
curl http://192.168.0.3:5000
To have both container on the same docker network, adjust your docker-compose.yml
like this: 要将两个容器都放在同一个docker-compose.yml
网络上,请像这样调整docker-compose.yml
:
services:
mysql:
[...]
ports:
- 3306:3306
networks:
- gadgetfreeiot
[...]
product_api:
ports:
- 5000:5000
networks:
- gadgetfreeiot
[...]
networks:
gadgetfreeiot:
Container hostnames like product_api
are not resolvable on the host. 在主机上无法解析诸如product_api
类的容器主机名。 They are however inside your containers. 但是它们在您的容器中。 Inside a container you have an extra docker DNS server at 127.0.0.11
which can resolve what your host can resove, plus docker hostnames like product_api.gadgetfreeiot_default
. 在容器内,您可以在127.0.0.11
处拥有一个额外的docker DNS服务器,该服务器可以解析主机可以解析的内容,以及docker主机名,如product_api.gadgetfreeiot_default
。 Try 尝试
nslookup product_api.gadgetfreeiot_default
on your host and from inside the container 在主机上以及从容器内部
docker exec -it mysql bash
Check https://docs.docker.com/network/ for more info on that. 检查https://docs.docker.com/network/了解更多信息。
With regards to your note: netstat
doesn't show you which port is "open", ie allowed by the firewall, but which port is bound to by a program. 关于您的注意事项: netstat
不会向您显示哪个端口是“开放”的,即防火墙允许的,但是哪个端口是由程序绑定的。 Whether a program binds to a port on an interface on IPv4, v6 or both, is up to the program. 程序是否绑定到IPv4,v6或两者上的接口上的端口,取决于程序。 This is not related to docker networking. 这与Docker网络无关。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.