izi DevOps
3.22K subscribers
7 photos
20 videos
1 file
35 links
Download Telegram
Что делать когда compose up поднялся, но сеть так и не работает

Ниже 4 инструмента и приёма чтобы понять, где именно проблема.

➖➖➖

▎1. docker network inspect

Посмотри что Docker реально создал:


docker network ls
docker network inspect myproject_default


Что важно увидеть в выводе:

▸ Containers. Кто реально подключён к этой сети. Если сервиса там нет, он в другой сети, и DNS его не увидит.
▸ Subnet и Gateway. Пригодится когда есть конфликт с корпоративной сетью (10.x / 172.x). У меня такое бывало пару раз.
▸ Driver. bridge, overlay или macvlan. Compose по умолчанию поднимает bridge user-defined.
▸ Internal: true. Сеть без выхода в интернет.

Чтобы увидеть к каким сетям подключён конкретный контейнер, кастуй команду ниже:


docker inspect web --format '{{json .NetworkSettings.Networks}}' | jq


Если у web сеть frontend, а у db сеть backend то они не увидят друга.

➖➖➖

▎2. Embedded DNS на 127.0.0.11

Когда контейнер делает nslookup db, запрос летит не в гугл и не в системный resolver. Он идёт на 127.0.0.11, встроенный DNS Docker. Этот резолвер живёт в каждом контейнере на user-defined bridge.

Внутри контейнера:


$ cat /etc/resolv.conf
nameserver 127.0.0.11


Что Docker делает с запросом:

1. Сначала смотрит, есть ли контейнер с таким именем в той же сети.
2. Если нет, форвардит на хостовый DNS.

Поэтому db резолвится в IP контейнера, а google.com уходит наружу.

На дефолтном bridge (без user-defined) этого DNS нет. Поэтому docker run без compose тебя по имени не свяжет, только по IP. Это одна из причин почему дефолтный bridge мертв.


Ещё про DNS: алиасы. У сервиса в compose можно задать дополнительные имена для сети:


services:
db:
image: postgres:16
networks:
app-net:
aliases:
- postgres
- primary-db


И теперь db, postgres, primary-db резолвятся в один и тот же контейнер. Удобно при переименованиях, чтобы не трогать код приложения, если вдруг он у вас так отвратительно написан).

➖➖➖

▎3. nicolaka/netshoot

Не нужно ставить tcpdump в свой образ. Запускаешь сайдкар, который делит сетевой namespace с проблемным контейнером:


docker run -it --rm \
--network container:web \
nicolaka/netshoot


Внутри netshoot есть всё: dig, tcpdump, nmap, iperf, mtr, nslookup, tshark, iproute2.


# 1. Резолвится ли имя?
dig db

# 2. Слушает ли db нужный порт?
nc -zv db 5432

# 3. Доходит ли пакет?
tcpdump -i any -n host db

# 4. Есть ли вообще маршрут наружу?
ip route


➖➖➖

▎4. external: true для сетей между compose-проектами

Частый кейс: фронт в одном docker-compose.yml, бэк в другом, observability в третьем, и хочется чтобы они видели друг друга по имени сервиса.

Создаёшь сеть один раз руками:


docker network create shared-net


И в каждом compose-файле ссылаешься на неё как на внешнюю:


services:
web:
image: app:1.0
networks:
- shared-net

networks:
shared-net:
external: true


external: true означает "используй уже существующую сеть". Если её нет, compose упадёт с ошибкой network not found.

Когда это к месту:

▸ несколько compose-проектов и нужно чтобы они общались
▸ база живёт вечно, а сервисы пересобираются

Альтернатива: затащить всё в один compose-файл. Если проектов уже три и они растут, external чище.

@izi.devops
1👍8❤2
Пока я делаю ластовый ролик по файловой системе докера, скажите какую тему дальше взять?
Anonymous Poll
18%
Copy fail уязвимость
52%
Начинать ролики про k8s
64%
Сети, маршруты и тд
2%
Я предложу тебе тему в комментариях
👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Copy Fail (CVE-2026-31431): и все твои гачиремиксы у майора в папке

➖➖➖

▎Что произошло

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

меняешь четыре байта в /usr/bin/sudo, и проверка пароля начинает всегда возвращать «ок, ты root». теперь sudo bash запускает шелл без пароля.

➖➖➖

▎Почему контейнеры опаснее физического хоста

этот сокет проходит сквозь Docker и Kubernetes namespace. контейнер видит его так же, как хост.

сценарий в k8s. взломан один pod. он правит четыре байта в общем системном бинаре (`busybox`, ld-linux, что угодно из shared base image). этот бинарь лежит в page cache ядра ноды. соседние pod'ы запускают его и подхватывают.

без CAP_SYS_ADMIN, без --privileged, без сетевой связности. побег из контейнера не нужен. ты компрометируешь соседей со своего же пода.

➖➖➖

▎Как защититься

Обновляй ядро или seccomp в docker или kyverno в кубе
👍5❤3🔥2
Что не влезло в ролик про MAC, ARP и DHCP

➖➖➖

▎1. Gratuitous ARP. Как переезжает виртуальный IP

