Deploy aplikacji legacy napisanej na PHP

Tutaj znajduje się kod, o którym jest artykuł .

Wstęp i założenia

Nie raz dostajemy propozycję przejęcia kodu po kimś z zewnątrz i dalsze utrzymanie takiego kodu. We wpisie założę pewne z góry ustalone rzeczy, takie jak:

  • klient ma serwer, jednak nie podoba mu się i chce przenieść aplikację na coś innego. Zgadza się, by całą obsługą na poziomie serwera zajęliśmy się my,
  • posiadamy serwer dedykowany z dostępem do konsoli i prawami roota,
  • nie mamy dostępu do repozytorium, na którym znajduje się aktualnie kod więc założymy swoje,
  • użyjemy Docksala, oprogramowania dla developerów opartego o Docker i Docker Compose wspomagające lokalną pracę na kodzie,
  • aplikację wgrywamy bezpośrednio na serwer produkcyjny, nie mamy serwerów pośrednich do testowania pomiędzy.

Wpis oprę o przeniesienie tego bloga, który został wrzucony przez FTP na metodę, która będzie polegała na dynamicznym deploymencie.

Stack serwera oparłem o oprogramowanie instalowane razem z https://vestacp.com/ więc ścieżki na serwerze, które niżej pokażę będą odnosiły się bezpośrednio do ścieżek jakie są generowane dla użytkowników w standardowych konfiguracjach tego panelu.
W momencie pisania tego artykułu oprogramowanie, które instalujemy na debianie zawiera PHP w wersji 5.6. Zalecam doinstalowanie PHP 7.x, wtedy z poziomu panelu vesta jesteśmy w stanie dla danego użytkownika przełączyć wersję PHP. Jak to zrobić znajdziemy tutaj: https://forum.vestacp.com/viewtopic.php?f=41&t=17129

Pamiętajmy, że nie zawsze możemy przełączyć naszej wersji PHP ze względu na kod aplikacji i funkcje, które mogą być niekompatybilne. Wspomnę o tym, że budowanie aplikacji powinno opierać się o testy, jednak nie pokażę w tym wpisie jak to zrobić.

Wirtualizacja środowiska programistycznego

Jak wspomniałem w założeniach, naszym lokalnym środowiskiem będzie Docksal. Jest to oprogramowanie, które zintegruje nam Docker i Docker Compose, a także wiele innych narzędzi ułatwiających i wspierających proces programowania. Więcej informacji z opisem narzędzi i o tym jak zainstalować narzędzie znajdziemy na https://docksal.io/
Po prawidłowej instalacji spróbujmy włączyć wirtualizację komendą

fin system start

Struktura katalogów

Stwórzmy teraz wstępną strukturę, która będzie szkieletem naszej aplikacji. W zależności od systemu na jakim pracujemy ścieżki będą się różnić. Ja pracuję na Windowsie ale ścieżki lokalne oprę o ścieżki linuksowe. Przyjmijmy, że nasze projektu znajdują się w katalogu

/var/www

co za tym idzie swoją stronę umieszczę

/var/www/onblue

Struktura ostateczna będzie wyglądała zatem tak

/var/www/onblue
/var/www/onblue/.docksal – pliki konfiguracyjne naszego środowiska
/var/www/onblue/docroot – pliki naszej aplikacji
/var/www/onblue/dump.sql – dump bazy naszej aplikacji

Do katalogu docroot wrzućmy aktualną wersję naszego kodu. A do katalogu konfiguracyjnego środowiska to, co niżej

/var/www/onblue/.docksal/commands/init
/var/www/onblue/.docksal/commands/url
/var/www/onblue/.docksal/docksal.env
/var/www/onblue/.docksal/docksal.yml

Odpowiednio init i url są plikami ze skryptem bashowym, który później pomoże nam w procesie odpalania lokalnej wersji projektu. W plikach docksal wprowadźmy co następuje

/var/www/onblue/.docksal/docksal.env

