【问题标题】:Can't connect to a docker container using its IP address无法使用其 IP 地址连接到 docker 容器
【发布时间】:2021-07-28 22:44:18
【问题描述】:

我正在使用 docker-compose 启动一些容器,这些容器形成了 Solr 和 Zookeeper 节点的集群。

这是我的撰写文件(取自here):

version: '3.8'
services:
  solr1:
    image: solr:8.7.0
    container_name: solr1
    ports:
     - "8981:8983"
    environment:
      - ZK_HOST=zoo1:2181,zoo2:2181,zoo3:2181
    networks:
      - solr
    depends_on:
      - zoo1
      - zoo2
      - zoo3

  solr2:
    image: solr:8.7.0
    container_name: solr2
    ports:
     - "8982:8983"
    environment:
      - ZK_HOST=zoo1:2181,zoo2:2181,zoo3:2181
    networks:
      - solr
    depends_on:
      - zoo1
      - zoo2
      - zoo3

  solr3:
    image: solr:8.7.0
    container_name: solr3
    ports:
     - "8983:8983"
    environment:
      - ZK_HOST=zoo1:2181,zoo2:2181,zoo3:2181
    networks:
      - solr
    depends_on:
      - zoo1
      - zoo2
      - zoo3

  zoo1:
    image: zookeeper:3.6.2
    container_name: zoo1
    restart: always
    hostname: zoo1
    ports:
      - 2181:2181
      - 7001:7000
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
      ZOO_4LW_COMMANDS_WHITELIST: mntr, conf, ruok
      ZOO_CFG_EXTRA: "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider metricsProvider.httpPort=7000 metricsProvider.exportJvmInfo=true"
    networks:
      - solr

  zoo2:
    image: zookeeper:3.6.2
    container_name: zoo2
    restart: always
    hostname: zoo2
    ports:
      - 2182:2181
      - 7002:7000
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
      ZOO_4LW_COMMANDS_WHITELIST: mntr, conf, ruok
      ZOO_CFG_EXTRA: "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider metricsProvider.httpPort=7000 metricsProvider.exportJvmInfo=true"
    networks:
      - solr

  zoo3:
    image: zookeeper:3.6.2
    container_name: zoo3
    restart: always
    hostname: zoo3
    ports:
      - 2183:2181
      - 7003:7000
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
      ZOO_4LW_COMMANDS_WHITELIST: mntr, conf, ruok
      ZOO_CFG_EXTRA: "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider metricsProvider.httpPort=7000 metricsProvider.exportJvmInfo=true"
    networks:
      - solr

networks:
  solr:

如果我运行docker compose ls,我看到项目正在正确运行:

NAME                STATUS
solr-cluster        running(6)

这是docker container ls的输出:

CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS          PORTS                                                                                                                NAMES
d5333378e78c   25b74ae1e488   "docker-entrypoint.s…"   23 hours ago   Up 52 minutes   0.0.0.0:8983->8983/tcp, :::8983->8983/tcp                                                                            solr3
5fac27cd0443   25b74ae1e488   "docker-entrypoint.s…"   23 hours ago   Up 52 minutes   0.0.0.0:8982->8983/tcp, :::8982->8983/tcp                                                                            solr2
db37ef90ca98   25b74ae1e488   "docker-entrypoint.s…"   23 hours ago   Up 52 minutes   0.0.0.0:8981->8983/tcp, :::8981->8983/tcp                                                                            solr1
b8b55694e281   a72350516291   "/docker-entrypoint.…"   23 hours ago   Up 52 minutes   2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2183->2181/tcp, :::2183->2181/tcp, 0.0.0.0:7003->7000/tcp, :::7003->7000/tcp   zoo3
10885eafe4e8   a72350516291   "/docker-entrypoint.…"   23 hours ago   Up 52 minutes   2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2182->2181/tcp, :::2182->2181/tcp, 0.0.0.0:7002->7000/tcp, :::7002->7000/tcp   zoo2
558f8574c036   a72350516291   "/docker-entrypoint.…"   23 hours ago   Up 52 minutes   2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, :::2181->2181/tcp, 8080/tcp, 0.0.0.0:7001->7000/tcp, :::7001->7000/tcp   zoo1

