Docker - instalacja i podstawy zarządzania kontenerami

Red Hat 7.x / CentOS 7.x
Docker to nowe spojrzenie na wirtualizację. Zamiast tradycyjnych maszyn wirtualnych wprowadza on niezależnie działające kontenery usług oparte o środowisko gospodarza, co zwiększa wydajność i elastyczność środowiska. Teorię można sobie doczytać w internecie, a nic tak nie przybliża do technologii, jak ćwiczenia praktyczne, więc bez zbędnych wstępów zaczynamy.

Instalacja

Jako środowiska bazowego używać będę systemu CentOS 7.2. Poza lokalizacją plików konfiguracyjnych dockera i procesem instalacji samo używanie go w tym srodowisku nie róźni się od innych platform.

Instalację możemy wykonać na trzy sposoby
- używając yum oraz systemowego repozytorium - yum install docker - w ten sposób instalujemy wersję zatwierdzoną przez CentOSa/Red Hata
- używając yum i konfigurując repozytorium dockera
- korzystając ze skryptu instalacyjnego dockera, który doda nam repozytorium i zainstaluje binaria curl -fsSL https://get.docker.com/ | sh

Jeśli zależy nam na aktualnej wersji najlepiej będzie użyć metody trzeciej, a jeśli wystarczy nam wersja wcześniejsza, ale "wygrzana" skorzystać możemy z metody pierwszej. Ja skorzystam z pierwszej.

[root@docker-base ~]# yum install docker

Możemy zweryfikować wersję zainstalowanego pakietu poprzez:

[root@docker-base ~]# docker --version
Docker version 1.8.2-el7.centos, build a01dc02/1.8.2

 Aby nie działać na koncie root-a, ale z drugiej strony nie robić wszystkiego przez sudo możemy dodać swojego użytkownika do grupy docker poprzez usermod -aG docker nasz_user. Jeśli grupa nie istnieje, należy ją utworzyć (groupadd docker).
Domyślnie serwis dockera nie jest wystartowany, więc trzeba do wystartować i zadbać, żeby startował wraz z systemem:

[root@docker-base ~]# systemctl enable docker
[root@docker-base ~]# systemctl start docker

I tu w zasadzie kończy się pierwszy etap - docker jest gotowy do użycia.

Zarządzanie kontenerami

Podstawowym poleceniem dockera, którego używać będziemy najczęściej jest wyświetlanie kontenerów działających na naszym hoście:

