Articles

Docker Run: Jak tworzyć obrazy z aplikacji

W naszej poprzedniej serii blogów, przyjrzeliśmy się jak wdrożyć Kubernetes i stworzyć klaster. Przyjrzeliśmy się również jak wdrożyć aplikację w środowisku klastra i skonfigurować instancje OpenStack (w tym zabezpieczenia), aby pomóc Ci uzyskać do nich dostęp. Teraz zagłębimy się w rozwój Kubernetesa, sprawdzając, jak tworzyć obrazy Dockera, aby móc wdrażać własne aplikacje i udostępniać je innym ludziom.

Jak działają obrazy Dockera

Przed nauką tworzenia obrazów Dockera, pierwszą rzeczą, którą musimy zrozumieć, jest to, jak działają same obrazy Dockera.

Kluczem do obrazu Dockera jest to, że jest to warstwowy system plików. Innymi słowy, jeśli zaczniesz od obrazu, który jest tylko systemem operacyjnym (powiedzmy Windows), a następnie dodasz aplikację (powiedzmy Nginx), skończysz z czymś takim:

Jak widzisz, różnica między IMAGE1 i IMAGE2 to tylko sama aplikacja, a IMAGE4 zawiera zmiany dokonane na warstwach 3 i 4. Tak więc, aby stworzyć obraz, w zasadzie zaczynasz od obrazu bazowego i definiujesz zmiany w nim.

Teraz słyszę, że pytasz: „Ale co, jeśli chcę zacząć od zera?”. Cóż, zdefiniujmy „od zera” na minutę. Szanse są takie, że masz na myśli, że chcesz zacząć od czystego systemu operacyjnego i przejść stamtąd. Cóż, w większości przypadków istnieje obraz bazowy dla tego, więc nadal zaczynasz od obrazu bazowego. (Jeśli nie, możesz sprawdzić instrukcje dotyczące tworzenia obrazu bazowego Dockera.)

Ogólnie istnieją dwa sposoby tworzenia nowego obrazu Dockera:

  • Utwórz obraz Dockera z istniejącego kontenera: W tym przypadku zaczynasz od istniejącego obrazu, dostosowujesz go ze zmianami, które chcesz, a następnie budujesz z niego nowy obraz.
  • Użyj pliku Dockerfile: W tym przypadku używasz pliku instrukcji – Dockerfile – aby określić obraz bazowy i zmiany, które chcesz w nim wprowadzić.

W tym artykule przyjrzymy się obu tym metodom. Zacznijmy od stworzenia nowego obrazu z istniejącego kontenera.

Tworzenie z istniejącego kontenera

Jeśli chodzi o Dockera, rozpoczęcie pracy może być całkiem proste. W tym przykładzie, zaczniemy od obrazu, który zawiera serwer aplikacji internetowych nginx i PHP. Do tego dodamy obsługę odczytu danych RSS za pomocą pakietu open-source o nazwie SimplePie (do pobrania na GitHub). Następnie utworzymy nowy obraz ze zmienionego kontenera.

Tworzenie oryginalnego kontenera Dockera

Pierwszą rzeczą, którą musimy zrobić, jest instancjonowanie oryginalnego obrazu bazowego lub zlecenie dockerowi utworzenia kontenera z obrazu.

  1. Pierwszym krokiem jest upewnienie się, że w systemie jest zainstalowany Docker. Jeśli śledziłeś naszą wcześniejszą serię dotyczącą uruchamiania Kubernetes na OpenStack, masz już to załatwione. Jeśli nie, możesz podążać za instrukcjami tutaj, aby po prostu wdrożyć Dockera.
  2. Następnie należy pobrać obraz bazowy. W przypadku tego tutoriala jest to webdevops/php-nginx, który jest częścią Docker Hub, więc aby go „wyciągnąć” będziesz musiał mieć ID Docker Hub. Jeśli jeszcze go nie masz, wejdź na stronę https://hub.docker.com i utwórz darmowe konto.
  3. Przejdź do wiersza poleceń, w którym masz zainstalowanego Dockera i zaloguj się do Docker Hub:
    # docker loginZaloguj się za pomocą swojego Docker ID, aby pchać i ciągnąć obrazy z Docker Hub. Jeśli nie masz Docker ID, przejdź na stronę https://hub.docker.com aby je utworzyć.Username: nickchasePassword:Login Succeeded
  4. Zaczniemy od obrazu bazowego i każemy Dockerowi uruchomić kontener. Zainstaluj webdevops/php-nginx:
    # docker run -dP webdevops/php-nginx

    Flaga -dP upewnia się, że kontener działa w tle, a porty, na których nasłuchuje, są dostępne.

  5. Sprawdź, czy kontener jest uruchomiony:
    # docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES1311034ca7dc webdevops/php-nginx "/opt/docker/bin/entr" 35 sekund temu Up 34 seconds 0.0.0.0.0:32822->80/tcp, 0.0.0.0:32821->443/tcp, 0.0.0.0.0:32820->9000/tcp small_bassi

