当前位置: 首页 > 知识库问答 >
问题:

为什么我的自定义docker文件不能通过docker compose网络连接,而其他服务会连接?

巫晋鹏
2023-03-14

我试图创建一个docker-comuse文件,该文件将托管三个服务。在填充数据库的客户Dockerfile中,流xDB、Grafana和自定义脚本。我有网络问题,由于连接拒绝错误,自定义脚本无法连接到流xDB(如下所示)。

有趣的是,当我从docker-comuse文件中删除自定义脚本服务(称为ads_agent),并从localhost运行该脚本,甚至在自己的容器中构建和运行Dockerfile时,它连接得很好。

我的脚本读取一个名为KTS_TELEMETRY_INFLUXDB_URL的环境变量,该变量用于INFLUXDB客户端的URL连接。我可以用“http://localhost:8086“对于仅从命令行运行的URL,这是可行的。当我将脚本包装到Docker容器中时,我使用本地计算机的LAN IP地址,因为对它来说,localhost就是容器。但尽管如此,这还是很好用的。

在我的docker-comuse中,由于所有三个服务都在同一个网络上,所以我使用了“超文本传输协议://infxdb: 8086”,因为主机名应该绑定到该服务的网络接口上。确实如此,因为Grafana使用该网址连接得很好。可悲的是,当我用脚本尝试这个时,我被拒绝连接。

urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7f18c1fec970>: Failed to establish a new connection: [Errno 111] Connection refused

这是我的docker-compose.yaml

version: "3"
services:
  influxdb:
    container_name: influxdb
    image: influxdb:2.0.9-alpine # influxdb:latest
    networks:
      - telemetry_network
    ports:
      - 8086:8086
    volumes:
      - influxdb-storage:/var/lib/influxdb2
    restart: always
    environment:
      - DOCKER_INFLUXDB_INIT_MODE=setup
      - DOCKER_INFLUXDB_INIT_USERNAME=$KTS_TELEMETRY_INFLUXDB_USERNAME
      - DOCKER_INFLUXDB_INIT_PASSWORD=$KTS_TELEMETRY_INFLUXDB_PASSWORD
      - DOCKER_INFLUXDB_INIT_ORG=$KTS_TELEMETRY_INFLUXDB_ORG
      - DOCKER_INFLUXDB_INIT_BUCKET=$KTS_TELEMETRY_INFLUXDB_BUCKET
      - DOCKER_INFLUXDB_INIT_RETENTION=$KTS_TELEMETRY_INFLUXDB_RETENTION
      - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=$KTS_TELEMETRY_INFLUXDB_TOKEN
  grafana:
    container_name: grafana
    image: grafana/grafana:8.1.7 # grafana/grafana:latest
    networks:
      - telemetry_network
    ports:
      - 3000:3000
    volumes:
      - grafana-storage:/var/lib/grafana
    restart: always
    depends_on:
      - influxdb
  ads_agent:
    container_name: ads_agent
    build: ./ads_agent
    networks:
      - telemetry_network
    restart: always
    depends_on:
      - influxdb
    environment:
      - KTS_TELEMETRY_INFLUXDB_URL=http://influxdb:8086
      - KTS_TELEMETRY_INFLUXDB_TOKEN=$KTS_TELEMETRY_INFLUXDB_TOKEN
      - KTS_TELEMETRY_INFLUXDB_ORG=$KTS_TELEMETRY_INFLUXDB_ORG
      - KTS_TELEMETRY_INFLUXDB_BUCKET=$KTS_TELEMETRY_INFLUXDB_BUCKET

networks:
  telemetry_network:

volumes:
  influxdb-storage:
  grafana-storage:

这是我的ads_agent/Dockerfile

FROM python:3.9
COPY requirements.txt .
RUN pip install --upgrade pip
RUN pip install -r /requirements.txt
COPY main.py .
ENTRYPOINT /usr/local/bin/python3 /main.py

广告代理/要求。txt有一个XDB客户端,这是我的ads/main。py

import os
from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS
from datetime import datetime
import random
import time

token = os.environ["KTS_TELEMETRY_INFLUXDB_TOKEN"]
org = os.environ["KTS_TELEMETRY_INFLUXDB_ORG"]
bucket = os.environ["KTS_TELEMETRY_INFLUXDB_BUCKET"]
url = os.environ["KTS_TELEMETRY_INFLUXDB_URL"]

