Рождение плохой архитектуры
RomanТрудные времена рождают сильных людей. Сильные люди рождают хуёвую архитектуру (с) Платон.
Вообще, эта статья даже не техническая, это, наверное для психотерапевтов больше, а то и для психиатров - просто понаблюдать почему и в какой момент принимаются хуёвые решения и чем они мотивируются.
Сначала есть какая-то хорошая девственная сеть. Она работает и есть не просит. В сети есть пользователь и сервис, которым этот пользователь пользуется.
Сеть знает как сроутить трафик от пользователя к сервису. Сервис висит на физическом интерфейсе сервера, интерфейс сервера воткнут в access порт коммутатора, коммутатор анонсирует в Сеть префикс висящий на SVI интерфейсе. А ещё мы решили делать всё на IPv6, но пока что это ничего не меняет.
Однажды сервак "упал" и пиздец - сервис умер :(
Реактивное мышление (а на проактивное времени нет!!1):
- Сервер надо срочно зарезервировать! Ставьте скорее второй!
- Ну а IP-адрес-то на первом сервере останется! Не DNS-ом же балансить дурацким, там же TTL и всё такое
- Ну придумайте там что-нибудь, шареный IP на лупбек повесьте и как-нибудь в сеть anycast-ом заанонсируйте. Круто будет
Так появляется несколько серверов, на серверах появляется BGP демон, который анонсирует адрес сервиса в сеть.
- А чё, пацаны, какой BGP будем делать между серверами и сетью? iBGP или eBGP?
- Да давайте eBGP - у каждого сервера своя AS-ка будет, можно будет по AS-Path потом смотреть откуда префикс прилетает - удобно для траблшутинга! Обсервабилите же!
Сервисов становится много (красный, синий, зелёный...).
Сервера падают, а сервисы живы, красота, ещё и нагрузку можно балансить. Каеф.
Бля, свитч забыли зарезервировать!
Количество сервисов растёт, количество серверов растёт, количество свитчей растёт, добавляется некий уровень агрегации. И повсюду eBGP.
BGP там, BGP сям, много BGP везде, надо как-то "упрощать". Каждый коммутатор, в который включаются сервера выглядит как stub - можно отдать только дефолт с агрегации, а те дефолт до серверов спустят, например. А свичи доступа наверх заанонсят только то, что им сервера отдают. Ну на том и порешили.
В какой-то момент "соседнее подразделение", отвечающее за сервера говорит - "Мы чёт подзаебались ручками на сервера IPv6 адреса прописывать, прочитали тут в интернете что есть такой зверь - SLAAC! Можете его нам на интерфейсе включить, и префикс нам скажите, а мы будем сами из MAC-а адрес IPv6 вычислять!". В этот момент, конечно "соседнее подразделение" будучи подразделением в серьёзной компании всё продумало, взвесило все за и против и учли много других факторов, придя к такому решению.
- Ну вот вам SLAAC, ребята.
- Спасибо! Адреса выдаются, сервера свои видим! Тока это, чёт BGP не взлетает со свичём
- Ну да, свитч-то теперь откуда знает куда BGP строить, раньше как-то руками всё прописывали и норм было, а теперь вы на динамику завязались, это нам тоже получается скрипт какой-то писать надо, чтобы адреса откуда-то дёргать и BGP на свиче конфигурить? Ну мы можем, но только послезавтра, а вам же завтра надо что бы всё работало, да? Хм...
- ... а давайте так - у нас уже автоматика есть кое-какая, да и компетенций в автоматизации поболя вашего будет. Мы в общем, у себя роут-сервер развернём, свои сервера с ним запирим, а вам только надо будет с роут-сервером запириться - мы вам все маршруты и отдадим, ну а вы дальше в сеть их пульнёте.
И схема получается такой вот (для упрощения отображены не все коммутаторы доступа - их сотни, и не все сервера - их тысячи)
1) Сервер_1 подключен в акцесный порт коммутатора своим интерфейсом eth0. На eth0 висит ipv6 адрес, сгенерированный SLAAС-ом, префикс слаака висит на SVI итерфейсе свитча_доступа_1. Префиксы, конечно, уникальны на каждом свитче доступа. Префиксы анонсируются по BGP "наверх" - то есть на свитчи агрегации, которые анонсируют их в Сеть. Взамен свитчи агрегации анонсируют на свитчи доступа дефолт.
1.1) Допустим, префикс на свитче_доступа_1 - 2001:db8:1000:1000::/64. И так уж получилось что по SLAAC-у сгенерировался адрес у сервера_1 - 2001:db8:1000:1000::dead:beef
2) Связанность между eth0 интерфейсом и роут-сервером есть. Они могут, например, установить мультихоп BGP сессию, что и делают. Сервер_1 отдаёт по BGP в сторону роут-сервера анонс на сервис - например 2001:db8:9999::1/128, где в качестве next-hop-а будет адрес физического интерфейса сервера_1, то есть 2001:db8:1000:1000::dead:beef - что логично, ведь чтобы добраться до сервиса нужно прийти на интерфейс сервера.
То есть где-то в недрах bgp появился маршрут:
2001:db8:9999::1/128 ->2001:db8:1000:1000::dead:beef
3) Роут-сервер строит eBGP сессии до свитчей агрегации. Только до агрегации, потому что принимается решение уровня "Нахуя нам строить BGP до всех свитчей вообще? Свитчей дохуя, слишком много конфигурационного оверхеда. А автоматизации нет. Да и кажется, что до свитчей агрегации сессиий будет достаточно."
3.1) Что важно, анонс от роут-сервера до свитчей агрегации должен прилететь с неизменным next-hop-ом. Таким образом, свитч агрегации будет иметь маршрут с next-hop-ом 2001:db8:1000:1000::dead:beef, а он знает как до него добраться, потому что получил от свитча_доступа_1 подсеть 2001:db8:1000:1000::/64 по eBGP
4) Дальше свитч агрегации анонсирует полученный анонс в Сеть по eBGP, отдавая в качестве next-hop-а уже свой адрес, которым смотрит в Сеть. Сеть знает что сервис доступен через свитч агрегации.
И это даже работает. До поры до времени.*** Потом мы вспоминаем, что пользователем сервиса может быть другой сервис (машины разговаривают с машинами, пиздец!). Хотя даже и такой кейс работает, когда сервисы подключены в разные свитчи. А вот когда в один и тот же - начинается заloop-а, и вот почему:
1) Агрегат отдаёт на доступ только дефолт
2) Доступ отдаёт в сторону агрегат (2001:db8:1000:1000::/64)
3) Агреагат имеет у себя в таблице машрутизации вот эти два маршрута:
DB-сервер, 2001:db8:7777::7/128 -> 2001:db8:1000:1000::aaaa:beee
WEB-сервер, 2001:db8:9999::1/128 ->2001:db8:1000:1000::dead:beef
Оба префикса в итоге рекурсивно доступны через 2001:db8:1000:1000::/64, то есть через линк до свитча_доступа_1
4) web-сервер, захотевши связаться с DB-сервером, выйдет на свитч_доступа_1, откуда дефолт ведёт на свитч_агрегации_1, а там есть специфичный маршрут на IP-адрес DB-сервера, ведущий на свитч_доступа_1 как раз, откуда дефолт ведёт на свитч_агрегации_1, а там есть специфичный маршрут на IP-адрес DB-сервера, ведущий на свитч_доступа_1 как раз... Ну и так далее кароче.
Тут бы в пору остановиться, СЕСТЬ и ПОДУМАТЬ, и таки написать какую-то автоматизацию, ну выходы же очевидные:
- либо пирить роут-сервер со ВСЕМИ свитчами, что бы все свитчи обладали консистентными таблицами;
- либо отказаться от роут-сервера нахуй, и вернуться к вопросу пиринга серверов напрямую со свитчами доступа;
но, нет! роут-сервер же уже развёрнут, чё зря работу сделали (эффект Конкорда), да и devops-ы ушли пиво-смузи пить. Ну и оно же ПОЧТИ РАБОТАЕТ КАК НАДО, где-то надо чёто подкрутить и всё заебись будет!
Технически решение понятно - надо от свитча агрегации на свитчи доступа не только дефолт отдавать, но и вот эти вот специфики, которые от роут-сервера прилетают. Однако, загвостка - маршруты от роут-сервера надо отдавать не меняя next-hop (то есть что бы в маршруте в качестве next-hop-а оставался адрес сервера, который маршрут породил), а с дефолтом такая история не проканает - дефолт на свитчи агрегации прилетает "сверху" из Сети.
Используемая линейка свитчей не позволяет "гранулярно" какие-то префиксы отдавать с неизменным next-hop-ом, а какие-то с next-hop-self (что является дефолтом для eBGP сессии). Оригинировать дефолт - не помогает. Менять на iBGP? Ну не серьёзно - надо всю сеть переделывать.
Ну чё, городить что-ли две сессии? Одну с next-hop-self, другую с next-hop-unchanged? Бред сумасшедшего. Очень хуёвый дизайн кароче.
Однако, в итоге так и сделали, да - от свитча агрегации до свитча доступа две, блять, сессии - одна отдаёт дефолт, другая - эти вот специфики, с неизменным nexth-hop-ом. Хуёвый дизайн. И пошли решать другие задачи.
Ну, а когда пришёл новый человечек в команду, и спросил что эта за хуета - так ему и сказали - "Так исторически сложилось" ¯\_(ツ)_/¯
UPD.:
*** в комментариях меня ткнули носом в этот момент и я понял что напиздел - нет, оно, действительно не работает вообще, даже в случае когда трафик идёт от "человека". Там будет происходить таже залупа.
Между рождением этой хуёвой архитектуры и написанием статьи прошло больше двух месяцев, и я действительно забыл, что оно не работало - там я подпёр другим костылём, когда тестировал )