Почему этот docker -compose yml-файл не выполняет команду, подробно описанную в этом dockerfile? - PullRequest
0 голосов
/ 09 мая 2020

У меня есть два docker образа: производитель и очередь RabbitMQ. Моя цель - заставить производителя (Python) вставлять записи в очередь. Затем я хочу позвонить docker-compose up и посмотреть, как продюсер добавляет вещи в очередь.

Итак, я не самый яркий мелок в коробке, и я был бы очень признателен, если бы кто-то мог указать на мне, почему все работает не так, как я планировал. Мой производитель - это простые 2 файла в каталоге ./producer. Файл докеров для этого каталога выглядит так:

FROM ubuntu:latest

ENV DEBIAN_FRONTEND=noninteractive

# Prepare to install 3.7 + GDAL libraries
RUN apt-get update --fix-missing
RUN apt-get install -y software-properties-common apt-utils
RUN add-apt-repository ppa:ubuntugis/ppa
RUN add-apt-repository ppa:deadsnakes/ppa
RUN apt-get update --fix-missing

# Install the packages for GDAL
RUN apt-get install libgdal-dev gdal-bin -y
# Install the packages for python
RUN apt-get install python3.7 python3-pip python3.7-dev -y

RUN python3.7 -m pip install pika

COPY ./example.py example.py

CMD [ "/bin/bash", "-c \"python3.7 example.py\"" ]

Я заменил последнюю строку на ENTRYPOINT, CMD, различные версии /bin/bash, python3, python3.7 . Запуск docker build -t blah && docker run --rm blah приводит к ожидаемому мной поведению (не удается подключиться к очереди, потому что не запущено исключение).

В каталоге, содержащем ./producer, у меня есть файл docker-compose.yml, который выглядит так :

version: "3.3"
services:

  # RabbitMQ that connects the backend to the frontend
  queue:
    image: rabbitmq:3-management
    expose:
      # The standard AMQP protocol port
      - 5672
    ports:
      # HTTP management UI
      - '15672:15672'
    environment:
      RABBITMQ_DEFAULT_USER: "guest"
      RABBITMQ_DEFAULT_PASS: "guest"
    networks:
      rakan:
        ipv4_address: 172.16.238.10
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 3
        window: 120s
    healthcheck:
      test: [ "CMD", "nc", "-z", "localhost", "5672" ]
      interval: 5s
      timeout: 15s
      retries: 1


  producer:
    depends_on: 
      - queue
    build: 
      context: ./producer
      dockerfile: dockerfile
    # entrypoint: "/bin/bash -c \"python example.py\""
    expose:
      - "5672"
    networks:
      rakan:
        ipv4_address: 172.16.238.11
    links:
      - "queue"
    networks:
      - rakan

networks:
  rakan:
    ipam:
      driver: default
      config:
        - subnet: "172.16.238.0/24"

Что ужасно расстраивает, так это то, что docker-compose up больше не выполняет команду в ./producer/dockerfile. Он запустит очередь, но он будет игнорировать мои желаемые команды, говоря:

Attaching to toyexample_queue_1, toyexample_producer_1
toyexample_producer_1 exited with code 0
... All the logs of the RabbitMQ ...

Почему, почему это происходит? Почему он не ведет себя так же, когда я выполнил docker run? Любая помощь будет очень оценена.

То, что я пробовал:

  • Добавление entrypoint к docker-compose.yml формы python3.7 example.py, bin/bash python3.7 example.py, bash python example.py. Все будет завершено с кодом ошибки 127, утверждая, что python или python3.7 является нераспознанной командой.
  • Добавление cmd к docker-compose.yml с теми же точными результатами, что и последняя точка маркера
  • Замена CMD на ENTRYPOINT в ./producer/dockerfile
  • Пробуем разные варианты python, python3.7 в docker-compose.yml и dockerfile.

То, что я не знаю, актуально, но может помочь

  • Я использую docker v19.03.8 на windows 10 (процессор AMD Ryzen)
  • 0 других контейнеров запущено
  • docker-compose down, docker network/container/image prune - это все команды, которые я пробовал много во время этого epi c путешествие
  • Код в example.py выглядит так:
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('172.16.238.10'))
channel = connection.channel()

for i in range(100):
    # make a lot of noise
    channel.queue_declare(queue=f'hello_{i}')
    channel.basic_publish(exchange='',
                        routing_key='hello_{i}',
                        body='Hello World!')
    print(f" [x] Sent 'Hello World!' to {i}")

connection.close()
  • Обязательно: «Это не домашнее задание, я не пытаюсь обмануть и т. Д. c»

1 Ответ

2 голосов
/ 09 мая 2020

Во-первых, несколько замечаний:

  • EXPOSE в вашем Dockerfile и expose в docker-compose.yml в большинстве случаев не нужны, за исключением формы документации.
  • Просто назовите свой Dockerfile "Dockerfile" вместо того, чтобы заменять имя в вашем docker-compose.yml. Уменьшение количества посторонней конфигурации облегчает чтение (для других людей и для вас в будущем).
  • Не вводите жестко IP-адреса в свой код. Вместо этого используйте имена контейнеров.
  • Точно так же не используйте ключевое слово links в вашем файле создания. DNS, предоставляемый docker, намного более гибок.
  • depends_on почти полностью бесполезен. Он ничего не знает о приложениях , поэтому, хотя он гарантирует, что один контейнер запускается за другим контейнером, он не знает, действительно ли служба, от которой вы зависите, работает или нет. . В большинстве случаев вы хотите избавиться от depends_on и просто реализовать лог c повторного подключения в своем приложении.

Этот последний пункт может быть источником вашей проблемы: по крайней мере, в моих тестах RabbitMQ начинает принимать запросы намного дольше, чем запускается контейнер producer.

С учетом всего этого я переписал ваш docker-compose.yml, чтобы он выглядел так:

version: "3.3"

services:

  # RabbitMQ that connects the backend to the frontend
  queue:
    image: rabbitmq:3-management
    environment:
      RABBITMQ_DEFAULT_USER: "guest"
      RABBITMQ_DEFAULT_PASS: "guest"

  producer:
    build: 
      context: ./producer

И ваш example.py чтобы он выглядел так:

import pika
import time

while True:
    try:
        connection = pika.BlockingConnection(pika.ConnectionParameters('queue'))
    except pika.exceptions.AMQPConnectionError as err:
        print('rabbitmq connection failed; retrying in 1 second...')
        time.sleep(1)
    else:
        break

channel = connection.channel()

for i in range(100):
    # make a lot of noise
    channel.queue_declare(queue=f'hello_{i}')
    channel.basic_publish(exchange='',
                        routing_key='hello_{i}',
                        body='Hello World!')
    print(f" [x] Sent 'Hello World!' to {i}")

connection.close()

Запуск вышеуказанной конфигурации дает (каждый раз):

[lars@madhatter npengra317] (master *)$ docker-compose up
Starting npengra317_queue_1    ... done
Starting npengra317_producer_1 ... done
Attaching to npengra317_queue_1, npengra317_producer_1
queue_1     | 2020-05-09 03:38:25.676 [info] <0.9.0> Feature flags: list of feature flags found:
.
.
.
queue_1     | 2020-05-09 03:38:26.599 [info] <0.9.0> Server startup complete; 3 plugins started.
queue_1     |  * rabbitmq_management
queue_1     |  * rabbitmq_web_dispatch
queue_1     |  * rabbitmq_management_agent
queue_1     |  completed with 3 plugins.
queue_1     | 2020-05-09 03:38:26.868 [info] <0.653.0> accepting AMQP connection <0.653.0> (172.25.0.3:34874 -> 172.25.0.2:5672)
producer_1  | rabbitmq connection failed; retrying in 1 second...
producer_1  | rabbitmq connection failed; retrying in 1 second...
producer_1  | rabbitmq connection failed; retrying in 1 second...
producer_1  | rabbitmq connection failed; retrying in 1 second...
producer_1  | rabbitmq connection failed; retrying in 1 second...
producer_1  | rabbitmq connection failed; retrying in 1 second...
producer_1  | rabbitmq connection failed; retrying in 1 second...
producer_1  | rabbitmq connection failed; retrying in 1 second...
producer_1  |  [x] Sent 'Hello World!' to 0
producer_1  |  [x] Sent 'Hello World!' to 1
.
.
.
producer_1  |  [x] Sent 'Hello World!' to 97
producer_1  |  [x] Sent 'Hello World!' to 98
producer_1  |  [x] Sent 'Hello World!' to 99
npengra317_producer_1 exited with code 0
...