Kilka uwag tutaj. Po pierwsze, ponieważ nie podaliśmy konkretnej nazwy dla kontenera, Docker ją przypisał. W tym przykładzie jest to small_bassi. Po drugie, zauważ, że otwarte są 3 porty: 80, 443, oraz 9000, oraz że zostały one zmapowane na inne porty (w tym przypadku odpowiednio 32822, 32821, oraz 32820 – na Twojej maszynie te porty będą inne). Dzięki temu możliwe jest, aby wiele kontenerów „nasłuchiwało” na tym samym porcie na tym samym hoście. Jeśli więc chcielibyśmy spróbować wejść na stronę internetową hostowaną przez ten kontener, zrobilibyśmy to wchodząc na port:

http://localhost:32822

Jak na razie nie ma żadnych stron, do których można by wejść; naprawmy to.

Twórz plik na kontenerze

Aby przetestować ten kontener, musimy utworzyć przykładowy plik PHP. Zrobimy to poprzez zalogowanie się do kontenera i utworzenie pliku.

  1. Zaloguj się do kontenera
    # docker exec -it small_bassi /bin/bashroot@1311034ca7dc:/#

    Użycie exec z przełącznikiem -it tworzy interaktywną sesję, umożliwiającą wykonywanie poleceń bezpośrednio w kontenerze. W tym przypadku wykonujemy polecenie /bin/bash, więc możemy zrobić wszystko inne, czego potrzebujemy.

  2. Korzeń dokumentu dla serwera nginx w tym kontenerze znajduje się w /app, więc utwórz plik /app/index.php:
    vi /app/index.php
  3. Dodaj prostą procedurę PHP do pliku i zapisz ją:
    <?phpfor ($i; $i < 10; $i++){ echo "Numer elementu ".$i."\n";}?>
  4. Teraz wyjdź z kontenera, aby wrócić do głównego wiersza poleceń:
    root@1311034ca7dc:/# exit
  5. Teraz przetestujmy stronę. Aby to zrobić, wykonaj proste polecenie curl:
    # curl http://localhost:32822/index.phpItem numberItem number 1Item number 2Item number 3Item number 4Item number 5Item number 6Item number 7Item number 8Item number 9

Teraz czas na dodanie RSS.

Wprowadź zmiany w kontenerze

