Соеденить две площадки…

… Казалось бы, что может пойти не так?

Недавно мне потребовалось соеденить две площадки с виртуалками. Обе у нас (ПОДЧЕРКИВАЮ!), обе у достаточно крупных провайдеров. В общем, надо сделать так, чтобы Н машин у одного провайдера видели М машин у другого. Трафик не большой, но достаточно критичный.

“ХА!” – сказал я и нарисовал классическую схему соединения.

Выделяем на каждой площадке машинку (или на одну из доступных вешаем внешний ip), обвешиваемся файрволами и закрываем трафик тем же IPSec. Инструкций много, вариантов много – в общем, прорвемся!

Быстренько собрал, накидал конфиги и получил веслом по морде. Протокол ESP где-то по пути заблокирован. Техподдержка обоих провайдеров клянется, что это не у них, но ipsec не верит и отказывается подниматься. Ладно, хотелось по-корпоративному, пойдем по-молодежному.

OpenVPN шустро поднялся, поначалу начал бодро гонять трафик, но через некоторое время начались проблемы. Он переподсоединялся, слал немного байт и снова уходил в нирвану. Смена протокола с UDP на TCP приносила лишь временное облегчение.

Кто виноват – мне, если честно говорить, абсолютно пофиг. Мне трафик нужно гонять. Поэтому расчехлил тяжелую хипстерскую артиллерию – shadowsocks + v2ray. Качаем с гита, просто распаковываем, плюем в конфиг сервера следующее (1.1.1.1 – это внешний адрес сервера, если что):

{
  "server": "1.1.1.1",
  "server_port": 888,
  "password": "verysecretpass",
  "method": "chacha20-ietf-poly1305",
  "timeout": 7200,
  "no_delay": true,
  "fast_open": true,
  "mode": "tcp_and_udp",
  "plugin": "/opt/shadowsocks/v2ray-plugin_linux_amd64",
  "plugin_opts": "server"
} 

А в конфиг клиента вот это:

{
  "server": "1.1.1.1",
  "server_port": 888,
  "local_address": "127.0.0.1",
  "local_port": 1080,
  "password": "verysecretpass",
  "method": "chacha20-ietf-poly1305",
  "timeout": 7200,
  "no_delay": true,
  "fast_open": true,
  "mode": "tcp_and_udp",
  "plugin": "/opt/shadowsocks/v2ray-plugin_linux_amd64",
  "plugin_opts": ""
}

Запускаем и получаем на клиенте socks5 сервер на 1080 порту. А теперь – финт конем. В конфиг OpenVPN на клиенте добавляем одну единственную строчку:

socks-proxy 127.0.0.1 1080

Ну и перезапускаем все, чтобы прочитало конфиги. Вуаля! У нас получилась следующая схема:

OpenVPN ходит через ShadowSocks, который ходит через хрен знает как настроенный интернет.

Но через некоторое время проявилась та же самая боль: немного погодя клиент терял соединение с сервером. Причем перезапустишь – все снова начинает бегать. Ставил опции ping, менял MSS и MTU – пофиг: рандомно теряем коннект.

Ок, перевел openvpn и shadowsock на TCP. Всё магически исправилось. Коннект стабильный, не рвется, пакетики бегают туда-сюда.

Отключил "mode": "tcp_and_udp", позакрывал фаирволлами и начал тестить.

Итак, прямой tcp линк безо всяких штук

[  1] 0.0000-10.2561 sec   112 MBytes  91.8 Mbits/sec

Да, клиент сидит на дешевом тарифном плане в 100 мегабит, поэтому практически упираемся в полку. Теперь через все эти навороты:

[  1] 0.0000-10.3474 sec  50.8 MBytes  41.1 Mbits/sec

И это без какого-либо тюнинга! Да, tcp-over-tcp-over-tcp еще тот изврат, но ведь работает же! А после тюнинга (банальные буфера и прочее – в любом мануале по openvpn) я получил следующее:

[  1] 0.0000-100.4276 sec   896 MBytes  74.8 Mbits/sec

Что в плюсах:

  1. Нам надо платить меньше. На одной стороне не нужен выделенный ip (а они нынче дорогие). Выпускают всех через SNAT и норм.
  2. Настраивается не просто, а очень просто.
  3. Снаружи на сервере порт OpenVPN можно спокойно закрыть фаирволлом. Соединение идет с локалхоста. Больше сесуретей богу сесурити!
  4. Память не жрет. Можно смело брать самую дешевую виртуалку под “роутеры”. Вся вот эта машинерия + FRR с OSPF сьели 200 мегов.
  5. Оно работает. Реально, за неделю уже не одиного разрыва.

Что в минусах:

  1. Потеряли в скорости. Немного, но есть. Проблема в том, что на стороне клиента я банально уперся в единственный ЦПУ виртуалки. Когда тесты идут, на той стороне в топе такое:

С другой стороны, там трафик в 20-30 мегабит уже редкость, так что в любом случае все в порядке. Но запас карман не тянет.

Ну и нафига я все это делал: мне нужно было среплицировать один MySQL в другой. Предложенная схема их удовлетворила, значит задача выполнена.