Docker – pierwsze kroki – część 2/2

Jak postawić swój pierwszy projekt oparty o Dockera? Stwórz razem ze mną swój pierwszy plik yaml, który pozwoli Ci uruchomić niezależne środowisko.

Zabawę czas zacząć

Wiemy już czym jest Docker (jeśli nie wiesz, zajrzyj tutaj). Teraz musimy nauczyć się tworzyć pliki konfiguracyjne oraz podstawowe komendy. Naszym celem będzie stworzenie aplikacji opartej o Nginx, używającej PHP w wersji 7 i bazy danych MySQL. Pierwszy krok to wygenerowanie odpowiedniej struktury katalogów.

Katalog główny zawiera dwa elementy. Pierwszy z nich to plik index.php, który będzie uruchamiany jako aplikacja PHP. Drugim elementem jest folder docker, który zawiera całą potrzebną konfigurację naszych kontenerów. Wewnątrz znajdziemy:

  • docker-compose.yml – plik z pełną konfiguracją naszej aplikacji Dockerowej
  • folder nginx – wewnątrz tego folderu mamy plik nginx.conf, w którym tworzymy ustawienia naszego serwera Nginx,
  • folder php-fpm – zawiera dwa pliki – Dockerfile (konfiguracja pakietów PHP7) oraz php-ini-overrides.ini – plik, który nadpisze domyślne ustawienia php.ini
  • folder db – ten folder stworzy się automatycznie po odpaleniu docker-composer (o tym nieco później)

Konfiguracja kontenera MySQL

Plik konfiguracyjny docker-compose składa się z 3 osobnych sekcji. Pierwszy z nich to MySQL.

zkodemprzezswiat-mysql:
    image: mysql:5.7
    container_name: zkodemprzezswiat-mysql
    environment:
        - MYSQL_ROOT_PASSWORD=root123
        - MYSQL_DATABASE=zkodeprzezswiat_database
        - MYSQL_USER=zkodemprzezswiat_mysql
        - MYSQL_PASSWORD=secret123
    volumes:
        - ./db:/var/lib/mysql

