Настройка нескольких контейнеров Docker и MongoDB для запуска в CircleCI

Я пытаюсь настроить непрерывную интеграцию для группы из нескольких приложений-приложений Rails, которые общаются друг с другом через конечные точки. Идея состоит в том, чтобы настроить CircleCI таким образом, чтобы при запуске потока тестирования он вызывал предварительно настроенные образы Docker для каждого из приложений, запускал контейнеры Docker для каждого из них, а затем запускал набор тестов, который проверяет, работает ли интеграция с полным потоком. из одного приложения через другое. Одно из сервисных приложений использует MongoDB, поэтому оно также должно взаимодействовать с mongodb, который автоматически устанавливается CircleCI. Поток должен быть:client_app -> service_app -> mongodb Однако у меня проблемы с подключением контейнеров.

Dockerfile для client_app устанавливает Ruby и все зависимости, добавляет репо в образ и затем запускает:

RUN bundle install

EXPOSE 3000

CMD ["bundle", "exec", "rails", "s", "-e", "development", "-p", "3000"]

Dockerfile для service_app делает то же самое, затем

RUN bundle install

EXPOSE 8080

CMD ["bundle", "exec", "rails", "s", "-e", "test", "-p", "8080"]

Оба этих файла Docker хранятся в нашем частном репозитории Docker. Я создал и извлек эти образы Docker локально и подтвердил, что они запускаются правильно.

Когда поток запускается на CircleCI, я использую circle.yml, чтобы раскрыть каждое из изображений. Это мой circle.yml (имена приложений изменены):

machine:
  services:
    - docker

dependencies:
  pre:
    - sed "s/<EMAIL>/$DOCKER_EMAIL/;s/<AUTH>/$DOCKER_AUTH/" < .dockercfg.template > ~/.dockercfg
    - docker pull myorg/service_app
    - docker pull myorg/client_app

test:
  override:
    - docker run -d -p 8080:8080 --name service_app myorg/service_app:docker-test
    - docker run -d -p 3000:3000 --env SERVICE_APP_URL=http://localhost:8080 --name client_app myorg/client_app:docker-test
    - docker ps -a
    - bundle exec rspec spec

client_app должен быть настроен для связи с service_app на SERVICE_APP_URL (внутренне приложение запускает соединение с ENV['SERVICE_APP_URL']), так как контейнер service_app работает на порте 8080, я установил его на http://localhost:8080, но это не работает. Когда я просматриваю логи для client_app, в первом представлении, где он должен сделать вызов, он возвращает:

Connection refused - connect(2) for "localhost" port 8080

я добавил docker ps -a в circle.yml, чтобы увидеть, правильно ли запускались контейнеры. Вот что он выводит на этом шаге:

CONTAINER ID        IMAGE                           COMMAND                CREATED             STATUS              PORTS                    NAMES
782d09c4f3db        myorg/client_app:docker-test    bundle exec rails s    3 seconds ago       Up 2 seconds        0.0.0.0:3000->3000/tcp   berserk_mcclintock   
64f8af8ab535        myorg/service_app:docker-test   bundle exec rails s    5 seconds ago       Up 4 seconds        0.0.0.0:8080->8080/tcp   furious_wozniak

Таким образом, похоже, что контейнеры запущены и правильные порты открыты, но client_app все еще не подключается к service_app.

Я изучил использование функции связывания Docker, но если я правильно понял, для этого требуется, чтобы приложение было внутренне сконфигурировано для поиска параметров настройки среды Docker, таких как DB_PORT_5000_TCP если связанный контейнер назван dbи я хотел бы избежать необходимости изменять внутренние конфигурации, если это возможно.

Кроме того, мне понадобится service_app, чтобы поговорить с работающим mongodb. В настоящее время приложение настроено для подключения к localhost:27017Похоже, что CircleCI запускает службу Mongo, но я не уверен, сможет ли контейнер Docker его увидеть.

Изменить: я пытался настроить мой service_app для общения с работающим контейнером MongoDB (используя доверенную сборку Mongo, используя --link но это тоже не работает. Я вытащил последнее изображение монго, затем побежал:

docker run -d -p 27017:27017 -p 28017:28017 --name mongodb dockerfile/mongodb mongod --rest --httpinterface

как предложено на этой странице, затем побежал

docker run -d -p 8080:8080 --name service_app --link mongodb:mongodb myorg/service_app:v1

В моем service_app перед сборкой я настроил mongoid.yml:

test:
  sessions:
    default:
      database: test
      hosts:
        -  ENV['MONGODB_PORT'] || 'localhost:27017' %>
      options:
        safe: true

Насколько я понимаю, Докер должен установить MONGODB_PORT var при связывании таких контейнеров, поэтому он должен подключаться к контейнеру Mongo. Я побежал env внутри контейнера, и он установил MONGODB_PORT=tcp://172.17.0.95:27017,

Однако на моем локальном компьютере, когда я пытаюсь подключиться к service_app для выполнения запроса, он возвращает

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
    <HEAD>
        <TITLE>Internal Server Error</TITLE>
    </HEAD>
    <BODY>
        <H1>Internal Server Error</H1>
    Could not connect to any secondary or primary nodes for replica set &lt;Moped::Cluster nodes=[&lt;Moped::Node resolved_address=nil&gt;]&gt;

        <HR>
            <ADDRESS>
     WEBrick/1.3.1 (Ruby/2.0.0/2014-02-24) at
     192.168.59.103:8080
     </ADDRESS>
        </BODY>
    </HTML>

Ясно, что у меня нет правильной настройки ссылок. Есть идеи?

1 ответ

Проблема связана с точкой происхождения. Если вы обращаетесь к localhost из контейнера Docker, localhost указывает на сам докер, а не на хост-сервер, и, следовательно, вызов не достигает хоста или других докеров.

Если все ваши докеры находятся на одном хост-компьютере, самый простой способ заставить их общаться друг с другом через localhost - это разделять сеть между контейнерами во время работы. Сначала нормально запустите бэкэнд, затем запустите другие контейнеры с ключом --net:

docker run [other params] -d -p 8080:8080 --name service-app-container service_app_image docker run [other params] -p 3000:3000 --net="container:service-app-container" --name client-app-container client_app_image

Теперь все порты, отображаемые и отображаемые любым из контейнеров, совместно использующих сеть, должны быть доступны через localhost из любого докера.

  • Чтобы получить доступ к service-app-container из любого места, используйте machine:8080.
  • Чтобы получить к нему локальный доступ с хост-сервера, используйте localhost:8080.
  • Для внутреннего доступа к нему из приложения-службы используйте locahost:8080.
  • Чтобы получить доступ к приложению-службе из клиентского приложения, используйте localhost: 8080

Клиентское приложение будет доступно миру через порт 3000 только в том случае, если вы также выставите его в докере с контейнером. Открытый порт не должен совпадать, так как это сбивает с толку сеть:

docker run [other params] -d -p 8080:8080 3001:3000 --name service-app-container service_app_image docker run [other params] -p 3000:3000 --net="container:service-app-container" client_app_image

Теперь вы можете получить доступ к клиентскому приложению извне, используя машину:3001.

Другие вопросы по тегам