【问题标题】:Why won't my custom Dockerfile connect over the docker-compose network when other services will?为什么我的自定义 Dockerfile 不能通过 docker-compose 网络连接,而其他服务可以?
【发布时间】:2021-12-02 07:26:56
【问题描述】:

问题

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

到目前为止的工作情况

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

两者有什么区别

我的脚本读取一个名为 KTS_TELEMETRY_INFLUXDB_URL 的环境变量,用于连接 InfluxDB 客户端的 URL。当我只从命令行运行时,我可以使用“http://localhost:8086”作为 URL,这是可行的。当我将脚本包装在 Docker 容器中时,我使用本地机器的 LAN IP 地址,因为对于它来说,localhost 只是容器。但是,这很好用。

在我的 docker-compose 中,由于所有三个服务都在同一个网络上,所以我使用“http://influxdb:8086”,因为该主机名应该绑定到该服务的网络接口。确实如此,因为 Grafana 使用该 URL 连接得很好。可悲的是,当我使用脚本尝试此操作时,连接被拒绝。

错误

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

ads_agent/requirements.txt 只有 influxdb-client,这是我的 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)

【问题讨论】:

    标签: docker docker-compose influxdb docker-networking influxdb-python


    【解决方案1】:

    您的问题与network connectivity 无关,仅与startup order 有关。虽然你定义depends_on - influxdbads_agent,还是会有机会 当您的脚本尝试连接 influxdb 时,influx db 仍然没有完成。

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

    原因见this

    depends_on 在启动 web 之前不会等待 db 和 redis “准备好” - 仅在它们启动之前。如果您需要等待服务准备好。 )

    为了确保您的数据库在您的脚本开始之前真正启动,您需要参考Control startup and shutdown order in Compose

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

    最好的解决方案是在您的应用程序代码中执行此检查,无论是在启动时还是因任何原因失去连接时。但是,如果您不需要这种级别的弹性,您可以使用包装脚本解决此问题:

    • 使用wait-for-itdockerize、sh 兼容的wait-forRelayAndContainers 模板等工具。这些是小型包装脚本,您可以将它们包含在应用程序的映像中,以轮询给定的主机和端口,直到它接受 TCP 连接。 例如,使用 wait-for-it.sh 或 wait-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
      
    • 或者,编写您自己的包装脚本来执行更多特定于应用程序的运行状况检查。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-05
      相关资源
      最近更新 更多