Teraz, gdy wiemy, że PHP działa, możemy dodać obsługę RSS za pomocą pakietu SimplePie. Aby to zrobić, po prostu pobierzemy go do kontenera i zainstalujemy.

  1. Pierwszym krokiem jest ponowne zalogowanie się do kontenera:
    # docker exec -it small_bassi /bin/bashroot@1311034ca7dc:/#
  2. Następnie przejdź dalej i użyj curl, aby pobrać pakiet, zapisując go jako plik zip:
    root@1311034ca7dc:/# curl https://codeload.github.com/simplepie/simplepie/zip/1.4.3> simplepie1.4.3.zip
  3. Teraz musisz go zainstalować. Aby to zrobić, rozpakuj pakiet, utwórz odpowiednie katalogi i skopiuj do nich potrzebne pliki w następujący sposób:
    root@1311034ca7dc:/# unzip simplepie1.4.3.ziproot@1311034ca7dc:/# mkdir /app/phproot@1311034ca7dc:/# mkdir /app/cacheroot@1311034ca7dc:/# mkdir /app/php/libraryroot@1311034ca7dc:/# cp -r s*/library/* /app/php/library/.root@1311034ca7dc:/# cp s*/autoloader.php /app/php/.root@1311034ca7dc:/# chmod 777 /app/cache
  4. Teraz potrzebujemy tylko strony testowej, aby upewnić się, że to działa. Utwórz nowy plik w katalogu /app:
    root@1311034ca7dc:/# vi /app/rss.php
  5. Teraz dodaj treść dla przykładowego pliku. (Ten plik jest fragmentem strony SimplePie, ale skróciłem go ze względu na zwięzłość, ponieważ tak naprawdę nie jest on głównym celem tego, co robimy. Proszę zapoznać się z oryginalną wersją w celu uzyskania komentarzy, itp.)
    <?phprequire_once('php/autoloader.php');$feed = new SimplePie();$feed->set_feed_url("http://rss.cnn.com/rss/edition.rss");$feed->init();$feed->handle_content_type();?><html><head><title>Przykładowa strona SimplePie</title></head><body><div class="header"><h1><a href="<?php echo $feed->get_permalink(); ?>><?php echo $feed->get_title(); ?></a></h1><p><?php echo $feed->get_description(); ?></p><><?php foreach ($feed->get_items() as $item): ?><iv class="item"><h2><a href="<?php echo $item->get_permalink(); ?>><?php echo $item->get_title(); ?></a></h2><p><?php echo $item->get_description(); ?></p><p><small>Posted on <?php echo $item->get_date('j F Y | g:i a'); ?></small></p></div><?php endforeach; ?></body></html>
  6. Wyjście z kontenera:
    root@1311034ca7dc:/# exit
  7. Upewnijmy się, że to działa. Pamiętaj, że musimy uzyskać dostęp do kontenera na alternatywnym porcie (sprawdź docker ps, aby zobaczyć, jakich portów musisz użyć):
    # curl http://localhost:32822/rss.php<html><head><title>Przykładowa strona SimplePie</title></head><body><div class="header"><h1><a href="http://www.cnn.com/intl_index.html">CNN.com - - Kanał RSS. Kanał RSS - Strona główna - Intl Wiadomości</a></h1><p>CNN.com dostarcza najświeższe wiadomości i informacje o najnowszych wydarzeniach, pogodzie, rozrywce, polityce i nie tylko.</p><>...

Teraz możemy przekształcić go w nowy obraz.

Tworzenie nowego obrazu

Teraz przyjrzyjmy się jak stworzyć obraz Dockera z kontenera. Mamy działający kontener i chcemy przekształcić go w obraz i przesłać do Docker Hub, aby użytkownicy społeczności mogli mieć do niego dostęp. Nazwa, której użyjesz dla swojego kontenera, zazwyczaj będzie się składać z trzech części:

/:

Na przykład, moja nazwa użytkownika Docker Hub to nickchase, więc nazwę wersję 1 mojego nowego kontenera z RSS

