Docker – Podstawy

Maciej Lelusz
23. maja 2019
Reading time: 7 min
Docker – Podstawy

Wstęp do konteneryzacji za nami, opublikowany na blogu został już jakiś czas temu i możecie go znaleźć tutaj. Skoro już wiemy mniej więcej jak to ustrojstwo działa, to już najwyższy czas pobrudzić rączki i postawić sobie jakieś środowisko konteneryzacyjne.

Myślę, że warto rozpocząć swoją przygodę z konteneryzacją od platformy Docker. Jest ona relatywnie prosta, a do jej zrozumienia nie trzeba mieć doktoratu z systemów rozproszonych czy też profesury z Go. W kolejnych artykułach uderzymy w temat Kubernetesa, OpenShift, czy też VMware PKS. Na razie jednak wystartujmy spokojnie i rozgrzejmy się na Docker CE.

Do zabawy potrzebujemy maszyny wirtualnej z Ububtu, może być też inny linuch, to bez różnicy – po prostu będą się różnić komendy. Na początku wystarczy jedna VM, później będzie się to rozrastać jak będziemy rozwijać Laba. Zaczynamy!

Zaczynamy od aktualizacji systemu i instalacji Dockera:

uname -a sudo apt-get -y update sudo apt-get -y upgrade sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" sudo apt-get -y update sudo apt-get -y install docker-ce sudo docker info

Nie posysamy Dockera z repozytoriów dystrybucji, bo zazwyczaj jest stary i śmierdzący. Trzeba bawić się na nowym sofcie. Zatem dodajemy repozytorium a później instalujemy docker-ce, czyli darmową wersję platformy.

Zdarza się, że potrzebne są zmiany w firewall (jeżeli jest), wykonuje się je następująco:

sudo vi /etc/default/ufw DEFAULT_FORWARD_POLICY="DROP" -> DEFAULT_FORWARD_POLICY="ACCEPT" sudo ufw reload

Po udanej instalacji pozostaje nam wystartować demona docker:

sudo service docker start netstat -npea | grep -i docker ps aux | grep -i docker

Warto tutaj zauważyć, że netstat pokazuje nam zależności sieciowe dot. samego Dockera, jak i później kontenerów. Podobnie ps aux, daje nam to możliwość ubicia procesu odpowiedzialnego za kontener z ręki, gdyby inne bardziej cywilizowane metody zawiodły.

Może to zaskakujące, ale to w zasadzie wszystko, jeśli chodzi o taką podstawową konfigurację. Te kilka komend daje nam w pełni działające środowisko. To dobry moment, aby powołać swój pierwszy kontener… jeszcze tylko wywołacie proszę:

hostname

Komenda ta zwróci ci aktualną nazwę hosta. Zwróć na nią uwagę, wrócimy do tego za chwilę. Tymczasem! Werble, pierwszy kontener:

sudo docker run -i -t ubuntu /bin/bash

Kiedy wywołamy powyższą komendę, uruchomimy pierwszy kontener. Dzięki przełącznikowi -i wskoczymy w tryb interakcji z ni, dzięki przełącznikowi -t zwróci on na nasz ekran swoje standardowe wyjście – czyli zobaczymy co do nas mówi. Kontener oparty będzie o obraz ubuntu zassany domyślnie z Docker Hub (potrzebny dostęp do internetu). Miejsce to jest publicznym rejestrem obrazów, można również wybrać rejestry prywatne, ale o tym później. Uruchomimy w kontenerze komendę /bin/bash. Następnie warto wywołać kilka komend:

hostname

Zwróćcie uwagę, że różni się wynik tej komendy od tej wydanej wcześniej. Dzieje się tak dlatego, że uruchamiając kontener w trybie interaktywnym niejako wskakujemy do niego. Można to porównać do warstw. VM, na której zainstalowaliśmy demona Docker jest warstwą nr 1 nazywaną Docker Engine (DE), warstwą nr 2 jest Kontener. Na obu warstwach możemy mieć różne parametry systemu, różne systemy itp. Zatem siedząc teraz w kontenerze znajdujemy się niejako w innym systemie (pod wieloma względami, acz nie do końca – tutaj znajdziecie więcej o tym). Warto wydać kilka komend, które pokażą nam kilka różnic:

cat /etc/hosts hostname -I ps -aux

Kontener ma własne pliki, własny hostnam, jak również i procesy. Doinstalujmy coś!

apt-get update && apt-get upgrade && apt-get install vim vim

W kontenerze możemy mieć inne programy niż w Docker Engine. Wyjdźmy z kontenera do systemu bazowego komendą:

exit

Pamiętajcie, kontener umiera, gdy z niego wychodzicie w trybie interaktywnym. Zabijacie bowiem proces bash, który jest jedynym powodem jego istnienia. Wywołacie sobie komendę:

sudo docker ps -a

Zobaczcie, że Wasz poprzedni kontener miał nazwę wygenerowaną, teraz czas stworzyć sobie kontener z nazwą:

sudo docker run --name chochlik_1 -i -t ubuntu /bin/bash exit

Ponownie wywołaj:

sudo docker ps -a

Fajnie nie? Mamy naszego stworka! Możemy teraz na nim wywołać kilka operacji:

sudo docker ps -a sudo docker start chochlik_1 sudo docker start [ID] sudo docker attach chochlik_1 sudo docker attach [ID]

Zauważcie, że można to robić zarówno po ID, jak również po nazwie. Komenda attach podłącza nas do kontenera, który już działa coś jak przełączniki -i i -t przy jego starcie. Pamiętajcie, wywołanie komendy exit prowadzi do zabicia kontenera.

Czas na coś bardziej samodzielnego. Uruchommy kontener z zadaniem:

sudo docker run --name chochlik_2 -d ubuntu /bin/sh -c "while true; do echo praca praca; sleep 1; done

Przełącznik -d uruchamia kontener w tle. Po jego odpaleniu zobaczmy, jak wygląda w rejestrze:

sudo docker ps

A teraz jak z niego wyciągnąć informację co robi? Możemy powołać się na logi, niekoniecznie podłączając się do samego standardowego wyjścia:

sudo docker logs chochlik_2 sudo docker logs -f chochlik_2

Pierwsza komenda wyświetli nam logi z momentu jej wywołania. Przełącznik -f, tak jak w przypadku komendy tail daje nam możliwość oglądania ich w czasie rzeczywistym. Możemy je również wysyłać do syslog Docker Engine:

sudo docker run --log-driver="syslog" --name chochlik_3 -d ubuntu /bin/sh -c "while true; do echo praca praca; sleep 1; done" sudo docker logs -f chochlik_3 tail -f /var/log/syslog

Tak jak w normalnym systemie możemy i kontenerki potraktować narzędziami do prostego monitoringu:

sudo docker top chochlik_3 sudo docker stats chochlik_2 chochlik_3

Możemy również z perspektywy DE stworzyć pliki w kontenerze:

sudo docker exec -d chochlik_2 touch /etc/bomba sudo docker exec -t -i chochlik_2 /bin/bash ls -alh /etc/bomba exit

Możemy również zatrzymać kontener:

sudo docker ps -a sudo docker stop chochlik_2 sudo docker stop [ID]

Jak zaczynamy posiadać nieco więcej kontenerów (a dzieje się to nad wyraz szybko) przydadzą nam się komendy z rodziny inspect, poniżej klika przydatnych przykładów:

sudo docker inspect chochlik_3 sudo docker inspect --format='{{ .State.Running }}' chochlik_3 sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' chochlik_3 sudo docker inspect --format '{{.Name}} {{.State.Running}}' chochlik_2 chochlik_3 sudo ls -alh /var/lib/docker/containers

Ciekawym przełącznikiem jest format, który pozwala wyciągać tylko konkretne informacje z obszernego raportu.

Ciekawym tematem jest ubijanie kontenera – można to robić na kilka sposobów:

sudo docker ps -a sudo docker kill chochlik_3 sudo docker ps -a sudo docker start chochlik_3 sudo ps aux | grep docker sudo kill -9 [PID] sudo docker ps -a

Na początku proponuję zaczynać od tych z góry, są one bowiem bardziej cywilizowane. Kill i rodzinka służy raczej do tego, gdy coś nam się zawiesi i nie będzie można wykonać standardowego wyłączenia. Po wyłączeniu kontenera nie jest on usuwany, można to zrobić za pomocą:

sudo docker rm [ID] sudo docker rm -f `sudo docker ps -a -q`

A generalne utrzymanie czystości, czyli usuwanie niepotrzebnych obrazów z Docker Engine można wykonać za pomocą:

sudo docker container prune sudo docker system prune --volumes

To już tyle jeśli chodzi o pierwsze kroki. W kolejnej odsłonie poruszymy temat wolumenów i punktów montowania, obrazów, docker hub, jak również i definiowania prywatnego rejestru. Pamiętaj, to tylko początki, dalej czeka nas definiowanie kontenera w Dockerfile, a później klaster Swarm i cała infrastruktura jako kod. Podekscytowani? Pewka.