如果我尝试使用主机 localhost(例如 http://localhost:8983/)在浏览器中导航 solr 节点,容器会通过 Solr 管理界面正确响应。

但是,如果我尝试使用浏览器访问同一个容器,但从其 IP 访问(例如 http://172.23.0.7:8983/,其中 172.23.0.7solr3 容器的 IP),我会遇到连接超时。如果我尝试 ping 该 IP,也会出现连接超时。

为什么会这样? localhost172.23.0.7 主机不应该都工作吗?

我需要从容器的 IP 访问我的容器,因为 Solr 节点使用它们的 IP 注册到 Zookeeper。因此,由于我无法从它们的 IP 访问容器,因此当我尝试通过 SolrJ API 以编程方式连接到它们时,我得到了 ConnectionTimeout 异常:

public static void main(String[] args)
{
    List<String> zkNodes = new ArrayList<>(3);

    zkNodes.add("localhost:2181");
    zkNodes.add("localhost:2182");
    zkNodes.add("localhost:2183");

    SolrClient solrClient = new CloudSolrClient.Builder(zkNodes, Optional.empty())
        .withConnectionTimeout(10000)
        .withSocketTimeout(10000)
        .build();

    try
    {
        CollectionAdminRequest.listCollections(solrClient);
    }
    catch (IOException | SolrServerException e)
    {
        e.printStackTrace();
    }
}

这是我得到的例外:

org.apache.solr.client.solrj.SolrServerException: IOException occurred when talking to server at: http://172.23.0.7:8983/solr
    at org.apache.solr.client.solrj.impl.HttpSolrClient.executeMethod(HttpSolrClient.java:695)
    at org.apache.solr.client.solrj.impl.HttpSolrClient.request(HttpSolrClient.java:266)
    at org.apache.solr.client.solrj.impl.HttpSolrClient.request(HttpSolrClient.java:248)
    at org.apache.solr.client.solrj.impl.LBSolrClient.doRequest(LBSolrClient.java:370)
    at org.apache.solr.client.solrj.impl.LBSolrClient.request(LBSolrClient.java:298)
    at org.apache.solr.client.solrj.impl.BaseCloudSolrClient.sendRequest(BaseCloudSolrClient.java:1157)
    at org.apache.solr.client.solrj.impl.BaseCloudSolrClient.requestWithRetryOnStaleState(BaseCloudSolrClient.java:918)
    at org.apache.solr.client.solrj.impl.BaseCloudSolrClient.request(BaseCloudSolrClient.java:850)
    at org.apache.solr.client.solrj.SolrRequest.process(SolrRequest.java:214)
    at org.apache.solr.client.solrj.SolrRequest.process(SolrRequest.java:231)
    at org.apache.solr.client.solrj.request.CollectionAdminRequest.listCollections(CollectionAdminRequest.java:2690)
    at Main.main(Main.java:28)
Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to 172.23.0.7:8983 [/172.23.0.7] failed: connect timed out
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151)
Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to 172.23.0.7:8983 [/172.23.0.7] failed: connect timed out
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:374)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
    at org.apache.solr.client.solrj.impl.HttpSolrClient.executeMethod(HttpSolrClient.java:571)
    ... 11 more
Caused by: java.net.SocketTimeoutException: connect timed out
Caused by: java.net.SocketTimeoutException: connect timed out
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:75)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
    ... 21 more

我不知道这是否有帮助,但无论如何我在 Windows 主机上,所以我不能为 Docker 使用 --network host 标志。

【问题讨论】:

    标签: docker docker-compose solr apache-zookeeper solrj


    【解决方案1】:

    172.x.x.x IP 是只能在 Docker 网络内访问的 IP,即 Solr 和 Zookeeper 节点之间。

    当你从外部连接到 Zookeeper 时,Zookeeper 并不知道有一个“外部”,它只知道其网络中 Solr 服务器的 IP 并将它们发送回给你。但这些 IP 无法从“外部”访问。

    一种解决方法是直接连接到 Solr 服务器,而不是使用 Zookeeper(使用像 localhost:8981HttpSolrClient 这样的 URL)。

    或者,您需要告诉 Solr 服务器将外部 IP“呈现”给 Zookeeper。

    【讨论】:

    • 所以当我认为localhost172.23.0.7 都应该工作时我错了。我用谷歌搜索,发现通过SOLR_HOST environemt 变量 Solr 可以使用可从外部访问的主机名注册到 Zookeeper。非常感谢!
    【解决方案2】:

    我认为太阳能实例的广告地址是 docker 实例的 IP,端口是默认的,而不是重定向的。您应该在 pod 中注册 docker 端口而不是 solr 端口。

    也许 solr.xml 的 solrcloud 部分可以提供帮助,但不确定...

    https://solr.apache.org/guide/8_8/format-of-solr-xml.html

    【讨论】:

      【解决方案3】:

      尽管Gaël J's answer 解决了一般情况下的问题,我还是会发布一个答案来解释 Solr 需要做什么。

      首先,您需要使用SOLR_HOST 环境变量告诉 Solr 它的主机名是什么。这是 Solr 在向 Zookeeper 注册时将使用的主机名,也是 Zookeeper 在请求 Solr URL 时发送给其客户端的主机名。

      就我而言,这样的客户是:

      1. 在 Docker 主机上运行的 SolrJ 应用程序(但在 Docker 之外);
      2. 其他 Solr 节点,可能会向 Zookeeper 询问其他节点的 URL

      为了让这两个客户端都能理解SOLR_HOST,我将services.solrX.container_name 的值用作SOLR_HOST,并将该值也添加到Docker 主机上的hosts 文件中。

      所以,这是docker-compose.yml 文件:

      version: '3.7'
      services:
        solr1:
          image: solr:8.7.0
          container_name: solr1
          ports:
           - "8981:8981"
          environment:
            - ZK_HOST=zoo1:2181
            - SOLR_HOST=solr1
            - SOLR_PORT=8981
          networks:
            - solr
          depends_on:
            - zoo1
      
        solr2:
          image: solr:8.7.0
          container_name: solr2
          ports:
           - "8982:8982"
          environment:
            - ZK_HOST=zoo1:2181
            - SOLR_HOST=solr2
            - SOLR_PORT=8982
          networks:
            - solr
          depends_on:
            - zoo1
            
        zoo1:
          image: zookeeper:3.6.2
          container_name: zoo1
          restart: unless-stopped
          hostname: zoo1
          ports:
            - 2181:2181
            - 7001:7000
          environment:
            ZOO_MY_ID: 1
            ZOO_SERVERS: server.1=zoo1:2888:3888;2181
            ZOO_4LW_COMMANDS_WHITELIST: mntr, conf, ruok
            ZOO_CFG_EXTRA: "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider metricsProvider.httpPort=7000 metricsProvider.exportJvmInfo=true"
          networks:
            - solr
      
      networks:
        solr:
      

      这是hosts 文件:

      # local solr cloud cluster
      127.0.0.1       solr1
      127.0.0.1       solr2
      

      还要注意solr1solr2 都指向localhost,因此它们应该有不同的端口(这就是需要SOLR_PORT 环境变量的原因;否则两个节点都将使用默认的8983 端口)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-11-01
        • 2021-04-07
        • 2019-06-15
        • 2018-03-01
        • 2020-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多