Docker w Proxmox: LXC czy VM?
Dockera można uruchomić bezpośrednio na hoście Proxmoxa albo w kontenerze LXC. Oba podejścia działają — do pierwszej aktualizacji, po której coś przestaje działać. Dokumentacja Proxmoxa zaleca maszynę wirtualną i w tej serii trzymamy się tej zasady:
- Host zostaje czysty. Docker modyfikuje reguły iptables i konfigurację sieci, co może kolidować z firewallem i mostami Proxmoxa.
- Pełna izolacja. Kontener z luką w zabezpieczeniach ma do przejścia jądro maszyny wirtualnej, a nie wspólne jądro hosta.
- Snapshot i backup całości. Jeden snapshot ZFS dysku VM obejmuje Dockera, obrazy, wolumeny i konfigurację.
Narzut maszyny wirtualnej z virtio to kilka procent CPU i kilkaset megabajtów RAM-u. W zamian dostajesz przewidywalność.
Szablon Debiana 13 z cloud-init
Zamiast instalować system z ISO, użyjemy oficjalnego obrazu chmurowego Debiana. Cloud-init przy pierwszym starcie ustawi użytkownika, klucz SSH i adres IP. Szablon przygotowujesz raz, a każda kolejna maszyna powstaje w kilka sekund.
Najpierw skopiuj swój publiczny klucz SSH na hosta Proxmox. Na swoim komputerze:
scp ~/.ssh/id_ed25519.pub root@192.168.1.10:/root/admin.pubNa hoście Proxmox:
cd /var/lib/vz/templatewget -N https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2
qm create 9000 \ --name debian13-cloud \ --ostype l26 \ --machine q35 \ --bios ovmf \ --efidisk0 tank-vm:0,efitype=4m,pre-enrolled-keys=0 \ --cpu host \ --cores 2 \ --memory 2048 \ --net0 virtio,bridge=vmbr0 \ --scsihw virtio-scsi-single \ --scsi0 tank-vm:0,import-from=/var/lib/vz/template/debian-13-genericcloud-amd64.qcow2,discard=on,ssd=1,iothread=1 \ --ide2 tank-vm:cloudinit \ --boot order=scsi0 \ --serial0 socket \ --vga serial0 \ --agent enabled=1,fstrim_cloned_disks=1 \ --ciuser admin \ --sshkeys /root/admin.pub \ --ipconfig0 ip=dhcp
qm template 9000Najważniejsze decyzje:
--cpu hostprzekazuje maszynie wszystkie instrukcje procesora (AES-NI, AVX). Wadą jest brak migracji na żywo między serwerami z różnymi CPU — w klastrze z dwoma identycznymi R620 to nie problem.discard=on,ssd=1— TRIM z maszyny trafia do ZFS, więc zwolnione miejsce wraca do puli.virtio-scsi-single+iothread=1— osobny wątek I/O dla każdego dysku.--serial0 socket --vga serial0— obrazy genericcloud wypisują konsolę na port szeregowy. W panelu Proxmoxa otwierasz ją przez Console → xterm.js.
Klonowanie maszyny docker01
qm clone 9000 110 --name docker01 --full
qm set 110 \ --cores 4 \ --memory 8192 \ --ipconfig0 ip=192.168.1.20/24,gw=192.168.1.1 \ --nameserver 192.168.1.1 \ --onboot 1
# Obraz chmurowy ma ~3 GB — powiększ dysk, cloud-init rozciągnie partycję przy starcieqm disk resize 110 scsi0 +40G
qm start 110Po kilkunastu sekundach zaloguj się ze swojego komputera:
ssh admin@192.168.1.20Przygotowanie systemu
W maszynie docker01 doinstaluj agenta QEMU, dzięki któremu Proxmox widzi adres IP maszyny, zamraża system plików przed snapshotem i poprawnie ją wyłącza:
sudo apt update && sudo apt full-upgrade -ysudo apt install -y qemu-guest-agent unattended-upgradessudo systemctl start qemu-guest-agentsudo timedatectl set-timezone Europe/Warsawunattended-upgrades z domyślną konfiguracją Debiana instaluje automatycznie tylko poprawki bezpieczeństwa.
Instalacja Dockera z oficjalnego repozytorium
Pakiet docker.io z repozytorium Debiana jest starszy i nie zawiera wtyczki Compose v2. Instalujemy z repozytorium Dockera:
#!/usr/bin/env bashset -euo pipefail
sudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.ascsudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOFTypes: debURIs: https://download.docker.com/linux/debianSuites: $(. /etc/os-release && echo "$VERSION_CODENAME")Components: stableArchitectures: $(dpkg --print-architecture)Signed-By: /etc/apt/keyrings/docker.ascEOF
sudo apt updatesudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Rotacja logów — bez tego logi kontenerów potrafią zapełnić dysksudo tee /etc/docker/daemon.json > /dev/null <<'EOF'{ "log-driver": "local", "log-opts": { "max-size": "20m", "max-file": "5" }}EOFsudo systemctl restart docker
sudo docker run --rm hello-worldsudo usermod -aG docker admin# Wyloguj się i zaloguj ponownie, żeby grupa zaczęła działaćPorządek w stosach
Każda usługa dostaje własny katalog z plikiem compose.yaml, sekretami w .env i danymi w podkatalogach. Kopia zapasowa /opt/stacks plus snapshot dysku VM to kompletna kopia całej warstwy aplikacji.
/opt/stacks/├── cloudflared/│ ├── compose.yaml│ └── .env└── vaultwarden/ ├── compose.yaml ├── .env └── data/sudo mkdir -p /opt/stackssudo chown admin:admin /opt/stacksPierwsza usługa to Vaultwarden — lekki, zgodny z Bitwardenem menedżer haseł. To dobry przykład aplikacji, którą chcesz mieć dostępną spoza domu. W następnej części wystawisz ją przez Cloudflare Tunnel:
services: vaultwarden: image: vaultwarden/server:latest container_name: vaultwarden restart: unless-stopped env_file: .env environment: DOMAIN: https://vault.${BASE_DOMAIN} volumes: - ./data:/data networks: - cf-tunnel
networks: cf-tunnel: external: trueBASE_DOMAIN=prywatnylab.pl# Włącz na czas zakładania własnego konta, potem zmień na false i zrób docker compose up -dSIGNUPS_ALLOWED=trueSieć cf-tunnel łączy aplikacje z kontenerem cloudflared. Utwórz ją raz:
docker network create cf-tunnelVaultwarden nie publikuje żadnego portu na zewnątrz maszyny. Będzie dostępny wyłącznie przez tunel, a jego interfejs webowy i tak wymaga HTTPS, bo kryptografia w przeglądarce działa tylko w bezpiecznym kontekście.
cd /opt/stacks/vaultwardenchmod 600 .envdocker compose up -ddocker compose logs -fAktualizacje kontenerów
cd /opt/stacks/vaultwardendocker compose pulldocker compose up -ddocker image prune -fZanim zaktualizujesz coś ważnego, zrób snapshot maszyny: qm snapshot 110 przed-aktualizacja na hoście Proxmox. Jeśli nowa wersja coś zepsuje, qm rollback 110 przed-aktualizacja przywróci całą maszynę w kilka sekund.
Kolejne maszyny w minutę
Szablon jest gotowy na kolejne usługi. Nowa maszyna z innym adresem to cztery polecenia:
qm clone 9000 111 --name apps02 --fullqm set 111 --cores 2 --memory 4096 --ipconfig0 ip=192.168.1.21/24,gw=192.168.1.1 --onboot 1qm disk resize 111 scsi0 +20Gqm start 111Maszyna z Dockerem działa, Vaultwarden czeka w sieci cf-tunnel. W następnej części wystawisz go bezpiecznie do internetu — bez otwierania ani jednego portu na routerze.