[docker@docker-base ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

W wyniku jego wywołania uzyskamy listę działających w środowisku kontenerów. Lista jest wyświetlana w postaci kolumn, które oznaczają odpowiednio:
CONTAINER_ID - identyfikator uruchomionego kontenera
IMAGE - identyfikator obrazu z którego kontener został uruchomiony (o obrazach później)
COMMAND - polecenie wykonywane wewnątrz kontenera podczas jedo inicjalizacji
CREATED - czas utworzenia kontenera
STATUS - obecny status kontenera
PORTS - wykaz mapowanych do kontenera portów (opiszę przy okazji sieci w ramach kontenerów)
NAMES - nazwa naszego kontenera

Polecenie to posiada jeszcze jeden często używany przełącznik docker ps -a, który wyświetla wszystkie kontenery w systemie - również te z różnych powodów nieaktywne.

Jako, że temat zarządzania kontenerami jest ściśle powiązany z innym aspektem - zarządzaniem obrazami - na pierwszy rzut oka polecenia mogą nasuwać wiele pytań. Póki co przyjmij składnię jako pewnego rodzaju kanon, a wszystko rozjaśni się po poznaniu tematu obrazów. Temat ten jest szeroki, więc pewnie pojawi się w osobnym wpisie.

Na początek całą naszą pracę oprzemy o kontener, który dostarczy nam niewielki system operacyjny o nazwie busybox. Rozpocznijmy więc naszą przygodę.

Uruchamianie nowego kontenera


Jako, że tekst jest początkiem początków przygody z Dockerem nie będę tu przedstawiał wszystkich przydatnych opcji uruchomienia kontenera (pewnie później pojawi się zbiorówka tych opcji w osobnym tekście), a jedynie te niezbędne do uruchomienia najprostrzego funkcjonalnego kontenera.

Każdy kontener uruchamiany jest w naszym systemie na bazie posiadanych przez nas obrazów. Obrazy takie - jeśli jeszcze nie istnieją w lokalnym repozytorium są pobierane przez serwer dockera z oficjalnego repozytorium. Proces ten powoduje, że uruchomienie pierwszej instancji kontenera może trwać dość długo, ale nie należy się tym zrażać.
Podstawowa składnia uruchamiająca kontener wyglądanastępująco: docker run nazwa_obrazu. Zastosujmy ją więc praktycznie, opierając się o rzeczywisy obraz systemu wymienianego wcześniej:

[docker@docker-base ~]$ docker run busybox
Unable to find image 'busybox:latest' locally
Trying to pull repository docker.io/library/busybox ... latest: Pulling from library/busybox

56ed16bd6310: Extracting [==================================================>]   676 kB/676 kB
bc744c4ab376: Download complete

Jak zaobserwujemy docker pobiera sobie obraz busybox, aby uruchomić kontener. Po zakończeniu procesu moglibyśmy się spodziewać, że zastaniemy uruchomiony kontener z systemem busybox - sprawdźmy zatem:

[docker@docker-base ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Pusto. Pomimo tego co mogłoby się wydawać, proces uruchomienia kontenera przebiegł właściwie. Wyjaśnienie sytuacji jest proste i widoczne w listingu wszystkich kontenerów:

[docker@docker-base ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
cf7e33398159        busybox             "sh"                3 minutes ago       Exited (0) 3 minutes ago                       dreamy_morse

Zrzut ten pokazuje nam, że kontener został utworzony 3 minuty wcześniej, a w chwili obecnej ma status Exited(0). Kontener wyłączył się, ponieważ operacją jaką miał za zadanie wykonać była egzekucja komendy sh. Udało się ją wykonać, więc kontener zrobił co miał do zrobienia i przestał być potrzebny.
Mój pierwszy kontakt z kontenerami opraty był na tym przykładzie, i szczerze mówiąc bardziej oddalał mnie od tej technologii niż do niej zbliżał. Po co komu "twór", który po uruchomieniu wchodzi do sh i się wyłącza? Kolejny wykopany przykład użycia był równie bezsensowny:

[docker@docker-base ~]$ docker run busybox echo "Echo kontrolne"
Echo kontrolne
[docker@docker-base ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
2033115ffe8c        busybox             "echo 'Echo kontrolne"   3 minutes ago       Exited (0) 3 minutes ago                        berserk_brown
cf7e33398159        busybox             "sh"                     13 minutes ago      Exited (0) 13 minutes ago                       dreamy_morse

Przykład demonstruje jak przekazywać parametry do kontenera - nakazujemy tu odpalenie kontenera i wykonanie w nim echa... po co to komu? i jak to się ma do maszyny wirtualnej? Kontener znów się wyłączył - wykonał swoje zadanie, więc nie jest już do niczego przydatny....
Przykłady te są chyba najsłabszą reklamą technologii jaką widziałem, dlatego warto o nich szybko zapomnieć. Zróbmy więc coś, co przekona nas do Dockera, i udowodni słuszność koncepcji. Założeniem działania Dockera jest szybkie i niskozasobowe dostarczanie usługi, a dobrym przykładem jego realizacji może być prosty serwer www.
Warto tu poznać pierwsze przydatne opcje komendy docker run, a mianowicie -d - pozwala ona uruchomić kontener w tzw. detached mode, czyli oddzielić działanie  kontenera od naszej powłoki shell, oraz -P, które mapuje wszystkie porty kontenera na porty naszego hosta.
Stwórzmy zatem wspomiany kontener hostujący stronę www.

[docker@docker-base ~]$ docker run -d -P httpd
Unable to find image 'httpd:latest' locally
Trying to pull repository docker.io/library/httpd ... latest: Pulling from library/httpd

d8bd0657b25f: Pull complete
a582cd499e0f: Pull complete
4d035354d707: Pull complete
152d136f2b33: Pull complete
36c9fec13bf5: Pull complete
2e56fcbe3fad: Pull complete
ceef08ecfd76: Pull complete
a023717bbace: Pull complete
1fcf3155d7dc: Pull complete
698af7c24a15: Pull complete
cca3d6822dae: Pull complete
c7c39c3750a6: Pull complete
ee4a5faa57f7: Pull complete
Digest: sha256:4aba8de9c396e4f20d682fbc9ee8e06fd91700fdbb88ed36157d6f6487a99da7
Status: Downloaded newer image for docker.io/httpd:latest

22b8aba2db983f1ef6340118ab797a3f8e88680a24e680d3e77c1090264e5357
[docker@docker-base ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
22b8aba2db98        httpd               "httpd-foreground"   8 seconds ago       Up 6 seconds        0.0.0.0:32768->80/tcp   jolly_meitner

Analogicznie do poprzedniego kontenera, obrazu httpd nie było w lokalnym repozytorium, więc został pobrany z sieci. Co się zmieniło w stosunku do poprzedniego przykładu? Po pierwsze, kontener działa, po drugie mamy wpis w kolumnie PORTS.
Kontener działa, więc powinien dostarczać nam usługę httpd. Do sprawdzenia tej teorii potrzebny jest nam drugi element - mapowanie portów. Powyższa forma wpisu oznacza, że port 32768 naszego serwera dockerowego jest mapowany na port 80 kontenera. Weryfikacja jest prosta - otwórz przeglądarkę i udaj się pod adres <ip_serwera_docker>:<port_mapowany> - u mnie to 192.168.1.150:32768. Voila. Apache działa!.

Interakcja z kontenerem


Pierwszym pytaniem jakie mi się nasunęło po uruchomieniu kontenera z httpd było mniej więcej "jak się dostać do środka i zmienić domyślną zawartość index.html". Okazuje się, że są przynajmniej dwie metody podłączenia się z systemem w kontenerze (patrząc z poziomu dockera).
Pierwszą z nich jest docker attach - metoda działa kiedy kontener uruchamia się z aktywnym shellem, i szybko przestałem z niej korzystać.
Druga, to docker exec.
Do podłączenia się do kontenera musimy znać jego id lub nazwę - z pomocą przychodzi nam tu docker ps .

[docker@docker-base ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
b399b5f6b2ce        httpd               "httpd-foreground"   5 seconds ago       Up 4 seconds        0.0.0.0:32769->80/tcp   silly_sinoussi
[docker@docker-base ~]$ docker exec -it silly_sinoussi bash
root@b399b5f6b2ce:/usr/local/apache2#

Polecenie docker exec pozwala na wywołanie wenątrz kontenera komendy podawanej jako argument. Przy interaktywnym podłączeniu istotne są przełączniki użyte powyżej: -i pozwala na interakcję podłączając do kontenera STDIN, -t natomiast uruchamia pseudo terminal TTY dla kontenera. Wewnątrz kontenera poruszamy się tak, jak w zwykłym systemie operacyjnym.
Muszę tu wspomnieć o jednej właściwości dockera w odniesieniu do interakcji z kontenerem. Przy podłączeniu interaktywnym poprzez docker attach, lub uruchomieniu kontenera od razu z opcjami -it, który przeniesie nas do shella kontenera wyjście z niego przy użyciu standardowego exit lub kombinacji ctrl+d zabije nasz kontener - jeśli tego nie chcemy trzeba wyrobić sobie nawyk używania kombinacji wyjścia dockera ctrl+p ctrl+q

Uruchamianie i zatrzymywanie kontenerów


Pierwsze uruchomienie kontenera dodaje go do naszego inwentarza, który przeglądamy poprzez docker ps -a. Znajdujące się tu kontenery możemy zatrzymywać lub uruchamiać, zależnie od potrzeb.

[docker@docker-base ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
b399b5f6b2ce        httpd               "httpd-foreground"   10 minutes ago      Up 3 minutes        0.0.0.0:32770->80/tcp   silly_sinoussi
[docker@docker-base ~]$ docker stop b399b5f6b2ce
b399b5f6b2ce
[docker@docker-base ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS                     PORTS               NAMES
b399b5f6b2ce        httpd               "httpd-foreground"   11 minutes ago      Exited (0) 4 seconds ago                       silly_sinoussi
[docker@docker-base ~]$ docker start silly_sinoussi
silly_sinoussi
[docker@docker-base ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
b399b5f6b2ce        httpd               "httpd-foreground"   11 minutes ago      Up 1 seconds        0.0.0.0:32771->80/tcp   silly_sinoussi

Jak widać powyżej, stosowanie ID i nazwy kontenera jest zamienne i uwarunkowane jedynie preferencjami użytkownika. Dodatkowo, dostępne jest również polecenie docker restart restartujące kontener, a także, w przypadku tworów opornych na polecenie stop - docker kill.

Usuwanie kontenerów


Polecenie docker stop zatrzymuje kontener, ale nie usuwa go z naszego systemu. Kontener taki zajmuje ciągle zasoby dyskowe naszego hosta. Oczywiście istnieje możliwość permanentnego usunięcia nieużywanego już kontenera - wykonać to możemy poprzez

[docker@docker-base ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS                     PORTS                   NAMES
96d2915d0302        busybox             "sh"                 3 seconds ago       Exited (0) 3 seconds ago                           jolly_fermat
b399b5f6b2ce        httpd               "httpd-foreground"   19 minutes ago      Up 4 minutes               0.0.0.0:32772->80/tcp   silly_sinoussi
[docker@docker-base ~]$ docker rm 96d2915d0302
96d2915d0302
[docker@docker-base ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
b399b5f6b2ce        httpd               "httpd-foreground"   19 minutes ago      Up 4 minutes        0.0.0.0:32772->80/tcp   silly_sinoussi

Tu również możemy zamiennie stosować id oraz nazwę kontenera.

Przydatne opcje i polecenia

Jednym z pierwszych przełączników jakich szukałem, był ten umożliwiający nadawanie konkretnych nazw kontenerom. Jeśli chcemy postawić kilka maszyn opartych o ten sam obraz, to nazwy typu "jolly_fermat" i "silly_sinoussi" niewiela nam pomogą przy identyfikacji konkretnej maszyny.
Do nadawania własnych nazw kontenerów używamy przełącznika --name nazwa_kontenera.

Przydatnymi poleceniami mogą okazać się dwa, pozwalające na zatrzymywanie oraz usuwanie WSZYSTKICH maszyn z dockera.
Do zatrzymania wszystkich kontenerów możemy użyć polecenia docker stop $(docker ps -q).
Usunięcie wszystkich kontenerów zrealizujemy w sposób analogiczny: docker rm $(docker ps -qa)

Osobiście w linuksie bardzo lubię fakt, że jeśli czegoś zapomnę, mogę to w bardziej lub mniej łatwy sposób znaleźć bez korzystania za każdym razem z google. Oczywiście mówię tu o helpach i man-ach dla wszelakich poleceń. Trzeba przyznać, że deweloperzy dockera wpisują się bardzo dobrze w zwyczaje dokumentowania binariów. Szczególnie przydatny jest help do dockera, który skonstruowany jest wielopoziomowo:
docker help wyświetli nam ogólnego helpa
docker help komenda daje helpa dla konkretnej opcji (np. docker help run)

Brak komentarzy:

Prześlij komentarz