简体   繁体   English

如何使用 docker-compose 将 docker 容器相互链接

[英]how to link docker container to each other with docker-compose

I have to setup a mongo replica set with docker-compose.我必须使用 docker-compose 设置一个 mongo 副本集。 For the replica set the containers have to know each other.对于副本集,容器必须相互了解。

I tried in docker-compose.yml我在docker-compose.yml尝试过

    dbreplicasetpart1:
      image: mongo:2.6.8
      expose:
        - '27018'
      links:
        - replicasetpart2
        - replicasetpart3
      cap_add:
        - NET_ADMIN

    dbreplicasetpart2:
      image: mongo:2.6.8
      links:
        - replicasetpart1
        - replicasetpart3
      expose:
        - '27019'
      cap_add:
        - NET_ADMIN
...

I get an circular import message.我收到一条循环导入消息。 But if I remove the back-link to dbreplicasetpart1 I can't ping from dbreplicasetpart2 to dbreplicasetpart1.但是,如果我删除到 dbreplicasetpart1 的反向链接,我将无法从 dbreplicasetpart2 ping 到 dbreplicasetpart1。 What is the solution?解决办法是什么?

Updated for Docker 1.10为 Docker 1.10 更新

Docker 1.10 allows the definition of networks within the compose file. Docker 1.10 允许在撰写文件中定义网络。 Here's the updated code这是更新后的代码

version: "2"

services:
  replica1:
    image: mongo:2.6.8
    container_name: replica1
    networks:
      - my-net
    ports:
      - "27018"
    environment:
      REPLICA2_URL: "http://replica2:27019"
  replica2:
    image: mongo:2.6.8
    container_name: replica2
    networks:
      - my-net
    ports:
      - "27019"
    environment:
      REPLICA1_URL: "http://replica1:27018"

networks:
  my-net:
    driver: bridge

Previous answer for Docker 1.9 Docker 1.9 的上一个答案

As of Docker 1.9, the solution to this is to create a custom network and pass it to the docker-compose up command.从 Docker 1.9 开始,解决方案是创建一个自定义网络并将其传递给docker-compose up命令。

  1. Create a network docker network create --driver bridge my-net创建网络docker network create --driver bridge my-net

  2. Reference that network as an environment variable ( ${NETWORK} )in the docker-compose.yml files.在 docker-compose.yml 文件中将该网络作为环境变量 ( ${NETWORK} ) 引用。 Eg:例如:

``` ``

replica1:
  image: mongo:2.6.8
  container_name: replica1
  net: ${NETWORK}
  ports:
    - "27018"
  environment:
    REPLICA2_URL: "http://replica2:27019"

replica2:
  image: mongo:2.6.8
  container_name: replica2
  net: ${NETWORK}
  ports:
    - "27019"
  environment:
    REPLICA1_URL: "http://replica1:27018"

``` ``

Note that replica1 in http://replica1:27018 will resolve to the ip address of the replica1 service (container).需要注意的是replica1http://replica1:27018解析到replica1服务(容器)的IP地址。 No need to hardcode ip addresses;无需硬编码 IP 地址; An entry for replica1 is automatically added to the /etc/host of the replica2 container. replica1 的条目会自动添加到 replica2 容器的 /etc/host 中。 Same goes for the replica1 container. replica1 容器也是如此。 Docker will add an entry for replica2 in its /etc/host file. Docker 将在其 /etc/host 文件中为 replica2 添加一个条目。

  1. Call docker-compose, passing it the network you created NETWORK=my-net docker-compose up -d -f docker-compose.yml调用 docker-compose,将您创建的NETWORK=my-net docker-compose up -d -f docker-compose.yml传递给它NETWORK=my-net docker-compose up -d -f docker-compose.yml

I've created a bridge network above which only works within one node (host).我在上面创建了一个桥接网络,它只能在一个节点(主机)内工作。 Good for dev.对开发有好处。 If you need to get two nodes to talk to each other, you need to create an overlay network .如果您需要让两个节点相互通信,则需要创建一个覆盖网络 Same principle though.不过原理一样。 You pass the network name to the docker-compose up command.您将网络名称传递给 docker-compose up 命令。

You should use the ambassador pattern:您应该使用大使模式:

https://docs.docker.com/engine/admin/ambassador_pattern_linking/ https://docs.docker.com/engine/admin/ambassador_pattern_linking/

Basically you create an intermediate component that bridges both of them together.基本上,您创建了一个将它们连接在一起的中间组件。 You can see an example that we use with Spring Cloud's Eureka discovery service:您可以看到我们与 Spring Cloud 的 Eureka 发现服务一起使用的示例:

ambassador:
  image: cpuguy83/docker-grand-ambassador
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock"
  command: "-name eureka_1 -name eureka2_1 "

eureka:
  links:
    - "ambassador:eureka2"

eureka2:
  links:
    - "ambassador:eureka"

For simplicity, I only copied the links为简单起见,我只复制了链接

Without updating the docker-compose.yml file,无需更新docker-compose.yml文件,

docker network connect docker-compose-network-you-want-to-connect conatianer-name-from-another-docker-compose

