W codziennej pracy, programiści pracując na dużej ilości plików chcą mieć do nich bezpośredni i szybki dostęp, a efekt zmian w kodzie powinien być widoczny bez zbędnych i dodatkowych działań. Po drodze spotykamy wiele blokad związanych z konfiguracją, zastosowaną technologią, używanym systemem operacyjnym lub źródłem danych.
Przykłady?
– pracujesz nad dużym projektem PHP w środowisku Dockera na OSX – okazuje się, że montowanie twoich lokalnych plików drastycznie spowalnia działanie aplikacji, a uruchomienie composer install trwa wieczność.
– jesteś zmuszony do wykonania bezpośredniej akcji na plikach znajdujących się na serwerze. Praca przez SSH okazuje się uciążliwa i marzysz o tym, żeby móc pracować na tych plikach lokalnie – w swoim IDE.
– rozpoczynasz pracę nad zdockeryzowaną aplikacją (np. fluentbit, elasticsearch, solr), której konfiguracja zaszyta jest w obrazie. Zamiast tworzyć pliki konfiguracyjne lokalnie i odpowiednio je montować, wolałbyś mieć do nich bezpośredni dostęp „na żywo”.
– pracujesz lokalnie na Ubuntu, a twoja aplikacja uruchomiona jest w Dockerze, z podmontowanymi katalogami. Okazuje się, że aplikacja ma problemy z uprawnieniami do plików i katalogów lub je zmienia, a to tylko początek problemów.
Mutagen
Takie problemy (uproszczone na potrzeby artykułu) można mnożyć bez końca, ale jak sobie z nimi radzić? Z pomocą przychodzi nam jedno narzędzie – Mutagen (https://mutagen.io/).
Mutagen jest narzędziem open-source umożliwiającym proste, wielostronne, w pełni konfigurowalne i błyskawiczne synchronizowanie plików. W porównaniu z podobnymi narzędziami używanymi dotychczas (np. Unison, docker-sync) charakteryzuje się wysoką wydajnością, stabilnością, prostotą użycia, wieloplatformowością oraz aktywnym wsparciem ze strony twórców.
Ogólne działanie sprowadza się do uruchomienia sesji synchronizacji pomiędzy źródłem (alpha) i celem (beta), która na samym początku rozpoznaje użyte środowiska, aby uruchomić na nich proces „agenta„. Agenci komunikują się między sobą za pomocą dobranego protokołu (SCP, Docker API i inne) i obserwują zmiany na plikach. Dalsze działanie, przenoszenie zmian, ignorowanie konkretnych plików, zarządzanie uprawnieniami i symlinkami konfigurowalne jest za pomocą pliku yaml.
Od wersji 0.10 Mutagen wspiera również orkiestrację synchronizacji na poziomie projektu (https://mutagen.io/documentation/orchestration/) oraz kierowanie ruchem sieciowym (https://mutagen.io/documentation/forwarding/).
Poniżej przedstawiam przykładową konfigurację synchronizacji plików dla aplikacji Symfony Demo w systemie OSX z pomocą Mutagena w wersji 0.10.
Zacznijmy od instalacji Mutagena:
brew install mutagen-io/mutagen/mutagen
Po instalacji należy uruchomić daemon process aplikacji i zarejestrować go w autostarcie systemu:
mutagen daemon start mutagen daemon register
Mając uruchomioną aplikację Docker, z odpowiednimi kontenerami PHP i Nginx, oczekującymi na pliki w katalogu /var/www/symfony możemy uruchomić nasze sesje synchronizacji.
➜ docker-compose up -d Creating network "sync-example_default" with the default driver Creating sync-example_mysql_1 ... done Creating sync-example_php_1 ... done Creating sync-example_nginx_1 ... done ➜ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f1382f624b00 sync-example_nginx "nginx" 15 seconds ago Up 13 seconds 0.0.0.0:80->80/tcp sync-example_nginx_1 a6f42a5c3c89 sync-example_php "php-fpm7 -F" 16 seconds ago Up 14 seconds 0.0.0.0:9000->9001/tcp sync-example_php_1 1a9cec92ed8e mysql:5.7 "docker-entrypoint.s…" 17 seconds ago Up 15 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp sync-example_mysql_1
Tworzymy plik mutagen.yml z przykładową zawartością:
sync:
defaults:
ignore:
paths:
- .DS_Store
code:
alpha: "./symfony"
beta: "docker://sync-example_php_1/var/www/symfony"
mode: "one-way-safe"
ignore:
vcs: true
paths:
- "/build/"
- "/vendor/"
- "/var/"
composerjson:
alpha: "./symfony/composer.json"
beta: "docker://sync-example_php_1/var/www/symfony/composer.json"
mode: "two-way-resolved"
watch:
pollingInterval: 2
permissions:
defaultFileMode: 666
defaultDirectoryMode: 777
ignore:
vcs: false
symlink:
mode: "ignore"
composerlock:
alpha: "./symfony/composer.lock"
beta: "docker://sync-example_php_1/var/www/symfony/composer.lock"
mode: "two-way-resolved"
watch:
pollingInterval: 2
permissions:
defaultFileMode: 666
defaultDirectoryMode: 777
ignore:
vcs: false
symlink:
mode: "ignore"
var:
alpha: "./symfony/var"
beta: "docker://sync-example_php_1/var/www/symfony/var"
mode: "two-way-resolved"
watch:
pollingInterval: 5
vendor:
alpha: "./symfony/vendor"
beta: "docker://sync-example_php_1/var/www/symfony/vendor"
mode: "two-way-resolved"
watch:
pollingInterval: 5
ignore:
vcs: false
Zawartość pliku należy dostosować do swoich nazw kontenerów (format to docker://NAZWA_KONTENERA/SCIEZKA). Poszczególne klucze w pliku wyjaśnione są w dokumentacji pod adresem https://mutagen.io/documentation/. Podczas tworzenia konfiguracji, należy zwrócić uwagę na klucze „mode„, „pollingInterval” oraz na wielkość synchronizowanych katalogów. Każdy z tych elementów ma wpływ na wydajność i obciążenie generowane przez procesy „mutagen agent” w kontenerach i na hoście.
Moje doświadczenia potwierdzają, że nawet bardzo duży projekt może być synchronizowany w całości z minimalny obciążeniem CPU. Warunkiem koniecznym jest dobranie odpowiedniej konfiguracji, nawet kosztem dużej ilości sesji mutagena.
Tworzymy nasz projekt Symfony Demo w katalogu symfony:
composer create-project symfony/symfony-demo symfony
Następnym krokiem będzie uruchomienie stworzonych sesji projektu:
mutagen project create mutagen.yml
W rezultacie otrzymamy listę ID utworzonych sesji. Aby sprawdzić ich status należy wywołać komendę
mutagen list
Aby obserwować zachodzące zmiany oraz status transferowanych plików, możemy użyć komendy:
mutagen monitor {ID_SESJI}
Już po paru sekundach na naszych kontenerach znajduje się cała zawartość projektu. Pliki vendora będą synchronizowane dwustronnie, a pliki projektu jednostronnie (w przypadku ewentualnych konfliktów zostaną one wyświetlone po użyciu mutagen list).
Powyższa konfiguracja jest jedną z bardziej skomplikowanych. Jeżeli interesuje nas synchronizacja tylko jednego katalogu (np. konfiguracji PHP w obrazie) wystarczy, że wywołamy komendę:
mutagen create -m two-way-safe docker://sync-example_php_1/etc/php7 ~/Desktop/php
a na naszym pulpicie pojawi się synchronizowany katalog z kontenera, w praktyce działający tak szybko, jak gdyby był podmontowany.
Sesje możemy oczywiście w dowolnej chwili zatrzymywać i wznawiać, usuwać i tworzyć. Nad wszystkim panuje aplikacja.
Podsumowując, uważam, że dzięki Mutagenowi synchronizacja plików nie jest już smutną koniecznością, a narzędziem, które stwarza nowe możliwości. Możemy na przykład w prosty sposób pozbyć się obciążenia komputera, wynosząc warstwy aplikacji poza lokalne środowisko, działając jedynie na IDE.
Serdecznie polecam to narzędzie oraz zachęcam do wspierania twórcy.
Podczas tworzenia artykułu, korzystałem z poniższych linków:
https://mutagen.io/
https://github.com/mutagen-io/mutagen
https://github.com/symfony/demo
https://github.com/coloso/symfony-docker
Autorem tekstu jest Janusz Maciejewski.