1

我正在尝试为一组通过端点相互通信的几个 Rails 服务应用程序设置一个持续集成流。这个想法是配置 CircleCI,以便在触发测试流时,它将为每个应用程序拉下预配置的 Docker 映像,为每个应用程序启动 Docker 容器,然后运行一个测试套件来测试全流集成是否有效从一个应用程序到另一个应用程序。其中一个服务应用程序使用 MongoDB,因此它还需要与 CircleCI 自动安装的 mongodb 进行通信。流程应该是: client_app -> service_app -> mongodb 但是,我在连接容器时遇到问题。

client_app 的 Dockerfile 安装 Ruby 和所有依赖项,将 repo 添加到映像中,然后运行:

RUN bundle install

EXPOSE 3000

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

service_app 的 Dockerfile 也一样,然后

RUN bundle install

EXPOSE 8080

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

这两个 Dockerfile 都存储在我们的私有 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_URL 与 service_app 通信(在内部应用程序启动到 的连接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 对话。目前该应用程序设置为 connect to localhost:27017,这似乎是 CircleCI 启动 Mongo 服务的原因,但我不确定 Docker 容器是否能够看到它。

编辑: 我尝试将我的 service_app 配置为与正在运行的 MongoDB 容器通信(使用受信任的 Mongo 构建--link,但这也不起作用。我提取了最新的 mongo 映像,然后运行:

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

我的理解是 DockerMONGODB_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>

很明显,我没有正确的链接设置。有任何想法吗?

4

1 回答 1

1

问题与原点有关。如果您从 Docker 容器内部访问 localhost,则 localhost 指向 docker 本身,而不是主机服务器,因此调用不会到达主机或其他 docker。

如果所有 docker 都在同一台主机上,让它们通过 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 下从任何 docker 访问。

  • 要从任何地方访问 service-app-container,请使用 machine:8080。
  • 要从主机服务器本地访问它,请使用 localhost:8080。
  • 要从服务应用程序内部访问它,请使用 locahost:8080。
  • 要从客户端应用程序访问服务应用程序,请使用 localhost:8080

如果您还在拥有该容器的 docker 中公开客户端应用程序,则该客户端应用程序将仅通过端口 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

现在您可以使用 machine:3001 从外部访问客户端应用程序。

于 2014-12-18T01:27:38.023 回答