nickchase/rss-php-nginx:v1
  1. Jeśli kiedy po raz pierwszy zaczęliśmy mówić o różnicach między warstwami, zacząłeś myśleć o systemach kontroli wersji, masz rację. Pierwszym krokiem przy tworzeniu nowego obrazu jest commitowanie zmian, które już wprowadziliśmy, dodanie komunikatu o zmianach i określenie autora, jak w:
    docker commit -m "Message" -a "Author Name" 

    Więc w moim przypadku będzie to:

    # docker commit -m "Added RSS" -a "Nick Chase" small_bassi nickchase/rss-php-nginx:v1sha256:148f1dbceb292b38b40ae6cb7f12f096acf95d85bb3ead40e07d6b1621ad529e
  2. Następnie chcemy iść naprzód i popchnąć nowy obraz do Docker Hub, abyśmy mogli go użyć:
    # docker push nickchase/rss-php-nginx:v1The push odnosi się do repozytorium 69671563c949: Pushed3e78222b8621: Pushed5b33e5939134: Pushed54798bfbf935: Pushedb8c21f8faea9: Pushed...v1: digest: sha256:48da56a77fe4ecff4917121365d8e0ce615ebbdfe31f48a996255f5592894e2b size: 3667
  3. Teraz, jeśli lista obrazów, które są dostępne, powinieneś zobaczyć go na liście:
    # docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEnickchase/rss-php-nginx v1 148f1dbceb29 11 minut temu 677 MBnginx latest abf312888d13 3 dni temu 181.5 MBwebdevops/php-nginx latest 93037e4c8998 3 dni temu 675.4 MBubuntu latest e4415b714b62 2 tygodnie temu 128.1 MBhello-world latest c54a2cc56cbb 5 miesięcy temu 1.848 kB
  4. Teraz przejdźmy dalej i przetestujmy to. Zaczniemy od zatrzymania oryginalnego kontenera, abyśmy mogli usunąć lokalną kopię obrazu:
    # docker stop small_bassi# docker rm small_bassi
  5. Teraz możemy usunąć sam obraz:
    # docker rmi nickchase/rss-php-nginx:v1Untagged: nickchase/rss-php-nginx:v1Untagged: nickchase/rss-php-nginx@sha256:0a33c7a25a6d2db4b82517b039e9e21a77e5e2262206fdcac8b96f5afa64d96cDeleted: sha256:208c4fc237bb6b2d3ef8fa16a78e105d80d00d75fe0792e1dcc77aa0835455e3Deleted: sha256:d7de4d9c00136e2852c65e228944a3dea3712a4e7bcb477eb7393cd309be179b
  6. Jeśli ponownie uruchomisz docker images, zobaczysz, że już go nie ma:
    # docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEnginx latest abf312888d13 3 days ago 181.5 MBwebdevops/php-nginx latest 93037e4c8998 3 dni temu 675.4 MBubuntu latest e4415b714b62 2 tygodnie temu 128.1 MBhello-world latest c54a2cc56cbb 5 miesięcy temu 1.848 kB
  7. Teraz, jeśli utworzysz nowy kontener w oparciu o ten obraz, zobaczysz, że zostanie on pobrany z Docker Hub:
    # docker run -dP nickchase/rss-php-nginx:v1
  8. Na koniec przetestuj nowy kontener poprzez uzyskanie nowego portu…
    # docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES13a423324d80 nickchase/rss-php-nginx:v1 "/opt/docker/bin/entr" 6 sekund temu Up 5 sekund 0.0.0.0.0:32825->80/tcp, 0.0.0.0:32824->443/tcp, 0.0.0.0:32823->9000/tcp goofy_brahmagupta
  9. … i dostęp do pliku rss.php.
    curl http://localhost:32825/rss.php

Powinieneś zobaczyć takie same dane wyjściowe jak poprzednio.

Użyj pliku Dockerfile

Ręczne tworzenie nowego obrazu z istniejącego kontenera daje ci dużo kontroli, ale ma jeden minus. Jeśli bazowy kontener zostanie zaktualizowany, niekoniecznie będziesz miał korzyści z tych zmian.

Na przykład, załóżmy, że chcę mieć kontener, który zawsze pobiera najnowszą wersję systemu operacyjnego Linux, takiego jak Ubuntu i na niej buduje. Poprzednia metoda nie daje nam tej przewagi.

Zamiast tego możemy użyć metody zwanej Dockerfile, która pozwala nam określić konkretną wersję obrazu bazowego lub określić, że chcemy zawsze używać najnowszej wersji.

Na przykład, powiedzmy, że chcemy stworzyć wersję kontenera rss-php-nginx, która zaczyna się od v1, ale obsługuje port 88 (zamiast tradycyjnego 80). Aby to zrobić, zasadniczo chcemy wykonać trzy kroki:

  1. Zacznij od pożądanego kontenera bazowego.
  2. Powiedz Nginxowi, aby nasłuchiwał na porcie 88 zamiast 80.
  3. Pozwól Dockerowi wiedzieć, że kontener nasłuchuje na porcie 88.

Zrobimy to tworząc lokalny kontekst, pobierając lokalną kopię pliku konfiguracyjnego, aktualizując go i tworząc plik Dockerfile, który zawiera instrukcje budowania nowego kontenera.

