O Docker revolucionou a forma como desenvolvemos e implantamos aplicações, e com PHP não é diferente. Nesta aula, você vai aprender a configurar um ambiente PHP profissional usando Docker, com foco na imagem PHP-FPM, que é a base para servidores web modernos como Nginx. Vamos explorar como o docker-compose simplifica a orquestração de múltiplos serviços, como volumes garantem a persistência e sincronização de arquivos, e quais boas práticas adotar para manter seu ambiente limpo, seguro e eficiente.

Se você já tem alguma familiaridade com Docker, esta aula vai aprofundar seu conhecimento em um cenário específico de PHP. Se é iniciante, não se preocupe: começaremos com uma visão geral e depois avançaremos para exemplos práticos que você pode aplicar imediatamente. Ao final, você terá um ambiente de desenvolvimento PHP containerizado, pronto para usar.

Imagem PHP-FPM

A imagem oficial do PHP no Docker Hub oferece várias variantes, e uma das mais importantes é a PHP-FPM (FastCGI Process Manager). O PHP-FPM é um daemon que gerencia processos PHP, permitindo que servidores web como Nginx ou Apache processem scripts PHP de forma eficiente. Em vez de embutir o PHP no servidor web, usamos o PHP-FPM como um serviço separado, o que melhora o desempenho e a escalabilidade.

No Docker, a imagem php:8.2-fpm (ou outra versão) já vem com o PHP-FPM configurado e pronto para executar. Mas você pode precisar de extensões adicionais, como pdo_mysql, mysqli, gd, entre outras. A imagem oficial é enxuta, e você deve instalar as extensões necessárias via Dockerfile ou usando um script de instalação. Vamos ver um exemplo de Dockerfile que estende a imagem PHP-FPM e adiciona algumas extensões comuns:

FROM php:8.2-fpm

RUN apt-get update && apt-get install -y \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install pdo_mysql mysqli zip gd

Neste Dockerfile, usamos os comandos docker-php-ext-configure e docker-php-ext-install que são fornecidos pela imagem oficial do PHP. Eles simplificam a instalação de extensões. Além disso, instalamos algumas bibliotecas do sistema necessárias para essas extensões. Ao construir uma imagem personalizada, você garante que seu ambiente tenha exatamente as extensões que sua aplicação precisa, sem comprometer o tamanho da imagem.

docker-compose (visão geral)

O docker-compose é uma ferramenta que permite definir e gerenciar múltiplos containers como uma única aplicação. Com um arquivo docker-compose.yml, você pode configurar serviços (como PHP-FPM, Nginx, MySQL), redes, volumes e outras opções de forma declarativa. Isso é fundamental para projetos PHP, pois normalmente precisamos de um servidor web, o PHP-FPM e um banco de dados.

Um exemplo típico de docker-compose.yml para um projeto PHP com Nginx e MySQL seria:

version: '3.8'

services:
  php:
    build: .
    volumes:
      - ./src:/var/www/html
    networks:
      - app-network

  nginx:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php
    networks:
      - app-network

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: myapp
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - app-network

volumes:
  db_data:

networks:
  app-network:
    driver: bridge

Neste arquivo, definimos três serviços: php (build a partir do Dockerfile), nginx (servindo a aplicação) e db (MySQL). O serviço php não expõe portas, pois é interno; o Nginx é quem recebe as requisições e as encaminha para o PHP-FPM via FastCGI. O volume ./src é montado em ambos os serviços para que o código seja compartilhado. O Nginx depende do PHP para funcionar, e o MySQL tem seu próprio volume para persistência de dados.

Volumes

Volumes são o mecanismo do Docker para persistir dados e compartilhar arquivos entre o host e os containers ou entre containers. No contexto PHP, usamos volumes para montar o código-fonte da aplicação dentro do container, permitindo que alterações no host sejam refletidas imediatamente (útil em desenvolvimento). Também usamos volumes para armazenar dados de banco de dados, logs ou arquivos de upload.

Existem dois tipos principais de montagem: bind mounts e named volumes. Um bind mount é quando você especifica um caminho do host, como ./src:/var/www/html. Isso é ótimo para desenvolvimento, pois você edita os arquivos no seu editor e o container vê as mudanças. Um named volume é gerenciado pelo Docker e é ideal para dados que precisam persistir, como o banco de dados. No exemplo anterior, db_data é um named volume.

Em ambientes de produção, você deve ter cuidado com volumes: não monte o código-fonte como bind mount, pois isso pode reduzir a portabilidade e a segurança. Em vez disso, copie o código para a imagem no build. No desenvolvimento, o bind mount é essencial para produtividade.

