VPS dla początkujących cz. 2: Docker, WordPress, phpMyAdmin

Napisano dnia 16.07.2021 r. o godzinie 7:00
Autor: Piotr Sperka

Wstęp

Witaj w drugim odcinku serii na temat konfiguracji i administracji VPS dla początkujących. W pierwszym odcinku uruchomiliśmy maszynę z systemem Debian 10 i stworzyliśmy konto użytkownika. Skonfigurowaliśmy również SSH oraz firewall. W tym odcinku zajmiemy się najpierw instalacją Dockera i przedstawieniem kilku podstawowych poleceń do jego obsługi. Następnie postawimy dwie pierwsze usługi – WordPressa oraz phpMyAdmin, obie w formie kontenerów. W całym poniższym opisie założyłem, że operujesz z poziomu konta roota.

Instalacja Dockera

Na początek zacznę od ważnej uwagi: obecne tutaj polecenia dotyczące instalacji są aktualne na początek lipca 2021 i dla systemu Debian 10. Przed przystąpieniem do instalacji Dockera zawsze warto najpierw zajrzeć do dokumentacji, gdzie jest opisana dokładna ścieżka. Zatem, działając zgodnie z dokumentacją, najpierw musimy zainstalować kilka potrzebnych zależności i następnie dodać repozytorium APT. Ten krok w szczególności będzie się różnił pomiędzy systemami. Wykonujemy polecenia:

apt update
apt install apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

Następnie ponownie odświeżamy APT i instalujemy Dockera:

apt update
apt install docker-ce docker-ce-cli containerd.io

Gdy instalacja zakończy się, sprawdzamy wersję zainstalowanego Dockera poleceniem: docker version. W ten sposób pośrednio zweryfikujemy, czy instalacja przebiegła poprawnie. W odpowiedzi na polecenie powinieneś zobaczyć odpowiedź zbliżoną do poniższej:

Client: Docker Engine - Community
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        f0df350
 Built:             Wed Jun  2 11:56:47 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       b0f5bc3
  Built:            Wed Jun  2 11:54:58 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.6
  GitCommit:        d71fcd7d8303cbf684402823e425e9dd2e99285d
 runc:
  Version:          1.0.0-rc95
  GitCommit:        b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Kolejnym krokiem jest instalacja Docker Compose. W skrócie, narzędzie to bardzo ułatwia tworzenie, włączanie i wyłączanie kontenerów. W zasadzie cały proces stawiania lub wyłączania usługi można sprowadzić do jednego polecenia. Instalujemy je poleceniem: apt install docker-compose.

Podstawowe polecenia Dockera i docker-compose

Poniżej opisałem kilka podstawowych poleceń Dockera i docker-compose, które wyjątkowo często wykorzystywałem podczas konfiguracji VPS. Oczywiście, dostępnych komend jest znacznie więcej, ale tego już musisz poszukać w dokumentacji lub w innych dostępnych źródłach.

  • docker-compose up – uruchamia kontenery opisane w pliku docker-compose.yml znajdującym się w aktualnej ścieżce. Konsola z której polecenie zostanie wywołane pozostanie zajęta i pojawią się w niej logi.
  • docker-compose up -d – uruchamia kontenery opisane w pliku docker-compose.yml znajdującym się w aktualnej ścieżce. Konsola z której polecenie zostało wywołane zostanie zwolniona po zakończeniu uruchamiania (-d oznacza detach).
  • docker-compose down – wyłącza kontenery opisane w pliku docker-compose.yml znajdującym się w aktualnej ścieżce.
  • docker-compose restart – restartuje kontenery opisane w pliku docker-compose.yml znajdującym się w aktualnej ścieżce.
  • docker container ls – listuje kontenery działające na Dockerze.
  • docker network ls – listuje sieci działające na Dockerze. Domyślnie, jeśli nie wyspecyfikujemy inaczej, każdy „docker-compose” działa w osobnej sieci.
  • docker network inspect <nazwa_sieci> – wyświetla szczegóły dotyczące sieci, między innymi podłączone kontenery z ich wewnętrznymi IP.
  • docker system prune – usuwa niewykorzystywane kontenery, sieci, itp.
  • docker image prune --all – usuwa wszystkie nieużywane obrazy.

WordPress

A więc po tym przydługim wstępie przejdziemy do instacji WordPressa w formie kontenera. Świeże obrazy WordPressa w kilku różnych wydaniach dostępne są na Docker Hubie. Posiłkując się zawartym tam obszernym opisem, wybrałem obrazy w wersji latest. Ogólnie rzecz biorąc, najczęściej będziemy wybierali obrazy różnych usług właśnie w wersji latest. Całą operację zaczynamy od stworzenia katalogu docker w głównym drzewie dysku: mkdir /docker. Przechodzimy do stworzonego katalogu, i tworzymy podkatalog wordpress:

cd /docker
mkdir wordpress
cd wordpress

Teraz tworzymy plik docker-compose.yml przy użyciu ulubionego edytora, na przykład nano docker-compose.yml. Poniższa treść powstała na podstawie dokumentacji obrazu WordPressa z Docker Huba. Jako bazę danych wybrałem otwartoźródłową mariadb w najnowszej wersji. W całym pliku warto zwrócić uwagę na opis wolumenów (volumes). Wskazuje on lokalizację na naszej maszynie w jakiej będą zamontowane wybrane katalogi z kontenera. W przypadku WordPressa jego pliki będą przechowywane w katalogu /docker/wordpress/html, natomiast pliki bazy danych w katalogu /docker/wordpress/mysql. W kontenerze wordpress zdefiniowaliśmy również przekierowanie portu 80 kontenera na port 8080 naszego VPS. Bez tego nasz WordPress nie byłby widoczny na zewnątrz.

