Программирование
March 8

Как мы docker с VPN дружили

В прошлом году столкнулся с задачей по настройке VPN-подключения внутри docker для обеспечения доступа к API, находящемуся во внутренней сети предприятия. Недавно с подобной проблемой столкнулся и мой друг, но ситуации у нас несколько разные: я настраивал связку для openfortivpn, а ему нужно было настроить для openvpn.

Основная проблема, которая возникает при настройке vpn-соединения для нескольких контейнеров заключается в необходимости настройки сетевых параметров и особенностях работы docker. Без контейнеризации всё было бы намного проще: вы запускаете VPN-подключение и все ваши запросы к соответствующим хостам внутри vpn-сети проходят через это подключение.

Как работает сеть в docker и docker-compose

По умолчанию, все наши сервисы объединяются в рамках сети default. При необходимости мы можем выделять отдельные сети для разных сервисов, чтобы изолировать их друг от друга. Кроме прочего, мы можем использовать внешнюю docker-сеть, чтобы объединить сервисы из разных приложений (отделённых своими compose-файлами) между собой.

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

Сетевые драйверы

В официальной документации описано целых 7 различных сетевых драйверов. Начнём с того, что сам по себе сетевой драйвер нужен для расширения возможностей сети. Рассмотрим какие сетевые драйверы существуют (адаптированная информация из документации):

  1. bridge — драйвер по умолчанию, необходим для того, чтобы сервисы могли общаться друг с другом внутри docker-сети;
  2. host — драйвер, который позволяет использовать сеть хоста напрямую, убирая изоляцию контейнера от хоста;
  3. overlay — драйвер, позволяющий соединить несколько хостов, где находятся docker-контейнеры вместе, чтобы обеспечить взаимодействие между ними (такой вариант отлично подходит для обеспечения коммуникации между нодами в swarm mode);
  4. ipvlan — драйвер, предоставляющий полный контроль над адресацией IPv4 и IPv6;
  5. macvlan — драйвер, позволяющий назначить MAC-адрес для контейнера, делая его доступным в виде физического устройства внутри вашей сети;
  6. none — драйвер, позволяющий изолировать сеть контейнера от хостовой сети и сети других контейнеров;
  7. network plugins — возможность использования в качестве сетевого драйвера любого внешнего решения.

network_mode

network_mode это атрибут сервиса внутри конфигурации docker-compose, необходимый для более тонкой настройки. Существует несколько значений у атрибута newtork_mode:

  1. bridge — дефолтный способ для связи между контейнерами, работает по умолчанию;
  2. host — использование единого сетевого пространства между выбранным сервисом и хостом;
  3. none — отсутствие сетевого взаимодействия для выбранного сервиса;
  4. service:[service_name] — использование сетевого пространства выбранного сервиса;
  5. container:[container_name/id] — использование сетевого пространства выбранного контейнера (отличается от прошлого необходимость указания именно container_name/container_id, а не service_name).

К сожалению, в официальной документации compose, подробно ничего не сказано об этом атрибуте, кроме ссылки на то, что значения могут быть те же самые, что и у парамерта --network, но также добавляется специальная форма service:[service name]. Возможно, это сделано так именно потому, что все значения по смыслу похожи.

Пример compose-файла

Разницы для конфигурации между openfortivpn и openvpn особо нет, поэтому рассмотрим на примере openfortivpn:

version: '3'

services:
 vpn:
  container_name: openfortivpn
  restart: unless-stopped
  build: .
  privileged: true
  volumes:
   - ./config:/etc/openfortivpn/config.conf
  command: ["openfortivpn", "--config=/etc/openfortivpn/config.conf"]

 some-service:
  image: your-container-image
  network_mode: service:vpn