_____ _   _ _    _    ___      _
 / ____| \ | | |  | |  / / |    (_)
| |  __|  \| | |  | | / /| |     _ _ __  _   ___  __
| | |_ | . ` | |  | |/ / | |    | | '_ \| | | \ \/ /
| |__| | |\  | |__| / /  | |____| | | | | |_| |>  <
 \_____|_| \_|\____/_/   |______|_|_| |_|\__,_/_/\_\

Instalacja i konfiguracja kontenerów LXC

Dawno temu na tej stronie zajmowałem się tematem instalacji LXD, czyli kontenerów, będących alternatywą dla maszyn wirtualnych, gdzie możemy korzystać z zalet VM-ek, ale nie potrzebujemy pełnej wirtualizacji. Po mimo tego, że mówiliśmy tam o LXD, to tak naprawdę całym mechanizmem kontenerów zajmowało się LXC - temat tego artykułu. LXD nawet nie robi tego samego co LXC, ale LXD daje nam możliwość skonfigurowania LXC i zarządania kontenerami tej technologii w bardziej przystępny sposób. Można uznać LXD za frontend dla LXC. W tym przypadku, będziemy ciąć niepotrzebne bajery i przygotujemy do pracy LXC do pracy z kontenerami nieuprzywilejowanymi - uruchamianymi z uprawnieniami zwykłego użytkownika w jego przestrzeni. Kontenery uprzywilejowane - uruchamiane z uprawnieniami superużytkownika - działają od razu po zainstalowaniu LXC w systemie.

Na nieuprzywilejowanych kontenerach nie będziemy mogli:

W momencie gdy tworzenie i zarządzanie uprzywilejowanymi kontenerami sprowadza się do poprzedzenia poleceń LXC, poleceniem sudo, to konfiguracja LXC w celu uruchamiania nieuprzywilejowanych kontenerów wymaga już nieco więcej zachodu.

Sam ten materiał powstał w oparciu o różne strony zajmujące się instalacją i konfiguracją LXC, nie mniej jednak zebrano i zweryfikowano różne rozwiązania, aby zapewnić konkretne, działające rozwiązanie. Wiele rozwiązań, prezentowanych nawet na głównej stronie projektu nie zawsze okazuje się prawidłowe dla naszego środowiska. W tym materiale skupiłem się na dystrybucji GNU/Linux Debian i to dla niej dedytkowane są poniższe rowiązania.

  1. Konfigurację rozpoczynamy od zainstalowania pakietu LXC z repozytorium.
    xf0r3m@lxc-host:~$ sudo apt install lxc -y
    
  2. Wiążemy użytkownika, który będzie uruchamiał kontenery z dodatkowym UID oraz GID. Te identyfikatory natomiast będą powiązane z użytkownikiem root wewnątrz kontenera, ale na początku system musi wiedzieć, z którym z użytkowników je powiązać. Do tego służą pliki /etc/subuid oraz /etc/subgid.
    xf0r3m@lxc-host:~$ echo "xf0r3m:100000:65536" | sudo tee -a /etc/subuid
    xf0r3m:100000:65536
    xf0r3m@lxc-host:~$ echo "xf0r3m:100000:65536" | sudo tee -a /etc/subgid
    xf0r3m:100000:65536
    
  3. Tworzymy przydział możliwych do utworzenia urządzeń sieciowych (uruchomionych jednocześnie kontenerów) przez nieuprzywilejowanego użytkownika. Utworzenie takiego przydziału wymaga dodanie wpisu do pliku /etc/lxc/lxc-usernet.
    xf0r3m@lxc-host:~$ echo "xf0r3m veth lxcbr0 50" | sudo tee -a /etc/lxc/lxc-usernet
    xf0r3m veth lxcbr0 50
    
    Liczba 50, na końcu polecenie wskazuje ile będzie można uruchomić jednocześnie kontenerów (wpiętych do sieci).
  4. Tworzymy katalog lxc użytkownika. Do niego kopiujemy globalny plik konfiguracyjny LXC (/etc/lxc/default.conf) oraz wiążemy superużytkownika kontenera z użytkownikiem systemowym za pomocą wcześniej zdefiniowanych dodatkowych identyfikatorów UID oraz GID.
    xf0r3m@lxc-host:~$ mkdir -p ~/.config/lxc
    xf0r3m@lxc-host:~$ cp /etc/lxc/default.conf ~/.config/lxc/default.conf
    xf0r3m@lxc-host:~$ echo "lxc.idmap = u 0 100000 65536" >> ~/.config/lxc/default.conf
    xf0r3m@lxc-host:~$ echo "lxc.idmap = g 0 100000 65536" >> ~/.config/lxc/default.conf
    
  5. LXC w celu zapewnienia odpowiedniego poziomu bezpieczeństwa wykorzystuje AppArmor. Przynajmniej korzysta z jego profili. Wpis, który znajduje się w pliku domyślnej konfiguracji kontenerów nieuprzywilejowanych lub użytkownika (~/.config/lxc/default.conf), zawiera profil, którego zwykły użytkownik nie może użyć. Dlatego też trzeba go zmienić oraz usunąć możliwość zagnieżdzania (w celach bezpieczeństwa).
    xf0r3m@lxc-host:~$ sed -i 's/generated/unconfined/' ~/.config/lxc/default.conf
    xf0r3m@lxc-host:~$ sed -i '6d' ~/.config/lxc/default.conf
    xf0r3m@lxc-host:~$ cat -n ~/.config/lxc/default.conf 
         1	lxc.net.0.type = veth
         2	lxc.net.0.link = lxcbr0
         3	lxc.net.0.flags = up
         4	
         5	lxc.apparmor.profile = unconfined
         6	lxc.idmap = u 0 100000 65536
         7	lxc.idmap = g 0 100000 65536
    
    Jeśli będziemy wprowadzać zmiany w tym plików i mają mieć one wpływ na obecne kontenery, to... Nie będą miały. Zmiany będą miały tylko wpływ na nowe kontenery.
  6. W najnowszych dystrybucjach Debiana, katalogi domowe mają domyślne uprawnienia o wartości 700. Aby można było uruchamiać kontenery, których, roofs jest ukryty gdzieś w dotdirs. Potrzbne są co najmniej możlwości uruchomienia i takie uprawnienia trzeba nadać inaczej kontenery się nie uruchomią.
    xf0r3m@lxc-host:~$ chmod +x .
    
  7. Ostatnią czynnością, którą musmy wykonać jest dodanie ścieżki do polecenia apparmor_parser do zmiennej PATH, która odpowiada z wyszukiwanie poleceń w systemie. Tą konfigurację musimy nadać na stałe więc dodamy linię do naszego pliku ~/.bashrc.
    echo "export PATH=${PATH}:/usr/sbin/apparmor_parser" >> ~/.bashrc;
    
  8. Jeśli już dodajemy ochoczo linię do ~/.bashrc to możemym dodać aliasy, które umożlwią nam szybsze tworzenie, uruchamianie oraz podłączanie się pod kontenery.
    echo 'alias unpriv-lxc-create="systemd-run --user --scope -p "Delegate=yes" -- lxc-create"' >> ~/.bashrc;
    echo 'alias unpriv-lxc-start="systemd-run --user --scope -p "Delegate=yes" -- lxc-start"' >> ~/.bashrc;
    echo 'alias unpriv-lxc-attach="systemd-run --user --scope -p "Delegate=yes" -- lxc-attach"' >> ~/.bashrc;
    

Po wykonaniu tych czynności warto się wylogować i zalogować ponownie, chociażby po to, aby ponownie wczytać plik ~/.bashrc. Zarządzanie takimi kontenerami wygląda w następujący sposób:

W taki o to sposób możemy skonfigurować LXC do działania bez potrzeby instalacji LXD, który był przez dłuższy czas niedostępny w dystrybucji Debian i trzeb było go instalować przez Snap. Powyższe polecenia, instalująco-konfigurujące możemy zapisać za pomocą skryptu, zapisać go, nadać uprawnienia i uruchomić.

#!/bin/bash

sudo apt install lxc -y;
echo "${USER}:100000:65536" | sudo tee -a /etc/subuid;
echo "${USER}:100000:65536" | sudo tee -a /etc/subgid;

echo "${USER} veth lxcbr0 50" | sudo tee -a /etc/lxc/lxc-usernet;

mkdir -p ${HOME}/.config/lxc;
cp /etc/lxc/default.conf ${HOME}/.config/lxc/default.conf;
echo "lxc.idmap = u 0 100000 65536" >> ${HOME}/.config/lxc/default.conf;
echo "lxc.idmap = g 0 100000 65536" >> ${HOME}/.config/lxc/default.conf;
sed -i 's/generated/unconfined/' ${HOME}/.config/lxc/default.conf;
sed -i '6d' ${HOME}/.config/lxc/default.conf;

chmod +x ${HOME};

echo "export PATH=${PATH}:/usr/sbin/apparmor_parser" >> ${HOME}/.bashrc;
echo 'alias unpriv-lxc-create="systemd-run --user --scope -p "Delegate=yes" -- lxc-create"' >> ${HOME}/.bashrc;
echo 'alias unpriv-lxc-start="systemd-run --user --scope -p "Delegate=yes" -- lxc-start"' >> ${HOME}/.bashrc;
echo 'alias unpriv-lxc-attach="systemd-run --user --scope -p "Delegate=yes" -- lxc-attach"' >> ${HOME}/.bashrc;

Źródła:

  1. Linux Containers - LXC - Getting started
  2. Known Debian problems with Debian package 4.0.2-1~1
  3. About lxd and lxc
  4. Docker vs LXC – czym to się różni?

~xf0r3m