设置多个Docker容器和MongoDB在CircleCI中运行 [英] Setting up multiple Docker containers and MongoDB to run in CircleCI

查看:537
本文介绍了设置多个Docker容器和MongoDB在CircleCI中运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图为一组几个Rails服务应用程序设置一个连续集成流程,这些服务应用程序通过端点彼此通信。想法是配置CircleCI,以便当测试流被触发时,它将为每个应用程序下拉预先配置的Docker镜像,为每个应用程序启动Docker容器,然后运行一个测试套件,测试全流集成的工作原理从一个应用程序到另一个。其中一个服务应用程序使用MongoDB,因此它还需要与CircleCI自动安装的mongodb进行通信。流应该是:
client_app - > service_app - >



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

 运行捆绑安装

EXPOSE 3000

CMD [bundle,exec,rails,s,-e,development,-p,3000]
/ pre>

service_app的Dockerfile也是这样,然后

  RUN bundle install 

EXPOSE 8080

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



这些Dockerfiles都存储在我们的私有Docker仓库中。我已经在本地构建并提取了这些Docker镜像并确认它们正确启动。



当在CircleCI上触发流时,我使用circle.yml拉下每个图片。这是我的circle.yml(应用名称已更改):

 机器:
服务:
- docker

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

测试:
覆盖:
- 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的日志时,在第一个视图中它应该进行调用,它返回:



连接被拒绝 - 连接(2)localhostport 8080



我添加了 docker ps -a 进入circle.yml以查看容器是否正确启动。

  CONTAINER ID IMAGE COMMAND CREATED状态端口名称
782d09c4f3db myorg / client_app:docker -test bundle exec rails s 3秒前上传2秒0.0.0.0:3000->3000/tcp berserk_mcclintock
64f8af8ab535 myorg / service_app:docker-test bundle exec rails s 5秒前上传4秒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容器交谈(使用<使用 - link 创建一个href =http://dockerfile.github.io/#/mongodb =nofollow>可信任的Mongo版本我拖动了最新的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:

 
sessions:
默认值:
数据库:test
主机:
- ENV ['MONGODB_PORT'] || 'localhost:27017'%>
选项:
safe:true



我理解Docker应该设置 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>内部伺服器错误< / TITLE>
< / HEAD>
< BODY>
< H1>内部服务器错误< / H1>
无法连接到副本集& 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>

很清楚,我没有这个链接设置权。任何想法?

解决方案

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



如果所有的dockers都在同一台主机上,使他们通过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 -app-container client_app_image



现在,共享网络的任何容器公开和映射的所有端口都应该可以从localhost




  • 要从任何地方访问service-app-container,请使用machine:8080。

  • 要从主机服务器本地访问它,请使用localhost:8080。

  • 要通过服务应用内部访问,请使用locahost:8080。

  • 要从客户端应用访问服务应用,请使用localhost:8080



客户端应用程序只会通过端口3000公开到世界上,如果您还将其暴露在具有容器的docker中。暴露的端口不应该是相同的,因为这混淆了网络:



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-containerclient_app_image



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


I'm trying to setup a continuous integration flow for a group of several Rails service apps I have that communicate with each other through endpoints. The idea is to configure CircleCI so that when the test flow is triggered, it will pull down preconfigured Docker images for each of the apps, start Docker containers for each one, and then run a test suite that tests that the full-flow integration works from one app through the other. One of the service apps uses MongoDB, so it needs to also communicate with the mongodb that CircleCI automatically installs. The flow should be: client_app -> service_app -> mongodb However, I'm having problems getting the containers to connect.

The Dockerfile for client_app installs Ruby and all dependencies, adds the repo into the image, and then runs:

RUN bundle install

EXPOSE 3000

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

The Dockerfile for service_app does the same, then

RUN bundle install

EXPOSE 8080

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

Both these Dockerfiles are stored in our private Docker repo. I have built and pulled these Docker images locally and confirmed that they start correctly.

When the flow is triggered on CircleCI, I use circle.yml to pull down each of the images. This is my circle.yml (app names changed):

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 should be configured to communicate with service_app at SERVICE_APP_URL (internally the app starts the connection to ENV['SERVICE_APP_URL']), so since the service_app container is running on port 8080, I set it to http://localhost:8080, but it doesn't work. When I look in the logs for client_app, in the first view where it is supposed to make a call, it returns:

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

I added docker ps -a into the circle.yml to see if the containers were being started correctly. Here's what it output at that step:

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

So it looks as if the containers are started and the right ports are exposed, but client_app still isn't connecting to service_app.

I did look into using Docker's linking functionality, but if I understand it correctly, it requires the app to be internally configured to look for an environment variable setup by Docker, such as DB_PORT_5000_TCP if the linked container is named db, and I would like to avoid having to modify the internal configurations if possible.

Additionally, I will need service_app to talk to a running mongodb. Currently the app is set to connect to localhost:27017, which seems to be what CircleCI starts the Mongo service on, but I'm not sure if the Docker container will be able to see it.

Edit: I've tried to configure my service_app to talk to a running MongoDB container (using the trusted Mongo build using --link but that's not working either. I pulled the latest mongo image, then ran:

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

as suggested on that page, then ran

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

In my service_app, before building, I had configured mongoid.yml:

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

My understanding is Docker should set the MONGODB_PORT var when linking containers like this, and so it should connect to the Mongo container. I ran env inside the container and it had set MONGODB_PORT=tcp://172.17.0.95:27017.

However, on my local machine, when I try to connect to service_app to make a query, it returns

<!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>

So clearly I don't have this linking setup right. Any ideas?

解决方案

The problem is related to point of origin. If you access localhost from inside a Docker container, the localhost points to the docker itself, not the host server, and therefore the call is not reaching the host or the other dockers.

If all your dockers are on the same host machine, the easiest way to make them talk with each other via localhost is to share a network between the containers at run. First run the backend normally, then start the other containers with the --net switch:

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

Now all the ports exposed and mapped by any of the containers sharing the network should be reachable under localhost from any of the dockers.

  • To access the service-app-container from anywhere, use machine:8080.
  • To access it locally from the host server, use localhost:8080.
  • To access it internally from the service app, use locahost:8080.
  • To access the service app from the client app, use localhost:8080

The client app will only be exposed over port 3000 to the world if you also expose it in the docker that has the container. The exposed port should not be the same as this confuses the network:

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

Now you could access the client app from outside using machine:3001.

这篇关于设置多个Docker容器和MongoDB在CircleCI中运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