SSD Nodes Learn 🎉 VPS od $5.50/mies.
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-13

Instalacja Docker na Rocky Linux i AlmaLinux

Instalacja Docker Engine przy uzyciu dnf na systemach RHEL. Rozwiazanie problemow z konfliktem aliasu podman, konfiguracja SELinux dla bind mounts oraz bezpieczna obsluga portow.

Instalacja Docker na systemach Rocky Linux i AlmaLinux

Aby zainstalować Docker na systemie Rocky Linux lub AlmaLinux, należy dodać oficjalne repozytorium dnf, zainstalować silnik wraz z wtyczką compose, a następnie włączyć usługę. Proces ten składa się z czterech poleceń i jest identyczny dla obu dystrybucji, ponieważ obie stanowią przebudowane wersje Red Hat Enterprise Linux (RHEL) i współdzielą układ pakietów. CentOS Stream działa w ten sam sposób.

Instalacja jest krótka, dlatego większość tego przewodnika opisuje różnice w działaniu Enterprise Linux (EL) w porównaniu z Ubuntu. Podman może już zajmować polecenie docker w obrazie systemu. SELinux blokuje pliki montowane przez bind-mount, dopóki nie otrzymają one odpowiedniej etykiety. Firewalld nie filtruje portów udostępnionych przez Docker, więc port kontenera może być otwarty na świat, podczas gdy firewall-cmd raportuje, że żaden port nie jest otwarty.

Nie należy używać skryptu instalacyjnego z get.docker.com. Dokumentacja Docker wskazuje, że nie jest on zalecany w środowiskach produkcyjnych. Skrypt nadpisuje konfigurację repozytoriów bez pytania i nie może być bezpiecznie uruchomiony ponownie w celu aktualizacji. Ręczne dodanie repozytorium sprawia, że dnf upgrade traktuje Docker jak każdy inny pakiet w systemie.

Czy podman odpowiada już na polecenie docker?

Systemy Rocky Linux oraz AlmaLinux dostarczają pakiet podman w domyślnych repozytoriach, a wiele obrazów VPS instaluje go automatycznie. Niektóre obrazy idą o krok dalej i instalują podman-docker, co umieszcza skrypt powłoki w /usr/bin/docker, który wywołuje podman. Każde wpisane polecenie docker uruchamia wtedy podman, przez co poradnik napisany dla Docker generuje nieoczekiwane wyniki.

Pierwszą wskazówką jest baner. Skrypt /usr/bin/docker sprawdza obecność pliku /etc/containers/nodocker i jeśli plik ten nie istnieje, wyświetla jedną linię przed wykonaniem jakiejkolwiek operacji:

Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.

Ktoś mógł utworzyć ten plik, aby wyciszyć baner, więc nie należy polegać wyłącznie na tym. Należy zapytać bazę danych pakietów, który pakiet jest właścicielem pliku binarnego:

command -v docker
rpm -qf "$(command -v docker)"

Odpowiedź zaczynająca się od podman-docker oznacza, że odpowiada podman. Odpowiedź zaczynająca się od docker-ce-cli oznacza rzeczywisty Docker. Jeśli rpm -qf zgłasza, że żaden pakiet nie jest właścicielem pliku, został on zainstalowany ręcznie i przed zaufaniem mu należy przeczytać treść skryptu.

Podman uruchamia te same obrazy OCI i jest rozsądnym wyborem. Jeśli użytkownik chce z niego korzystać, należy przerwać w tym miejscu. Jeśli wymagany jest Docker Engine, należy najpierw usunąć konfliktowe pakiety. Oto lista dokumentowana przez Docker dla RHEL:

sudo dnf remove docker docker-client docker-client-latest docker-common \
  docker-latest docker-latest-logrotate docker-logrotate docker-engine podman runc

Przed potwierdzeniem należy sprawdzić, co dnf planuje usunąć. Na świeżym obrazie VPS lista jest krótka. Na serwerze, który był już używany, usunięcie podman może pociągnąć za sobą cockpit-podman lub inne narzędzie, które jest od niego zależne.