/var/www/onblue/.docksal/docksal.env

Obie konfiguracje nie mają niczego szczególnego oprócz docksal.yml, która ma dwa niestandardowe parametry, są to kolejno

Postaramy się, żeby nasza lokalna aplikacja działała pod domeną onblue.pl, a samą konfigurację bazy oprzemy o zmienne środowiskowe.
Żeby osiągnąć punkt pierwszy dotyczący domeny musimy odpowiednio dodać wpis do

/etc/hosts

w której zawrzemy informacje, że onblue.pl tyczy się adresu ip 192.168.64.100.
Nasze dane dostępowe do produkcyjnej bazy umieśćmy w pliku pod ścieżką

/var/www/onblue/.env.prod

Który może wyglądać następująco

Zmiennych środowiskowych lokalnych nie zmieniajmy, upewnijmy się tylko czy table_prefix zgadza się z tym ustawionym w bazie, której uprzednio zrobiliśmy backup.
Kolejnym krokiem będzie przygotowanie naszego pliku konfiguracyjnego, który pozwoli odczytywać wartości ze zmiennych środowiskowych.
By przystąpić do dalszych prac włączmy nasz projekt komendą

fin project start

dzięki czemu będziemy mogli korzystać z narzędzi zintegrowanych w Docksal.
Jednym z takich narzędzi jest Composer, który zastosujemy do ściągnięcia biblioteki https://github.com/vlucas/phpdotenv

Przejdźmy do katalogu z kodem źródłowym naszej aplikacji

cd /var/www/onblue/docroot

a następnie wykonajmy komendę, dzięki której ściągniemy potrzebną bibliotekę

fin composer require vlucas/phpdotenv

Po poprawnym przebiegu ściągnięcia jej lokalnie możemy przystąpić do zmodyfikowania naszego pliku wp-config.php
Na samej górze naszego pliku umieśćmy ładowanie zmiennych środowiskowych z pliku

a samą definicję konfiguracji zmieńmy na następującą

Dzięki temu, że nasze lokalne zmienne środowiskowe umieściliśmy w pliku konfiguracyjnym Docksala nie musimy martwić się o to, że nasz serwer tego nie odczyta. Z kolei biorąc pod uwagę fakt stawiania aplikacji na serwerze, gdzie proces obsługujący nasz skrypt nie ma dostępu do zmiennych środowiskowych musimy skorzystać z odczytywania ich z pliku.

Wgranie backupu bazy danych

Wróćmy do naszego katalogu nadrzędnego, gdzie będziemy obsługiwać cały proces wgrywania kodu na serwer produkcyjny.

cd /var/www/onblue

Wykorzystajmy fakt, że mamy odpalony proces wirtualizacji środowiska i wgrajmy nasz backup bazy danych

fin db import dump.sql

Jeżeli nic nie pominęliśmy powinniśmy móc wejść na lokalne środowisko https://onblue.pl/

.htaccess i Docksal commands

W tym momencie możemy zauważyć dwie rzeczy, mianowicie niepoprawny .htaccess, ponieważ mój produkcyjny różni się od lokalnego między innymi tym, że lokalnie nie obsługuję SSL, a produkcyjnie tak. Drugą sprawą jest fakt, że nie zmieniliśmy ustawień ścieżek w bazie dla WordPressa.

W katalogu aplikacji umieściłem dwa różniące się pliki .htaccess, kolejno .htaccess.dev i .htaccess.prod

Następnie wykorzystałem wcześniej przygotowane pliki

/var/www/onblue/.docksal/commands/init
/var/www/onblue/.docksal/commands/url

Które teraz pomogą mi w postawieniu lokalnie środowiska. Dla pliku init stworzymy skrypt, który ustawi nam poprawny plik .htaccess lokalnie

/var/www/onblue/.docksal/commands/init

Z kolei dla pliku url zrobimy możliwość wprowadzenia zmian w bazie dzięki klientowi WordPressa, który również jest zintegrowany z Docksalem