Boas práticas

Ao usar Docker com PHP, siga estas boas práticas para garantir um ambiente eficiente e seguro:

  • Use imagens oficiais e específicas: prefira php:8.2-fpm em vez de tags latest para garantir consistência.
  • Instale apenas as extensões necessárias: isso reduz o tamanho da imagem e a superfície de ataque.
  • Não rode o container como root: crie um usuário com permissões restritas no Dockerfile.
  • Use .dockerignore: para evitar copiar arquivos desnecessários (como .git, node_modules) para a imagem.
  • Separe ambientes: use arquivos docker-compose diferentes para dev e prod (ex.: docker-compose.override.yml).
  • Gerencie variáveis de ambiente: use arquivos .env e referencie no docker-compose.

Um exemplo de Dockerfile com usuário não-root:

FROM php:8.2-fpm

# ... instalação de extensões ...

RUN useradd -m -u 1000 -s /bin/bash developer
USER developer

WORKDIR /var/www/html

Lembre-se de que o Nginx precisa acessar os arquivos, então o usuário do PHP-FPM deve ter permissão de leitura. Em muitos casos, você pode usar o mesmo UID do usuário do host para evitar problemas de permissão.

Referências

Exercícios

  1. Crie um Dockerfile que estenda a imagem php:8.1-fpm e instale as extensões pdo_mysql e redis. Explique os comandos usados.

    ✓ Resposta:
    FROM php:8.1-fpm
    RUN apt-get update && apt-get install -y libzip-dev \
        && docker-php-ext-install pdo_mysql \
        && pecl install redis && docker-php-ext-enable redis
    O comando docker-php-ext-install instala a extensão pdo_mysql. Para redis, usamos o PECL para compilar e instalar, e depois habilitamos com docker-php-ext-enable.
  2. Escreva um arquivo docker-compose.yml que defina os serviços php (build local) e nginx (imagem nginx:alpine) com um volume compartilhado para o código em ./app. O Nginx deve expor a porta 8080.

    ✓ Resposta:
    version: '3.8'
    services:
      php:
        build: .
        volumes:
          - ./app:/var/www/html
      nginx:
        image: nginx:alpine
        ports:
          - "8080:80"
        volumes:
          - ./app:/var/www/html
          - ./nginx.conf:/etc/nginx/conf.d/default.conf
        depends_on:
          - php
  3. Explique a diferença entre bind mount e named volume e dê um exemplo de uso para cada um em um projeto PHP.

    ✓ Resposta: Bind mount é uma montagem de um diretório do host no container, como ./src:/var/www/html. É útil em desenvolvimento para sincronizar código. Named volume é um volume gerenciado pelo Docker, como db_data, usado para persistir dados do banco de dados, independente do ciclo de vida do container.
  4. Quais são pelo menos três boas práticas ao construir imagens Docker para PHP? Justifique cada uma.

    ✓ Resposta: 1) Usar tags específicas de imagem (ex.: php:8.2-fpm) para reprodutibilidade. 2) Instalar apenas extensões necessárias para reduzir o tamanho e vulnerabilidades. 3) Executar o container como usuário não-root para segurança. 4) Usar .dockerignore para evitar copiar arquivos desnecessários.
  5. Monte um ambiente docker-compose completo com PHP-FPM, Nginx e MySQL, incluindo volumes para o código e para o banco. Escreva o arquivo docker-compose.yml e explique a função de cada serviço.

    ✓ Resposta:
    version: '3.8'
    services:
      php:
        build: .
        volumes:
          - ./src:/var/www/html
        networks:
          - app-net
      nginx:
        image: nginx:alpine
        ports:
          - "8080:80"
        volumes:
          - ./src:/var/www/html
          - ./nginx.conf:/etc/nginx/conf.d/default.conf
        depends_on:
          - php
        networks:
          - app-net
      db:
        image: mysql:8.0
        environment:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: myapp
        volumes:
          - db_data:/var/lib/mysql
        networks:
          - app-net
    volumes:
      db_data:
    networks:
      app-net:
    O serviço php executa o PHP-FPM e monta o código. O nginx recebe as requisições HTTP e as encaminha para o PHP. O db fornece o MySQL com persistência em volume.

Observações finais

Dominar Docker com PHP é uma habilidade essencial para o desenvolvimento moderno. Nesta aula, você aprendeu a configurar a imagem PHP-FPM, a orquestrar serviços com docker-compose, a usar volumes para persistência e a aplicar boas práticas. Agora, pratique criando um ambiente completo para um projeto real, experimente adicionar serviços como Redis ou Mailhog, e explore como o Docker pode melhorar seu fluxo de trabalho.