Utrzymanie podman obok Docker jest w zasadzie możliwe: należy usunąć tylko podman-docker, aby nazwa docker była wolna, oraz runc, który jest zastępowany przez pakiet containerd.io. Dokumentacja Docker traktuje podman jako pakiet konfliktowy, więc taki układ nie jest wspierany przez Docker. Jeśli instalacja nadal zgłasza konflikt, należy użyć pełnej listy usuwania podanej powyżej.

Dodawanie repozytorium Docker za pomocą dnf config-manager

Docker publikuje pakiety RPM dla systemów Enterprise Linux pod adresem download.docker.com. Plik repozytorium wskazuje na drzewo CentOS, z którym integrują się systemy Rocky Linux oraz AlmaLinux. Stan na sierpień 2026 potwierdza, że Docker dokumentuje to repozytorium dla CentOS Stream 9 oraz CentOS Stream 10.

sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

Wersja 5 narzędzia dnf usunęła argument --add-repo, dlatego drugie polecenie kończy się niepowodzeniem w nowszych wydaniach. Należy sprawdzić posiadaną wersję, a następnie wybrać odpowiednią formę:

dnf --version

Jeśli wyświetlona zostanie wersja 5.x, należy użyć formy z podpoleceniem:

sudo dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/centos/docker-ce.repo

Oba polecenia zapisują ten sam plik w lokalizacji /etc/yum.repos.d/docker-ce.repo. Błędna forma kończy się błędem nieznanego argumentu zamiast cichego wykonania nieprawidłowej operacji, więc ryzyko pomyłki jest zminimalizowane.

Plik repozytorium ustawia baseurl na ścieżkę zawierającą $releasever, a dnf rozwija tę zmienną na podstawie pakietu wydania. Systemy Rocky Linux i AlmaLinux ustawiają ją na numer wersji głównej, czyli 9 w EL 9 oraz 10 w EL 10, dzięki czemu repozytorium CentOS poprawnie rozpoznaje system Rocky. Przed instalacją należy zweryfikować rozwinięcie zmiennej:

sudo dnf repoinfo docker-ce-stable

Należy sprawdzić linię Repo-baseurl. Powinna ona kończyć się ciągiem /9/x86_64/stable lub /10/x86_64/stable. Jeśli wydanie ustawia $releasever na wersję punktową, taką jak 9.6, dnf zgłosi błąd Status code: 404 dla tego adresu URL podczas pobierania metadanych. Problem można rozwiązać, edytując plik /etc/yum.repos.d/docker-ce.repo i zastępując $releasever samym numerem wersji głównej.

Instalacja silnika i wtyczki compose

sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Pięć pakietów, z których każdy pełni określoną funkcję. docker-ce to demon, dockerd. docker-ce-cli to polecenie docker, które wpisujesz. containerd.io to środowisko uruchomieniowe kontenerów, którym zarządza demon. docker-buildx-plugin służy do budowania obrazów. docker-compose-plugin udostępnia docker compose jako podpolecenie.

Te pakiety nie instalują pliku binarnego docker-compose z łącznikiem. Był to Compose w wersji 1, której okres wsparcia zakończył się w lipcu 2023 roku. Każde wywołanie docker-compose z łącznikiem wymaga aktualizacji do docker compose ze spacją.

Pierwsza instalacja zatrzymuje się, aby zaimportować klucz podpisu Docker i wyświetla jego odcisk. Klucz pochodzi z gpgkey=https://download.docker.com/linux/centos/gpg w pliku repozytorium, który właśnie dodano, więc porównaj odcisk wyświetlony przez dnf z tym adresem URL przed jego zaakceptowaniem.

Jeden błąd pojawia się wystarczająco często, aby o nim wspomnieć. Jeśli dnf zgłasza, że containerd.io wymaga container-selinux i żaden pakiet go nie dostarcza, oznacza to, że repozytorium AppStream jest wyłączone. Uruchom dnf repolist i sprawdź, czy appstream znajduje się na liście, ponieważ to właśnie tam znajduje się container-selinux w systemach EL 9 oraz EL 10.

Uruchomienie Docker i weryfikacja działania

