Docker + php-fpm + PhpStorm + Xdebug

Vor nicht allzu langer Zeit sagte der Teamleiter: Leute, ich möchte, dass jeder die gleiche Entwicklungsumgebung für unsere Kampfprojekte hat. Wir müssen in der Lage sein, alles zu debuggen - sowohl Webanwendungen als auch API-Anfragen und Konsolenskripte, um unsere Nerven und Zeit zu sparen. Und helfen Sie uns mit diesem Docker.

Kaum gesagt als getan. Details unter dem Schnitt.

Es gibt viele Containerisierungshandbücher im Netzwerk, aber wie kann man sie auf die echte Kampfentwicklung anwenden? Schreiben Sie für jedes Projekt Ihre eigene docker-compose.yml? Aber alle unsere Projekte kommunizieren über API miteinander. Sie verwenden alle den Standard-Technologie-Stack: nginx + php-fpm + mysql.

Lassen Sie uns daher die Bedingungen des Problems klären:

  1. Wir arbeiten in einer Firma, in einem Team, begleiten mehrere Kampfprojekte. Wir arbeiten alle unter Ubuntu + PhpStorm
  2. Für die lokale Entwicklung möchten wir den Docker verwenden, um für jedes Teammitglied dieselbe Entwicklungsumgebung zu haben, und damit ein neuer Entwickler bei Ankunft schnell eine Arbeitsumgebung bereitstellen kann
  3. Wir wollen mit Komfort entwickeln, wir wollen alles debütieren: sowohl Webanwendungen als auch Konsolenskripte und API-Anfragen.

Noch einmal: Wir wollen mehrere Arbeitsprojekte in den Docker bringen.

Auf Kampfservern wird das Standardpaket nginx + php-fpm + mysql verwendet. Und was ist das Problem?

Wir stellen genau dieselbe Umgebung + Xdebug auf dem lokalen Computer bereit, konfigurieren unsere Projekte in PhpStorm und arbeiten. Schalten Sie zum Debuggen die "Tube" in PhpStorm ein, alles funktioniert sofort, alles ist in Ordnung.



All dies ist wahr - alles funktioniert sofort. Aber lassen Sie uns versuchen, unter die Haube unserer Arbeitsumgebung zu schauen.

