Как связать контейнер докеров друг с другом с помощью докеров
Мне нужно настроить набор реплик mongo с помощью docker-compose. Для набора реплик контейнеры должны знать друг друга.
Я пробовал в 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
...
Получаю циркулярное сообщение об ошибке. Но если я удалю обратную ссылку на dbreplicasetpart1, я не могу выполнить ping из dbreplicasetpart2 в dbreplicasetpart1.
Каково решение?
Ответы
Ответ 1
Обновлено для Docker 1.10
Docker 1.10 позволяет определять сети внутри файла компоновки.
Здесь обновленный код
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
Предыдущий ответ для Docker 1.9
Начиная с Docker 1.9, решение этой задачи - создать пользовательскую сеть и передать ее команде docker-compose up
.
`` `
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"
`` `
Обратите внимание, что replica1
в http://replica1:27018
будет разрешено ip-адрес службы replica1 (контейнер). Нет необходимости жестко кодировать IP-адреса; Запись для replica1 автоматически добавляется в /etc/host контейнера replica2. То же самое касается контейнера replica1. Docker добавит запись для replica2 в файл /etc/host.
- Позвоните в docker-compose, передав ему созданную вами сеть
NETWORK=my-net docker-compose up -d -f docker-compose.yml
Я создал сеть моста , которая работает только с одним node (хостом). Хорошо для dev. Если вам нужно, чтобы два узла разговаривали друг с другом, вам необходимо создать . Тем не менее, тот же принцип. Вы передаете сетевое имя команде docker-compose up.
Ответ 2
Вы должны использовать шаблон посла:
https://docs.docker.com/engine/admin/ambassador_pattern_linking/
В основном вы создаете промежуточный компонент, который соединяет их обоих вместе. Вы можете увидеть пример, который мы используем с помощью службы поиска 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"
Для простоты я только скопировал ссылки
Ответ 3
Мы решили использовать решение с послом. Это действительно более удобное решение.
Конфигурация, которая работает для нас:
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"
Ответ 4
Здесь то, что должно по-прежнему работать в 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:
#!/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\"}"
Вот объяснение:
- Мы создали собственный DNS-сервер в контейнере
- Мы настраиваем наши контейнеры для использования этого сервера
- Мы настраиваем этот DNS-сервер с использованием специальных HTTP-запросов