sudo systemctl enable --now docker
sudo systemctl status docker --no-pager
sudo docker run --rm hello-world

Pakiety RPM oprogramowania Docker pozostawiają demona w stanie zatrzymanym i wyłączonym po instalacji. Z tego powodu ten krok pojawia się w dokumentacji Docker dla systemu CentOS, a nie dla Ubuntu, gdzie pakiet deb automatycznie uruchamia usługę. Pominięcie enable sprawi, że Docker będzie działał tylko do następnego restartu, po czym zostanie wyłączony, zabierając ze sobą wszystkie kontenery.

Polecenie systemctl status powinno zwrócić Active: active (running). Kontener hello-world powinien wyświetlić This message shows that your installation appears to be working correctly. i zakończyć działanie. Jeśli zamiast tego pojawi się błąd uprawnień dotyczący /var/run/docker.sock, oznacza to pominięcie sudo, co zostanie naprawione w sekcji dotyczącej grupy docker poniżej.

Sprawdź wtyczkę compose oddzielnie, ponieważ jest to inny pakiet, który może być nieobecny, mimo poprawnego działania silnika:

docker compose version

Poprawna odpowiedź wygląda jak Docker Compose version v2.x.x. Przywracanie usług po restarcie to kwestia odrębna od włączania demona, a polityki restartu decydują o tym, czy usługi Compose uruchomią się ponownie po starcie systemu.

Dlaczego bind mount zwraca błąd permission denied?

Systemy Rocky Linux oraz AlmaLinux domyślnie uruchamiają SELinux (Security-Enhanced Linux) w trybie enforcing. Potwierdź to za pomocą getenforce, co wyświetli Enforcing.

Kontenery Docker działają z typem SELinux container_t, który może odczytywać i zapisywać wyłącznie pliki oznaczone etykietą container_file_t. Katalog utworzony na hoście dziedziczy etykietę od ścieżki nadrzędnej, która nie jest container_file_t. Kontener otrzymuje odmowę dostępu, mimo że właściciel, grupa oraz uprawnienia wyglądają poprawnie z perspektywy hosta. Można to odtworzyć trzema poleceniami:

sudo mkdir -p /srv/site
echo hello | sudo tee /srv/site/index.html
sudo docker run --rm -v /srv/site:/usr/share/nginx/html:ro nginx:alpine cat /usr/share/nginx/html/index.html

Kontener wyświetli komunikat:

cat: can't open '/usr/share/nginx/html/index.html': Permission denied

Dwa polecenia wskazują przyczynę. ls -ldZ /srv/site wyświetla etykietę, która dla ścieżki w /srv wynosi system_u:object_r:var_t:s0, a nie container_file_t. Następnie sudo ausearch -m avc -ts recent wyświetla wpis w dzienniku audytu jądra, zawierający avc: denied { read }, pole scontext= wskazujące na container_t oraz pole tcontext= wskazujące na etykietę widoczną na katalogu. Niezgodność między tymi dwoma polami jest jedyną przyczyną problemu.

Rozwiązaniem jest dodanie przyrostka do argumentu wolumenu. Docker automatycznie zmieni etykiety ścieżki:

sudo docker run --rm -v /srv/site:/usr/share/nginx/html:ro,z nginx:alpine cat /usr/share/nginx/html/index.html

:z zapisane małymi literami oznacza etykietę współdzieloną, dzięki czemu wiele kontenerów może korzystać z tego samego katalogu. :Z zapisane wielkimi literami oznacza etykietę prywatną, przypisaną do jednego kontenera; próba odczytu tej samej ścieżki przez drugi kontener zakończy się odmową. Używaj :z dla zasobów, do których dostęp mają również kontenery typu sidecar lub backup. Używaj :Z dla katalogów baz danych, które należą do jednego kontenera.

Dokumentacja Docker zawiera ostrzeżenie, które warto powtórzyć: zmiana etykiet jest rekurencyjna. Bind mount katalogu systemowego, takiego jak /home lub /usr, z użyciem :Z „czyni hosta bezużytecznym i może wymagać ręcznego przywracania etykiet plików systemowych”. Stosuj te przyrostki wyłącznie dla katalogów utworzonych na potrzeby kontenera, nigdy dla ścieżek systemowych.

