Кантэйнеры адказваюць у офіснай LAN, а затым перастаюць адказваць у той момант, калі падключаецца карпаратыўны VPN. У кантэйнеры нічога не змянілася: няма перазапуску, няма абнаўлення вобраза, няма праўкі канфігурацыі. Змянілася табліца маршрутызацыі хаста, дзе маршрут, дададзены тунэлем, цяпер пакрывае адрас, які выдаў Docker. Перш чым правіць падсетку або прасіць выключэнне з VPN, пакладзіце абодва планы адрасацыі побач, бо выпраўленні каштуюць вельмі рознага часу.

Прачытайце маршрут, перш чым змяняць канфігурацыю

Пачніце з сеткі, якую Docker сапраўды пабудаваў. Блок IPAM — гэта план адрасацыі, а падсетка — радок, які мае значэнне:

docker network inspect project_default --format '{{json .IPAM.Config}}'
# [{"Subnet":"172.18.0.0/16","Gateway":"172.18.0.1"}]

Compose па змаўчанні выдзяляе /16 для кожнага новага праекта, таму дзве службы могуць размясціцца ў дыяпазоне з 65,536 адрасоў. Менавіта гэтая шырыня робіць перасячэнні частымі: выпадкова выбраная /16 дастаткова вялікая, каб праглынуць сайт, да якога вы звяртаецеся праз тунэль, і ніхто не заўважае гэтага, пакуль тунэль не ўзнімецца.

Затым параўнайце выбар маршруту для аднаго адраса кантэйнера — адзін раз з выключаным тунэлем і адзін раз з уключаным:

ip route get 172.18.0.7
# 172.18.0.7 dev br-3f2a9c src 172.18.0.1

Дзве формы адказу вядуць у розныя месцы. Калі вывад называе tun0, wg0 або іншую тунэльную прыладу, прэфікс VPN прынамсі такі ж канкрэтны, як маршрут моста, і пакет ніколі не дасягае кантэйнера. Калі ён па-ранейшаму называе мост, хаст можа дасягнуць кантэйнера, а ваша непаладка — гэта фільтраванне, DNS або зваротны шлях, які збаўляе толькі ў адзін бок.

Чаму сутыкненне /16 лёгка атрымаць

Docker бярэ маставыя сеткі з прыватных пулаў, а пул па змаўчанні выходзіць з блока 172.16.0.0/12 долямі па /16. Карпаратыўныя сеткі часта выкарыстоўваюць тую ж прыватную прастору, а VPN аддаленага доступу перадае гэтыя прэфіксы кожнаму кліенту, які падключаецца. Калі абодва бакі лічаць, што валодаюць 172.18.0.0/16, адна табліца маршрутызацыі трымае два супярэчлівыя сцвярджэнні.

Даўжыня прэфікса вырашае, хто пераможа, а не парадак з'яўлення маршрутаў. Тунэль, які перадае 10.0.0.0/8 не перамагае маставы маршрут 172.18.0.0/16, бо /8 менш канкрэтны. Тунэль, які перадае 172.18.0.0/16, або 172.18.5.0/24 унутры яго, перамагае. Менавіта таму адзін ноўтбук працуе ў офіснай сетцы і збаўляе ў Wi-Fi гатэля з тым жа VPN: кліент атрымлівае розныя прэфіксы.

Тая ж табліца кіруе і адваротным кірункам. Кантэйнер, якому патрэбны ўнутраны хаст на 10.8.4.20 адрасе, адпраўляе пакет на свой маставы шлюз, і хаст затым маршрутызуе яго ў тунэль. Гэты шлях звычайна працуе, бо хаст выконвае NAT, але ён збаўляе, калі карпаратыўны бок прымае толькі VPN-адрас ноўтбука або калі фільтраванне зваротнага шляху адкідвае асіметрычны адказ.

Параўнайце тры выпраўленні

Ёсць толькі тры выйсці, і яны розняцца тым, хто павінен іх ухваліць і што ламаецца, пакуль вы ўжываеце адно з іх.

RepairWho owns itWhat it costs
Renumber the container networkYouRecreates the network, restarts services, invalidates literal addresses in configs and scripts
Exclude your range from the tunnelNetwork teamChanges what every laptop sees, needs a change request and a client profile update
Reach the service through a published portYou and the clientOne port only, no direct container-to-container routing across the tunnel

Перанумарацыя — адзінае выпраўленне, якое можна скончыць без заяўкі, і менавіта таму большасць апісанняў на ёй спыняецца. Яна танна на маладым праекце і дорага, як толькі інструмент міграцыі або захаваны радок злучэння паказвае на літаральны адрас. Падлічыце гэтыя спасылкі да праўкі YAML, а не пасля.

