Como permitir que o DHCP interno atribua um IP estático ao contêiner LXC com base no nome, não no endereço MAC

10

Eu sei que posso atribuir IP estático manualmente, usando /etc/network/interfaces.

Também sei que posso ler o endereço MAC do contêiner LXC (por exemplo, procurando lxc.network.hwaddrentrada /var/lib/lxc/<container-name>/confige atribuir o IP com base dhcp-host=<mac-addr>,10.0.3.3nas entradas /etc/dnsmasq.d/<some file>.

No arquivo /etc/default/lxc-netque li

# 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

Isso atenderia às minhas necessidades; infelizmente fazê-lo não tem efeito.

Adam Ryczkowski
fonte
2
Funciona para mim, mas observe que você precisa reiniciar o lxc-net para que ele entre em vigor. E há um problema conhecido de que o lxc-net não é reiniciado se algum contêiner for iniciado no momento. Você precisa parar todos eles e reiniciar o serviço lxc-net.
HRJ
Além disso, não consegui atribuir endereços IP usando apenas o nome do contêiner. Eu tive que codificar um endereço MAC para o contêiner e para a configuração DHCP.
HRJ
@HRJ, você poderia postar seu arquivo dnsmasq.conf, por favor?
tonytony
@HRJ No Ubuntu 14.04, reiniciar lxc-netnão ajuda se você não remover a ponte lxcbr0. Veja minha resposta.
Adam Ryczkowski

Respostas:

17

Eu me deparei com isso recentemente e acho que encontrei uma solução fácil. Eu (apenas) testei no Ubuntu 14.04.

Primeiro, remova o comentário desta linha / etc / default / lxc-net:

LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

Em /etc/lxc/dnsmasq.conf, defina um arquivo dhcp-hosts:

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

Em seguida, adicione entradas no /etc/lxc/dnsmasq-hosts.conf assim:

mail,10.0.3.16
web,10.0.3.17

Cuidado: as alterações entrarão em vigor depois que você reiniciar o lxc-net (que reinicia o dnsmasq):

service lxc-net restart

Depois, você pode modificar o /etc/lxc/dnsmasq-hosts.conf e enviar o sinal SIGHUP para o dnsmasq:

killall -s SIGHUP dnsmasq

Então, sim, você precisa reiniciar o lxc-net, mas apenas uma vez. Espero que isto ajude.

mtp
fonte
Eu gosto da idéia de delegar a lista de hosts em um arquivo externo. Além disso, seu método difere do meu por causa do killall -s SIGHUP dnsmasq. Concordo que apenas o dnsmasq "SIGHUP-ing" é mais eficiente do que reiniciar o daemon inteiro (especialmente se ele não funcionar sem corrigir os scripts iniciais).
Adam Ryczkowski
A reinicialização do serviço lxc-neté necessária apenas para permitir que o dnsmasq use a configuração em /etc/lxc/dnsmasq.conf (e essa parte da informação está presente na /etc/default/lxc-netque é desconhecida dnsmasq). Se você o configurou antes, apenas outro SIGHUP deve ser suficiente.
Adam Ryczkowski
Cuidado: o lxc-net não reiniciará o dnsmasq se houver contêineres em execução.
S3v3n 9/03/2015
IMO esta é a melhor resposta
s3v3n
kill -HUP $(cat /var/run/lxc/dnsmasq.pid)se você não deseja instalar killallou recarregar outros dnsmasqcasos
gertas
4

Funciona bem no Ubuntu 14.04.1

Remova o comentário desta linha /etc/default/lxc-net

#LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

pare todos os contêineres, reinicie o lxc-net:

service lxc-net restart

Configure endereços IP em /etc/lxc/dnsmasq.conf

dhcp-host={NAME},10.0.3.2

Onde {NAME}está o nome do seu contêiner LXC:

/var/lib/lxc/{NAME}
Tombart
fonte
Funciona apenas se o script puder desligar a rede lxcbr0 , o que exclui o caso quando houver outros contêineres lxc em execução. Em resumo, como está agora, você não pode atribuir concessões estáticas de DHCP sem reiniciar todos os contêineres.
Adam Ryczkowski
Sim, isso é verdade, é bastante inconveniente :( I encontrar solução muito mais fácil de editar. /var/lib/lxc/<container-name>/rootfs/etc/network/interfacesArquivo e endereço IP estático atribuído ao recipiente.
Tombart
É verdade, mas não há nada para protegê-lo contra a concessão de dois convidados com o mesmo IP. Veja minha resposta aceita - resolve o problema.
Adam Ryczkowski
1

A resposta do Tombart funciona se você for paciente o suficiente para aguardar a atualização do DNS E estiver disposto a reiniciar o contêiner (o convidado) posteriormente.

A seguir, é apresentada a receita que exige que todos os outros contêineres lxc possivelmente em execução sejam desligados . Se você não puder pagar por isso, não vejo como forçar a nova configuração do dnsmasq. (Para alguns usuários que sinalizam o HUP para o pid do dnsmasq encontrado em, /run/lxc/dnsmasq.pidtambém não funciona.)

Portanto, se você quiser ter algo que funcione instantaneamente e não houver outros contêineres lxc em execução, siga minha resposta. $nameé o nome do nó para o qual queremos redefinir a atribuição e $internalifé o nome do adaptador em ponte do LXC. Você pode obter o valor de $internalifcom, por exemplo, augtool -L -A --transform "Shellvars incl /etc/default/lxc-net" get "/files/etc/default/lxc-net/LXC_BRIDGE" | sed -En 's/\/.* = (.*)/\1/p'se você instalar, augeas-toolsmas geralmente é justo 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

Infelizmente, existe um bug (recurso?) No /etc/init/lxc-net.confUbuntu 14.04 que impede o recarregamento, a dnsmasqmenos que o dispositivo bridge esteja inativo para o host.

Adam Ryczkowski
fonte
0

Essa solução funciona corrigindo os scripts iniciais do lxc. Ele divide a tarefa complexa de ativar a ponte lxcbr0 e iniciar um dnsmasqem dois trabalhos separados. Agora você não precisa reiniciar a lxc-netponte inteira para apenas recarregar a dnsmasq- recarregar a sudo service restart lxc-dnsmasqé suficiente e não requer o desligamento da ponte.

  1. Interrompa o serviço lxc-net sudo service lxc-net stope verifique se não há ponte lxcbr0 (ou equivalente).
  2. Substitua o conteúdo do /etc/init/lxc-net.confseguinte pelo seguinte:

.

description "lxc network"
author "Serge Hallyn <[email protected]>"

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. Adicione outro arquivo, /etc/init/lxc-dnsmasqcom o seguinte conteúdo:

.

description "lxc dnsmasq service"
author "Adam Ryczkowski, ispired by Serge Hallyn <[email protected]>"

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
Adam Ryczkowski
fonte
0

Aqui está um script python simples que libera a concessão do LXC dnsmasq. Você pode executá-lo na máquina host ou forjá-lo em outro contêiner - sim, isso funciona!

#!/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')]))

O requisito acima é a biblioteca python scapy:

pip install scapy

Uma vez executado, você deverá ver no log do sistema algo como:

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

Para confirmar, basta verificar se a entrada foi removida /var/lib/misc/dnsmasq.lxcbr0.leases. O próprio contêiner manterá o IP, pelo que deve ser parado antes de iniciar qualquer novo contêiner que deva reutilizá-lo.

gertas
fonte
1
Isso é legal! Eu nem sabia que o DHCP suporta isso! Vou votar imediatamente depois de confirmar que funciona.
Adam Ryczkowski
0

Sei que minha resposta está atrasada anos, mas talvez ajude outra pessoa. O problema foi que você editou o código específico do pacote ( write_lxc_netfunção) do LXC Ubuntu, que deveria ser gravado em outro destino como uma sequência, não processada no lxc-netpróprio script!

Como resultado, o processo dnsmasq não recebeu o arquivo de configuração que você tentou passar, deixando-o "sem efeito", como você diz.

Em vez disso, você deseja definir essa variável na parte superior do script, entre as demais:

#!/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=""
Adrian
fonte