W pliku Compose przyrostek dodaje się do tego samego ciągu znaków:

services:
  web:
    image: nginx:alpine
    volumes:
      - /srv/site:/usr/share/nginx/html:ro,z

Łatwo natknąć się na dwa ograniczenia. Flaga --mount nie pozwala na ustawienie etykiety SELinux, dlatego w razie potrzeby należy użyć -v. Wolumeny nazwane nie wymagają przyrostka, ponieważ Docker samodzielnie etykietuje katalogi tworzone w /var/lib/docker/volumes.

Nie wyłączaj SELinux. Używaj sudo setenforce 0 wyłącznie jako minutowego testu: jeśli kontener zacznie działać, problemem jest etykieta, a rozwiązaniem :z. Natychmiast przywróć działanie poleceniem sudo setenforce 1. W systemach Enterprise Linux błąd permission denied przy bind mount ma dwie niezależne przyczyny, które z wnętrza kontenera wyglądają identycznie. Pierwszą jest etykieta SELinux. Drugą są standardowe numeryczne uprawnienia użytkownika i grupy, co rozwiązuje zastosowanie zmiennych PUID i PGID. ls -lnZ wyświetla w jednej linii tryb, numerycznego właściciela oraz etykietę, co pozwala ustalić, z którym problemem masz do czynienia.

Dlaczego opublikowany port jest dostępny, mimo że firewalld wskazuje na jego zamknięcie?

Firewalld jest domyślnym firewallem w systemach Rocky Linux oraz AlmaLinux. Sprawdź jego działanie za pomocą sudo systemctl is-active firewalld. Opublikuj port i sprawdź, które porty według firewalld są otwarte:

sudo docker run -d --name web -p 8080:80 nginx:alpine
sudo firewall-cmd --list-ports

Polecenie firewall-cmd wyświetla pustą linię. Z innej maszyny curl -I http://YOUR_SERVER_IP:8080/ zwraca HTTP/1.1 200 OK. Port jest otwarty dla Internetu, a firewall nie zgłasza żadnych otwartych portów.

Przyczyną jest ścieżka, którą pokonuje pakiet. Reguły stref firewalld filtrują ruch kierowany bezpośrednio do hosta. Opublikowany port nie jest kierowany do hosta: Docker instaluje regułę NAT (network address translation), która nadpisuje adres docelowy na adres kontenera, zanim pakiet dotrze do ścieżki wejściowej hosta, więc jądro przekazuje pakiet zamiast dostarczać go lokalnie. Docker umieszcza swoje interfejsy typu bridge w strefie firewalld o nazwie docker, której celem jest ACCEPT, oraz dodaje politykę przekazywania docker-forwarding, która zezwala na przekazywanie ruchu z dowolnej strefy do strefy docker. Reguły Twojej strefy nigdy nie widzą tego pakietu.

Najczystsze rozwiązanie nie wymaga żadnej reguły firewalla. Powiąż stronę hosta publikacji z interfejsem loopback i umieść przed nią reverse proxy:

sudo docker rm -f web
sudo docker run -d --name web -p 127.0.0.1:8080:80 nginx:alpine
curl -I http://127.0.0.1:8080/

Lokalne curl zwraca HTTP/1.1 200 OK, a to samo żądanie z innej maszyny nie nawiązuje już połączenia. Każdy port bez określonego adresu hosta w argumencie -p jest publikowany na wszystkich interfejsach, więc traktuj samo -p 8080:80 jako decyzję o publicznym udostępnieniu usługi.

Jeśli potrzebujesz, aby usługa była dostępna z wybranych adresów, a z innych nie, Docker rezerwuje dla Ciebie odpowiedni łańcuch. DOCKER-USER jest przetwarzany przed własnymi regułami akceptacji Dockera, więc reguła tam umieszczona przetrwa restart Dockera i nadpisanie przez niego łańcuchów:

sudo iptables -I DOCKER-USER -i enp1s0 ! -s 203.0.113.10 -j DROP
sudo iptables -S DOCKER-USER

