Как позволить встроенному DHCP назначать статический IP-адрес контейнеру LXC на основе имени, а не MAC-адреса

10

Я знаю, что могу назначить статический IP вручную, используя /etc/network/interfaces.

Я также знаю, что я могу прочитать MAC-адрес контейнера LXC (например, ища lxc.network.hwaddrзапись в /var/lib/lxc/<container-name>/configи назначать IP на основе записей dhcp-host=<mac-addr>,10.0.3.3в /etc/dnsmasq.d/<some file>.

В файле, который /etc/default/lxc-netя прочитал

# Uncomment the next line if you'd like to use a conf-file for the lxcbr0
# dnsmasq.  For instance, you can use 'dhcp-host=mail1,10.0.3.100' to have
# container 'mail1' always get ip address 10.0.3.100.
#LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

Это будет соответствовать моим потребностям; к сожалению, это не имеет никакого эффекта.

Адам Рычковски
источник
2
Это работает для меня, но учтите, что вам нужно перезапустить lxc-net, чтобы он вступил в силу. И есть известная проблема, что lxc-net не перезапускается, если какой-либо контейнер запущен в данный момент. Вам необходимо остановить их все, а затем перезапустить службу lxc-net.
HRJ
Кроме того, я не смог назначить IP-адреса, используя только имя контейнера. Мне пришлось жестко закодировать MAC-адрес для контейнера и для конфигурации DHCP.
HRJ
@HRJ, не могли бы вы опубликовать свой файл dnsmasq.conf, пожалуйста?
Tonytony
@HRJ В Ubuntu 14.04 перезапуск lxc-netне поможет, если вы не удалите мост lxcbr0. Смотри мой ответ.
Адам Рычковски

Ответы:

17

Я столкнулся с этим недавно, и я думаю, что нашел простое решение. Я (только) проверил это на Ubuntu 14.04.

Во-первых, раскомментируйте эту строку / etc / default / lxc-net:

LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

В /etc/lxc/dnsmasq.conf определите файл dhcp-hosts:

dhcp-hostsfile=/etc/lxc/dnsmasq-hosts.conf

Затем добавьте записи в /etc/lxc/dnsmasq-hosts.conf следующим образом:

mail,10.0.3.16
web,10.0.3.17

Осторожно: изменения вступят в силу после перезапуска lxc-net (который перезапускает dnsmasq):

service lxc-net restart

После этого вы можете изменить /etc/lxc/dnsmasq-hosts.conf и отправить сигнал SIGHUP в dnsmasq:

killall -s SIGHUP dnsmasq

Так что да, вам нужно перезапустить lxc-net, но только один раз. Надеюсь это поможет.

мтп
источник
Мне нравится идея делегировать список хостов во внешний файл. Кроме того, ваш метод отличается от моего из-за killall -s SIGHUP dnsmasq. Я согласен, что просто «SIGHUP-ing» dnsmasq более эффективен, чем перезапуск всего демона (особенно, если он не работает без исправления его сценариев выскочки).
Адам Рычковски
Перезапуск службы lxc-netнеобходим только для того, чтобы позволить dnsmasq использовать конфигурацию из /etc/lxc/dnsmasq.conf (и этот фрагмент информации присутствует в /etc/default/lxc-netнеизвестном для dnsmasq). Если вы установили его раньше, достаточно еще одного SIGHUP.
Адам Рычковски
Осторожно: lxc-net не перезапустит dnsmasq, если запущены контейнеры.
s3v3n
ИМО это лучший ответ
s3v3n
kill -HUP $(cat /var/run/lxc/dnsmasq.pid)если вы не хотите устанавливать killallили перезагружать другие dnsmasqэкземпляры
gertas
4

Работает нормально в Ubuntu 14.04.1

Раскомментируйте эту строку /etc/default/lxc-net

#LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

остановите все контейнеры, перезапустите lxc-net:

service lxc-net restart

Настройте IP-адреса в /etc/lxc/dnsmasq.conf

dhcp-host={NAME},10.0.3.2

где {NAME}имя вашего контейнера LXC:

/var/lib/lxc/{NAME}
Tombart
источник
Он работает только в том случае, если скрипт может закрыть сеть lxcbr0 , что исключает случай, когда работают другие контейнеры lxc. Короче говоря, в нынешнем виде вы не можете назначить статические аренды DHCP, не перезапуская все контейнеры.
Адам Рычковски
Да, это правда, это довольно неудобно :(. Я нахожу намного более простое решение для редактирования /var/lib/lxc/<container-name>/rootfs/etc/network/interfacesфайла и назначения статического IP-адреса для контейнера.
Tombart
Правда, но тогда ничто не защитит вас от предоставления двум гостям одинакового IP. Смотрите мой принятый ответ - это решает проблему.
Адам Рычковски,
1

Ответ Tombart работает, если вы достаточно терпеливы, чтобы дождаться обновления DNS, и вы готовы перезапустить контейнер (гость) после этого.

Далее следует рецепт, который требует, чтобы все остальные, возможно, работающие контейнеры lxc были закрыты . Если вы не можете себе этого позволить, то я не вижу способа заставить новую конфигурацию dnsmasq. (Для некоторой причины сигнализация HUP к pid dnsmasq, найденному в, /run/lxc/dnsmasq.pidтоже не работает.)

Поэтому, если вы хотите, чтобы что-то работало мгновенно, а другие контейнеры lxc не запущены, следуйте моему ответу. $nameэто имя узла, для которого мы хотим сбросить назначение, и $internalifэто имя мостового адаптера LXC. Вы можете получить значение $internalifс, например, augtool -L -A --transform "Shellvars incl /etc/default/lxc-net" get "/files/etc/default/lxc-net/LXC_BRIDGE" | sed -En 's/\/.* = (.*)/\1/p'если вы устанавливаете, augeas-toolsно обычно это просто lxcbr0.

sudo lxc-stop -n $name >/dev/null
sudo service lxc-net stop >/dev/null
if [ -d /sys/class/net/$internalif ]; then
   sudo brctl delbr $internalif >/dev/null #Why? See below.
fi
sudo rm /var/lib/misc/dnsmasq.$internalif.leases
sudo service lxc-net start >/dev/null
sudo lxc-start -d -n $name >/dev/null
sleep 5

К сожалению, /etc/init/lxc-net.confв Ubuntu 14.04 есть ошибка (функция?), Которая предотвращает перезагрузку, dnsmasqесли мостовое устройство не отключено для хоста.

Адам Рычковски
источник
0

Это решение работает путем исправления сценариев lxc upstart. Он разбивает сложную задачу по созданию моста lxcbr0 и запуску dnsmasqв два отдельных задания. Теперь вам не нужно перезагружать весь lxc-netмост, чтобы просто перезагрузить dnsmasq- перезагрузка sudo service restart lxc-dnsmasqдостаточна и не требует выключения моста.

  1. Остановите службу lxc-net sudo service lxc-net stopи убедитесь, что нет моста lxcbr0 (или эквивалентного).
  2. Замените содержимое /etc/init/lxc-net.confследующим содержимым:

,

description "lxc network"
author "Serge Hallyn <serge.hallyn@canonical.com>"

start on starting lxc
stop on stopped lxc

env USE_LXC_BRIDGE="true"
env LXC_BRIDGE="lxcbr0"
env LXC_ADDR="10.0.3.1"
env LXC_NETMASK="255.255.255.0"
env LXC_NETWORK="10.0.3.0/24"
env varrun="/run/lxc"
env LXC_DOMAIN=""

pre-start script
    [ -f /etc/default/lxc ] && . /etc/default/lxc

    [ "x$USE_LXC_BRIDGE" = "xtrue" ] || { stop; exit 0; }

    use_iptables_lock="-w"
    iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
    cleanup() {
        # dnsmasq failed to start, clean up the bridge
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
        iptables $use_iptables_lock -D FORWARD -i ${LXC_BRIDGE} -j ACCEPT
        iptables $use_iptables_lock -D FORWARD -o ${LXC_BRIDGE} -j ACCEPT
        iptables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE || true
        iptables $use_iptables_lock -t mangle -D POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
        ifconfig ${LXC_BRIDGE} down || true
        brctl delbr ${LXC_BRIDGE} || true
    }
    if [ -d /sys/class/net/${LXC_BRIDGE} ]; then
        if [ ! -f ${varrun}/network_up ]; then
            # bridge exists, but we didn't start it
            stop;
        fi
        exit 0;
    fi

    # set up the lxc network
    brctl addbr ${LXC_BRIDGE} || { echo "Missing bridge support in kernel"; stop; exit 0; }
    echo 1 > /proc/sys/net/ipv4/ip_forward
    mkdir -p ${varrun}
    ifconfig ${LXC_BRIDGE} ${LXC_ADDR} netmask ${LXC_NETMASK} up
    iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
    iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
    iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
    iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
    iptables $use_iptables_lock -I FORWARD -i ${LXC_BRIDGE} -j ACCEPT
    iptables $use_iptables_lock -I FORWARD -o ${LXC_BRIDGE} -j ACCEPT
    iptables $use_iptables_lock -t nat -A POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE
    iptables $use_iptables_lock -t mangle -A POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill

    touch ${varrun}/network_up
end script

post-stop script
    [ -f /etc/default/lxc ] && . /etc/default/lxc
    [ -f "${varrun}/network_up" ] || exit 0;
    # if $LXC_BRIDGE has attached interfaces, don't shut it down
    ls /sys/class/net/${LXC_BRIDGE}/brif/* > /dev/null 2>&1 && exit 0;

    if [ -d /sys/class/net/${LXC_BRIDGE} ]; then
        use_iptables_lock="-w"
        iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
        ifconfig ${LXC_BRIDGE} down
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
        iptables $use_iptables_lock -D FORWARD -i ${LXC_BRIDGE} -j ACCEPT
        iptables $use_iptables_lock -D FORWARD -o ${LXC_BRIDGE} -j ACCEPT
        iptables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE || true
        iptables $use_iptables_lock -t mangle -D POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
        pid=`cat ${varrun}/dnsmasq.pid 2>/dev/null` && kill -9 $pid || true
        rm -f ${varrun}/dnsmasq.pid
        brctl delbr ${LXC_BRIDGE}
    fi
    rm -f ${varrun}/network_up
end script
  1. Добавьте другой файл /etc/init/lxc-dnsmasqсо следующим содержимым:

,

description "lxc dnsmasq service"
author "Adam Ryczkowski, ispired by Serge Hallyn <serge.hallyn@canonical.com>"

expect fork

start on started lxc-net
stop on stopped lxc-net

env USE_LXC_BRIDGE="true"
env LXC_BRIDGE="lxcbr0"
env LXC_ADDR="10.0.3.1"
env LXC_NETMASK="255.255.255.0"
env LXC_NETWORK="10.0.3.0/24"
env LXC_DHCP_RANGE="10.0.3.2,10.0.3.254"
env LXC_DHCP_MAX="253"
env LXC_DHCP_CONFILE=""
env varrun="/run/lxc-dnsmasq"
env LXC_DOMAIN=""

pre-start script
    [ -f /etc/default/lxc ] && . /etc/default/lxc

    [ "x$USE_LXC_BRIDGE" = "xtrue" ] || { stop; exit 0; }

    if [ ! -d ${varrun} ]; then
        mkdir -p ${varrun}
    fi
    opts="$LXC_DOMAIN_ARG -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=${varrun}/dnsmasq.pid --conf-file=${LXC_DHCP_CONFILE} --listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} --dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override --except-interface=lo --interface=${LXC_BRIDGE} --dhcp-leasefile=/var/lib/misc/dnsmasq2.${LXC_BRIDGE}.leases --dhcp-authoritative --keep-in-foreground"

    /usr/sbin/dnsmasq $opts &

end script

post-stop script
    if [ -f ${varrun}/dnsmasq.pid ]; then
        PID=`cat ${varrun}/dnsmasq.pid`
        kill $PID
    fi
end script
Адам Рычковски
источник
0

Вот простой скрипт на python, который выпускает LXC dnsmasq rent. Вы можете запустить его с хост-машины или подделать из другого контейнера - да, это работает !:

#!/usr/bin/env python
from scapy.all import *
conf.checkIPaddr=False
leaseMAC = '00:16:3e:11:71:b0' #container MAC here
releaseIP='10.0.3.33' #container IP here
serverIP='10.0.3.1'
hostname='container-name-here'
rawMAC = leaseMAC.replace(':','').decode('hex')
send(IP(dst=serverIP) / \
     UDP(sport=68,dport=67) / \
     BOOTP(chaddr=rawMAC, ciaddr=releaseIP, xid=RandInt()) / \
     DHCP(options=[('message-type','release'),('server_id',serverIP),('hostname',hostname), ('end')]))

Перечисленным выше условием является библиотека scapy python:

pip install scapy

После запуска вы должны увидеть в системном журнале что-то вроде:

dnsmasq-dhcp[3242]: DHCPRELEASE(lxcbr0) 10.0.3.33 00:16:3e:11:71:b0 container-name-here

Для подтверждения просто проверьте, если запись удалена из /var/lib/misc/dnsmasq.lxcbr0.leases. Сам контейнер будет сохранять IP-адрес, поэтому его следует остановить перед запуском любого нового контейнера, который должен повторно использовать IP-адрес.

gertas
источник
1
Это классно! Я даже не знал, что DHCP поддерживает это! Я буду голосовать сразу после того, как я подтверждаю, что это работает.
Адам Рычковски
0

Я понимаю, что мой ответ опоздал на несколько лет, но, возможно, он поможет кому-то еще. Проблема заключалась в том, что вы редактировали код, специфичный для пакета ( write_lxc_netфункции) LXC Ubuntu, который предназначался для записи в другое место назначения в виде строки, а не для обработки внутри самого lxc-netскрипта!

В результате процесс dnsmasq не получил файл конфигурации, который вы пытались пропустить, и у вас, как вы говорите, не было никакого эффекта.

Вместо этого вы хотите установить эту переменную в верхней части скрипта, среди остальных:

#!/bin/sh -

distrosysconfdir="/etc/default"
varrun="/run/lxc"
varlib="/var/lib"

# These can be overridden in /etc/default/lxc
#   or in /etc/default/lxc-net

USE_LXC_BRIDGE="true"
LXC_BRIDGE="lxcbr0"
LXC_BRIDGE_MAC="00:16:3e:00:00:00"
LXC_ADDR="10.0.3.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.3.0/24"
LXC_DHCP_RANGE="10.0.3.2,10.0.3.254"
LXC_DHCP_MAX="253"
LXC_DHCP_CONFILE="/etc/lxc/dnsmasq.conf"   <-- Here for instance
LXC_DOMAIN=""
Адриан
источник