Załatwmy to.

  1. Utwórz katalog roboczy, w którym zbudujesz swój nowy kontener. To, jak go nazwiesz, zależy całkowicie od ciebie. Ja nazwałem swój k8stutorial.
  2. Z linii poleceń, W lokalnym kontekście, zacznij od instancjonowania obrazu, abyśmy mieli z czego pracować:
    # docker run -dP nickchase/rss-php-nginx:v1
  3. Teraz pobierz kopię istniejącego pliku vhost.conf. W tym konkretnym kontenerze, możesz go znaleźć w /opt/docker/etc/nginx/vhost.conf.
    # docker cp amazing_minksy:/opt/docker/etc/nginx/vhost.conf .

    Zauważ, że mam nowy kontener o nazwie amazing_minsky, aby zastąpić small_bassi. W tym momencie powinieneś mieć kopię vhost.conf w swoim lokalnym katalogu, więc w moim przypadku będzie to ~/k8stutorial/vhost.conf.

  4. Masz teraz lokalną kopię pliku vhost.conf. Używając edytora tekstowego, otwórz plik i określ, że nginx powinien nasłuchiwać na porcie 88 zamiast na porcie 80:
    server { listen 88 default_server; listen 8000 default_server; server_name _ *.vm docker;...
  5. Następnie chcemy przejść do tworzenia pliku Dockerfile. Możesz to zrobić w dowolnym edytorze tekstu. Plik, który powinien nazywać się Dockerfile, powinien zaczynać się od określenia obrazu bazowego:
    FROM nickchase/rss-php-nginx:v1
  6. Każdy kontener, który jest instancjonowany z tego obrazu, będzie nasłuchiwał na porcie 80, więc chcemy iść naprzód i nadpisać ten plik konfiguracyjny Nginx tym, który edytowaliśmy:
    FROM nickchase/rss-php-nginx:v1COPY vhost.conf /opt/docker/etc/nginx/vhost.conf
  7. Na koniec musimy powiedzieć Dockerowi, że kontener nasłuchuje na porcie 88:
    FROM nickchase/rss-php-nginx:v1COPY vhost.conf /opt/docker/etc/nginx/vhost.confEXPOSE 88
  8. Teraz musimy zbudować właściwy obraz. Aby to zrobić, użyjemy polecenia docker build:
    # docker build -t nickchase/rss-php-nginx:v2 .Sending build context to Docker daemon 2.048 kBKrok 1 : FROM nickchase/rss-php-nginx:v1 ---> 208c4fc237bbKrok 2 : EXPOSE 88 ---> Running in 23408def6214 ---> 93a43c3df834Removing intermediate container 23408def6214Successfully built 93a43c3df834

    Zauważ, że określiliśmy nazwę obrazu, wraz z nowym tagiem (można też utworzyć zupełnie nowy obraz) oraz katalog, w którym ma się znaleźć plik Dockerfile i wszelkie pliki pomocnicze.

  9. Na koniec wypchnij nowy obraz do huba:
    # docker push nickchase/rss-php-nginx:v2
  10. Przetestuj swój nowy obraz, instancjonując go i wywołując stronę testową. za pomocą polecenia takiego jak docker run <image>. Na przykład:
    # docker run -dP nickchase/rss-php-nginx:v2root@kubeclient:/home/ubuntu/tutorial# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES04f4b384e8e2 nickchase/rss-php-nginx:v2 "/opt/docker/bin/entr" 8 sekund temu Up 7 sekund 0.0.0.0.0:32829->80/tcp, 0.0.0.0:32828->88/tcp, 0.0.0:32827->443/tcp, 0.0.0.0:32826->9000/tcp goofy_brahmagupta13a423324d80 nickchase/rss-php-nginx:v1 "/opt/docker/bin/entr" 12 minut temu Up 12 minutes 0.0.0.0:32825->80/tcp, 0.0.0.0:32824->443/tcp, 0.0.0.0:32823->9000/tcp amazing_minsky

Zauważ, że masz teraz zmapowany port dla portu 88, który możesz wywołać:

curl http://localhost:32828/rss.php

Inne rzeczy, które możesz zrobić z Dockerfile

Docker definiuje całą listę rzeczy, które możesz zrobić z Dockerfile, takich jak:

  • .dockerignore
  • FROM
  • MAINTAINER
  • RUN
  • CMD
  • EXPOSE
  • ENV
  • COPY
  • ENTRYPOINT
  • VOLUME
  • USER
  • WORKDIR
  • ARG
  • ONBUILD
  • STOPSIGNAL
  • LABEL

Jak widać, jest tu całkiem sporo elastyczności. Możesz zobaczyć dokumentację, aby uzyskać więcej informacji, a wsargent opublikował dobry Dockerfile cheat sheet.

Ruszając naprzód

Tworzenie nowych obrazów Dockera, które mogą być używane przez Ciebie lub innych deweloperów jest całkiem proste. Masz możliwość ręcznego tworzenia i wprowadzania zmian, lub oskryptowania ich za pomocą pliku Dockerfile.

W naszym następnym tutorialu przyjrzymy się użyciu YAML do zarządzania tymi kontenerami za pomocą Kubernetes.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *