Ambiente PHP e Ngnix com Docker

Há alguns dias atrás precisei criar ou recriar um ambiente PHP semelhante ao ambiente de produção, em produção era utilizado o PHP na versão 7.2, com o Nginx na versão 1.14.0 e também o PHP-FPM que é o cara responsável por interpretar o código PHP já que o Nginx não consegue fazer isso, mais isso tudo diretamente pelo sistema usando unix sockets, tudo instalado diretamente no sistema.
Porém tive algumas dificuldades para criar o ambiente usando o fastcgi e então resolvi escrever este artigo para ajudar outras pessoas que venham a precisar e também para o meu eu do futuro que pode vir a precisar fazer algo semelhante.
Dockerfile
Bem, primeiro precisamos criar um Dockerfile na raiz do projeto para termos uma imagem com o nosso projeto php, e já com o php-fpm. Podemos ter o Dockerfile o seguinte conteúdo:
FROM php:7.2.24-fpm
COPY . /var/www/html
WORKDIR /var/www/html
RUN chmod -R 777 /var/www/html
EXPOSE 9000
CMD ["php-fpm"]
Explicando o Dockerfile
  • FROM php:7.2.24-fpm: Com isso vamos ter uma imagem com o php-fpm na versão 7.2.24.

  • COPY . /var/www/html: Aqui fazemos a cópia de todos os arquivos do projeto (.) para a pasta /var/www/html do container.

  • WORKDIR /var/www/html: E precisamos mudar o diretório de trabalho para que seja o primeiro e consigamos ter acesso aos arquivos nesse container.

  • RUN chmod -R 777 /var/www/html: Esse comando é para evitar possíveis erros caso o projeto precise criar ou gerenciar arquivos dentro do container.

  • EXPOSE 9000: Aqui liberamos a porta 9000 para podermos acessar de fora, ou no caso em outros conatiners.

  • CMD ["php-fpm"]: Por fim, executamos o php-fpm.

  • docker-compose
    Agora que temos o Dockerfile, precisamos criar um docker-compose.yml na raiz do projeto para usarmos o Dockerfile criado anteriormente. E nesse docker-compose temos o seguinte conteúdo:
    version: '3.7'
    
    services:
      php:
        build:
          context: .
          dockerfile: Dockerfile
        container_name: dev-site
        volumes:
          - ./nginx/php-fpm.conf:/etc/php/7.2/fpm/php-fpm.conf
        networks:
          - site-network
    
      nginx:
        image: nginx:1.14.0
        container_name: dev-nginx
        ports:
          - "8001:80"
        volumes:
          - ./nginx/nginx.conf:/etc/nginx/nginx.conf
          - ./nginx/sites.conf/:/etc/nginx/conf.d/default.conf
        command: [ nginx-debug, '-g', 'daemon off;' ]
        networks:
          - site-network
    
    networks:
      site-network:
        driver: bridge
    Explicando o docker-compose
  • services: Temos dois serviços, um para o PHP e o outro para o Nginx.

  • Serviço php: Nesse bloco fazemos o build na imagem a partir do nosso Dockerfile criado anteriormente. Adicionamos um nome ao container para facilitar a utilização do mesmo. Também fizemos um bind do arquivo de configuração do php-fpm (php-fpm.conf) para o container. E por fim adicionamos a rede que é criada no bloco networks que é o último bloco do arquivo para podermos fazer a comunicação entre ambos os containers.

  • Serviço Nginx: Nesse bloco usamos uma imagem pronta do Nginx na versão 1.14.0 que é a versão que estava sendo executada em produção, também adicionamos um nome para facilitar o uso. E liberamos a porta 8001 da máquina para a porta 80 do container, isso porque podemos já utilizar a porta 80 da máquina por algum outro motivo. E adicionamos os volumes, na verdade fazemos apenas o bind do nginx.conf e do sites.conf que ambos estão dentro da pasta nginx na raiz do projeto com o /etc/nginx/nginx.conf e /etc/nginx/conf.d/default.conf respectivamente. Você pode estar se perguntando sobre esses arquivos, mas calma, ainda vamos ver esses arquivos mais adiante. Também executamos um comando para habilitar o modo de debug do nginx para podemos ver possíveis problemas quando executarmos o mesmo. E por fim a rede para comunicação com o container PHP.

  • networks: Criamos esse bloco apenas para criar a rede e conseguimos comunicar ambos os containers.

  • Nginx.conf
    Como você deve ter visto anteriormente fazemos o bind da configuração do Nginx, isso porque nossa configuração pode ser diferente da configuração default. Mas nesse ponto mantive quase a mesma configuração do Nginx:
    user  nginx;
    worker_processes  auto;
    
    error_log  /var/log/nginx/error.log notice;
    pid        /var/run/nginx.pid;
    
    load_module modules/ngx_http_image_filter_module.so;
    
    events {
        worker_connections  1024;
    }
    
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
    
        access_log  /var/log/nginx/access.log  main;
    
        sendfile        on;
        keepalive_timeout  65;
    
        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
    }
    Não vou entrar muito nessa parte de configuração do Nginx porque penso que foge um pouco do escopo deste artigo.
    Sites
    E chegamos a outro ponto importante de toda essa configuração que é a comunicação entre o Nginx e o php-fpm, e essa configuração pode ser feita de duas formas.
    Proxy reverso
    A primeira forma é usando o proxy reverso do Nginx, e para isso utilizamos o proxy_pass para encaminhar a requisição para o nosso outro container.
    Então naquele arquivo sites.conf que fizemos o bind para o container:
    - ./nginx/sites.conf/:/etc/nginx/conf.d/default.conf
    Teríamos o seguinte conteúdo:
    upstream container {
        least_conn;
        server dev-site:9000;
    }
    
    server {
        listen 80;
        location / {
            proxy_pass http://container;
        }
    }
    Explicando: Aqui criamos um upstream com o nome container, e esse basicamente aponta para o nosso container, que pode ser acessado usando o nome que criamos lá no docker-compose dev-site e indicando a porta 9000 que foi a porta que liberamos no container (EXPOSE 9000). E em seguida, no bloco server passamos para o proxy_pass o upstream criado acima porém usando o HTTP, isso porque aqui estamos enviando via HTTP.
    Fastcgi
    A outra forma, e nesse caso a mais interessante é usando o fastcgi que é um protocolo para a comunicação entre o PHP e o Nginx. Também não vou entrar nesse foco aqui. Teremos a seguinte configuração naquele arquivo sites.conf (no lugar da configuração anterior):
    server {
        listen 80;
    
        root /var/www/html;
    
        location / {
            include fastcgi_params;
            fastcgi_pass dev-site:9000;
            fastcgi_param SCRIPT_FILENAME $document_root/index.php;
        }
    }
    Nesse caso não teremos o upstream, apenas o bloco server e os pontos importantes aqui são as linhas:
  • include fastcgi_params;: que inclui os outros parâmetros, que ficam no arquivo fastcgi_params dentro dos arquivos de configuração do Nginx.

  • fastcgi_pass dev-site:9000;: Essa linhas é responsável pelo direcionamento das requisições para o php-fpm, por isso indicamos o nome e a porta do nosso container do php dev-site:9000.

  • fastcgi_param SCRIPT_FILENAME $document_root/index.php;: E aqui indicamos qual o arquivo deve ser executado no container do php.

  • Conclusão
    Agora é só subir os containers usando o comando docker-compose up estando dentro da pasta do projeto e logo em seguida acessar o endereço http://localhost:8001 no navegador.

    28

    This website collects cookies to deliver better user experience

    Ambiente PHP e Ngnix com Docker