Назад | Перейти на главную страницу

Контейнер Linux с общедоступной маршрутизацией IPv6

Моя цель - иметь маршрутизируемый общедоступный IPv6-адрес для каждого из моих контейнеров докеров. Я хочу иметь возможность подключаться к своим контейнерам и выходить из них, используя протокол IPv6.

Я использую Linode, и мне назначен общедоступный пул IPv6:

2600:3c01:e000:00e2:: / 64 routed to 2600:3c01::f03c:91ff:feae:d7d7

Этот адрес "перенаправлен на" был автоматически настроен dhcp:

# ip -6 addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2600:3c01::f03c:91ff:feae:d7d7/64 scope global mngtmpaddr dynamic
       valid_lft 2591987sec preferred_lft 604787sec
    inet6 fe80::f03c:91ff:feae:d7d7/64 scope link
       valid_lft forever preferred_lft forever

Я установил запись AAAA для ipv6.daaku.org для облегчения работы с:

# nslookup -q=AAAA ipv6.daaku.org
ipv6.daaku.org  has AAAA address 2600:3c01:e000:e2::1

Для проверки я назначил этот адрес вручную:

# ip -6 addr add 2600:3c01:e000:00e2::1/64 dev eth0
# ip -6 addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2600:3c01:e000:e2::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 2600:3c01::f03c:91ff:feae:d7d7/64 scope global mngtmpaddr dynamic
       valid_lft 2591984sec preferred_lft 604784sec
    inet6 fe80::f03c:91ff:feae:d7d7/64 scope link
       valid_lft forever preferred_lft forever

Теперь я могу пинговать это из моей домашней сети с поддержкой IPv6:

# ping6 -c3 ipv6.daaku.org
PING6(56=40+8+8 bytes) 2601:9:400:12ab:1db7:a353:a7b4:c192 --> 2600:3c01:e000:e2::1
16 bytes from 2600:3c01:e000:e2::1, icmp_seq=0 hlim=54 time=16.855 ms
16 bytes from 2600:3c01:e000:e2::1, icmp_seq=1 hlim=54 time=19.506 ms
16 bytes from 2600:3c01:e000:e2::1, icmp_seq=2 hlim=54 time=17.467 ms

--- ipv6.daaku.org ping6 statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 16.855/17.943/19.506/1.133 ms

Я удалил адрес, потому что хочу, чтобы он был только в контейнере, и вернулся в исходное состояние:

# ip -6 addr del 2600:3c01:e000:00e2::1/64 dev eth0
# ip -6 addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2600:3c01::f03c:91ff:feae:d7d7/64 scope global mngtmpaddr dynamic
       valid_lft 2591987sec preferred_lft 604787sec
    inet6 fe80::f03c:91ff:feae:d7d7/64 scope link
       valid_lft forever preferred_lft forever

Я запустил докер-контейнер без сети в другом терминале:

# docker run -it --rm --net=none debian bash
root@b96ea38f03b3:/#

Застрял его pid в переменной для простоты использования:

CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' b96ea38f03b3)

Настройте netns для этого pid:

# mkdir -p /run/netns
# ln -s /proc/$CONTAINER_PID/ns/net /run/netns/$CONTAINER_PID

Создал новое устройство, присвоил ему IP:

# ip link add container0 link eth0 type macvlan
# ip link set container0 netns $CONTAINER_PID
# ip netns exec $CONTAINER_PID ip link set dev container0 name eth0
# ip netns exec $CONTAINER_PID ip link set eth0 up
# ip netns exec $CONTAINER_PID ip addr add 2600:3c01:e000:00e2::1/64 dev eth0

Вернемся к другому терминалу, где я запустил контейнер:

# ip -6 addr show eth0
22: eth0@gre0: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500
    inet6 2600:3c01::a083:1eff:fea5:5ad2/64 scope global dynamic
       valid_lft 2591979sec preferred_lft 604779sec
    inet6 2600:3c01:e000:e2::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::a083:1eff:fea5:5ad2/64 scope link
       valid_lft forever preferred_lft forever

# ip -6 route
2600:3c01::/64 dev eth0  proto kernel  metric 256  expires 2591976sec
2600:3c01:e000:e2::/64 dev eth0  proto kernel  metric 256
fe80::/64 dev eth0  proto kernel  metric 256
default via fe80::1 dev eth0  proto ra  metric 1024  expires 67sec

Это не работает, и я не могу подключиться из контейнера (используя ping6 ipv6.google.com в качестве теста), а также я не могу пинговать контейнер через Интернет из моей домашней сети (используя ping6 ipv6.daaku.org как мой тест).