Обычный ARP это вопрос «у кого 192.168.1.1». Gratuitous ARP это ARP, который никто не просил. Машина просто кричит в сеть: «теперь этот IP у меня, мой MAC такой».

Зачем. Есть VIP, который держит keepalived или VRRP. Основной упал, резерв поднял IP у себя. У всех в кэше старый MAC, трафик летит в мёртвый сервер. Резерв шлёт gratuitous ARP - все обновляют кэш, трафик идёт в живой.

Где встречается: keepalived, Pacemaker, kube-vip, MetalLB в L2.


tcpdump -i eth0 -n 'arp and arp[14:4] = arp[24:4]'


Фильтр ловит gratuitous независимо от того, request это или reply.

➖➖➖

▎2. Два одинаковых MAC в одной сети

MAC обычно уникальный (первые 3 байта - это вендор), но его можно поменять руками. Иногда два устройства реально оказываются с одним MAC: склонировали виртуалку, дешёвый вендор повторил адрес, кто-то задал руками.

Что происходит на свиче. CAM это MAC → порт. Свич видит aa:bb на порту 5 запоминает. Потом видит тот же aa:bb на порту 12 перезаписывает. Через секунду опять видит на 5-м порту. Называется это поведение MAC flapping.

Симптомы: пинг через раз, в логах свича MAC flap between port 5 and port 12, ARP-кэш нестабильный.

Найти:


# linux bridge
bridge fdb show | sort | uniq -c -w 17 | sort -rn | head


Фикс - сменить MAC на одном из устройств:


ip link set dev eth0 address 02:00:00:11:22:33


➖➖➖

▎3. Два DHCP-сервера в одной сети

DHCP Discover это broadcast. Несколько серверов в одной сети значит, что каждый ответит из них и клиент возьмёт первый пришедший Offer.

▸ Подняли dnsmasq или ещё один тестовый DHCP, забыли выключить.

Защита на свиче - DHCP snooping. Свич знает, на каких портах разрешён DHCP-сервер (uplink), на остальных Offer/ACK режутся.


tcpdump -i eth0 -n 'udp port 67'


Если в логе несколько IP-источников Offer в сети больше одного DHCP.

Легитимный второй DHCP это failover: ISC DHCP failover или HA решения. Два сервера синхронят время аренды, клиент не замечает падения одного.

➖➖➖

▎4. DHCP FORCERENEW. Когда сервер выдёргивает клиента

Обычно цикл такой: клиент получил lease, через половину аренды шлёт Renew. Всё инициирует клиент.

А что если поменяли шлюз или DNS и хотим, чтобы клиенты подхватили это сейчас, не через 12 часов? Для этого есть FORCERENEW (RFC 3203).

Сервер шлёт клиенту unicast FORCERENEW. Клиент должен немедленно уйти в Renew и получить свежий ACK с новыми опциями.

Условия:

▸ Сервер и клиент знают общий ключ (HMAC-MD5). Без ключа клиент игнорит, иначе любой левый сервер мог бы дёргать чужих.
▸ Клиент поддерживает: ISC dhclient, systemd-networkd.

Альтернатива если FORCERENEW не настроен, поставить короткий lease (5 минут) на время изменений, дождаться пока все обновятся, вернуть нормальный.

➖➖➖

Не пропусти следующий ролик про VPN
👍9❤6🔥1
Я купил микрофон нормальный, теперь будет собственная озвучка 🌚
3🔥26❤7👍1
Думали я делал только видосики всё это время? А вот нет, еще я сделал сайт с теорией и маленько практики добавил в браузере.
https://izidevops.com/
если находите какие-то артефакты или ошибки или прочую шляпу пишите. Скоро буду делать нормальные практические уроки по куберу и разным другим технологиям по подписке. Всех поднял, обнял, пользуйтесь ❤️
🔥21❤3👾1
VPN темы, которые не влезли в 2 минуты

Дефолтный wg-quick up wg0 гонит весь трафик в туннель, DNS течёт мимо, при обрыве ноут долбит гугл с реальным IP, а DPI со временем научится резать (WG он уже режет спокойно). Примеры на WireGuard, но у других протоколов те же грабли.

➖➖➖

▎1. Split tunnel через AllowedIPs

Отдельной галочки «split tunnel» в WireGuard нет, всё решает одно поле в [Peer]:


[Peer]
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0


0.0.0.0/0 это full tunnel, весь IPv4 в туннель (вариант из видео). Хочешь гнать в VPN только корп-подсеть, а ютуб напрямую:


AllowedIPs = 10.10.0.0/16, 172.16.0.0/12


wg-quick пропишет в ip route только эти префиксы, дефолт останется на роутере. Реверса (всё минус что-то) в WG нет.

➖➖➖

▎2. Kill switch против утечки при обрыве

Туннель упал, ноут продолжает слать пакеты, и без kill switch они уйдут через роутер с реальным IP. Сам wg-quick его не делает, но в man-странице есть готовый рецепт через PostUp`/`PreDown (маршруты при этом дефолтные, `Table = auto`):


[Interface]
Address = 10.0.0.2/32
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT


Правило режет любой исходящий не через wg0, кроме самих шифро-пакетов WG (по fwmark`) и localhost. `-j REJECT, а не DROP, чтобы приложения сразу видели ошибку, а не висели в таймауте. wg-quick down снимает правило, после ребута нет ни правила, ни туннеля.

В клиентах отдельной кнопки kill switch нет. На Android его включают в системных настройках VPN («Постоянная VPN» + «Блокировать соединения без VPN»), на iOS и macOS похожий эффект даёт «On-Demand», который сам переподнимает упавший туннель.

➖➖➖

▎3. DNS leak. Куда деваются `.com`-запросы

Туннель поднят, AllowedIPs = 0.0.0.0/0, а /etc/resolv.conf всё ещё nameserver 192.168.1.1. Браузер резолвит google.com через домашний роутер, тот идёт к провайдеру. Сам HTTPS потом шифрованный и в туннеле, но какие домены ты открывал провайдер уже записал.

Лечится строкой в конфиге, wg-quick подменит resolv.conf:


[Interface]
DNS = 1.1.1.1, 1.0.0.1


Теперь DNS летит к Cloudflare через туннель, провайдер видит только поток на твой сервер.

Проверка: dnsleaktest.com → Extended Test. Вылез провайдер, значит течёт.

На macOS DNS живёт не в resolv.conf, а в scutil, и mDNSResponder может кэшировать своё. Лечится dscacheutil -flushcache; sudo killall -HUP mDNSResponder.

➖➖➖

▎4. MTU. Почему «после VPN всё тормозит»

VPN кладёт твой пакет в новый: IP-заголовок снаружи, заголовок WireGuard, UDP. ~60 байт оверхеда. Пихаешь 1500 в туннель, на выходе 1560, это больше MTU линка, пакет фрагментируется или дропается.

wg-quick сам считает MTU как у маршрута до сервера минус 80, на обычном Ethernet это 1420, обычно норм. Но PPPoE режет до 1492, мобила до 1400, IPv6-туннели до 1280, и 1420 уже не лезет:


[Interface]
MTU = 1380


Симптом: handshake проходит, а большая страница виснет на середине, картинки в телеге не грузятся, rsync зависает. Тест:


ping -M do -s 1372 1.1.1.1 # Linux: 1372 + 28 = 1400
ping -D -s 1372 1.1.1.1 # macOS


Проходит на 1372 и нет на 1400, значит MTU около 1400. Ставь 1380 с запасом.

➖➖➖

▎5. Когда обычный WireGuard режется DPI

DPI у больших провайдеров узнаёт WireGuard по первому пакету: хэндшейк всегда начинается с 0x01 0x00 0x00 0x00 и имеет фиксированный размер (148 байт). Видит этот префикс и рубит соединение.

➖➖➖

Писал огромную пасту, какие впн сейчас работают, но подумал что могут притянуть за распространение. Так что залетайте в инсту под последний ролик про ВПН, там в комментах обсуждение (хотя если вы тут, то впн у вас уже есть). По белым спискам инфа тоже быстро устаревает, но на гитхабе есть рабочие варианты (поднять прокси у российского провайдера, который сам в белом списке, и всё заработает).
👍9🔥3❤1
Привет! Запускаю в закрытую бету платформу для подготовки к CKAD и CKA. Там нет видосов, но есть живые лабы: у тебя прямо в браузере настоящий кластер, задания и автопроверка.
Беру 5 человек в первую группу. Взамен прошу пройти несколько уроков и честно сказать, что непонятно, где баг или где некрасиво.
Доступ бесплатный. Нужны и те, кто уже знает куб, и те, кто только слышал про него, но хочет разобраться. Если интересно, напиши в комментариях свой уровень: новичок, готовлюсь к CKAD, или уже работаю с k8s.
🔥15❤1
Как ТСПУ ищет тунель, ни разу не заглянув внутрь

Зашифрованный трафик нельзя прочитать. Но это и не нужно. Цензору хватает того, как поток выглядит снаружи: энтропии первого пакета, ритма рукопожатия, формы сессии и того, что ответит сервер на пустой запрос. Самая изученная штука в этом плане великий китайский факрвол GFW: его правила вытащили наружу академики, и по ним видно, что именно меряет машина. ТСПУ сначала шел тем же путём, полностью переняв опыт, но сейчас вырвался вперед и блочит даже то, что не умеет китайский.

Дисклеймер: разбор механики по открытым источникам, без инструкций по обходу и без рекламы сервисов.

➖➖➖

▎1. Энтропия первого пакета

В ноябре 2021 GFW включил детектор «полностью зашифрованного» трафика. Логика обратная: система не ищет VPN, она вычёркивает всё, что на VPN не похоже, и блокирует остаток. Пять правил-исключений (USENIX Security 2023):

считается доля единичных бит на байт в первом TCP-пейлоаде. Если ≤3.4 или ≥4.6 бит, то поток помилован. Зашифрованные данные держатся около середины (примерно половина бит это единицы), и именно это выдаёт их;
Также помилование, если первые 6+ байт лежат в печатном ASCII (0x20–0x7e), либо печатных байт больше половины, либо подряд идёт больше 20 печатных символов;
Ну и помилование по сигнатуре TLS и HTTP-методов (GET, POST и т.п.).

Тонкость: блокируется только ~26% соединений к подозрительному серверу, и работает это лишь по TCP. UDP детектор не трогает вовсе.

➖➖➖

▎2. Отпечаток рукопожатия

Даже обёрнутый протокол выдаёт себя порядком пакетов. Разбор OpenVPN (USENIX Security 2022) показал: в заголовке есть поле opcode, у него больше 10 значений, и их последовательность в начале сессии складывается в узнаваемый узор. Второй признак P_ACK: эти пакеты без TLS-нагрузки, одинакового размера, и в ванильном OpenVPN и в XOR-обфускации первый ACK обычно приходит третьим пакетом сессии.

obfs4 этот класс атак держит: на каждый мост нужен отдельный секрет, который клиент обязан доказать в первом сообщении, поэтому отпечатка наружу не торчит.

➖➖➖

▎3. Форма потока вместо содержимого

Размеры пакетов и паузы между ними рисуют картинку, которую читает потом загоняют в ИИ для анализа потока.

➖➖➖

▎4. Активное прозванивание

Если пассивно непонятно система сама стучится на сервер. И может определять действительно ли вы стучитесь на сервер просто так и там не установлен впн, повторяет ваш запрос и смотрит что ему отвечает сервер.
➖➖➖

▎5. Один пул и география

С 2025 в ТСПУ заявлены поведенческие ML-признаки: длительность сессий, частота подключений к одному адресу, объёмы. Общий публичный сервер палится очень быстро, из-за того, что тысячи незнакомых клиентов на одном IP такого узора в норме не дают. И раскатка идёт не разом: с декабря 2025 отлов VLESS сначала включили в Татарстане и Удмуртии, потом в Свердловской области, потом в Москве.

➖➖➖

Итого, что мы имеем.
Детектор не читает байты, он меряет их статистику: энтропию первого пакета, порядок opcode, форму потока, ответ на прозвон и плотность клиентов на адресе. Чем ровнее и многолюднее канал, тем быстрее он попадает в остаток, который блокируют. Всё по открытым источникам, цифры устаревают за недели. Также нет прямой информации по ТСПУ, это все или сливы от людей кто с ним работает или косвенный анализ поведения или тестовые лабы.

Поэтому платные решения меньше живут, чем собственные
1❤10🔥4
Серты, что не влезло в ролик

Самое частое и обидное это дата. Внутри серта две метки, начало и конец срока, браузер просто сверяет их с часами системы. Опоздал на минуту, и держи NET::ERR_CERT_DATE_INVALID. Мелочь, скажешь ты, но на этом падали Microsoft Teams в 2020 и Spotify позже. Огромные сервисы легли, потому что забыли продлить серт. Сейчас серты и так живут недолго: публичные CA выдают максимум на 398 дней, а в 2025 решили резать до 47 дней к 2029 году.


openssl x509 -in cert.pem -noout -dates


➖➖➖

Дальше браузер смотрит, на чьё имя серт выписан. Берёт хост из адресной строки и ищет его в поле SAN. Раньше для этого был Common Name, но он устарел, теперь имя живёт только в SAN. Серт выдан на bank.ru, а ты зашёл на www.bank.ru, которого в списке нет, и получаешь ERR_CERT_COMMON_NAME_INVALID. Подпись правильная, цепочка целая, серт настоящий, просто не от этого адреса.


openssl x509 -in cert.pem -noout -ext subjectAltName


Заодно проверяется, чем серт подписан. SHA-1 выкинули ещё в 2017, RSA короче 2048 бит не пропустят. Тут обычно всё ровно.

➖➖➖

Допустим, у банка украли приватный ключ. По дате серт ещё годен, но доверять ему уже нельзя, его надо отозвать досрочно. Для этого два механизма: CRL, длинный список отозванных, и OCSP, точечный вопрос «этот серт ещё живой?». Куда стучаться, зашито прямо в серте.


openssl x509 -in cert.pem -noout -ocsp_uri


Только в жизни всё держится на честном слове. Сервер OCSP у CA прилёг, и браузер не ругается, а молча пускает (soft-fail), иначе при каждом сбое CA встал бы весь интернет. То есть атакующему хватит заблокировать OCSP, и отозванный серт снова «валиден». Плюс каждым запросом ты докладываешь центру, какие сайты открываешь. В итоге браузеры на живой OCSP махнули рукой: Chrome таскает свои CRLSets, Firefox городит CRLite. Проверка вроде есть, а по факту её отключили сами вендоры.

➖➖➖

Корневой серт вшит в систему, серт банка прилетает при подключении, а промежуточный между ними сервер обязан отдать сам. Не положил его в конфиг, и цепочка до корня не достроится. Самое противное, что на десктопе Chrome промолчит: нужный промежуточный он уже видел на других сайтах и достанет из кэша. А свежий браузер или curl без кэша упрутся в ошибку.


openssl s_client -connect bank.ru:443 -showcerts



ОБЯЗАТЕЛЬНО К ПРОЧТЕНИЮ

И отзыв только что перестал быть теорией. В июне 2026 GlobalSign начал массово отзывать серты российских сайтов: CA/Browser Forum обязал центры сверять клиентов с санкционными списками. Под раздачу попали тысячи доменов, а среди западных коммерческих сертов в рунете у GlobalSign было около 90%.

Тут и вылезает та самая дырявость. Эффект размазанный: где-то браузер увидит отзыв и покраснеет, где-то soft-fail и урезанные CRLSets пропустят. Оттого и оценки гуляют, от десятков тысяч сайтов до «не больше 5%» по версии Минцифры. Ведомство зовёт на серты своего Национального удостоверяющего центра (НУЦ), их бесплатно выдают через Госуслуги. Только корень НУЦ по умолчанию доверяют лишь Яндекс.Браузер и Атом, в Chrome его ставят руками.


И вот тут стоит дважды подумать. Корень это абсолютное доверие: кто им владеет, тот может выписать валидный серт на любой домен, хоть на gmail, хоть на твой банк, и браузер покажет зелёный замок без вопросов. Тот самый человек посередине из ролика, только впускаешь ты его сам.

Для НУЦ это значит, что владелец корня (Минцифры, а значит и СПЕЦСЛУЖБЫ) при желании может вклиниться в твой HTTPS на своей инфраструктуре, у провайдера, и читать трафик, который ты считаешь зашифрованным. Поэтому если корень НУЦ всё же нужен, держи его в отдельном браузере под госуслуги и госбанки, а НЕ СУЙ в системное хранилище для всего подряд.
👍7❤1
Всем привет! Запустил тренажёр по Kubernetes. Живые лабы с настоящим kubectl прямо в браузере:

Первая лаба бесплатная. А если платить не хочешь, на сайте доработал десятки бесплатных уроков роадмап, теория, разборы, вся обязательная база.

izidevops.com
11🔥22😍2❤1🏆1🤝1
VPN включён. А тебя всё равно видно.

Под прошлым видео разгорелся спор: мол, все эти деаноны работают только на древних L2TP и SSTP, а на Xray с Reality такое не прокатит.

Reality прячет одну вещь: факт, что ты под VPN, от провайдера. Сайт, который тебя палит, живёт на другом уровне.

➖➖➖

▎1. Транспорт и браузер это разные слои

Reality, uTLS, VLESS, выбор протокола, всё это про транспорт. Как трафик доезжает до сервера и как выглядит со стороны провайдера. Деанон на сайте происходит выше, в самом браузере.

➖➖➖

▎2. DNS течёт на уровне резолвера

Браузер спрашивает «где сайт?» у DNS. Если резолвинг не завёрнут в туннель, запрос уходит мимо, и провайдер видит список доменов. Xray тоже течёт, если не настроить sniffing и роутинг DNS руками. Протокол сам по себе тут не помогает.

➖➖➖

▎3. WebRTC сливает реальный IP

WebRTC шлёт STUN-запросы по UDP напрямую через сетевой стек ОС, мимо настроек прокси браузера. Если трафик идёт мимо туннеля (браузерный VPN, proxy-режим, split-tunnel), пара строк JS вытаскивает твой реальный адрес, пока VPN спокойно крутится. Системный full-tunnel это закрывает, но дефолтная связка «расширение + браузер» нет. Надёжнее всего рубить WebRTC в самом браузере, а не надеяться на VPN.

➖➖➖

▎4. Фингерпринт от протокола не зависит

uTLS правда меняет отпечаток TLS-хендшейка, это JA3/JA4. Но это сетевой уровень, до того как выполнится хоть одна строчка JS. А canvas, WebGL, шрифты, разрешение, язык сайт снимает из самого браузера. Хоть SSTP, хоть Reality, отпечаток один и тот же.

➖➖➖

▎5. Залогинен значит опознан

SameSite-куки это защита от CSRF, к деанону отношения ноль. Сидишь залогиненным в гугле, вк, я.браузере, тебя палит сессия. Хоть через цепочку из 50 прокси. Дальше идёт поведение: движения мыши, ритм печати, паттерны кликов. Всё сшивается в один профиль, и узнают тебя даже с нового адреса.

➖➖➖

▎6. «А Hysteria2 и новые ядра уже всё чинят»

Частично. TUN / full-tunnel режим перехватывает весь UDP ОС и может завернуть STUN в туннель. Но это руками включить, а не дефолт.

Люди и сейчас ловят DNS-утечку на VLESS/Reality, и каждый раз лечится одним: руками настроить DNS-роутинг через туннель. Reality сам по себе резолвинг не закрывает.
[Xray #4299](https://github.com/XTLS/Xray-core/discussions/4299) · [Xray #5618](https://github.com/XTLS/Xray-core/discussions/5618)

И главное: фингерпринт и поведение ни одно ядро не трогает в принципе. Это прикладной слой.
3❤11👍4🤔1
Kubernetes сам поднимает копии под нагрузку. Разберёмся, как это устроено.

В ролике копии приложения множились в чёрную пятницу, гасли ночью, а упавшее восстанавливалось само. За этим стоят конкретные механизмы, давай посмотрим на них.

▎1. Копии живут не сами по себе

Поды руками не запускают. Вместо этого описывают Deployment: «хочу три копии этого образа», а контроллер постоянно сравнивает желаемое число копий с текущим и устраняет разницу. Этот цикл называется control loop, и на нём построен весь Kubernetes.

▎2. Кто добавляет копии под нагрузку

За автоскейл подов отвечает HorizontalPodAutoscaler (HPA). Каждые 15 секунд он проверяет метрику (обычно CPU или память) и пересчитывает нужное число копий: если целевая утилизация 50%, а поды работают на 100%, копий нужно вдвое больше. HPA меняет число реплик в Deployment, а поднимает их контроллер из первого пункта.


apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: shop
spec:
scaleTargetRef: { kind: Deployment, name: shop }
minReplicas: 3
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target: { type: Utilization, averageUtilization: 50 }


Днём HPA растит реплики с 3 до 50, ночью возвращает обратно, причём вниз масштабирует с пятиминутным окном стабилизации, чтобы реплики не скакали при коротких провалах трафика.

▎3. Откуда берутся цифры нагрузки

Сам кластер потребление CPU не отслеживает, для этого отдельно ставят metrics-server: он собирает данные с нод и отдаёт их HPA. Второе условие: у контейнеров заданы resources.requests, ведь «50% CPU» считается как процент от request, и без него HPA показывает unknown. Пока не выполнены оба условия, автоскейл не заработает, об это и спотыкаются чаще всего.

Для масштабирования по очереди в RabbitMQ, лагу в Kafka или числу запросов ставят KEDA: она умеет сокращать копии до нуля при отсутствии работы и берёт метрики в том числе из Prometheus по PromQL-запросу.

▎4. Self-healing: три уровня

«Упала копия, поднялась новая» на деле три разных механизма. Завершившийся процесс kubelet перезапускает сразу, по restartPolicy. Зависшее приложение ловят пробы: liveness проверяет, отвечает ли оно, и при молчании kubelet перезапускает контейнер, а readiness исключает неготовый под из балансировки. Если вышла из строя нода целиком, кластер видит статус NotReady и примерно через пять минут пересоздаёт её поды на живых нодах. Пауза ощутимая, поэтому копии заранее распределяют по серверам через topologySpreadConstraints или podAntiAffinity, и приложение переживает потерю ноды без простоя.

▎5. Кто добавит сами серверы

HPA управляет только подами. Когда реплики не влезают на ноды и висят в Pending, Cluster Autoscaler запрашивает у облака новую ноду в node pool (в AWS это Auto Scaling Group), а при простое возвращает лишние обратно. Две петли работают вместе: HPA масштабирует копии, Cluster Autoscaler добавляет серверы под них. В GKE, EKS и AKS он включается одной настройкой, а многие, особенно в AWS, перешли на Karpenter, который поднимает ноды быстрее и подбирает тип инстанса под конкретные поды.

▎6. Оператор, ключевое слово

KEDA и Karpenter устроены по паттерну «оператор»: в кластер добавляется свой тип объекта (CRD) и контроллер с тем же control loop. Вместо скриптов «если случилось X, сделай Y» ты декларативно описываешь цель, а оператор приводит систему к ней. Cluster Autoscaler написан по более старой схеме, это такой же контроллер, но без собственных CRD.

Так и складывается автоскейл: metrics-server даёт цифры, HPA управляет копиями, Cluster Autoscaler или Karpenter добавляет серверы, KEDA привязывает масштаб к реальным событиям. В основе несколько циклов «сравнить желаемое с текущим и устранить разницу», и если разобрать каждый по отдельности, в автоскейле не остаётся ничего непонятного.

Учись куберу на практике на 🔗 izidevops.com и получай свои 500к наносек.
1🔥10👍2❤1
OpenAI, как масштабируют postgres под 800M юзеров. Разбираю их цифры и где я в ролике упростил.

Один мастер + около 50 реплик. Чтения летят на реплики, пишет только мастер, поэтому потолок write-нагрузки это один сервер. Ниже конкретно что у них работает, что чуть не убило и почему они НЕ шардировали postgres.

➖➖➖

▎1. 50 реплик и лаг возле нуля

В ролике я сказал «реплика отстаёт на десятки мс». У OpenAI лаг практически ноль.

Реплики стоят рядом с мастером в тех же дата-центрах Azure, канал жирный, WAL применяется без задержек. Плюс сами запросы к базе короткие: весь тяжёлый вычислительный слой это LLM, а не SQL. Реплики успевают за мастером.

Сейчас они упёрлись в другое. 50 реплик это потолок для прямой стриминг-репликации, мастер захлёбывается собственным WAL-трафиком. Работают с Azure над cascading replication (реплика реплики), чтобы уйти в сотни копий.

➖➖➖

▎2. pgbouncer: 50 мс → 5 мс

Самое конкретное число из блога. До pgbouncer открытие соединения к postgres занимало 50 мс. После стало 5 мс, уменьшили в десять раз.

Работает у них в transaction или statement pooling. Оба режима ломают prepared statements: клиент шлёт PREPARE, при следующем EXECUTE попадает уже на другое соединение, где такого prepared statement нет, падает. Лечится отключением prepared statements в клиенте (JDBC, node-postgres) или переключением в session mode с потерей экономии.

Плюс потолок Azure Postgres максимум 5000 клиент-коннектов на инстанс. Без pooler'а тысячи воркеров упираются в этот лимит.

➖➖➖

▎3. OpenAI НЕ шардировали

В ролике я показал шардинг как один из четырёх слоёв. У OpenAI шардинга postgres нет и в ближайшее время не планируется.

Вместо этого они выносят write-heavy нагрузки из postgres в CosmosDB (документная БД Azure с горизонтальным шардированием из коробки).

Причина простая. Шардинг postgres требует переписать пол-приложения: cross-shard джоины, транзакции, миграции. Дешевле выделить конкретный write-heavy кусок и перекатить в БД, которая шардится сама. Postgres остаётся простой и быстрой.

Контр-интуитивно. Обычно думают «упрёмся в один мастер, будем шардить». На практике сначала выносят самое горячее в специализированную систему.

➖➖➖

▎4. SEV-0 на запуске ImageGen

За 12 месяцев у них был один крупный инцидент. Запуск генератора картинок бахнул writes в 10 раз, один мастер такого не тянет.

Из блога видно чем закрылись. idle_in_transaction_session_timeout и жёсткий таймаут на schema-change в 5 секунд. Долгая транзакция или ALTER TABLE в проде с 800M юзеров может заморозить весь мастер, потому что берут ExclusiveLock и всё встаёт в очередь. Лучше отвалиться по таймауту, чем повесить базу.

➖➖➖

▎5. Что забрать себе

Даже если у тебя не 800M юзеров, забирать надо ровно то, что у них работает.

Ставь connection pooler, даже с одним инстансом приложения, это реальная экономия на handshake.

Ограничивай длину транзакции. idle_in_transaction_session_timeout=30s в конфиге может сэкономить инцидент, когда воркер зависнет с открытой транзакцией.

Шардинг это ультра гипер ласт опция, не первая. Сначала реплики, кэш, вынос горячего в специализированную БД.

➖➖➖

Учись теории и практике на izidevops.com.
🔥11❤7👍2
Ошибка в видео и три технических детали, которые не влезли в 2 минуты. Плюс ответ на комментарий про Rust-прослойку.

➖➖➖

▎1. Моя ошибка: MySQL у GitHub не для кода

В ролике сказал «GitHub держит код на MySQL». Точнее MySQL держит метаданные: issues, pull request'ы, users, permissions, ссылки на репо. Сам код лежит в git-репозиториях на файловой системе (packed object store в .git/objects/pack/, DEFLATE + delta compression).

Из официального GitHub blog дословно: «GitHub uses MySQL as its main datastore for all things non-git». Спасибо челику в комментах.

➖➖➖

▎2. Почему vertical, а не horizontal шардинг у GitHub

В ролике сказал «взяли 130 таблиц и разнесли». Не сказал почему выбрали именно вертикальный путь.

При горизонтальном шардинге MySQL режем одну большую таблицу по ключу (user_id). Требует переписать пол-приложения: cross-shard джоины, распределённые транзакции, миграции ключей. Vitess это умеет, но много затрат временных.

при вертикальном группа таблиц (issues, PR, comments) целиком уезжает в отдельный MySQL-кластер. Приложение почти не меняется, надо просто научить его знать «issues живут вот здесь». Cutover через Vitess VReplication: копируем данные в фон, включаем dual-write, переключаем reads, отключаем старую копию.

GitHub так вынес 130 самых горячих таблиц.

➖➖➖

▎3. Discord

Cassandra на Java, memtable перед flush держит гигабайты в heap. При GC young generation зависает на десятки мс. Discord пробовал G1GC, ZGC, тюнинг heap-size смогли паузы срезать, но не убрали. Плюс read-repair и compaction тоже держат объекты в памяти, накладываясь на пользовательскую нагрузку.

ScyllaDB на C++, свой планировщик shard-per-core (thread-per-core модель, каждое ядро владеет своим срезом данных, без блокировок).

Discord посчитали цену перехода в шардах: 177 нод Cassandra. ScyllaDB смогла потянуть на 72 нодах, а это почти в 2.5 раза меньше железа. Статья старая, так что думаю объемы больше сейчас у ребят

➖➖➖

▎4. Ответ на вопрос про Rust-прослойку

В комментах был вопрос: «зачем ждать транш запросов, если можно бахнуть ответ сразу? Гасится ли latency?»

Прослойка не ждёт транш. Работает так. Первый запрос на популярное сообщение поднимает worker-задачу и она уходит в базу. Следующие запросы за то же сообщение видят что задача уже крутится, подписываются на её результат вместо своего похода в базу. Worker получает ответ, рассылает всем подписчикам одновременно.

Latency почти не растёт. Первый ждёт обычный round-trip (~15 мс с ScyllaDB). Второй и следующие получают ответ практически бесплатно только IPC overhead в микросекундах.

Смысл не в latency-гонке, а в защите базы. Без coalescing тысяча одновременных читателей одного сообщения, а это тысяча одинаковых запросов, hot partition захлёбывается, все запросы к партиции начинают тормозить.

Плюс consistent hashing по channel_id: все запросы одного канала попадают на один инстанс сервиса, где coalescing работает эффективнее (больше одновременных подписчиков на одну задачу).

➖➖➖

Ссылки:

GitHub MySQL: github.blog/engineering/infrastructure/mysql-high-availability-at-github
GitHub sharding: github.blog/engineering/infrastructure/partitioning-githubs-relational-databases-scale
GitHub 5.7→8.0: github.blog/engineering/infrastructure/upgrading-github-com-to-mysql-8-0
Git internals: github.blog/open-source/git/gits-database-internals-i-packed-object-store
Vitess: vitess.io
Discord ScyllaDB: discord.com/blog/how-discord-stores-trillions-of-messages
❤6🔥5
Ура!! Нас 2000 человеков🎉, за это вы получаете промокоды на скидку на сайте izidevops.com
я девопс — 40%
я нищий девопс — 41%

P.S. Все кто уже в этом месяце приобрел лабы получит бесплатный месяц дополнительно ❤️
😁18❤‍🔥9👍6🎉4
Media is too big
VIEW IN TELEGRAM
Оказалось, что тут есть люди которые не подписаны в инсте, но подписаны тут. Поэтом буду дублировать сюда.
👍18🔥5
Media is too big
VIEW IN TELEGRAM
Что осталось за кадром:

▪️ Lumen и Cogent из ролика это Tier-1: сети, которые никому не платят за транзит, ядро интернета
▪️ веса из traceroute называются local preference, после них сравнивают длину AS-path: чем меньше сетей
до цели, тем лучше маршрут
▪️ RPKI подписывает только владельца префикса, сам путь не проверяется: подписана пока примерно половина маршрутов
▪️ посмотреть свои хопы: traceroute -a facebook.com покажет ASN каждой сети по дороге
👍7🔥3❤2
BGP

➖➖➖

▎1. Маршрут выбирают не по географии

Логично думать, что трафик идёт коротким путём. На деле роутер прогоняет анонсы через список правил и берёт первый, который отсеет остальные. Порядок такой: сначала local preference, число, которое провайдер ставит руками, чем больше тем лучше. Дальше длина AS-path, то есть через сколько чужих сетей ехать. Потом происхождение маршрута, потом MED, и только в самом конце физическая близость соседа.

Отсюда странности вроде трафика из Москвы в Питер через Франкфурт. Провайдер платит одному соседу за каждый мегабит, а с другим обменивается бесплатно, и в настройках руками помечает второго как приоритетного.

▎2. Кто такие Tier-1

Lumen, Cogent и Arelion из ролика это транзитные сети верхнего уровня. Они не платят за транзит никому: между собой обмениваются трафиком бесплатно, по пирингу, и вместе видят весь интернет целиком. Остальные покупают доступ у них или у тех, кто покупает у них.

Иногда две такие сети ссорятся из-за денег и рвут пиринг. Тогда часть интернета перестаёт видеть другую часть, хотя технически всё живо. Cogent воевал и с Level3, и с Telia, пользователи по обе стороны неделями сидели без доступа друг к другу.

▎3. Почему фейсбук чинили так долго

Отзыв маршрутов закрыл не только вход снаружи. У Meta в той же сети жили внутренние сервисы: DNS, инструменты управления, системы доступа. Когда анонсы ушли, инженеры потеряли способ зайти на оборудование удалённо. Попасть в здание физически тоже не вышло.

Отдельная деталь: пока фейсбука не было в маршрутах, приложения на телефонах продолжали ломиться к нему. Это дало всплеск запросов на публичные резолверы вроде 1.1.1.1 и 8.8.8.8, и часть интернета притормаживала уже из-за побочки, а не из-за самой аварии.

▎4. Как воровали деньги

Пакистан 2008 воспринимается как древность, но приём никуда не делся. В 2018 увели трафик DNS Amazon и подменили страницу криптокошелька MyEtherWallet, унесли около 150 тысяч долларов. В 2022 похожее провернули с корейским KlaySwap. Оба раза механика одинаковая: короткий анонс чужого префикса, и перенапривили трафик на фишинговый сервис.

Работает это из-за правила longest prefix match. Более узкий префикс всегда выигрывает у широкого, поэтому /24 бьёт /22, а /25 бьёт /24. Никакой проверки прав в самом протоколе нет.

▎5. RPKI и чего он не умеет

Владелец адресов подписывает запись «этот префикс анонсирую я, вот мой номер AS». Роутер проверяет подпись и отбрасывает мусор. Крупные операторы фильтруют по RPKI уже несколько лет.

Дыра в том, что подпись покрывает владельца префикса, а путь остаётся без проверки. Злоумышленник может анонсировать чужой префикс, подставив в конец пути настоящий номер владельца, и проверка это пропустит. Лечится это BGPsec, где подписывается каждый переход, но его в реальных сетях почти нет: дорого по железу и требует, чтобы поддержали все по цепочке.

▎6. Что попробовать руками


traceroute -a google.com # покажет ASN каждой сети по дороге
whois -h whois.radb.net AS12389 # чья это автономная система


Ещё есть bgp.he.net: вбиваешь свой IP и видишь, кому он принадлежит, с кем эта сеть соединена и какие префиксы анонсирует. Полезно, когда провайдер говорит, что «у нас всё хорошо».
🔥6❤3👍1
izi DevOps pinned a photo
Media is too big
VIEW IN TELEGRAM
Вы наверное забыли, что я существую. Надеюсь все отсылки будут поняты
1❤15👍5🔥5