Nginx + php-fpm kommunizieren über den Socket, xdebug lauscht auf Port 9000, PhpStorm lauscht standardmäßig auf Port 9000 zum Debuggen und alles scheint in Ordnung zu sein. Und wenn in PhpStorm mehrere Anwendungen geöffnet sind und das Abhören ("Tube" "für mehrere Anwendungen aktiviert ist? Was wird PhpStorm tun? Er wird schwören, dass eine neue Verbindung für Xdebug erkannt wurde. Möchten Sie diese ignorieren oder nicht?

Das heißt, mit den Standardeinstellungen in PhpStorm kann ich zu einem bestimmten Zeitpunkt nur eine Anwendung debütieren. Für alle anderen offenen Anwendungen muss das Debuggen deaktiviert sein. Verdammt, aber es ist unpraktisch. Ich möchte alle Anwendungen zum Debuggen anhören, und wenn in einer von ihnen ein Haltepunkt vorhanden ist, möchte ich, dass PhpStorm in dieser Anwendung in der Zeile stoppt, in der ich ihn benötige.

Und was wird dafür benötigt? Sie benötigen jedoch jede Anwendung, um mit ihren eigenen Einstellungen für Xdebug zu beginnen. Damit jede Anwendung ihren Port abhört, nach ihrem Server sucht und nicht alles gemeinsam hat, alles auf einem Haufen.

Und dafür gibt es einen wunderbaren Hafenarbeiter! Wir können jede unserer Kampfanwendungen in einem separaten Container starten, basierend auf einem gemeinsamen Bild, zum Beispiel php: 7.1-fpm. Dank der Docker-Technologie können wir unsere Anwendungen mit minimalem Overhead isolieren.

Ok, lassen Sie uns unsere Kampfprojekte unter dem Docker starten, jedes Projekt in einem separaten Container ausführen, jedes Projekt in PhpStorm so konfigurieren, dass es einzeln debuggt. Alles sollte in Ordnung sein.

Und, oops, das erste Problem: Die Container im Docker werden als Root ausgeführt, und lokal arbeiten wir, normalerweise als Benutzer mit UID 1000, GID 1000. Anwendungen kämpfen, und es ist keine Option, jeder Anwendung 777 Rechte für alles zu geben. Unsere Anwendungen befinden sich unter dem Git, und wenn wir die Rechte 777 lokal vergeben, zeichnet der Git all dies auf und überträgt es auf den Battle Server.

Krücken, hier ist ein Beispiel für ein PHP-Bild: 7.1-fpm, das kompiliert wird.

Update


Wie die Community zu Recht betont hat, besteht absolut keine Notwendigkeit, hart zu krücken.
Zum Beispiel 1vertrovert habrozer im Kommentar

Beispiel für ein erstes PHP-Bild: 7.1-fpm (UID und GID sind fest codiert)
FROM php:7.1-fpm RUN apt-get update && apt-get install -y \ git \ curl \ wget \ libfreetype6-dev \ libjpeg62-turbo-dev \ libmcrypt-dev \ libpng-dev zlib1g-dev libicu-dev g++ libmagickwand-dev libxml2-dev \ && docker-php-ext-configure intl \ && docker-php-ext-install intl \ && docker-php-ext-install mbstring zip xml gd mcrypt pdo_mysql \ && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ && docker-php-ext-install -j$(nproc) gd \ && pecl install imagick \ && docker-php-ext-enable imagick \ && pecl install xdebug \ && docker-php-ext-enable xdebug ADD ./php.ini /usr/local/etc/php/php.ini RUN wget https://getcomposer.org/installer -O - -q \ | php -- --install-dir=/bin --filename=composer --quiet RUN usermod -u 1000 www-data && groupmod -g 1000 www-data WORKDIR /var/www USER 1000:1000 CMD ["php-fpm"] 



Beispiel für ein korrigiertes Dockerfile

 FROM php:7.1-fpm ARG USER_ID ARG GROUP_ID RUN apt-get update && apt-get install -y \ git \ curl \ wget \ libfreetype6-dev \ libjpeg62-turbo-dev \ libmcrypt-dev \ libpng-dev zlib1g-dev libicu-dev g++ libmagickwand-dev --no-install-recommends libxml2-dev \ && docker-php-ext-configure intl \ && docker-php-ext-install intl \ && docker-php-ext-install mbstring zip xml gd mcrypt pdo_mysql \ && pecl install imagick \ && docker-php-ext-enable imagick \ && pecl install xdebug-2.5.0 \ && docker-php-ext-enable xdebug ADD ./php.ini /usr/local/etc/php/php.ini RUN wget https://getcomposer.org/installer -O - -q \ | php -- --install-dir=/bin --filename=composer --quiet RUN usermod -u ${USER_ID} www-data && groupmod -g ${GROUP_ID} www-data WORKDIR /var/www USER "${USER_ID}:${GROUP_ID}" CMD ["php-fpm"] 


Wenn ein Container von diesem Image aus gestartet wird, erhält der Benutzer von www-data uid = 1000, gid = 1000. Normalerweise hat der erste unter Linux erstellte Benutzer diese Rechte. Und genau mit solchen Rechten funktionieren unsere PHP-Fpm-Container. Ich wäre sehr dankbar, wenn mir jemand sagen würde, wie man ohne Krücken mit Zugriffsrechten auf den Docker arbeitet.

Wenn ein Container von diesem Image aus gestartet wird, erhält der Benutzer von www-data uid und gid, die von außen übertragen werden.

Auch in den Kommentaren wurde das Thema angesprochen : Warum die Rechte des WWW-Datenbenutzers überhaupt ändern, warum die Standardrechte nicht zu 33 passen. Nur eines: Wenn wir in den Container gehen und beispielsweise eine Migrationsdatei erstellen, sind wir nicht der Eigentümer der Datei auf dem Hostcomputer. Und jedes Mal wird es notwendig sein, so etwas auszuführen
  sudo chown -R user:user ./ 


Und das zweite kleine Problem: Damit Xdebug ordnungsgemäß funktioniert, müssen Sie die richtige IP-Adresse für den Host-Computer registrieren. Jedes Mitglied des Teams ist anders. 127.0.0.1 rollt nicht. Und hier kommt uns der Hafenarbeiter selbst zu Hilfe. Zum Beispiel können wir das Netzwerk explizit konfigurieren - 192.168.220.0/28. Und dann hat unsere Maschine immer die Adresse 192.168.220.1. Wir werden diese Adresse verwenden, um PhpStorm sowie andere Anwendungen zu konfigurieren. Zum Beispiel bei der Arbeit mit MySQL.

Docker-compose.yml selbst sieht nach Berücksichtigung der Kommentare folgendermaßen aus:

 version: '3' services: php71-first: build: context: ./images/php71 args: - USER_ID - GROUP_ID volumes: - ./www:/var/www - ./aliases/php71/bash.bashrc:/etc/bash.bashrc environment: XDEBUG_CONFIG: "remote_host=192.168.220.1 remote_enable=1 remote_autostart=off remote_port=9008" PHP_IDE_CONFIG: "serverName=first" networks: - test-network php71-two: build: context: ./images/php71 args: - USER_ID - GROUP_ID volumes: - ./www:/var/www - ./aliases/php71/bash.bashrc:/etc/bash.bashrc environment: XDEBUG_CONFIG: "remote_host=192.168.220.1 remote_enable=1 remote_autostart=off remote_port=9009" PHP_IDE_CONFIG: "serverName=two" networks: - test-network nginx-test: image: nginx volumes: - ./hosts:/etc/nginx/conf.d - ./www:/var/www - ./logs:/var/log/nginx ports: - "8080:80" depends_on: - php71-first - php71-two networks: test-network: aliases: #         . ,    api - first.loc - two.loc # mysql: # image: mysql:5.7 # ports: # - "3306:3306" # volumes: # - ./mysql/data:/var/lib/mysql # environment: # MYSQL_ROOT_PASSWORD: secret # networks: # - test-network networks: test-network: driver: bridge ipam: driver: default config: - subnet: 192.168.220.0/28 


Wir sehen, dass in dieser Konfiguration zwei Container php71-first und php71-two erstellt werden, basierend auf einem PHP-Image: 7.1-fpm. Jeder Container hat seine eigenen Einstellungen für Xdebug. Jeder einzelne Container wartet beim Debuggen auf seinen Port und seinen Server.

Ich mache Sie auch auf die Richtlinien aufmerksam
  args: - USER_ID - GROUP_ID 


Ohne diese Variablen wird das php-fpm-Image nicht gestartet. Frage: Wie übergebe ich sie an docker-compose.yml? Antwort: da es für Sie bequemer ist. Sie können beim Start:
 USER_ID=$(id -u) GROUP_ID=$(id -g) docker-compose up -d 

Sie können diese Variablen in die ENV-Datei schreiben, die sich auf derselben Ebene befindet wie die Datei docker-compose.yml
USER_ID=1000
GROUP_ID=1000

Ich mag die Version mit der .env-Datei mehr. Natürlich können Sie das Makefile verwenden. Wie du mehr magst.

Der vollständige Code für die Demoversion ist auf dem Github veröffentlicht .

Listing Demo-Projekt:



Gehen Sie kurz die Liste des Projekts durch.

Aliase -> php71 -> Verzeichnis bash.bashrc. Umstrittener Moment. Ich bevorzuge die Kommunikation mit PHP-Fpm-Containern über Aliase.

Diese Datei wird an docker-compose.yml weitergeleitet: - ./aliases/php71/bash.bashrc:/etc/bash.bashrc
Linux Standard Tool.

Das Hosts-Verzeichnis - Konfigurationsdateien für Nginx. Jede Konfiguration hat einen eigenen PHP-Fpm-Container. Ein Beispiel:

 server { listen 80; index index.php; server_name first.loc; error_log /var/log/nginx/first_error.log; root /var/www/first.loc; location / { try_files $uri /index.php?$args; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; #  php-fpm fastcgi_pass php71-first:9000; fastcgi_index index.php; fastcgi_read_timeout 1000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } } 

Das Bilderverzeichnis - Anweisungen zum Zusammenstellen von PHP-Fpm-Bildern, das MySQL-Verzeichnis - Wir speichern die Datenbanken, das WWW-Verzeichnis - alle unsere Webprojekte, in unserem Beispiel first.loc und two.loc.

Lassen Sie uns die Zwischenergebnisse zusammenfassen : Mit den Funktionen des Dockers haben wir alle unsere Arbeitsprojekte in einer Umgebung gestartet. Alle unsere Projekte sehen sich gegenseitig. Für jedes Projekt werden eindeutige Einstellungen für Xdebug registriert.

Es bleibt, PhpStorm für jedes der Projekte korrekt zu konfigurieren. Bei der Einrichtung müssen wir den Port für das Debuggen und den Servernamen an mehreren Stellen registrieren.

Erstellen Sie ein Projekt in PhpStorm







Wir werden die Menübereiche konfigurieren
- PHP (Sie müssen den CLI-Interpreter korrekt registrieren),
- Debuggen (ändern Sie den Port auf 9008, wie in der Datei docker-compose.yml),
- DBGp-Proxy (IDE-Schlüssel, Host, Port),
Update Dank des CrazyLazy Hub- Browsers für den wichtigen Punkt. Der Menüpunkt DBGp-Proxy muss nicht konfiguriert werden.
- Server (Sie müssen den Servernamen wie in der Datei docker-compose.yml korrekt angeben und Pfadzuordnungen verwenden.)



Ich werde alle weiteren Screenshots unter dem Spoiler verstecken.

Konfigurieren des CLI-Interpreters aus der Datei docker-compose.yml
Es gibt nichts Schwieriges - es ist wichtig, dass Sie beim Einrichten das gewünschte Image auswählen und den Servernamen korrekt registrieren. Standardmäßig haben wir den Namen des Docker-Servers.



















Richten Sie den Debug-Menübereich ein
Auch hier schreiben wir alles aus den Einstellungen von docker-compose.yml für einen bestimmten Container vor. Im selben Schritt überprüfen wir, wie unser Debug funktioniert.






Richten Sie den Menübereich Server ein
Es ist wichtig, die Pfadzuordnungen für die Verwendung korrekt zu registrieren. Auch hier übernehmen wir den Servernamen aus den Einstellungen





Wir verlassen den Menübereich Datei -> Einstellungen, gehen zum Menüabschnitt Ausführen -> Konfiguration bearbeiten, erstellen eine PHP-Webseite
Wir wählen unseren Server aus, der im vorherigen Schritt erstellt wurde.







Nun, das ist alles. Es sind viele Briefe geschrieben, es scheint, dass nicht alles einfach ist


In der Tat ist die Hauptsache, eine sehr einfache Sache zu verstehen. Dank der Docker-Technologie können wir alle unsere Arbeitsanwendungen in einem einzigen Bereich ausführen, jedoch mit unterschiedlichen Einstellungen für Xdebug. Jede Anwendung arbeitet in einem eigenen Container, und wir müssen die Einstellungen für jede Anwendung in PhpStorm sorgfältig vorschreiben.

Und am Ausgang bekommen wir ein wunderbares Bild.

1. Wir klonen ein Repository auf einem Github . Erstellen Sie eine .env-Datei mit Variablen
USER_ID= uid
GROUP_ID= gid


2. Wir registrieren die Knoten first.loc und two.loc in der Datei / etc / hosts

 127.0.0.1 first.loc 127.0.0.1 two.loc 

3. Führen Sie im Ordner git den docker-compose up -d

4. Wir konfigurieren beide Projekte first.loc und two.loc in PhpStorm, wie oben beschrieben, und führen beide Projekte in PhpStorm aus. Das heißt, Wir haben zwei geöffnete PhpStorm-Fenster mit zwei Projekten, von denen jedes auf eingehende Verbindungen wartet (das Mobilteil ist eingeschaltet).

5. Im Projekt two.loc setzen wir einen Haltepunkt in die zweite Zeile, zum Beispiel. Im ersten Projekt first.loc starten wir die http-Anfrage aus der Datei http.http

Und siehe da! Wir werden an unserem Haltepunkt in das zweite Projekt hineingeworfen.

Zum Debuggen von Konsolenskripten machen wir genau das Gleiche. Wir aktivieren das Abhören zum Abhören, setzen einen Haltepunkt, gehen zum richtigen Container und führen das richtige Skript aus.

So etwas wie:

 alex@alex-Aspire-ES1-572 ~ $ php71first www-data@a0e771cfac72:~$ cdf www-data@a0e771cfac72:~/first.loc$ php index.php I'am first host www-data@a0e771cfac72:~/first.loc$ 

Wobei php71first der Alias ​​auf dem Hostcomputer ist:

 alias php71first="cd ~/docker_git && docker-compose exec php71-first bash" 

cdf - ein Alias, der in einem Container funktioniert. Ich habe oben geschrieben, dass ich lieber Aliase verwende, um mit Containern zu kommunizieren.

Das ist alles, konstruktive Kritik, Kommentare sind willkommen.

PS Ich möchte Denis Bondar meinen tiefen Dank für seinen Artikel PhpStorm + Docker + Xdebug aussprechen , der der Ausgangspunkt für das Schreiben dieses Tutorials war.

Source: https://habr.com/ru/post/de473184/


All Articles