Nie ulega wątpliwości, iż 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ć, iż 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 realizowane są dzięki polecenia powłoki, _**podman**_, wykorzystującego bibliotekę _libpod_ do zarządzania całym ekosystemem kontenerów. Warto dodać, iż 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. o ile 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 kooperacja 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. o ile 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, iż bez problemu można zdefiniować podmana jako alias dla Dockera. W powłoce Bash służy do tego następujące polecenie:
```r
$ 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:
```r
$ brew install podman
```
W systemach typu Fedora, CentOS i RHEL instalacja podmana odbywa się dzięki polecenia:
```r
$ dnf install podman
```
Natomiast w dystrybucjach bazujących na Debianie, np. Ubuntu, aby zainstalować podmana, należy wydać polecenie:
```r
$ apt install podman
```
Instalacja podmana w Windows jest zdecydowanie trudniejsza i została wyjaśniona na stronie [link](https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md).
Dokładna procedura instalacji w różnych systemach operacyjnych została przedstawiona na stronie [link](https://podman.io/getting-started/installation).
#### Praca z narzędziem podman
Wprawdzie w przedstawionych tutaj przykładach wykorzystam jedynie wydawane w powłoce polecenie _**podman**_, ale warto wiedzieć, iż 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.:
```r
$ podman search python
NAME DESCRIPTION
registry.fedoraproject.org/f31/python-classroom
registry.fedoraproject.org/f31/python3
...
registry.access.redhat.com/ubi9/s2i-base rhcc_registry.access.redhat.com_ubi9/s2i-bas...
docker.io/library/python Python is an interpreted, interactive, objec...
...
docker.io/fnndsc/python-poetry Python Poetry
docker.io/ibmcom/python-ceilometerclient-ppc64le Docker image for python-ceilometerclient-ppc...
quay.io/centos7/python-27-centos7 Python 2.7 available as container is a base...
...
quay.io/cloudfirst/python-rating-service
quay.io/fedora/python-311
```
Skoro podman jest zamiennikiem Dockera, więc nie powinno być zaskoczeniem, iż 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:
```r
$ 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**_. o ile używasz w pełni kwalifikowanej nazwy, to jest ona zapisywana w przedstawionej tutaj postaci:
```r
nazwa-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, iż chcesz pobrać oznaczoną tagiem _**3-slim**_ mniejszą wersję kontenera zawierającego Pythona w wersji 3.x. Wówczas polecenie ma postać:
```r
_(nazwa skrócona)_
$ podman pull python:3-slim
_(użyta w pełni kwalifikowana nazwa obrazu)_
$ 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. o ile chcesz pobrać Pythona z repozytorium Quay.io, składnia polecenia _**pull**_ nie ulega zmianie:
```r
$ 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**_:
```r
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
quay.io/fedora/python-311 latest 13fa6ebca8f7 4 days ago 974 MB
docker.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.
```r
$ podman run --rm -it python:slim
Resolved "python" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull docker.io/library/python:slim...
Getting image source signatures
Copying blob 69038a8b17e6 skipped: already exists
Copying blob 5fa7ca705967 skipped: already exists
Copying blob be80bd1fa6e1 skipped: already exists
Copying blob a82a83a9446e skipped: already exists
Copying blob 8740c948ffd4 skipped: already exists
Copying config 9012e93183 done
Writing manifest to image destination
Storing signatures
Python 3.11.1 (main, Jan 17 2023, 23:45:25) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> credits
Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
for supporting Python development. See www.python.org for more information.
>>> exit()
$
```
W ten sposób dzięki 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, iż podman to bezpośredni zamiennik Dockera?).
W dużym uproszczeniu tryb interaktywny kontenera oznacza, iż 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.
```r
$ podman pull docker.io/library/httpd
Trying to pull docker.io/library/httpd:latest...
Getting image source signatures
Copying blob 70698c657149 done
Copying blob ec2ee6bdcb58 done
Copying blob 00df85967755 done
Copying blob 8740c948ffd4 skipped: already exists
Copying blob 8b4456c99d44 done
Copying config 6e794a4832 done
Writing manifest to image destination
Storing signatures
6e794a4832588ca05865700da59a3d333e7daaaf0544619e7f326eed7e72c903
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/library/httpd latest 6e794a483258 4 days ago 149 MB
quay.io/fedora/python-311 latest 13fa6ebca8f7 4 days ago 974 MB
docker.io/library/python slim 9012e93183ab 4 days ago 134 MB
docker.io/library/python 3-slim 9012e93183ab 4 days ago 134 MB
$ podman run -d httpd
4a2a2fc312f54ad302366976836f4bb9e7848f6a3e1bf8fcd6d1803d1cbf4ff6
```
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ć dzięki polecenia _**podman ps**_.
```r
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4a2a2fc312f5 docker.io/library/httpd:latest httpd-foreground 6 seconds ago Up 6 seconds ago elated_fermat
$
```
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, iż 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ę dzięki opcji _**-p**_, zmodyfikowana wersja polecenia _**podman run**_ przedstawia się następująco:
```r
$ podman run -dt -p 8080:80/tcp docker.io/library/httpd
d90b6bfad6d9b18cd9830761cca0b3fe6923ed84109383aee86a3089e50ea0a4
```
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 dzięki 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](http://localhost:8080). Po wpisaniu adresu pojawia się komunikat: **IT WORKS!**
Ewentualnie można skorzystać z polecenia _**curl**_:
```r
$ curl http://localhost:8080
It works!
```
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ć dzięki wspomnianego już wcześniej polecenia _**podman ps**_.
```r
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d90b6bfad6d9 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:
```r
podman 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:
```r
$ podman stop d90b6bfad6d9
```
lub
```r
$ podman stop -l
```
Z pomocą polecenia _**podman ps**_ potwierdzamy zatrzymanie kontenera:
```r
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$
```
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żeli 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.