Вопрос или проблема
Я использую LXC контейнеры и разрешаю CONTAINERNAME.lxd в IP-адрес указанного контейнера, используя:
sudo resolvectl dns lxdbr0 $bridge_ip
sudo resolvectl domain lxdbr0 '~lxd'
Это отлично работает! Но изменения не сохраняются после перезагрузки хоста – как сделать, чтобы они сохранялись?
Я использую Pop!_OS 22.04, основанную на Ubuntu 22.04.
(Я описал “что пробовал” в качестве ответов на этот вопрос, которые имеют различную степень успеха.)
Документация LXD описывает решение:
Поместите это в /etc/systemd/system/lxd-dns-lxdbr0.service:
[Unit]
Description=LXD per-link DNS configuration for lxdbr0
BindsTo=sys-subsystem-net-devices-lxdbr0.device
After=sys-subsystem-net-devices-lxdbr0.device
[Service]
Type=oneshot
ExecStart=/usr/bin/resolvectl dns lxdbr0 BRIDGEIP
ExecStart=/usr/bin/resolvectl domain lxdbr0 '~lxd'
ExecStopPost=/usr/bin/resolvectl revert lxdbr0
RemainAfterExit=yes
[Install]
WantedBy=sys-subsystem-net-devices-lxdbr0.device
(Измените BRIDGEIP на свой, взятый из lxc network show lxdbr0 | grep ipv4.address
)
Примените эти настройки без необходимости перезагрузки, используя:
sudo systemctl daemon-reload
sudo systemctl enable --now lxd-dns-lxdbr0
Я создал ужасный обходной путь: создал скрипт lxc-ip
, который получает IPv4 контейнера из вывода команды lxc list
. Пример использования: ping $(lxc-ip mycontainer)
.
Скрипт выглядит так:
#!/usr/bin/env bash
prog=$(basename $0)
function usage {
echo "Usage: $prog CONTAINER" >&2
echo "Outputs IPv4 address of given CONTAINER." >&2
}
container=""
while [[ $# -gt 0 ]]
do
case "$1" in
-h|--help)
usage
exit 0
;;
*)
if [ -z "$container" ]; then
container=$1
else
echo "$prog error: Not multiple CONTAINERs" >&2
usage
exit 1
fi
;;
esac
shift
done
if [ -z "$container" ]; then
echo "$prog error: Must pass a CONTAINER" >&2
usage
exit 1
fi
table=$(lxc list -c ns4 -f csv)
line=$(echo "$table" | grep "$container")
if [ -z "$line" ]; then
echo "$prog error: Container '$container' not found. Existing containers are:" >&2
lxc list -c n -f compact >&2
exit 2
fi
if ! grep -qs RUNNING <<<"$line" ; then
echo "$prog error: Container is not running: $line" >&2
exit 3
fi
ipv4=$(echo "$line" | cut -d',' -f3 | cut -d' ' -f1)
if [ -z "$ipv4" ]; then
echo "$prog error: Container has no IPv4: $line" >&2
exit 4
fi
echo "$ipv4"
На случай, если кто-то сможет это уточнить или подтвердить: мой коллега сообщает, что решил это с помощью механизма, в котором используется этот текст в /etc/systemd/network/lxd.network
:
[Match]
Name=lxdbr0
[Network]
Address=BRIDGEIP/24
DNS=BRIDGEIP
Domains=lxd
(Измените BRIDGEIP на свой, взятый из lxc network show lxdbr0 | grep ipv4.address
)
(Это также может потребовать одновременного запуска systemd-networkd и NetworkManager)
Я вижу похожий вопрос на askubuntu.com, в котором один (-1) ответ советует сохранять другие изменения resolvectl, превращая их в вызовы nmcli (интерфейс командной строки Network Manager). Это, по-видимому, сохраняет информацию где-то в постоянном хранилище, которая используется для наполнения конфигурации ‘resolvectl’ при загрузке.
Если бы я хотел это сделать, я думаю, я могу понять, как я бы конвертировал первый из моих вызовов resolvectl, используя что-то вроде:
sudo nmcli connection modify lxdbr0 ipv4.dns $bridge_ip
Но я не могу преобразовать мой второй вызов resolvectl, устанавливающий `domain=~lxd”, в команды nmcli.
Поэтому этот подход не решает проблему.
Ответ или решение
Для обеспечения постоянства настроек DNS через resolvectl
после перезагрузки системы в LXC-контейнерах на ОС Pop!_OS 22.04, есть несколько решений, которые можно использовать. Давайте подробно рассмотрим наиболее надежные и распространенные методы.
Проблема
При использовании команды:
sudo resolvectl dns lxdbr0 $bridge_ip
sudo resolvectl domain lxdbr0 '~lxd'
IP-адрес контейнера может быть успешно назначен, но после перезагрузки все изменения исчезают. Чтобы избежать этого, нужно интегрировать данные изменения в структуру systemd, обеспечив их устойчивость.
Решение с использованием systemd-сервиса
Создание пользовательского systemd-сервиса позволяет автоматически применять DNS-настройки. Вот как это можно реализовать:
-
Создайте новый сервис:
Создайте файл
/etc/systemd/system/lxd-dns-lxdbr0.service
с содержанием:[Unit] Description=LXD per-link DNS configuration for lxdbr0 BindsTo=sys-subsystem-net-devices-lxdbr0.device After=sys-subsystem-net-devices-lxdbr0.device [Service] Type=oneshot ExecStart=/usr/bin/resolvectl dns lxdbr0 BRIDGEIP ExecStart=/usr/bin/resolvectl domain lxdbr0 '~lxd' ExecStopPost=/usr/bin/resolvectl revert lxdbr0 RemainAfterExit=yes [Install] WantedBy=sys-subsystem-net-devices-lxdbr0.device
Замените
BRIDGEIP
на фактический IP-адрес, который можно получить с помощью команды:lxc network show lxdbr0 | grep ipv4.address
-
Активируйте сервис:
Выполните следующие команды, чтобы активировать и запустить сервис:
sudo systemctl daemon-reload sudo systemctl enable --now lxd-dns-lxdbr0
Альтернативное решение с использованием systemd-networkd
Для тех, кто предпочитает использовать конфигурации systemd-networkd, можно создать файл /etc/systemd/network/lxd.network
со следующим содержанием:
[Match]
Name=lxdbr0
[Network]
Address=BRIDGEIP/24
DNS=BRIDGEIP
Domains=lxd
Этот метод предполагает использование systemd-networkd для управления сетевыми подключениям, что может конфликтовать с некоторыми настройками NetworkManager.
Заключение
Каждое предложенное решение имеет свои преимущества и ограничения, поэтому выбор подходящего метода зависит от конкретной среды и требований. Автоматизированное развертывание через systemd-сервис чаще всего является предпочтительным подходом для автоматизации и удобства поддержки изменений. Убедитесь, что все настройки протестированы в тестовой среде перед применением на продакшене, чтобы убедиться в их корректности и предсказуемости.
Этот подход обеспечит надежное сохранение DNS-настроек для контейнеров LXC, а также упростит управление ими, особенно в масштабируемых средах.