Выключэнне з тунэля — самае чыстае рашэнне, калі перасячэнне знаходзіцца ў дыяпазоне, якім ваша кампанія сапраўды валодае. Яно ж і самае павольнае, і яно бескарыснае для падрадчыка, які не можа змяніць профіль кліента. Апублікаваны порт або невялікі адваротны проксі абыходзяць спрэчку: кліент звяртаецца да адраса, які тунэль ужо маршрутызуе правільна, і дасяжным павінен быць толькі гэты порт.

Закрапіце дыяпазон свядома

Для аднаго праекта абвясціце падсетку ў файле compose, каб праект перастаў браць з агульнага пула:

networks:
  default:
    ipam:
      config:
        - subnet: 10.201.7.0/24

Вазьміце гэты дыяпазон з рэестра, які вядзе ваша каманда, а не з прыкладу, знойдзенага падчас пошуку. Праверце яго супраць прэфіксаў, якія перадае VPN, хатніх LAN, з якіх працуюць людзі, і іншых сетак кантэйнераў на тым жа хасце. Затым сплануйце перастварэнне, бо існуючая сетка захоўвае старую падсетку: docker compose down, затым up -d. docker network rm адмаўляе, пакуль далучаныя канчатковыя пункты, і любы ipv4_address запіс у файле павінен трапляць у новы дыяпазон.

Для сетак, якія Docker стварае сам, задайце пул дэмана ў /etc/docker/daemon.json:

{
  "default-address-pools": [
    { "base": "10.201.0.0/16", "size": 24 },
    { "base": "10.202.0.0/16", "size": 24 }
  ]
}

Пул дзейнічае для сетак, створаных пасля перазапуску дэмана, а масты, якія ўжо існуюць, захоўваюць свае адрасы. Гэта зручна і лёгка забываецца, таму лічыце стары праект яшчэ перасякальным, пакуль нехта не перастворыць яго сетку. Дакументацыя Docker пра сеткі рухавіка апісвае правілы размеркавання, калі вам трэба абараніць пул на аглядзе.

Маст Linux і Docker Desktop збаўляюць па-рознаму

На хасце Linux кантэйнеры знаходзяцца на мастах у прасторы імёнаў хаста. Усё вырашае адна табліца, таму параўнанне вышэй — гэта ўся гісторыя: прачытайце маставы маршрут, прачытайце тунэльны маршрут і паглядзіце, які перамагае для рэальнага адраса кантэйнера.

Docker Desktop змяшчае кантэйнеры за ВМ з уласным NAT. Хаст зусім не мае маршруту да адраса кантэйнера; ён дасягае службы праз апублікаваны порт, звычайна прывязаны да 127.0.0.1. Таму кліент VPN можа зламаць службу без якога-небудзь перасячэння падсетак — або ўсталяваўшы маршрут для ўнутранага дыяпазону ВМ, або заблакаваўшы трафік loopback, пакуль падключаны тунэль. Калі ip route get на хасце паведамляе пра адсутнасць маршруту да адраса кантэйнера, гэта чакана, а не памылка.

Практычная выснова — з чаго пачынаць пошук. На Linux пачніце з табліцы маршрутызацыі. На Desktop пачніце з апублікаванага порта і правілаў брандмаўэра кліента VPN, затым праверце, ці не перасякаецца ўнутраная падсетка ВМ з чым-небудзь, што перадае тунэль.

Праверце з уключаным тунэлем

Перападключыце VPN двойчы, перш чым назваць гэта выпраўленым, бо профіль, які перадае маршруты пры падключэнні і забірае іх пры адключэнні, можа выглядаць правільным пасля першай спробы. Затым запусціце праверкі, якія кліент сапраўды выконвае:

  1. ip route get з хаста, выкарыстоўваючы рэальны адрас кантэйнера.
  2. Запыт з іншага кантэйнера, каб даказаць, што служба сама здаровая.
  3. curl -sv http://127.0.0.1:8080/ з кліента з уключаным тунэлем, затым traceroute -n да адраса кантэйнера з машыны ў LAN.
  4. sysctl net.ipv4.conf.all.rp_filter калі запыт дасягае хаста, а адказ знікае.

Нарэшце, запішыце выбраны дыяпазон у той жа рэестр, з якога вы яго бралі, з датай і праектам, якому ён належыць. Наступнае перасячэнне прыйдзе з праекта, якога ніхто не дакументаваў, і адзіная абарона — дыяпазон быў зарэзерваваны свядома, а не ўзяты выпадкова.

Падобныя артыкулы