简体   繁体   English

为什么我无法访问docker-compose创建的服务?

[英]Why I am unable to access service created by docker-compose?

I am building a micro-service based web app with Flask and Docker . 我正在用FlaskDocker构建一个基于微服务的Web应用程序。 Currently, I have 2 services running by docker-compose under the same default network. 目前,我有2个服务在相同的默认网络下由docker-compose运行。

  • mysql MySQL的
  • product_api product_api

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_apimysql ,从mysqlproduct_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已启动并正在运行,并且只能通过localhost127.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 ,将端口33065000映射到各自的容器。 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

Access 访问

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:

DNS DNS

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM