Nie ulega wątpliwości, że Docker jest najpopularniejszym narzędziem przeznaczonym do pracy z kontenerami. Faktycznie stał się standardem i niemalże synonimem kontenerów. Mimo tego to nie jedyne rozwiązanie przeznaczone do zarządzania kontenerami, a na pewno nie najbezpieczniejsze.
Docker
Wiele silników kontenerów bazuje na modelu klient-serwer, w którym system zawiera uruchomionego w tle tzw. demona, działającego w charakterze pośrednika między użytkownikiem i kontenerami. Niestety do prawidłowego działania wiele takich demonów — jednym z nich jest demon Dockera, dockerd — wymaga uprawnień użytkownika root i to można uznać za największy problem dotyczący Dockera. (Trzeba w tym miejscu dodać, że całkiem niedawno w Dockerze pojawiła się opcja pozwalająca na działanie demona dockerd bez uprawnień roota).
Użytkownik root ma dostęp do całego systemu, otrzymuje pełnię uprawnień w systemie i może zrobić w nim dosłownie wszystko np. tworzyć i usuwać pliki systemowe, instalować oprogramowanie, uruchamiać usługi itd. W efekcie potencjalna luka w zabezpieczeniach Dockera może atakującemu otworzyć drogę do całego systemu, ponieważ to użytkownik root jest właścicielem procesu dockerd. Podobne niebezpieczeństwo wiąże się z zawierającym luki w zabezpieczeniach obrazem kontenera — skoro jest on uruchamiany przez proces działający z uprawnieniami roota, atakujący może dzięki takiemu obrazowi uzyskać dostępu do dowolnego komponentu systemu. Co prawda zaleca się zmianę użytkownika kontenera, ale często się o tym zapomina i użytkownikiem pozostaje root.
Podman
Poznaj podmana, czyli opracowane przez inżynierów firmy Red Hat narzędzie typu open source przeznaczone do zarządzania kontenerami zgodnymi ze standardem OCI (ang. open container initiative). Dzięki podmanowi łatwo można wyszukiwać, tworzyć, uruchamiać, udostępniać i wdrażać aplikacje bazujących na kontenerach bądź obrazach kontenerów OCI.
Do prawidłowego działania podman nie wymaga demona, a wszystkie operacje odbywają się za pomocą polecenia powłoki, podman, wykorzystującego bibliotekę libpod do zarządzania całym ekosystemem kontenerów. Warto dodać, że podman współdziała z narzędziami Buildah i Skopeo, pozwalającymi dostosować środowisko kontenerów do własnych potrzeb.
Architektura podmana
Największą zaletą podmana jest możliwość działania bez uprawnień użytkownika root. Dzięki temu kontener nie otrzyma żadnych dodatkowych uprawnień, a podczas jego uruchamiania nie trzeba używać mechanizmu sudo i podawać hasła. Oczywiście istnieje możliwość uruchamiania kontenerów z poziomu użytkownika root bądź innego uprzywilejowanego użytkownika systemu.
Kolejną zaletą podejścia zastosowanego w podmanie jest możliwość uruchamiania kontenerów przez użytkowników nieuprzywilejowanych, co ma duże znaczenie w środowiskach wielodostępnych oraz w środowiskach HPC, czyli w systemach obliczeniowych charakteryzujących się wysoką wydajnością działania. Dzięki temu tworzenie i używanie kontenerów, a także zarządzanie nimi stało się dostępne dla zwykłych użytkowników, co z kolei oznacza dla nich większą wygodę, zaś dla systemu mniejsze niebezpieczeństwo.
Niewymagająca demona architektura to jedna z największych zalet podmana. Jeżeli kontener zostanie „złamany”, atakujący i tak nie będzie miał pełnej kontroli nad systemem, ponieważ do uruchomienia kontenera nie było wykorzystane konto z uprawnieniami użytkownika root. To ma istotne znaczenie z perspektywy zapewnienia bezpieczeństwa systemu. Kolejną mocną stroną podmana jest współpraca z architekturą SELinux, co zapewnia większą kontrolę nad zasobami, do których kontenery uzyskują dostęp.
Mimo niewątpliwych zalet architektura podmana ma również pewne wady. Przede wszystkim oznacza brak możliwości współdzielenia obrazów kontenerów między użytkownikami. Ponadto dołączanie portów o numerach do 1024 włącznie wymaga uprawnień roota, więc uruchomienie podmana bez użycia polecenia sudo eliminuje możliwość użycia wspomnianych portów. W tym artykule poznasz podstawy podmana. Jeżeli masz doświadczenie w pracy z Dockerem, nie będziesz mieć problemów z używaniem narzędzia podman, które można uznać za bezpośredni zamiennik Dockera. Oba te systemy zarządzania kontenerami są ze sobą tak zgodne, że bez problemu można zdefiniować podmana jako alias dla Dockera. W powłoce Bash służy do tego następujące polecenie:
1$ alias docker=podman
Jeżeli utworzysz ten alias, wówczas podczas pracy z podmanem możesz korzystać z poleceń Dockera — są one identyczne.
Instalacja podmana
Narzędzie podman jest dostępne dla różnych dystrybucji systemu Linux oraz na platformach Mac i Windows. Wprawdzie usługa podmana działa jedynie w Linuksie, ale dzięki rozwiązaniom opartym na maszynach wirtualnych jest dostępna także dla systemów Mac i Windows — w tym ostatnim opiera się na funkcjonalności WSL (ang. windows system for linux). Jeżeli używasz systemu macOS i menedżera pakietów Homebrew, w celu instalacji podmana wystarczy wydać następujące polecenie:
1$ brew install podman
W systemach typu Fedora, CentOS i RHEL instalacja podmana odbywa się za pomocą polecenia:
1$ dnf install podman
Natomiast w dystrybucjach bazujących na Debianie, np. Ubuntu, aby zainstalować podmana, należy wydać polecenie:
1$ apt install podman
Instalacja podmana w Windows jest zdecydowanie trudniejsza i została wyjaśniona na stronie link. Dokładna procedura instalacji w różnych systemach operacyjnych została przedstawiona na stronie link.
Praca z narzędziem podman
Wprawdzie w przedstawionych tutaj przykładach wykorzystam jedynie wydawane w powłoce polecenie podman, ale warto wiedzieć, że do zarządzania kontenerami narzędzie podman oferuje również API RESTful, które zapewnia dostęp do funkcji zaawansowanych podmana, np. przeznaczonych do obsługi podów. (Pod to po prostu grupa kontenerów korzystających z tych samych zasobów, podobnie jak w Kubernetes).
Wyszukiwanie i pobieranie kontenerów
Do wyszukiwania kontenerów należy użyć polecenia podman search z argumentem w postaci szukanego wyrażenia, np.:
1$ podman search python 2NAME DESCRIPTION 3registry.fedoraproject.org/f31/python-classroom 4registry.fedoraproject.org/f31/python3 5... 6registry.access.redhat.com/ubi9/s2i-base rhcc_registry.access.redhat.com_ubi9/s2i-bas... 7docker.io/library/python Python is an interpreted, interactive, objec... 8... 9docker.io/fnndsc/python-poetry Python Poetry 10docker.io/ibmcom/python-ceilometerclient-ppc64le Docker image for python-ceilometerclient-ppc... 11quay.io/centos7/python-27-centos7 Python 2.7 available as container is a base... 12... 13quay.io/cloudfirst/python-rating-service 14quay.io/fedora/python-311
Skoro podman jest zamiennikiem Dockera, więc nie powinno być zaskoczeniem, że podman może korzystać z kontenerów znajdujących się w repozytorium Dockera pod adresem docker.io. Do pobierania kontenera służy polecenie pull, a jego składnia przedstawia się następująco:
1$ podman pull [opcje] nazwa-obrazu[:tag]
Tutaj nazwa obrazu może być w pełni kwalifikowana, np. docker.io/library/python, bądź skrócona i wówczas w omawianym przykładzie sprowadza się do słowa python. Jeżeli używasz w pełni kwalifikowanej nazwy, to jest ona zapisywana w przedstawionej tutaj postaci:
1nazwa-rejestru/nazwa-użytkownika/nazwa-obrazu
Istnieje możliwość pobrania obrazu oznaczonego konkretnym tagiem. W takim przypadku po nazwie obrazu należy umieścić dwukropek (bez żadnych spacji), a po nim nazwę tagu. Załóżmy, że chcesz pobrać oznaczoną tagiem 3-slim mniejszą wersję kontenera zawierającego Pythona w wersji 3.x. Wówczas polecenie ma postać:
1_(nazwa skrócona)_ 2$ podman pull python:3-slim 3_(użyta w pełni kwalifikowana nazwa obrazu)_ 4$ podman pull docker.io/library/python:3-slim
Efektem wykonania dowolnego z tych poleceń jest pobranie żądanego obrazu z oficjalnego repozytorium kontenerów Dockera. Domyślnie narzędzie podman sprawdza nie tylko wymienione repozytorium, ale również inne, np. Quay.io. Dlatego też zaleca się podawanie pełnej nazwy obrazu, który ma być pobrany. Jeżeli chcesz pobrać Pythona z repozytorium Quay.io, składnia polecenia pull nie ulega zmianie:
1$ podman pull quay.io/fedora/python-311
W ten sposób zostały pobrane pewne obrazy. Aby sprawdzić, które z nich są dostępne lokalnie, należy skorzystać z polecenia podman images:
1$ podman images 2REPOSITORY TAG IMAGE ID CREATED SIZE 3quay.io/fedora/python-311 latest 13fa6ebca8f7 4 days ago 974 MB 4docker.io/library/python 3-slim 9012e93183ab 4 days ago 134 MB
Uruchamianie kontenera
Skoro mamy obrazy, można przygotować kontener i go uruchomić. Podobnie jak w przypadku Dockera, także podman używa polecenia run do uruchomienia kontenera.
1$ podman run --rm -it python:slim 2Resolved "python" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf) 3Trying to pull docker.io/library/python:slim... 4Getting image source signatures 5Copying blob 69038a8b17e6 skipped: already exists 6Copying blob 5fa7ca705967 skipped: already exists 7Copying blob be80bd1fa6e1 skipped: already exists 8Copying blob a82a83a9446e skipped: already exists 9Copying blob 8740c948ffd4 skipped: already exists 10Copying config 9012e93183 done 11Writing manifest to image destination 12Storing signatures 13Python 3.11.1 (main, Jan 17 2023, 23:45:25) [GCC 10.2.1 20210110] on linux 14Type "help", "copyright", "credits" or "license" for more information. 15>>> credits 16 Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands 17 for supporting Python development. See www.python.org for more information. 18>>> exit() 19$
W ten sposób za pomocą narzędzia podman mamy działający kontener Dockera z uruchomionym interpreterem Pythona, w którym można wydawać polecenia Pythona. Opcja --rm powoduje automatyczne usunięcie kontenera po zakończeniu pracy z nim, natomiast opcja -it oznacza pracę z kontenerem w trybie interaktywnym. Dokładnie te same opcje są używane w Dockerze (pamiętasz, że podman to bezpośredni zamiennik Dockera?). W dużym uproszczeniu tryb interaktywny kontenera oznacza, że dane wprowadzane w powłoce używanej do pracy z podmanem są przekazywane do standardowego wejścia kontenera. Natomiast dane wyjściowe wygenerowane przez kontener są wyświetlane w powłoce, w której zostało wydane polecenie podman. Nie zawsze chcemy pracować bezpośrednio w kontenerze, ale wykorzystać go np. do uruchomienia usługi takiej jak serwer WWW. W takiej sytuacji kontener powinien działać w tle. Uruchomienie kontenera działającego w tle jest możliwe dzięki opcji -d. W kolejnym przykładzie z repozytorium Dockera zostanie pobrany kontener serwera WWW, który następnie będzie uruchomiony w tle.
1$ podman pull docker.io/library/httpd 2Trying to pull docker.io/library/httpd:latest... 3Getting image source signatures 4Copying blob 70698c657149 done 5Copying blob ec2ee6bdcb58 done 6Copying blob 00df85967755 done 7Copying blob 8740c948ffd4 skipped: already exists 8Copying blob 8b4456c99d44 done 9Copying config 6e794a4832 done 10Writing manifest to image destination 11Storing signatures 126e794a4832588ca05865700da59a3d333e7daaaf0544619e7f326eed7e72c903 13$ podman images 14REPOSITORY TAG IMAGE ID CREATED SIZE 15docker.io/library/httpd latest 6e794a483258 4 days ago 149 MB 16quay.io/fedora/python-311 latest 13fa6ebca8f7 4 days ago 974 MB 17docker.io/library/python slim 9012e93183ab 4 days ago 134 MB 18docker.io/library/python 3-slim 9012e93183ab 4 days ago 134 MB 19$ podman run -d httpd 204a2a2fc312f54ad302366976836f4bb9e7848f6a3e1bf8fcd6d1803d1cbf4ff6
Kontener został uruchomiony w tle, więc jedynym widocznym na ekranie wynikiem wykonania polecenia podman run jest wyświetlony identyfikator kontenera. Działanie kontenera w tle można potwierdzić za pomocą polecenia podman ps.
1$ podman ps 2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 34a2a2fc312f5 docker.io/library/httpd:latest httpd-foreground 6 seconds ago Up 6 seconds ago elated_fermat 4$
Wprawdzie kontener działa, ale nie został mu przypisany żaden adres IP, więc trudno uzyskać dostęp do funkcjonalności oferowanej przez serwer WWW. Jak możesz zobaczyć w omawianym przykładzie, polecenie podman zostało wydane bez użycia mechanizmu sudo, a tym samym nie następuje podniesienie uprawnień kontenera. Wcześniej wspomniałem, że użycie portów o numerach do 1024 włącznie wymaga uprawnień roota, a serwer WWW nasłuchuje żądań na porcie 80. Czy wobec tego nasz serwer nie będzie spełniał swojej roli? Bez obaw, wystarczy mapować porty kontenera, a serwer WWW będzie działa zgodnie z oczekiwaniami. Konfigurację mapowania portów przeprowadza się za pomocą opcji -p, zmodyfikowana wersja polecenia podman run przedstawia się następująco:
1$ podman run -dt -p 8080:80/tcp docker.io/library/httpd 2d90b6bfad6d9b18cd9830761cca0b3fe6923ed84109383aee86a3089e50ea0a4
Działanie opcji -p polega na połączeniu portu zewnętrznego — tzn. portu w hoście, w którym jest uruchamiany kontener — z portem wewnętrznym kontenera. W tym przypadku za pomocą portu 8080 w komputerze lokalnym uzyskujemy dostęp do portu 80 w uruchomionym kontenerze. Mapowanie pozwoliło więc uniknąć konieczności podniesienia uprawnień kontenera, a jednocześnie umożliwiło serwerowi WWW w kontenerze nasłuchiwać żądań na porcie 80. Aby się o tym przekonać, wystarczy np. uruchomić przeglądarkę WWW i przejść pod adres http://localhost:8080. Po wpisaniu adresu pojawia się komunikat: IT WORKS!
Ewentualnie można skorzystać z polecenia curl:
1$ curl http://localhost:8080 2<html><body><h1>It works!</h1></body></html>
Zawartość pokazana wcześniej w oknie przeglądarki WWW została przez polecenie curl wyświetlona w powłoce. Nasz serwer WWW w kontenerze podmana działa! Listę wszystkich uruchomionych kontenerów można wyświetlić za pomocą wspomnianego już wcześniej polecenia podman ps.
1$ podman ps 2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3d90b6bfad6d9 docker.io/library/httpd:latest httpd-foreground About a minute ago Up About a minute ago 0.0.0.0:8080->80/tcp unruffled_napier
Dane wyjściowe tego polecenia zawierają różne informacje szczegółowe dotyczące działających kontenerów, takie jak skrócony identyfikator kontenera, obraz użyty do jego otworzenia, mapowane porty itd.
Zatrzymywanie i usuwanie kontenera
Po zakończeniu pracy z kontenerem trzeba go zatrzymać. Do tego celu służy następujące polecenie:
1podman stop [nazwa-kontenera] lub [identyfikator-kontenera]
Ponieważ w omawianym przykładzie kontenerowi nie została nadana żadna nazwa, należy użyć identyfikatora. Istnieje jeszcze wygodna opcja -l oznaczająca ostatnio użyty kontener. Dlatego też oba przedstawione tutaj polecenia spowodują zatrzymanie naszego kontenera z uruchomionym serwerem WWW:
1$ podman stop d90b6bfad6d9
lub
1$ podman stop -l
Z pomocą polecenia podman ps potwierdzamy zatrzymanie kontenera:
1$ podman ps 2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3$
Jeżeli podczas uruchamiania kontenera nie została użyta opcja --rm powodująca jego automatyczne usunięcie po zakończeniu pracy z nim, zatrzymany ostatnio kontener można usunąć wydając polecenie podman rm -l.
Podsumowanie
Podman to niewymagający użycia demona silnik kontenerów o możliwościach nieustępujących oferowanym przez Dockera. Jego największą zaletą jest możliwość uruchamiania kontenerów ze standardowymi uprawnieniami, co zapewnia większe bezpieczeństwo systemowi hosta. Oczywiście, jeśli zachodzi potrzeba, kontener można uruchomić z uprawnieniami roota. Dzięki pełnej zgodności z Dockerem podmana można wykorzystać do pracy z Testcontainers. W większości przypadków to nie będzie wymagało żadnej szczególnej konfiguracji.
Więcej o Podmanie możesz dowiedzieć się na szkoleniu Podman w praktyce.