Обновить: Мне удалось получить исходящий IPv6 работает следующим образом:

ip -6 addr add 2600:3c01:e000:00e2::1111:1/112 dev docker0 &&
ip6tables -P FORWARD ACCEPT &&
sysctl -w net.ipv6.conf.all.forwarding=1 &&
sysctl -w net.ipv6.conf.all.proxy_ndp=1

CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' 4fd3b05a04bb)
mkdir -p /run/netns &&
ln -s /proc/$CONTAINER_PID/ns/net /run/netns/$CONTAINER_PID &&
ip netns exec $CONTAINER_PID ip -6 addr add 2600:3c01:e000:00e2::1111:20/112 dev eth0 &&
ip netns exec $CONTAINER_PID ip -6 route add default via 2600:3c01:e000:00e2::1111:1 dev eth0

Маршруты IPv6 на хосте:

# ip -6 r
2600:3c01::/64 dev eth0  proto kernel  metric 256  expires 2582567sec
2600:3c01:e000:e2::1111:0/112 dev docker0  proto kernel  metric 256
2600:3c01:e000:e2::/64 dev eth0  proto kernel  metric 256
fe80::/64 dev eth0  proto kernel  metric 256
fe80::/64 dev docker0  proto kernel  metric 256
fe80::/64 dev veth1775864  proto kernel  metric 256
fe80::/64 dev veth102096c  proto kernel  metric 256
fe80::/64 dev vethdf3a55b  proto kernel  metric 256

Маршруты IPv6 в контейнере:

# ip -6 r
2600:3c01:e000:e2::1111:0/112 dev eth0  proto kernel  metric 256
fe80::/64 dev eth0  proto kernel  metric 256
default via 2600:3c01:e000:e2::1111:1 dev eth0  metric 1024

Все еще не могу пропинговать его с домашнего компьютера.

Думаю, ваша проблема связана с маршрутизацией. Беда в том, что вам дали квартиру /64, но вы решили разделить подсеть на /112. Это нормально для исходящего трафика, потому что ваш контейнерный хост знает обо всех отдельных подсетях, но когда ваш интернет-провайдер приходит для обработки возвращаемых пакетов, он не знает, что вы отключили подразделы. 2600:3c01:e000:e2::1111:0/112 и это должно быть направлено через 2600:3c01:e000:00e2::1. Они просто ожидают всего 2600:3c01:e000:00e2::/64 быть там, подключенным напрямую и доступным через одноадресную рассылку.

Проблема в том, что нет механизма сказать вашему интернет-провайдеру, что вы решили создать подсети (на самом деле, это ложь, есть несколько способов, но все они требуют сотрудничества вашего интернет-провайдера). Ваша самая простая ставка - остановиться маршрутизация трафик к контейнерам, и начать мосты Это.

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

В docker 1.0 есть два варианта включения подключения IPv6 к контейнерам докеров. Мне пришлось использовать драйвер lxc, а не libcontainer, чтобы оба этих метода работали. Возможно, вы сможете использовать RADVD. Я не пытался.

1) Попросите провайдера перенаправить / 64 на ваш хост-докер. Это самый простой вариант. Включите пересылку IPv6 и назначьте / 64 docker0. Вам не нужно разбивать эту сеть на более мелкие (например, / 112), если у вас нет нескольких мостов докеров или нескольких хостов докеров.

Этот метод подробно обсуждается в сообщении блога Андреаса Нойхауса «IPv6 в контейнерах Docker». Видеть http://zargony.com/2013/10/13/ipv6-in-docker-containers.

Обратите внимание, что очень немногие провайдеры IaaS с поддержкой IPv6 будут маршрутизировать / 64 на виртуальную машину. Второй метод частично преодолевает это ограничение.

2) Используйте подмножество / 64 из интерфейса LAN на мосту докеров - Этот метод не требует перенаправления / 64 на ваш хост-докер. Меньшая сеть в / 64 (например, / 112) в локальной сети назначена docker0. NDP настроен для прокси-сервера NDP от моста докеров к вашему интерфейсу LAN (возможно, eth0).

Подробное описание этого метода я написал на http://jeffloughridge.wordpress.com/2014/07/22/ipv6-in-docker-containers-on-digitalocean/.

Я не использовал версии докеров выше 1.0. Возможно, что в новых выпусках все изменилось.

Согласно RFC, все адреса в подсети находятся в пределах / 64. Назначения в этом пространстве используют один или несколько адресов IPv6.

Вы думаете, что IPv6 похож на IPv4, но с большими адресами. Я здесь, чтобы сказать вам, если вы проектируете свои системы таким образом, ожидаете увеличения затрат на установку, обслуживание - это безопасность!