More here更多在这里

We figured out to use the solution with the ambassador.我们想出了与大使一起使用的解决方案。 It is indeed the more comfortable solution.这确实是更舒适的解决方案。 The configuration that works for us:对我们有用的配置:

amba1:
  image: cpuguy83/docker-grand-ambassador
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock"
  command: "-name cucumber_dbreplicasetpart1_1"

amba2:
  image: cpuguy83/docker-grand-ambassador
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock"
  command: "-name cucumber_dbreplicasetpart2_1"

amba3:
  image: cpuguy83/docker-grand-ambassador
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock"
  command: "-name cucumber_dbreplicasetpart3_1"

dbreplicasetpart1:
  image: 'mongo:2.6.8'
  hostname: dbreplicasetpart1
  command: >
    bash -c
    '
      mongod --fork --logpath mongo.log --smallfiles --replSet rs1
      echo "
        printjson(
          rs.initiate(
            {
              _id : \"rs1\",
              members : [
                {_id : 0, host : \"dbreplicasetpart1:27017\"},
                {_id : 1, host : \"dbreplicasetpart2:27017\"},
                {_id : 2, host : \"dbreplicasetpart3:27017\"},
              ]
            }
          )
        );
      " | mongo;
      tail -f mongo.log
    '
  links:
    - "amba2:dbreplicasetpart2"
    - "amba3:dbreplicasetpart3"

dbreplicasetpart2:
  image: 'mongo:2.6.8'
  hostname: dbreplicasetpart2
  command: >
    bash -c
    '
      mongod --fork --logpath mongo.log --smallfiles --replSet rs1
      echo "
        printjson(
          rs.initiate(
            {
              _id : \"rs1\",
              members : [
                {_id : 0, host : \"dbreplicasetpart1:27017\"},
                {_id : 1, host : \"dbreplicasetpart2:27017\"},
                {_id : 2, host : \"dbreplicasetpart3:27017\"},
              ]
            }
          )
        );
      " | mongo;
      tail -f mongo.log
    '
  links:
    - "amba1:dbreplicasetpart1"
    - "amba3:dbreplicasetpart3"

dbreplicasetpart3:
  image: 'mongo:2.6.8'
  hostname: dbreplicasetpart3
  command: >
    bash -c
    '
      mongod --fork --logpath mongo.log --smallfiles --replSet rs1
      echo "
        printjson(
          rs.initiate(
            {
              _id : \"rs1\",
              members : [
                {_id : 0, host : \"dbreplicasetpart1:27017\"},
                {_id : 1, host : \"dbreplicasetpart2:27017\"},
                {_id : 2, host : \"dbreplicasetpart3:27017\"},
              ]
            }
          )
        );
      " | mongo;
      tail -f mongo.log
    '
  links:
    - "amba1:dbreplicasetpart1"
    - "amba2:dbreplicasetpart2"

Here's what should still work in Docker 1.7.1 (in case you stuck with CentOS 6):以下是在 Docker 1.7.1 中仍然可以使用的内容(以防您坚持使用 CentOS 6):

etcd:
  image: elcolio/etcd:latest
skydns:
  image: outrider/skydns
  links:
    - etcd
  environment:
    ETCD_MACHINES: "http://etcd:4001"
    SKYDNS_DOMAIN: "docker"
    SKYDNS_PATH_PREFIX: my
    SKYDNS_NDOTS: 0
    SKYDNS_VERBOSE: "true"
    SKYDNS_ADDR: 0.0.0.0:53
  expose:
    - 53

my-service:
    image: alpine
    command: sh -c "dns_add my-service && ping my-service"
    links:
      - etcd
      - skydns

dns_add script: dns_add脚本:

#!/usr/bin/env sh

# This script configures resov.conf to use
# "skydns" name server with "docker" domain
# and adds a service name specified in the first argument
SERVICE_NAME=$1

waitforit () {
  HOST=$1
  PORT=$2
  TIME_OUT=${3:-30};
  END=$(($(date "+%s+$TIME_OUT")))
  while [ $(date "+%s") -lt $END ]
    do nc -z -w1 $HOST $PORT && break
  done
  return $END
}

# Use skydns to resolve names
echo "nameserver `resolveip -s skydns`" > /etc/resolv.conf
echo "search docker" >> /etc/resolv.conf

# Put yourself to DNS
ETCD_HOST=etcd
ETCD_PORT=4001
waitforit $ETCD_HOST $ETCD_PORT
HOST_IP=`resolveip -s $HOSTNAME`
apk update && apk add curl
curl -XPUT http://$ETCD_HOST:$ETCD_PORT/v2/keys/my/docker/$SERVICE_NAME -d value="{\"host\":\"$HOST_IP\"}"

Here's an explanation:这是一个解释:

  1. We set up our own DNS server in a container我们在容器中设置了自己的 DNS 服务器
  2. We configure our containers to use that server我们将容器配置为使用该服务器
  3. We configure that DNS server using special HTTP requests我们使用特殊的 HTTP 请求配置该 DNS 服务器

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM