6 статья из 12. Экватор. Поймём как безопасно общаются клиенты с удалёнными хостами и мигрируем первый контейнер на другой хост в offline режиме. Live Migration будет рассмотрена в следующих статьях.
LXD 2.0 поддерживает 2 протокола:
Всё описанное ниже использует какой-либо из этих двух.
Аутентификация для LXD API осуществляется с помощью проверки подлинности сертификата клиента через TLS 1.2. Когда два LXD демона должны обменяться информацией, то временный токен генерирует демон source и передаётся через клиент демону target. Токен используется только для доступа к конкретному потоку и немедленно отзывается для предотвращения повторного использования.
Чтобы избежать атак "человек по середине" (Man In The Middle), клиентский инструментарий отсылает сертификат сервера source на сервер target. Это означает, что для конкретной операции сервер target обеспечивается URL сервера source, одноразовым токеном для доступа к требуемому ресурсу и сертификатом. Это предотвращает атаки MitM и даёт временный доступ для передачи объекта.
LXD 2.0 использует модель, где целевая сторона (target) подключается напрямую к source для получения данных (fetch). Это означает, что вы должны убедиться в возможности пройти через правила файрвола target серверу к source серверу. Сейчас рассматривается вопрос о возможности реверса общения - source к target или проксировании через клиента в особо тяжёлых случаях, когда драконовские правила файрвола предотвращают общение между двумя узлами.
Вместо того, чтобы заставлять пользователей каждый раз вводить имена хостов или их IP адреса, LXD вводит понятие remotes. По умолчанию единственным настроенным LXD remote является "local:", который так же является дефолтным. Данный local remote использует LXD REST API для общения с локальным демоном через unix сокет.
Представим, что у вас две машины с установленным LXD. Ваша локальная машина и удалённый хост по имени foo. Прежде вам нужно убедиться, что foo слушает сеть и имеет пароль. Зайдите доступным способом на foo и командуйте:
lxc config set core.https_address [::]:8443
lxc config set core.trust_password something-secure-password
Теперь на локальном LXD нужно просто сделать его видимым сеть, чтобы передавать контейнеры и образы - lxc config set core.https_address [::]:8443
Когда оба демона видят сеть, с локальной машины можно добавить foo - lxc remote add foo 1.2.3.4
Замените 1.2.3.4 на IP адрес или FQDN сервера.
Вы увидите что-то подобное
lxc remote add foo 2607:f2c0:f00f:2770:216:3eff:fee1:bd67 Certificate fingerprint: fdb06d909b77a5311d7437cabb6c203374462b907f3923cefc91dd5fce8d7b60 ok (y/n)? y Admin password for foo: Client certificate stored at server: foo
Можно посмотреть свои remotes, в том числе добавленный только что foo.
lxc remote list
+-----------------+-------------------------------------------------------+---------------+--------+--------+ | NAME | URL | PROTOCOL | PUBLIC | STATIC | +-----------------+-------------------------------------------------------+---------------+--------+--------+ | foo | https://[2607:f2c0:f00f:2770:216:3eff:fee1:bd67]:8443 | lxd | NO | NO | +-----------------+-------------------------------------------------------+---------------+--------+--------+ | images | https://images.linuxcontainers.org:8443 | lxd | YES | NO | +-----------------+-------------------------------------------------------+---------------+--------+--------+ | local (default) | unix:// | lxd | NO | YES | +-----------------+-------------------------------------------------------+---------------+--------+--------+ | ubuntu | https://cloud-images.ubuntu.com/releases | simplestreams | YES | YES | +-----------------+-------------------------------------------------------+---------------+--------+--------+ | ubuntu-daily | https://cloud-images.ubuntu.com/daily | simplestreams | YES | YES | +-----------------+-------------------------------------------------------+---------------+--------+--------+
Итак, у нас есть удалённый сервер, который только что добавили, и что с ним делать? Ну, почти всё, что вы видели в постах ранее, только указать на каком LXD хосте это делается. Пример: lxc launch ubuntu:14.04 c1
запустит контейнера на дефолтном remote (lxc remote get-default), которым является ваш локальный хост.
Можно запустить контейнер на хосте foo - lxc launch ubuntu:14.04 foo:c1
Что мы запустили на хосте foo? lxc list foo:
+------+---------+---------------------+-----------------------------------------------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+---------+---------------------+-----------------------------------------------+------------+-----------+ | c1 | RUNNING | 10.245.81.95 (eth0) | 2607:f2c0:f00f:2770:216:3eff:fe43:7994 (eth0) | PERSISTENT | 0 | +------+---------+---------------------+-----------------------------------------------+------------+-----------+
Одну вещь вы должны помнить - нужно указывать удалённый хост для образов и контейнеров. То есть если есть локальный образ my-image на foo и вы хотите на нём создать контейнер с2, то нужно указывать так:
lxc launch foo:my-image foo:c2
Запустить bash в контейнере на удалённом хосте foo - lxc exec foo:c1 bash
Копирование контейнеров между хостами делается просто, как и звучит: lxc copy foo:c1 c2
Вы получите новый контейнер c2 из c1, работающий на foo. Команда требует остановки c1 перед копированием, но можно воспользоваться механизмом снимка и создания контейнера из снимка в реалтайм.
lxc snapshot foo:c1 current
lxc copy foo:c1/current c3
Сейчас мы не рассматриваем живую миграцию (live migration), которая будет раскрыта в следующих постах. Вы должны остановить исходный контейнер до его перемещения, остальное работает как ожидается.
lxc stop foo:c1
lxc move foo:c1 local:
Пример идентичен вышеописанному
lxc stop foo:c1
lxc move foo:c1 c1
Взаимодействие с удалёнными контейнерами работает через REST API с помощью HTTPS транспорта. Чуток всё посложнее при взаимодействии между двумя демонами LXD, например при копировании или перемещении.
Что происходит:
1) Пользователь командует - lxc move foo:c1 c1
2) Клиент обращается к local: на предмет существования контейнера c1
3) Клиент забирает (fetch) информацию о контейнере с foo
4) Клиент запрашивает токен для миграции с демона на foo, который выступает сервером source.
5) Клиент посылает токен, URL и сертификат foo локальному демону LXD c информацией о контейнере и устройствах.
6) Локальный демон LXD соединяется напрямую к foo, используя токен:
a) соединяемся к websocket
b) согласовывается метод передачи файловой системы (родная send/receive zfs, родная send/receive btrfs, обычный rsync)
c) Если доступен локально образ, из которого был создан контейнер, то просто он распаковывается для создания черновика-контейнера. Это позволяет избежать ненужной передачи данных.
d) Передаётся контейнер и все его снимки как делта между текущим состоянием и черновиком-контейнером.
7) Если всё закончилось успехом, то клиент посылает инструкцию foo на удаление исходного контейнера.
Оглавление цикла статей про LXD 2.0.
Предыдущая статья LXD 2.0: Управление образами [5/12].
Следующая статья LXD 2.0: Docker в LXD [7/12].