Pobierz nazwę interfejsu z ip route show default zamiast zakładać eth0, ponieważ obecne obrazy EL używają nazw takich jak enp1s0 lub ens3. W systemach Rocky i AlmaLinux polecenie iptables jest warstwą kompatybilności nad nftables, a łańcuchy Dockera są przez nie widoczne. Reguły dodane w ten sposób znikają po restarcie, chyba że zostaną zapisane, więc po przetestowaniu umieść je w jednostce systemd.

Docker Engine 28.0, wydany w 2025 roku, zamknął powiązaną lukę: bezpośredni dostęp routowany do portów kontenerów, które nigdy nie zostały opublikowane, jest teraz blokowany w łańcuchu DOCKER. Ta zmiana nie dotyczy opublikowanych portów, więc wszystko powyższe nadal ma zastosowanie w obecnych wersjach. Warto wyrobić sobie nawyk operacyjny: po każdym sudo firewall-cmd --reload przetestuj ponownie opublikowany port. Jeśli przestał odpowiadać, sudo systemctl restart docker zainstaluje ponownie reguły Dockera.

Administratorzy Ubuntu napotykają tę samą przeszkodę przy użyciu innego narzędzia, co opisano w dlaczego opublikowane porty Dockera ignorują reguły ufw. W obu przypadkach przyczyną jest ścieżka NAT. Zmienia się jedynie używany firewall.

Dodawanie użytkownika bez uprawnień root do grupy docker

Wpisywanie sudo przed każdym poleceniem docker staje się uciążliwe, a przynależność do grupy docker eliminuje tę konieczność:

sudo usermod -aG docker $USER
newgrp docker
docker run --rm hello-world

usermod -aG edytuje /etc/group, jednak bieżąca powłoka posiada już załadowaną listę grup, więc zmiana nie zostanie zastosowana do momentu uruchomienia nowej sesji. newgrp docker uruchamia powłokę z przypisaną grupą, co pozwala na natychmiastowe przetestowanie zmian. Nowe sesje SSH pobierają te uprawnienia automatycznie.

Należy mieć świadomość, co daje ta grupa. Członkostwo zapewnia dostęp do zapisu w /var/run/docker.sock, a każdy proces mogący komunikować się z tym gniazdem może polecić demonowi uruchomienie kontenera, który zamontuje system plików hosta. Jedno polecenie pokazuje, co to oznacza:

docker run --rm -v /:/host alpine wc -l /host/etc/shadow

Odczytuje ono plik dostępny tylko dla użytkownika root, wykonany z konta bez uprawnień sudo. Dokumentacja instalacyjna Docker potwierdza ten fakt: grupa docker nadaje uprawnienia równoważne z root. Dodawaj konto do tej grupy tylko wtedy, gdy przyznałbyś temu kontu również sudo. Jeśli konfigurujesz konta na nowym serwerze, podejmij tę decyzję w ramach konfiguracji użytkownika z minimalnymi uprawnieniami na VPS, a nie po fakcie.

Docker oferuje również tryb rootless, który uruchamia demona jako użytkownik bez uprawnień. Jest to osobna ścieżka instalacji, która zmienia sposób działania sterowników pamięci masowej oraz portów poniżej 1024, dlatego należy zaplanować to jako osobny projekt, a nie jako flagę dodawaną później.

Dalsze kroki

System posiada już silnik, wtyczkę compose, usługę odporną na restarty oraz trzy zachowania specyficzne dla EL, opisane powyżej. Kolejnym etapem jest konfiguracja compose.yaml dla każdej usługi, a struktura pliku Compose omawia format pliku oraz sterujące nim polecenia. Jeśli jest to pierwszy host kontenerowy, uruchamianie Docker na VPS wyjaśnia kwestie doboru zasobów, pamięci masowej oraz higieny obrazów, które zostały pominięte w tym przewodniku.

FAQ

Czy repozytorium Docker dla CentOS działa na systemach Rocky Linux i AlmaLinux?