Na początku określamy obraz (image) z jakiego ma być zbudowany nasz kontener (obrazy możemy znaleźć na https://hub.docker.com/ – za niedługo zamieszczę cały artykuł o tym, w jaki sposób przeszukiwać DockerHuba). W naszym przypadku potrzebujemy obraz MySQL w wersji 5.7 (mysql:5.7 to pełna nazwa obrazu). Następnie ustawiamy nazwę kontenera (container_name), która jest dość istotnym elementem naszej aplikacji, ponieważ to właśnie jej używać będziemy do tworzenia połączeń pomiędzy kontenerami (linkowania). W przypadku obrazu MySQL musimy również określić 4 podstawowe zmienne środowiskowe (pełna lista dostępna jest w opisie repozytorium lub na DockerHubie). Kolejno hasło do konta root, nazwę bazy danych, nazwę oraz hasło użytkownika. Ostatnim ważnym elementem konfiguracji kontenera jest ustalenia volumenów. Przypisywanie volumenów jest bardzo proste. Każda deklaracja składa się z dwóch części oddzielonych znakiem dwukropka. Pierwsza to ścieżka na naszym hoście, druga – w kontenerze.

ścieżka_host:ścieżka_kontener

W przypadku MySQL jedynym volumenem jest /var/lib/mysql, które linkujemy do folderu db w bieżącym katalogu. W ten sposób skonfigurowaliśmy nasz pierwszy kontener. Super! Teraz potrzebujemy jeszcze dwóch i możemy zająć się tworzeniem aplikacji 🙂

Czas na silnik naszej aplikacji – tworzymy kontener z PHP

Mamy już bazę danych, teraz potrzebujemy podpiąć do naszego projektu interpreter PHP. W pliku docker-compose.yml dopisujemy kolejne linijki konfiguracji:

zkodemprzezswiat-php-fpm:
    build: .
    dockerfile: php-fpm/Dockerfile
    container_name: zkodemprzezswiat-php-fpm
    volumes:
        - ..:/var/www/zkodemprzezswiat
        - ./php-fpm/php-ini-overrides.ini:/etc/php/7.1/fpm/conf.d/99-overrides.ini
    links:
        - zkodemprzezswiat-mysql

W tym przypadku od razu rzuca nam się w oczy kilka zmian w porównaniu do kontenera MySQL. Gdzie podziała się konfiguracja obrazu? Czym jest links i dockerfile? Już śpieszę z wyjaśnieniem. Najważniejszym elementem tej konfiguracji jest parametr dockerfile. Wskazuje on na miejsce (na hoście), gdzie znajduje się plik Dockerfile z konfiguracją naszego obrazu i kontenera. Dlaczego go tutaj stosujemy? Chcę Wam pokazać jak budować kontenery, które musimy nieco zmodyfikować. W przypadku PHP często będziemy potrzebowali doinstalować jakąś dodatkową bibliotekę (np. jeśli chcemy postawić WordPressa, będzie nam potrzebny imagick, który rzadko kiedy dostarczany jest w podstawowych obrazach, jakie znajdziemy na DockerHubie). Stwórzmy więc plik Dockerfile w folderze php-fpm.

FROM phpdockerio/php71-fpm:latest
 
# Install selected extensions and other stuff
RUN apt-get update \
    && apt-get -y --no-install-recommends install  php-memcached php7.1-mysql php-yaml \
    && apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
 
WORKDIR "/var/www/zkodemprzezswiat"

ak łatwo się domyślić, pierwsza linijka zastępuje nam ustawienia obrazu z pliku docker-compose.yml. Słowem kluczowym FROM wskazujemy na obraz z DockerHuba, który posłuży nam do budowania tego kontenera. Następnie przy pomocy polecenia RUN wymieniamy listę instrukcji, jaka ma zostać wykonana w trakcie budowania kontenera. W ten sposób instalujemy między innymi: php-memcached, php-yaml lub php-mysql. Jeżeli będzie potrzebna nam kolejna biblioteka (np. wspomniany wyżej imagick), dodajemy kolejne polecenie do listy i budujemy ponownie nasz kontener. Po skonfigurowaniu pliku Dockerfile, wracamy ponownie do naszego docker-compose. Podobnie jak przy MySQL określamy nazwę kontenera i volumeny. Dla PHP potrzebne będą volumeny z plikami naszej aplikacji (folder nadrzędny) oraz plik php-inioverrides.ini z folderu php-fpm, którym nadpiszemy konfigurację domyślnego php.ini. Pozwoli nam to na dostosowanie np. upload_max_filesize lub post_max_size. Ostatnim elementem tego kontenera będzie połączenie go z naszą bazą danych. Żeby to zrobić, użyjemy links, gdzie wymieniamy listę kontenerów z jakimi ma łączyć się nasz PHP-owy kontener. W ten sposób zbudowaliśmy już konfigurację dwóch elementów – PHP oraz bazy danych. Teraz będziemy musli połączyć to wszystko z Nginx.

Pokażmy to światu – konfiguracja Nginx

Ostatnim, brakującym elementem naszej układanki jest Nginx. Podobnie jak w przypadku dwóch poprzednich kontenerów, wracamy do docker-compose.yml i tworzymy konfigurację:

zkodemprzezswiat-webserver:
    image: phpdockerio/nginx:latest
    container_name: zkodemprzezswiat-webserver
    volumes:
        - ..:/var/www/zkodemprzezswiat
        - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
    ports:
     - "1001:80"
    links:
     - zkodemprzezswiat-php-fpm

Pobieramy gotowy obraz z DockerHuba dla nginx:latest, określamy nazwę kontenera i volumeny. Tak samo jak w przypadku PHP – z folderu nadrzędnego, do folderu: var/www/zkodemprzezswiat w kontenerze. Ta deklaracja powoduje, że wszystkie pliki, znajdujące się w katalogu nadrzędnym, zostaną „skopiowane” do /var/www/zkodemprzezswiat, czyli miejsca, na które wskazywał będzie Nginx. Drugim volumenem jakiego użyjemy jest nasza konfiguracja Ngnix. W katalogu nginx tworzymy plik nginx.conf i mapujemy go do /etc/nginx/conf.d/default.conf. W ten sposób nadpisujemy domyślne ustawienia serwera – naszymi.

server {
    listen 80 default;
 
    client_max_body_size 108M;
 
    access_log /var/log/nginx/zkodemprzezswiat.access.log;
 
 
    root /var/www/zkodemprzezswiat;
    index index.php;
 
    if (!-e $request_filename) {
        rewrite ^.*$ /index.php last;
    }
 
    location ~ \.php$ {
        fastcgi_pass zkodemprzezswiat-php-fpm:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PHP_VALUE "error_log=/var/log/nginx/zkodemprzezswiat_php_errors.log";
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        include fastcgi_params;
    }
     
}

W tym miejscu pojawia się nowy element „ports”. Jest to określenie, jaki port naszego hosta, ma mapować port w kontenerze. Jeżeli nie zdefiniowalibyśmy tego elementu, nasz host przekierowałby ruch z portu 80 na kontener Dockera. Często możemy spotkać się z sytuacją, w której będziemy mieli uruchomione więcej niż jeden projekt, będziemy chcieli podpiąć lokalną domenę pod każdy z projektów osobno lub z portu 80 będzie korzystała już inna aplikacja (np. możemy mieć Nginx na naszym hoście). W takich przypadkach zalecam przekierować kontener na inny wolny port. W tym przypadku mapujemy port 1001(host) na port 80 w kontenerze. Ostatnim krokiem jest połączenie Nginx z PHP przy pomocy links.

Gotowe. Teraz możemy już odpalać!

Docker – pierwsze uruchomienie

Jeśli dotarłeś tutaj, to znaczy, że masz już gotową konfigurację całego projektu i chcesz go odpalić. Ok – do dzieła! Z katalogu, w którym znajduje się plik docker-compose.yml z poziomu konsoli uruchamiasz następujące polecenie:

docker-compose up -d

Composer sam zaciągnie wszystkie potrzebne obrazy i stworzy całą konfigurację za Ciebie. Może potrwać to kilka minut, ale warto czekać. Gdy wszystko będzie gotowe, na ekranie konsoli powinno pojawić się coś w tym stylu:

zkodemprzezswiat-mysql is up-to-date
zkodemprzezswiat-php-fpm is up-to-date
Recreating zkodemprzezswiat-webserver

Oznacza to nie mniej, nie więcej, że Twój pierwszy projekt oparty na Dockerze jest gotowy. Dorzućmy do pliku index.php phpinfo() i sprawdźmy co się stanie. Twój projekt powinien być dostępny pod adresem http://127.0.0.1:1001

Gratuluje! Jeśli okno Twojej przeglądarki wygląda tak jak na zdjęciu wyżej, oznacza to, że udało Ci się skonfigurować wszystko poprawnie.

Teraz wypada jeszcze sprawdzić czy oprócz Nginx i PHP, działa również MySQL. Spróbujmy nawiązać połączenie przy pomocy PDO. Wszystkie potrzebne dane mamy w pliku docker-compose.yml. Należy jedynie pamiętać, że naszym hostem, jest nazwa kontenera.

<?php
   try {
      $pdo = new PDO('mysql:host=zkodemprzezswiat-mysql;dbname=zkodeprzezswiat_database', 'zkodemprzezswiat_mysql', 'secret123');
      echo 'Połączenie nawiązane!';
   }
   catch(PDOException $e) {
      echo 'Połączenie nie mogło zostać utworzone: ' . $e->getMessage();
   }

Po wykonaniu powyższego kodu w index.php w przeglądarce powinieneś zobaczyć napis „Połączenie nawiązane”.

Podsumowanie

Docker to bardzo ciekawe narzędzie, które daje nam, programistom, wiele możliwości. Oprócz odizolowania systemu od środowiska developerskiego, pozwala także na bardzo szybkie instalowanie nowych komponentów i przede wszystkim jest prosty w obsłudze. Docker sprawdza się również jako środowisko produkcyjne, dzięki któremu w łatwy sposób możemy uruchomić kilka niezależnych aplikacji na jednym fizycznym serwerze – nawet, jeśli aplikacje te potrzebowałyby różnych wersji np. PHP.

Mam nadzieję, że tym artykułem zachęcę Cię do spróbowania swoich sił z Dockerem.

0 0 votes
Article Rating
Subscribe
Powiadom o
guest
2 komentarzy
najstarszy
najnowszy oceniany
Inline Feedbacks
View all comments
Tom
Tom
4 lat temu

Cześć. Dzięki za poradnik. Nic nie napisałeś jednak co w przypadku gdy mam na serwerze Direct Admin . Co w takim wypadku? Czy to ze sobą nie koliduje? Dzięki za wszelką pomoc