Há pouco tempo, o líder da equipe disse: pessoal, quero que todos tenham o mesmo ambiente de desenvolvimento para nossos projetos de combate + precisamos depurar tudo - aplicativos da web e solicitações de API e scripts de console para economizar nossos nervos e tempo. E nos ajude com esta janela de encaixe.
Mal disse o que fez. Detalhes sob o corte.
Existem muitos manuais de conteinerização na rede, mas como aplicá-los ao desenvolvimento real de combate? Para cada projeto, escreva seu próprio docker-compose.yml? Mas todos os nossos projetos se comunicam através da API, todos eles usam a pilha de tecnologia padrão: nginx + php-fpm + mysql.
Portanto, vamos esclarecer as condições do problema:
- Trabalhamos em uma empresa, em equipe, acompanhamos vários projetos de combate. Todos nós trabalhamos com o Ubuntu + PhpStorm
- Para desenvolvimento local, queremos usar a janela de encaixe, para ter o mesmo ambiente de desenvolvimento para cada membro da equipe e também para que, quando um novo desenvolvedor chegar, ele possa implantar rapidamente um ambiente de trabalho.
- Queremos desenvolver com conforto, queremos estrear tudo: aplicativos da web, scripts de console e solicitações de API.
Mais uma vez: queremos trazer
vários projetos de trabalho para a janela de encaixe.
Em servidores de combate, o pacote nginx + php-fpm + mysql padrão é usado. E qual é o problema?
Implementamos exatamente o mesmo ambiente + Xdebug na máquina local, configuramos nossos projetos no PhpStorm e trabalhamos. Para depuração, ligue o "tube" no PhpStorm, tudo funciona imediatamente, tudo está bem.

Tudo isso é verdade - tudo funciona imediatamente. Mas, vamos tentar olhar sob o capô do nosso ambiente de trabalho.
O Nginx + php-fpm se comunica através do soquete, o xdebug escuta na porta 9000, o PhpStorm também, por padrão, escuta na porta 9000 a depuração e tudo parece estar bem. E se tivermos vários aplicativos abertos no PhpStorm, e a escuta telefônica ("tubo)" estiver ativada para vários aplicativos? O que o PhpStorm fará? Ele começará a jurar que uma nova conexão para o Xdebug foi detectada, você deseja ignorá-la ou não?
Ou seja, com as configurações padrão do PhpStorm, em um determinado momento, posso iniciar apenas um aplicativo. Para todos os outros aplicativos abertos, a depuração deve estar desativada. Porra, mas é inconveniente. Quero ouvir todos os aplicativos para depuração e, se houver um ponto de interrupção em um deles, quero que o PhpStorm pare nesse aplicativo, na linha em que eu preciso.
E o que é necessário para isso? Mas você precisa que cada aplicativo inicie com suas próprias configurações para o Xdebug. Para que cada aplicativo ouça sua porta, procure seu servidor e não como se tivéssemos tudo em comum, tudo de uma só vez.
E para isso, há uma estivadora maravilhosa! Podemos iniciar cada um de nossos aplicativos de combate em um contêiner separado, com base em uma imagem comum, por exemplo, php: 7.1-fpm. Graças à tecnologia docker, podemos isolar nossos aplicativos com o mínimo de sobrecarga.
Ok, vamos começar nossos projetos de combate na janela de encaixe, executar cada projeto em um contêiner separado, configurar cada projeto no PhpStorm para depurar individualmente, tudo deve ficar bem.
E, opa, o primeiro problema: os contêineres na janela de encaixe são executados como raiz e, localmente, trabalhamos, geralmente como um usuário com uid 1000, gid 1000. Os aplicativos estão lutando, e dar a cada aplicativo 777 direitos sobre tudo não é uma opção. Nossas aplicações estão sob o git, e se dermos os direitos 777 localmente, o git registrará tudo isso e o transferirá para o servidor de batalha.
Muletas, aqui está um exemplo de imagem php: 7.1-fpm que será compilada.
Update
Como a comunidade corretamente apontou, não há absolutamente nenhuma necessidade de se segurar.
Por exemplo, 1novrovert
habrozer no comentárioExemplo inicial de imagem php: 7.1-fpm (uid e gid são codificados)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:
Exemplo corrigido do 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"]
Ao iniciar um contêiner a partir desta imagem, o usuário www-data obtém uid = 1000, gid = 1000. Normalmente, o primeiro usuário criado no Linux possui esses direitos. E, exatamente com esses direitos, nossos contêineres php-fpm funcionarão. Ficaria muito grato se alguém me dissesse como trabalhar sem muletas com direitos de acesso à janela de encaixe.Ao iniciar um contêiner a partir desta imagem, o usuário www-data fica uid e gid, que será transferido de fora.
Também nos comentários, o tópico foi levantado : por que alterar os direitos do usuário www-data, por que os direitos padrão não se adequam a 33. Apenas uma coisa: quando entrarmos no contêiner e criarmos, por exemplo, um arquivo de migração, não seremos o proprietário do arquivo na máquina host. E cada vez será necessário executar algo como
sudo chown -R user:user ./
E o segundo pequeno problema: para que o Xdebug funcione corretamente, você deve registrar o endereço IP correto para a máquina host. Cada membro da equipe é diferente. 127.0.0.1 não rola. E aqui o próprio estivador vem em nosso auxílio. Por exemplo, podemos configurar explicitamente a rede - 192.168.220.0/28. E então nossa máquina sempre terá o endereço 192.168.220.1. Usaremos esse endereço para configurar o PhpStorm, bem como para configurar outros aplicativos. Por exemplo, ao trabalhar com o MySql.
O próprio Docker-compose.yml, depois de considerar os comentários, fica assim:
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:
Vemos que nesta configuração são criados dois contêineres php71-first e php71-two, com base em uma imagem php: 7.1-fpm. Cada contêiner possui suas próprias configurações para o Xdebug. Cada contêiner individual escutará, para depuração, sua porta e seu servidor.
Além disso, chamo sua atenção para as diretrizes
args: - USER_ID - GROUP_ID
Sem essas variáveis, a imagem php-fpm não será iniciada. Pergunta: como passá-los para o docker-compose.yml? Resposta: como é mais conveniente para você. Você pode na inicialização:
USER_ID=$(id -u) GROUP_ID=$(id -g) docker-compose up -d
Você pode gravar essas variáveis no arquivo .env, que fica no mesmo nível do arquivo docker-compose.yml
USER_ID=1000
GROUP_ID=1000
Eu gosto mais da versão com o arquivo .env. Claro, você pode usar o Makefile. Como você gosta mais.
O código completo da versão demo está publicado no
github .
Listagem do projeto de demonstração:

Consulte brevemente a lista do projeto.
Aliases -> php71 -> diretório bash.bashrc. Momento controverso. Prefiro me comunicar com contêineres php-fpm por meio de aliases.
Este arquivo é encaminhado para docker-compose.yml: - ./aliases/php71/bash.bashrc:/etc/bash.bashrc
Ferramenta padrão do Linux.
O diretório hosts - arquivos de configuração para o Nginx. Cada configuração possui seu próprio contêiner php-fpm. Um exemplo:
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)(/.+)$;
O diretório images - instruções para montar imagens php-fpm, o diretório mysql - armazena bancos de dados, o diretório www - todos os nossos projetos web, em nosso exemplo first.loc e two.loc.
Vamos resumir os resultados intermediários : usando os recursos da janela de encaixe, lançamos todos os nossos projetos de trabalho em um ambiente. Todos os nossos projetos se vêem, configurações exclusivas para o Xdebug são registradas para cada um dos projetos.
Resta configurar corretamente o PhpStorm para cada um dos projetos. Ao configurar, devemos registrar a porta para depuração e o nome do servidor em vários locais.
Crie um projeto no PhpStorm