Wyłączmy na chwilę nasz projekt przez komendę

fin project stop

co pozwoli nam go włączyć dzięki naszemu dopiero co stworzonemu skryptowi, mianowicie

fin init

który wykona nam wszystko, co zawarliśmy w /var/www/onblue/.docksal/commands/init

Po poprawnym włączeniu aplikacji, wykonajmy

fin url

Od tego momentu nasze dane w bazie zmieniły się na te, określone w pliku url.

Tworzymy repozytorium

Następnym krokiem w celu osiągnięcia efektu, który długofalowo pomoże nam w utrzymaniu kodu będzie stworzenie repozytorium. W ten sposób będziemy mogli śledzić zmiany w kodzie, a w przypadku niepożądanych zachowań lub wydarzeń typu włamanie na stronę, będziemy mogli cofnąć kod do którejś z rewizji.
Pierwszą rzeczą jaką zrobimy to założenie repozytorium. Możemy to zrobić na jednej z darmowych usług, na przykład https://bitbucket.org/
Po założeniu repozytorium przejdziemy do katalogu z aplikacją

/var/www/onblue/docroot

Pamiętajmy, żeby nie śledzić zmian w katalogu wyżej, ponieważ śledzimy historię w plikach konfiguracyjnych, a więc wysyłamy na repozytorium hasła i inne wrażliwe dane. Jeżeli potrzebujemy wysłać katalog wyżej, pamiętajmy o wykluczeniu odpowiednich rzeczy w pliku .gitignore

Kolejną rzeczą, którą zrobimy to wygenerowanie klucza, dodanie go do repozytorium i serwera.

fin ssh-key new onblue_rsa

Gdzie onblue_rsa to nazwa klucza.
Z poziomu ustawień użytkownika na koncie bitbucket dodajmy klucz przez zakładkę Security i SSH keys.
Przyszedł czas na dodanie klucza do serwera. Służy do tego komenda

fin exec ssh-copy-id user@onblue.pl

Dzięki wyżej wymienionym komendom nie będziemy musięli autoryzować się hasłem, co w normalnej sytuacji jest mocno zalecane w sprawach typowo z poziomu bezpieczeństwa, tutaj przyspieszy proces.
Na koniec możemy sprawdzić czy jesteśmy autoryzowani poprawnym kluczem z poziomu bitbucketa. Służy do tego polecenie

fin exec ssh -T hg@bitbucket.org

Wyżej wymienione polecenie pomaga w przypadku debugowania, kiedy mamy więcej niż jeden klucz i obawiamy się, jeżeli musimy autoryzować się innym kluczem SSH.

Do katalogu z naszą aplikacją wrzućmy plik .gitignore, który wykluczy ze śledzenia zmian w konkretnych folderach i plikach. Wykorzystamy tutaj następujący listing https://github.com/github/gitignore/blob/master/WordPress.gitignore

Nawiążmy połączenie z naszym repozytorium tworząc konfigurację GIT

git init
git remote add origin git@bitbucket.org:user/onblue.git
git add .
git commit -m "init"
git push -u origin master

Deployer.phar

Dla sprawniejszego wdrożenia procesu deploymentu użyjemy narzędzia https://deployer.org/
Narzędzie przedstawione wyżej posiada w standardzie pewne założenia, a także formuły, których sami nie musimy pisać.

W katalogu wyżej niż nasza aplikacja ściągnimy binarny plik deployera.

fin exec curl -LO https://deployer.org/deployer.phar
fin exec chmod +x deployer.phar

Poniżej znajduje się listing kodu, który umieścimy pod ścieżką

/var/www/onblue/deploy.php