Tak. Należy dodać https://download.docker.com/linux/centos/docker-ce.repo za pomocą dnf config-manager. Plik baseurl zawiera zmienną $releasever, którą Rocky Linux oraz AlmaLinux rozwijają do numeru wersji głównej. Dzięki temu system EL 9 odwołuje się do drzewa CentOS 9, a system EL 10 do drzewa CentOS 10. Rozwinięcie zmiennej można potwierdzić poleceniem sudo dnf repoinfo docker-ce-stable, sprawdzając linię Repo-baseurl. Błąd Status code: 404 podczas pobierania metadanych przez dnf oznacza, że zmienna rozwinęła się do wersji punktowej; rozwiązaniem jest edycja /etc/yum.repos.d/docker-ce.repo i wpisanie samego numeru wersji głównej.

Czy Docker i podman mogą być zainstalowane na tym samym serwerze?

Dokumentacja Docker wskazuje podman oraz runc jako pakiety konfliktowe i zaleca usunięcie obu przed instalacją Docker Engine. Bezpośrednim źródłem konfliktu jest pakiet podman-docker, który zarządza plikiem /usr/bin/docker i sprawia, że każde polecenie docker jest interpretowane jako polecenie podman. Należy wykonać rpm -qf "$(command -v docker)", aby sprawdzić, który pakiet zarządza tą ścieżką. Jeśli wynik zaczyna się od podman-docker, oznacza to, że odpowiada za nią podman. Utrzymywanie obu silników nie jest wspierane przez Docker, dlatego na serwerach produkcyjnych należy wybrać jeden z nich.

Dlaczego kontener zwraca błąd permission denied przy montowaniu typu bind mount?

SELinux jest domyślnie włączony w trybie enforcing na systemach Rocky Linux i AlmaLinux. Kontenery działają z typem container_t i mogą uzyskiwać dostęp tylko do plików oznaczonych etykietą container_file_t. Katalog utworzony przez użytkownika posiada niewłaściwą etykietę, co skutkuje odmową dostępu niezależnie od uprawnień plików i właściciela. Można to potwierdzić za pomocą ls -ldZ dla ścieżki na hoście oraz sudo ausearch -m avc -ts recent, co wyświetli avc: denied z informacją o niedopasowaniu kontekstów. Należy dodać :z do argumentu wolumenu dla danych współdzielonych między kontenerami lub :Z dla danych prywatnych jednego kontenera. Nigdy nie należy wskazywać :Z na /home lub /usr, ponieważ zmiana etykiet jest rekurencyjna i spowoduje uszkodzenie systemu hosta.

Czy muszę otwierać port w firewalld, aby udostępnić port kontenera?

Nie, i w tym właśnie tkwi problem. Reguła NAT w Dockerze nadpisuje adres docelowy, zanim pakiet dotrze do ścieżki wejściowej hosta, więc reguły stref firewalld nigdy go nie sprawdzają. Docker umieszcza również swoje mosty w strefie firewalld o nazwie docker z celem ACCEPT. Kontener uruchomiony z -p 8080:80 jest dostępny z Internetu, mimo że sudo firewall-cmd --list-ports nie zwraca żadnych reguł. Aby ograniczyć dostęp tylko do hosta, należy publikować porty na konkretnym adresie za pomocą -p 127.0.0.1:8080:80 lub wstawić reguły filtrujące do łańcucha DOCKER-USER, który Docker przetwarza przed własnymi regułami akceptacji.

Czy dodanie użytkownika do grupy docker jest bezpieczne?

Daje to uprawnienia root. Członek grupy docker może zapisywać do /var/run/docker.sock, a docker run --rm -v /:/host alpine wc -l /host/etc/shadow odczytuje plik dostępny tylko dla roota z konta, które nie posiada uprawnień sudo. Dokumentacja poinstalacyjna Docker potwierdza tę równoważność. Do grupy należy dodawać tylko konta, którym już wcześniej powierzono uprawnienia sudo, a dla kont współdzielonych lub serwisowych należy używać sudo docker. Tryb rootless stanowi alternatywę w przypadku potrzeby uruchamiania kontenerów przez użytkownika bez uprawnień administracyjnych; jest to osobna ścieżka instalacji, a nie tylko zmiana ustawień.