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.