Ważne informacje co do wyżej wymienionego listingu to między innymi to, że korzystamy z przepisu na deploy kodu dla WordPressa. Kolejną rzeczą są trzy funkcje, które sami wdrożyliśmy. Jedna z nich prepare_htaccess odpowiada za to samo co nasz skrypt init lokalnie, mianowicie kopiuje .htacces.prod do pliku .htaccess na serwerze. Kolejną funkcją, o której wspominałem dużo wyżej jest skrypt do budowania aplikacji. W tym przypadku lokalnie wykonujemy proces composera, który instaluje dla nas potrzebne biblioteki. Taką funkcjonalność w przyszłości powinniśmy przebudować, między innymi do wdrożenia testów, budowania assetów i wiele więcej – w skrócie rzeczy, które nie powinny wykonać się na serwerze powinniśmy wykonać lokalnie albo na zdalnym serwerze, który odpowiada za deploy aplikacji. Jako, że wcześniej w pliku .gitignore umieściliśmy vendors do ignorowania ze śledzenia zmian powinniśmy wrzucić go ręcznie.

W punktach wyżej dodaliśmy klucze do serwera i repozytorium, a nie dodaliśmy klucza na serwerze, który pozwoli zautoryzować proces klonowania repozytorium na serwerze. Deployer łączy się z naszym SSH z flagą –A, która odpowiada za możliwość korzystania z kluczy klienta w pamięci, co pozwala pominąć proces kopiowania kluczy na serwer.

Jeżeli wszystkie zmienne ustawiliśmy na poprawne, powinniśmy móc przystąpić do procesu wgrania zmian na serwer produkcyjny.

Z katalogu

/var/www/onblue

Wykonajmy polecenie

fin exec php deployer.phar deploy –vvv

Po poprawnym wgraniu zmian powinien zostać zwrócony komunikat “Successfully deployed!“.
W związku z tym, że na serwerze nie mamy ustawionej zmiennej środowiskowej ENV nasz wp-config.php będzie próbował odczytać dane do bazy z pliku .env, z katalogu wyżej niż sam plik się znajduje.

Biorąc pod uwagę, że nasz skrypt znajduje się w tym miejscu

/home/user/web/onblue.pl/public_html/current

Skopiujmy nasz .env.prod do public_html. Pomoże nam w tym polecenie

fin exec scp .env.prod user@onblue.pl:/home/user/web/onblue.pl/public_html/.env

Upload mediów

Przed przełączeniem naszej domeny na nowy vhost zostało nam wgranie wszystkich plików z uploads, których nie śledzimy w repozytorium. Jak wyżej pomoże nam w tym narzędzie SCP

fin exec scp -r docroot/wp-content/uploads user@onblue.pl:/home/user/web/onblue.pl/public_html/shared/wp-content

Katalog shared jest współdzielony pomiędzy wszystkimi releases danej aplikacji.

Czego nie zrobiliśmy, a powinniśmy?

Jedną z rzeczy, które powinniśmy zrobić, a we wpisie nie zawarłem informacji o tym, to fakt, że przed wgraniem kolejnych zmian na serwer produkcyjny koniecznie powinniśmy zrobić backup przynajmniej katalogu z plikami dynamicznymi takimi jak te w uploads, a także wykonać dump bazy danych. Tak by w razie nieprzewidzianych komplikacji móc przywrócić te pliki.

Podsumowanie

Podsumowując wpis myślę, że zawarłem konkretną ilość informacji, by pokazać każdemu jak może wyglądać proces wdrażania zmian w aplikacji legacy, którą mamy się opiekować. Poświęcając niedużą ilość czasu w przygotowanie sobie podstaw pod wdrożenia, jesteśmy w stanie w przypadku chęci cofnięcia zmian, włamania na stronę internetową czy w przypadku, kiedy nad jedną aplikacją pracuje więcej niż jedna osoba. Prowadzona w ten sposób historia projektu jest transparentna dla klienta, a wdrożenie nowej osoby jest sprawniejsze niż tłumaczenie jej krok po kroku w jaki sposób wdrażać zmiany w aplikacji na serwerze produkcyjnym.