client = InfluxDBClient(url=url, token=token)
dbh = client.write_api(write_options=SYNCHRONOUS)

while True:
    symbol_name = 'rand_num'
    value = random.random()
    timestamp = datetime.utcnow()
    print(timestamp, symbol_name, value)
    point = Point("mem") \
        .field(symbol_name, value) \
        .time(timestamp, WritePrecision.NS)
    dbh.write(bucket, org, point)
    time.sleep(1)

共有1个答案

安泰平
2023-03-14

您的问题与网络连接无关,只与启动顺序有关。尽管您为广告代理定义了依赖于-influxdb,但当脚本尝试连接influxdb时,influxdb仍有可能无法完成。

这就是为什么手动操作可以成功的原因,因为手动操作有时间延迟,此时数据库已经准备就绪。

原因见此:

dependens_on在启动web之前,不会等待db和redis“就绪”——只在它们启动之前。如果您需要等待服务准备就绪。)

为了确保在脚本启动之前数据库真正启动,您需要参考Compose中的Control startup and shutdown order(控制启动和关闭顺序):

要处理此问题,请将应用程序设计为在出现故障后尝试重新建立与数据库的连接。如果应用程序重试连接,它最终可以连接到数据库。

最好的解决方案是在应用程序代码中执行此检查,无论是在启动时还是在任何原因导致连接丢失时。然而,如果您不需要这种级别的恢复能力,您可以使用包装脚本来解决这个问题:

>

  • 使用一个工具,如wate-for-it、dockerize、sh兼容的wate-for或RelayAndContainers模板。这些是小的包装脚本,您可以将它们包含在应用程序的映像中,以轮询给定的主机和端口,直到它接受TCP连接。例如,使用wait-for-it.sh或wate-for包装服务的命令:

    version: "2"
    services:
      web:
        build: .
        ports:
          - "80:8000"
        depends_on:
          - "db"
        command: ["./wait-for-it.sh", "db:5432", "--", "python", "app.py"]
      db:
        image: postgres
    

    或者,编写自己的包装器脚本来执行更特定于应用程序的运行状况检查。

  •  类似资料:
    • 问题内容: 我无法通过Java API连接到原始ElasticSearch集群。 复制: 结果: 结果: 因此,一切都可以通过HTTP运行。通过Java尝试(每个页面): 我得到以下堆栈跟踪: 与最接近的事我发现,到目前为止,这个问题是在这里,但线程落后了,但未得到解决。 问题答案: TransportClient的默认端口为9300。您必须在Java代码中使用它而不是9200。这可能是连接失败的

    • 我可以使用SQLDeveloper连接到远程数据库。 我试图从命令行使用sqlcl连接到同一个数据库,但我收到一个错误。 下面是我正在运行的命令: 我也尝试过: 以下是我收到的错误: 同样在SQLDeveloper中,我只是在“自定义jdbc url”下输入以下内容,它连接没有任何问题,所以我希望我可以使用相同的URL通过命令行连接,但到目前为止,它不起作用:

    • 我无法通过Java API连接到vanilla ElasticSearch集群。 复制: 我得到以下堆栈跟踪: 到目前为止,我发现的最接近这个问题的东西是这里,但线程拖尾没有解决。

    • 问题内容: 我有一个kubernetes单节点设置(请参阅https://coreos.com/kubernetes/docs/latest/kubernetes- on-vagrant-single.html ) 我有一个服务和一个创建吊舱的复制控制器。这些Pod需要连接到同一服务中的其他Pod(注意:这最终是使我可以使mongo运行带有副本集(非localhost),但是此简单示例演示了mon

    • 错误:Redis连接到Redis:6379失败-连接econnrejected 172.20.0.2:6379 码头集装箱 Redis工作: docker-compose.yml

    • 问题内容: 我正在尝试通过网络连接到MySQL数据库。我已经安装了MySQL,并且该服务在默认端口上运行。我还将SQL连接器安装到jar文件中,并将Java JDK添加到服务器计算机中。我可以使用以下代码连接到本地数据库: 但是,当我尝试通过IP地址(例如:192.168.1.45)通过网络连接到它时: 我收到连接错误: 有人知道这个问题是什么吗?我需要添加其他地址吗?我已经使用地址添加了默认端口