Vamos configurar as seções do menu
- PHP (você deve registrar corretamente o interpretador CLI),
- Depuração (altere a porta para 9008, como no arquivo docker-compose.yml),
- proxy DBGp (chave IDE, host, porta),atualizar Obrigado ao
navegador do hub CrazyLazy pelo ponto importante. O item de menu proxy DBGp não precisa ser configurado.
- Servidores (você deve especificar corretamente o nome do servidor, como no arquivo docker-compose.yml, e usar mapeamentos de caminho)

Vou esconder todas as outras capturas de tela sob o spoiler.
Configurando o interpretador da CLI a partir do arquivo docker-compose.yml Configure a seção do menu DebugNovamente, prescrevemos tudo, desde as configurações do docker-compose.yml para um contêiner específico. Na mesma etapa, validamos como nossa depuração funciona.


Configure a seção do menu ServidoresÉ importante registrar corretamente o uso de mapeamentos de caminhos, novamente pegamos o nome do servidor nas configurações


Deixamos a seção do menu Arquivo -> Configurações, vá para a seção do menu Executar -> Editar configuração, crie uma página da Web Php Bem, isso é tudo. Está escrito muitas letras, parece que tudo não é fácil
De fato, o principal é entender uma coisa muito simples. Graças à tecnologia docker, podemos executar todos os nossos aplicativos de trabalho em um único espaço, mas com configurações diferentes para o Xdebug. Cada aplicativo funciona em seu próprio contêiner, e precisamos prescrever cuidadosamente as configurações de cada aplicativo no PhpStorm.
E na saída temos uma imagem maravilhosa.
1. Clonamos um repositório no
github . Crie um arquivo .env com variáveis
USER_ID= uid
GROUP_ID= gid
2. Registramos os nós first.loc e two.loc no arquivo / etc / hosts
127.0.0.1 first.loc 127.0.0.1 two.loc
3. Na pasta git, execute o
docker-compose up -d
4. Configuramos os dois projetos first.loc e two.loc no PhpStorm, conforme descrito acima, e executamos os dois projetos no PhpStorm. I.e. temos duas janelas PhpStorm abertas, com dois projetos, cada um deles escutando as conexões de entrada (o telefone está ligado).
5. No projeto two.loc, colocamos um ponto de interrupção na segunda linha, por exemplo. No primeiro projeto first.loc, iniciamos a solicitação http a partir do arquivo http.http
E eis que eis! Somos lançados no segundo projeto, no nosso ponto de interrupção.
Para depurar scripts do console, fazemos exatamente a mesma coisa. Ativamos a escuta telefônica para escutas telefônicas, definimos um ponto de interrupção, vamos para o contêiner certo, executamos o script certo.
Algo como:
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$
Onde php71first é o alias na máquina host:
alias php71first="cd ~/docker_git && docker-compose exec php71-first bash"
cdf
- um alias que funciona em um contêiner. Eu escrevi acima que prefiro usar aliases para se comunicar com contêineres.
Isso é tudo, críticas construtivas, comentários são bem-vindos.
PS: Gostaria de expressar minha profunda gratidão a Denis Bondar por seu artigo
PhpStorm + Docker + Xdebug , que foi o ponto de partida para escrever este tutorial.