Docker host telepítése (22.04 LTS)

Innen: AdminWiki

Ebben a leírásban alaptelepített és biztosított szervergépen Docker host környezetet alakítunk ki, amely több, egymástól független standalone (nem orkesztrált) Docker szolgáltatás (a továbbiakban service) futtatását és (manuális) menedzselését biztosítja.

Megjegyzés: a standalone megközelítés a cloud világában elavultnak tűnik, azonban - nézetem szerint - kisvállalati környezetben lehet létjogosultsága.

Docker (standalone hosting, farm) házirend

Ebben a leírásban egy standalone szervergépen (nem swarm-ban) futtatunk egymástól független dockerezett szolgáltatásokat.

  • A szolgáltatásokat egy közös, nem sudo-képes, dedikált Linux felhasználó (dockeradmin) nevében futtatjuk.
  • A szolgáltatásokat kiszolgáló közös scriptek a dockeradmin HOME/bin könyvtárában találhatóak.
  • A szolgáltatásokhoz kapcsolódó valamennyi egyedi állomány (specifikus kód, karbantartó script, konfiguráció, adat, helyi mentés, log, stb.) egyetlen könyvtárszerkezetben, a dockeradmin $HOME/services/<szolgáltatás neve> könyvtárban (szolgáltatáskönyvtár) található.
  • A szolgáltatáskönyvtárak azonos skeletonból jönnek létre.
  • Minden szolgáltatást egy-egy, a szolgáltatáskönyvárban megtalálható docker-compose.yml állomány definiál.
  • A szolgáltatások számára a szervergép
    • közös külső IP-t,
    • hálózati forgalomirányítást,
    • közös web reverse proxyt,
    • SMTP smarthostot (technikai levelezést) és
    • periodikus (napi) mentést (DB dump, fájlterület time machine (git) vagy tar.gz) biztosít.

TODO!

Reverse web proxy telepítése

Amennyiben a telepítés alatti szervergépen még nincs telepítve webszerver, és a leendő szolgáltatások publikus web interface-szel fognak rendelkezni (ez utóbbi csaknem bizonyos), opcionálisan (de erősen javasoltan) érdemes egy professzionális webszervert reverse proxyként telepíteni a https tanúsítványok egyszerűbb kezelése és a könnyebb biztosíthatóság miatt. A jelen leírásban használandó skeleton az Apache 2 illetve az nginx webszerverekkel képes jól együttműködni.

nginx telepítése reverse web proxyként

Az nginx a szokásos módon telepíthető:

sudo apt install nginx --no-install-recommends

Sajnos a telepítés egy hiba miatt elakad, ha az IPv6 le van tiltva. Áthidaló megoldásként, miután a telepítő elakadt, szerkesszük meg az ekkor már telepített /etc/nginx/sites-available/default állományt:

sudo mcedit /etc/nginx/sites-available/default

és az elején kommentezzük ki az IPv6-os listen sort:

[...]
server {
        listen 80 default_server;
#       listen [::]:80 default_server;
[...]

Ezután a telepítő parancsot ismét kiadva:

sudo apt install nginx --no-install-recommends  # no, még egyszer!

a telepítés már hibátlanul végigmegy. A webszerver futását a

sudo systemctl status nginx

paranccsal verifikálhatjuk.

A publikus webszolgáltatáshoz szükséges még a bejövő webforgalom beengedése a csomagszűrő tűzfalon:

sudo ufw allow "Nginx Full"

Gyorstesztként web böngészőprogramban kérjük el a http://IP.IP.IP.IP/ weboldalt (ahol IP.IP.IP.IP a telepítés alatt álló szervergép publikus IP címe, vagy egy erre mutató DNS hostnév) - az nginx alapértelmezett weboldalát kell látnunk.

Egyéb csomagtelepítések

A Docker skeletonnak szüksége van az alábbi, eddig még nem telepített segédeszközökre:

sudo apt install git metastore socat   # a git általában már telepített, a teljesség kedvéért szerepel itt

Fentiek további beállítást nem igényelnek.

A Docker telepítése

A Docker (community edition) telepíthető az Ubuntu repositoryból (docker.io, Debian way), vagy a docker.com repositoryból (docker-ce, Golang way). A fő különbség, hogy a docker.ce statikusan linkelt (az összes függőségével egybecsomagolva érkezik), míg a docker.io esetében a függőségeket a Debian/Ubuntu kezeli (ami jelentős erőfeszítést igényel a maintainer-től). A Debian-way mellett szólhat a kiterjedtebb security- és tesztelési mechanizmus; ellene szólhat a kétely, hogy képes lesz-e lépést tartani a Docker kiadásaival az LTS támogatás teljes időtartamában.

Mivel mindkét kiadás egyazon operációs rendszer alá nem telepíthető, választanunk kell közülük. Jelen leírásban a Debian way-t preferálom.

docker.io

A szokásos módon telepíthető:

sudo apt install docker.io docker-compose  # Sok függőség, elsősorban Python

Ellenőrizzük, hogy elindult-e a szolgáltatás:

sudo systemctl status docker

Ha nem indulna el, engedélyezni kell, majd manuálisan indítható:

sudo systemctl enable --now docker
sudo systemctl status docker # újabb ellenőrzés
sudo systemctl start docker  # ha nem futna

Fentiek után az engine elindul, és a szervergép újraindításakor is automatikusan futni kezd.

docker-ce

TODO!

Docker alapbeállítások

Tűzfalbeállítások (UFW) módosítása a Docker használatához

Két lényeges problémát kell kezelnünk:

  • Alapértelmezésben az UFW blokkolja a szolgáltatások (Docker image-ek) kommunikációját a host gépen futó szolgáltatásokkal (pl. levélküldés a host MTA-n keresztül). Engedélyezzük a szolgáltatások alhálózatairól és a host gép közötti forgalmat korlátozások nélkül (átgondolni: TODO!):
sudo ufw allow in  from 172.17.0.0/16 to any comment 'From services to host'
sudo ufw allow out from any to 172.17.0.0/16 comment 'From host to services'
  • Alapértelmezésben a Docker által exportált portok kívülről láthatóak lesznek annak ellenére, hogy az UFW-ban nem engedélyeztük ezeket az in szabályokban. Ennek megoldására az innen származó (3rd party) ufw-docker scriptet alkalmazzuk, amely a routing átkonfigurálásával tiltja a fenti forgalmat.

Töltsük le a projekt legfrissebb verzióját, és a .zip-ből az ufw-docker állományt másoljuk a /usr/local/sbin könyvtárba, majd adjuk a root tulajdonába, és adjunk rá végrehajtási jogot:

sudo chown root:root /usr/local/sbin/ufw-docker
sudo chmod 750 /usr/local/sbin/ufw-docker

Ezután telepíttessük a scripttel a routing szabályokat, majd aktiváljuk azokat az UFW újraindításával:

sudo ufw-docker install
sudo systemctl restart ufw

A script csak a /etc/ufw/rules.after állományt módosítja (előtte az eredeti állapotot elmenti). Telepítés után a scriptet csak akkor kell használnunk, ha a blokkolt forgalmak valamelyikét engedélyezni szeretnénk (bővebben ld. a README.md leírást a fenti weboldalon, vagy a letöltött .zip-ben).

Gyorsteszt: TODO!

Levélküldés engedélyezése a dockerezett szolgáltatások számára

Hasznos lehet, ha a szolgáltatások is igénybe vehetik a korábban beállított technikai levélküldést. Ehhez engedélyezzük a mail relay-t a Postfixben a Docker network-ök felől is:

sudo mcedit /etc/postfix/main.cf
[...]
mynetworks = 127.0.0.0/8 172.16.0.0/12 [...]
[...]

A változtatást a Postfix újraindításával érvényesítsük:

sudo systemctl restart postfix

A dockeradmin felhasználó és tárhely elkészítése

Ebben a leírásban a Docker szolgáltatások tárhelyeit a szolgáltatásokat menedzselő, közös Linux felhasználó HOME-jában (/srv/docker) alakítjuk ki. Ennek a tárhelynek megfelelő méretű, futtathatóan és írható-olvashatóan csatolt partíción kell lennie.

A dockeradmin lényegét tekintve rendszer felhasználó, a gyakorlatban azonban rendszergazdák (emberek) fogják nevében belépve a szolgáltatások karbantartási műveleteit elvégezni. A belépéshez mindenkitől külön-külön (magán) SSH kulcsot fogunk kérni.

  • Hozzuk létre a felhasználót az alábbi (sudo-képes felhasználóként - sysadminként - kiadott) parancsokkal:
sudo adduser --gecos "Docker Administrator" --home /srv/docker dockeradmin   # kér egy jelszót a felhasználó számára

A jelszó lehetőleg ne triviális, preferáltan generált legyen (pl. innen). A jelszót csak a sudo-hoz fogjuk használni (mivel a jelszóval belépést SSH-n letiltottuk, használatával csak a virtuális konzolon lehet belépni).

  • Adjuk hozzá a dockeradmin-t a Docker kezelésére sudo nélkül is jogosultak csoportjához. A házirendtől eltérően jelenleg a Docker adminisztrátor számára is szükséges a sudo, a host és a szolgáltatások fájlrendszeri jogosultságainak egyeztetése miatt (TODO!):
sudo usermod -aG docker,sudo dockeradmin  # beállítás
sudo groups dockeradmin                   # ellenőrzés
  • Tegyük priváttá a felhasználó HOME könyvtárát:
export user='dockeradmin' home='/srv/docker'
sudo chmod -R o-rwx $home
sudo chmod g+rwx $home    # feleljen meg az UMASK-nak
sudo chmod o+x   $home    # szüksége lehet rá a Dockeren belül futó szolgáltatásoknak
sudo ls -lad $home        # drwxrwx--x dockeradmin dockeradmin /srv/docker
  • Módosítsuk a felhasználó profilbeállításait:
sudo mcedit $home/.profile

Szúrjuk be a file végére:

# Custom editor.
export EDITOR="/usr/bin/mcedit"

# More parseable ls -la format.
export TIME_STYLE="long-iso"

Megjegyzés: a szövegszerkesztő választása természetesen opcionális - bár az alaptelepített nano teljesen használható, részemről az mcedit-et preferálom.

  • Készítsük elő a dockeradmin számára a nyilvános kulcsú távoli bejelentkezéshez szükséges állományokat:
sudo mkdir $home/.ssh;                 sudo chown $user:$user $home/.ssh
sudo touch $home/.ssh/authorized_keys; sudo chown $user:$user $home/.ssh/authorized_keys

Amennyiben vannak publikus kulcsaink a dockeradmin felhasználóként történő bejelentkezéshez, töltsük fel és másoljuk be azokat az authorized_keys állományba (ha nincs kulcsunk, csak a virtuális konzolon tudunk dockeradmin-ként bejelentkezni!). Ezután zárjuk le ezt az állományt:

sudo chmod 400 $home/.ssh/authorized_keys
sudo chattr +i $home/.ssh/authorized_keys
sudo chmod 500 $home/.ssh/

A fenti beállításokkal már csak a root tud a dockeradmin felhasználó nevében történő bejelentkezéshez szükséges kulcsokat felvenni (az immutable bit levétele után).

  • Mivel a dockeradmin alapvetően nem szokványos felhasználó, nem hagyjuk, hogy a shelljére vonatkozó beállításokat megváltoztassa:
sudo chmod 440 $home/.bashrc;      sudo chattr +i $home/.bashrc
sudo chmod 440 $home/.bash_logout; sudo chattr +i $home/.bash_logout
sudo chmod 440 $home/.profile;     sudo chattr +i $home/.profile

Ezzel a felhasználót és a tárhelyet előkészítettük.

A Docker skeleton telepítése

A skeleton telepítéséhez (és minden további, a Docker szolgáltatásokkal kapcsolatos művelet elvégzéséhez) jelentkezzünk be dockeradmin felhasználóként!

Docker gyorsteszt

Első lépésként futtassuk le a hello-world példa image-et:

docker run hello-world

Siker esetén a Docker alapfunkciói használhatóak, a teszt containert törölhetjük:

docker system prune

Szükséges mappák és beállítások

Hozzuk létre a bin, services és tmp mappákat:

mkdir $HOME/bin $HOME/tmp
mkdir $HOME/services; chmod o+x $HOME/services; setfacl -d -m u:$USER:rwX,g::rwX $HOME/services

Az ACL-lel azt szeretnénk biztosítani, hogy a szolgáltatásmappák hierarchiájára a dockeradmin (user és group) mindig rendelkezzen írásjoggal, továbbá hogy ez a hierarchia a szolgáltatások belső felhasználói számára is bejárható legyen (átgondolni: TODO!).

Fentieken kívül:

  • A Midnight Commanderben hasznos beállítani (mc, F9, Beállítások, Alapbeállítások) a saját szövegszerkesztő használatát (F9, Beállítások, Saját szövegszerkesztő, OK).
  • Az mcedit-ben (F9, Beállítások, Általános) az új sorban automatikus behúzást (ha be lenne kapcsolva) és a látható tabulátorokat(!) kikapcsolni, végül az mc beállításokat elmenteni (F9, Beállítások, Beállítások mentése).

A technikai levelezés beállítása

Amennyiben a szervergép biztosít technikai levelezést, állítsuk be a dockeradmin felhasználónak küldött levelek továbbítását a Docker adminisztrátorok tényleges email címeire. Ehhez:

  • Küldjünk egy teszt levelet (dockeradmin-ként bejelentkezve):
echo 'Teszt' | mail -s 'Teszt' valid@email.address
  • Siker esetén állítsuk be a levéltovábbítást a $HOME/.forward állományban:
mcedit $HOME/.forward
dockeradmin1@email.cime
dockeradmin2@email.cime
[...]
  • Ellenőrizzük a levéltovábbítást:
echo Teszt | mail -s Teszt dockeradmin

Siker esetén ezután meg fogjuk kapni a Docker környezetek által küldött technikai leveleket is.

Opcionálisan, amennyiben a dockeradmin nem sudo-képes (TODO!), lezár(at)hatjuk a .forward állományt, megakadályozva ezzel, hogy a címlistát valamelyik Docker adminisztrátor (vagy egy dockeradmin-ként futó malware) törölje vagy módosítsa. Ehhez sudo-képes felhasználóként (pl. sysadminként) bejelentkezve adjuk ki az alábbi parancsokat:

export home='/srv/docker'
sudo chmod 400 $home/.forward
sudo chattr +i $home/.forward

Ezután a címlista már csak root-ként módosítható (az immutable bit levétele után).

A skeleton telepítése

Az egyes szolgáltatásokat egy közös skeletonból fogjuk kialakítani, amely tartalmaz csak egyszer telepítendő, server-wide elemeket is - ezek némelyikéhez szükséges a sudo jog!

  • Töltsük le (TODO!) a skeleton legfrissebb (tömörített, .tgz) változatát, célszerűen a $HOME/tmp könyvtárba;
  • Alkalmazzuk a skeletonbeli .templates beállításait:
    • A skeleton .templates/bin könyvtárának tartalmát másoljuk a $HOME/bin könyvtárba;
    • Amennyiben a szervergép nem biztosít technikai levelezést, adjunk futtatási jogot a $HOME/bin/mail (dummy) állományra (biztosítva ezzel, hogy a mail parancsot függőségként tartalmazó scriptek ennek ellenére lefussanak):
      chmod ug+x $HOME/bin/mail
    • Amennyiben a szervergépen nginx webszerver fut:
      • A skeleton .templates/nginx/.nginx könyvtárát másoljuk be a $HOME/services könyvtárba (a .gitignore törölhető);
      • A skeleton .templates/nginx/conf.d könyvtárának tartalmát másoljuk be a /etc/nginx/conf.d könyvtárba és adjuk a root tulajdonába 640-es jogosultságokkal (ehhez sudo szükséges!);
      • Amennyiben a webszervert más szolgáltatás nem használja, töröljük a /etc/nginx/sites-enabled/default symlinket (ehhez sudo szükséges!) - ezzel átvesszük az alapértelmezett weboldal szolgáltatását is;
    • A skeleton .templates/sudoers.d tartalmát másoljuk be a /etc/sudoers.d könyvtárba és adjuk a root tulajdonába 440-es jogosultságokkal (ehhez sudo szükséges!);
  • Olvastassuk újra a webszerver konfigurációját (a sudoers.d beállítás miatt ehhez nem kell sudo):
    • nginx esetén
      systemctl reolad nginx
    • Apache 2 esetén
      systemctl reload apache2
  • Állítsuk be az időzített karbantartások lefuttatását:
    crontab -e
    Másoljuk a fájl végére a skeletonbeli .templates/crontab tartalmát és mentsük el az új contab állományt.

Ezzel a skeleton server-wide elemeit telepítettük, készen állunk az első szolgáltatás létrehozatalára.

Karbantartások

TODO!

Irodalom