version: '3.1'

services:

  wordpress:
    image: wordpress:latest
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: haslodobazy
      WORDPRESS_DB_NAME: wordpress-db
    volumes:
      - /docker/wordpress/html:/var/www/html

  db:
    image: mariadb:latest
    restart: always
    environment:
      MYSQL_DATABASE: wordpress-db
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: haslodobazy
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - /docker/wordpress/mysql:/var/lib/mysql

Zapisujemy i zamykamy nano (Ctrl+O i Ctrl+X). Wykonujemy polecenie docker-compose up -d. Po uruchomieniu sprawdzamy uruchomione kontenery poleceniem docker container ls. W moim wypadku otrzymałem taką odpowiedź:

CONTAINER ID   IMAGE              COMMAND                  CREATED         STATUS         PORTS                                   NAMES
4bed2d990e7e   wordpress:latest   "docker-entrypoint.s…"   7 minutes ago   Up 7 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   wordpress_wordpress_1
e666ef3c70e4   mariadb:latest     "docker-entrypoint.s…"   7 minutes ago   Up 7 minutes   3306/tcp                                wordpress_db_1

Widzimy, że kontenery wstały, z czego wordpress_wordpress_1 jest wystawiony na zewnątrz na porcie 8080. Wchodzimy w przeglądarce internetowej na <adres>:8080. <adres> to może być zarówno nasza domena, jak i adres IP maszyny VPS. W tym momencie strona nie powinna być dostępna. Jest to zasługa firewalla. Wykonujemy polecenie ufw allow 8080/tcp w celu odblokowania portu 8080 i po odświeżeniu powinna włączyć się strona startowa konfiguratora WordPressa. Nasza pierwsza usługa w podstawowej formie została uruchomiona 🙂

phpMyAdmin

Kolejną usługą, którą sugeruję uruchomić, jest phpMyAdmin. Jest to interfejs webowy umożliwiający zarządzanie bazami MySQL. O ile już po uruchomieniu wszystkich usług możemy go wyłączyć, to zaręczam, że na czas uruchamiania i debugowania może okazać się niezastąpiony. Ponieważ dobrym zwyczajem jest trzmanie pliku docker-compose.yml dla każdej usługi w osobnym katalogu, tworzymy nowy katalog i przechodzimy do niego:

mkdir /docker/phpmyadmin
cd /docker/phpmyadmin

Tworzymy plik docker-compose.yml o następującej zawartości:

version: '3.1'

services:
  phpmyadmin:
    image: phpmyadmin
    restart: always
    ports:
      - 8081:80
    environment:
      - PMA_ARBITRARY=1
      - UPLOAD_LIMIT=300M
    networks:
      - wordpress_default

networks:
  wordpress_default:
    external: true

Warto zauważyć tutaj dwie rzeczy. Po pierwsze tym razem wybraliśmy port 8081 do wystawienia usługi. Póki co nie mamy obsługi subdomen i musimy posiłkować się wystawieniem każdej usługi na innym porcie. Tematem subdomen i potrzebnego do tego reverse proxy zajmiemy się w kolejnym odcinku. Tymczasem ciekawa jest jeszcze jedna kwestia – pojawił się nowy tag – networks. Opisuje on do jakiej sieci w Dockerze ma być podłączony kontener. Jak wspominałem na początku, dla każdego docker-compose Docker domyślnie tworzy osobną sieć, która jest izolowana od pozostałych w tym sensie, że nie możemy się odwołać do innego kontenera po jego nazwie. Jeżeli teraz wywołalibyśmy polecenie docker network ls okazałoby się, że mamy automatycznie utworzoną sieć wordpress_default. Działa w niej WordPress wraz ze swoją bazą danych. Dzięki dodatkowym wpisom w docker-compose.yml, Docker nie stworzy nowej sieci dla phpMyAdmin, i włączy go do sieci wordpress_default.

Uruchamiamy polecenie docker-compose up -d, tym razem nie zapominamy o odblokowaniu portu w firewallu poleceniem ufw allow 8081/tcp i wchodzimy w przeglądarce na adres taki jak w przypadku WordPressa, jedynie na port 8081. Powinna pojawić się strona logowania phpMyAdmin. Podajemy dane – serwer: db (tak nazwaliśmy kontener bazy w WordPressie), użytkownik i hasło jak w docker-compose.yml WordPressa. Po zalogowaniu otrzymujemy dostęp do bazy danych WordPressa.

Podsumowanie

Podsumowując, dzisiaj udało nam się zainstalować i uruchomić Dockera. Uruchomiliśmy na nim WordPressa oraz phpMyAdmin, przy okazji poznając podstawowe polecenia do obsługi Dockera. Zapoznaliśmy się także z podstawami budowy plików docker-compose. Zauważyliśmy również poważny problem. Jest nim brak obsługi subdomen i konieczność wystawiania każdej usługi na innym porcie. Tak być nie może, tym bardziej, że standardowo HTTP działa na porcie 80, a HTTPS na porcie 443. Nie chcemy przecież za każdym razem pamiętać i podawać nieintuicyjengo numeru portu. Przy okazji wyszedł również temat HTTPS. W dzisiejszym Internecie każda szanująca się strona powinna posiadać HTTPS, a strony bez tego są chociażby gorzej pozycjonowane w Google. Tak więc już za tydzień, w następnym odcinku, zajmiemy się konfiguracją reverse proxy, które wraz z certyfikatem z LetsEncrypt zapewni nam obsługę subdomen i SSL (HTTPS).

Na koniec standardowo – zapraszam do kontaktu i do następnego 😉