Ambiente de desenvolvimento PHP com Docker

Rodrigo Vieira
OperacionalTI
Published in
6 min readNov 27, 2017
Photo by Luca Bravo on Unsplash

Importante: este post foi atualizado e movido para https://rodrigodelimavieira.com.
Novos posts só serão feitos nesta nova plataforma.

Nesse artigo eu faço uma abordagem pragmática de como rodar uma aplicação web sobre três containers Docker: nginx, php-fpm e mysql.

Motivação

Executar projetos PHP em um ambiente padronizado, em qualquer computador, com o menor esforço possível para configurar esse ambiente de desenvolvimento e sem interferir nas configurações do sistema operacional instalado.

Você deve ter pensado em máquinas virtuais, mas apesar delas resolverem o problema, quando comparada aos containers são um grande desperdício de recursos [1].

Requisitos

  • Precisamos do Docker engine[2] instalado para rodar os containers.
  • Se você não tem conhecimento algum algum sobre Docker ou containers, sugiro o Quick Start oficial. Leia antes ou depois desse artigo, mas leia.

A aplicação

Como prova de conceito vamos executar um simples script php que consulta registros em um banco de dados MySQL e os exibe ao usuário. A aplicação é extremamente simples, o suficiente para exemplificar os conceitos do Docker, não sendo o foco desse artigo.

https://github.com/rodrigoSyscop/dockerarticle

# Clona o repositório da aplicação para a sua máquina
git clone https://github.com/rodrigoSyscop/dockerarticle

Será criada a pasta dockerarticle com o seguinte conteúdo:

dockerarticle
├── app
│ └── index.php
├── docker-compose.yml
├── mysql
│ └── initial_data
│ └── blog_2017-11-18.sql
├── nginx
│ └── nginx.conf
└── php
└── Dockerfile
  • Arquivo docker-compose.yml, o arquivo principal da infraestrutura da nossa aplicação.
  • O código fonte da aplicação eu optei por colocar na pastaapp.
  • Uma pasta para cada serviço (ou container) que iremos executar: nginx, php e mysql.

Perceba que o código fonte da aplicação está contido apenas na pasta app, o restante é código da infraestrutura (infrastructure as code).

Colocar o código fonte da infraestrutura junto com o código da aplicação é uma boa prática introduzida pela cultura DevOps. Deixando todas as equipes envolvidas cientes das alterações realizadas tanto na infra, quanto na aplicação.

Docker Compose

O compose é uma ferramenta do Docker a qual possibilita definirmos uma aplicação composta por diversos serviços (ou microserviços), cada um deles executado em seu próprio container.

Se não estiver especificado no docker-compose.yml, o Docker irá referenciar sua aplicação pelo nome da pasta onde o arquivo estiver armazenado. No nosso caso dockerarticleserá o nome da aplicação:

dockerarticle
└── docker-compose.yml

Veja o conteúdo desse arquivo:

Ao executardocker-compose up, serão exibidas uma série de mensagens relacionadas ao docker baixando as imagens dos containers pela primeira vez. Depois disso, executar seus containers será tão rápido quanto abrir qualquer outro aplicativo na sua máquina:

docker-compose up

Durante a primeira execução do container mysql, a estrutura inicial do banco de dados será criada em /var/lib/mysql:

docker-compose up (cont.)

Ter essa pasta dentro do container não é nada eficiente devido a forma como o aufs funciona, o sistema de arquivos padrão do Docker. Por esse motivo montamos esse diretório em um volume fora do container, o db_data definido do arquivo docker-compose.yml.

Se tudo deu certo até aqui, ao acessar http://localhostno seu browser você verá:

index.php

Nota: o problema mais comum nesse ponto é o container nginx não levantar pois ele tenta mapear a porta 80 do host que já pode estar em uso por outro serviço. Neste caso basta mudar o mapeamento das portas de "80:80" no container nginx para algo como "8080:80", executar o "compose up" novamente e acessar http://localhost:8080 no seu browser.

Ao mesmo tempo que você acessa a aplicação pelo browser, as seguintes mensagens de log são exibidas no mesmo terminal onde o docker-compose up foi executado:

logs do docker-compose up

Perceba que as mensagens de todos os containers (ou serviços) da sua aplicação estão agrupadas e recebem um prefixo colorido para ajudar a identificar de qual container elas vieram.

Entendendo o docker-compose.yml

Começamos especificando a versão do compose que foi utilizada, isso faz diferença para as instruções que podem ser utilizadas e que são reconhecidas pelo Docker, de acordo com a versão. Em seguida definimos os três serviços que compõem a aplicação:

  1. Nginx
    O nginx tem como base a imagem oficial nginx[3] em sua versão 1.13. Se a imagem não for encontrada na sua máquia, o Docker fará o download dela automaticamente.
    Também especificamos dois volumes, o primeiro para que o código fonte da aplicação seja montado na pasta /var/www/html dentro do container. O segundo para utilizar um arquivo de configuração personalizado, no lugar do arquivo nginx.conf padrão da imagem.
    Por fim especificamos que a porta 80 do host será mapeada para a porta 80 do container, além da dependência que esse container possui do container php.
  2. PHP
    A novidade aqui é que não especificamos uma imagem base, mas sim uma instrução build. Isso quer dizer que uma imagem personalizada será contruída a partir do arquivo Dockerfile presente na pasta ./php. Essa personalização foi necessária para podermos instalar as extensões mysqli e pdo_mysql do PHP, as quais não estão presentes na imagem base oficial. Com essa instrução o docker irá criar nossa imagem personalizada, com as extensões necessárias, a partir da imagem oficial php, referenciada no Dockerfile. Isso acontece somente na primeira execução.
    Outra novidade é a definição de variáveis de ambiente MYSQL_USER e MYSQL_PASS que serão utilizadas pelo script php dentro do container.
    Nota: para informações sensíveis, como senhas, é recomendável definir variáveis de ambiente através de arquivos .env[5].
  3. MySQL
    Já o container do serviço de banco de dados, baseado na imagem oficial mysql[6], as novidades ficam por conta do volume de dados, que é mapeado para um volume gerenciado pelo docker db_data, além do arquivo blog_2017-11-18.sql que está na pasta initial_data do projeto, mapeada para uma pasta especial dentro do conteiner mysql: docker-entrypoint-initdb.d. A imagem oficial do container mysql verifica essa pasta e qualquer arquivo .sql que estiver nela será automaticamente importado durante a primeira inicialização do container.
blog_2017-11-18.sql

Comandos úteis

Para executar os comandos abaixo, você deve estar dentro da pasta do projeto, a pasta dockerarticle:

# lista os containers dessa aplicação
docker-compose ps
# acessa o terminal do container php
docker container exec -it dockerarticle_php_1 bash
# para os containers
docker-compose stop
# para e remove os containers
docker-compose down

Perceba que o comando ps fax foi executado dentro do container php. Os processos exibidos estão isolados no container pelo Docker engine.

Finalizando

O docker é uma baita ferramenta para padronização de ambientes de desenvolvimento. Além disso esse mesmo ambiente poderá ser aplicado em produção, alterando somente as variáveis de ambiente em que os containers serão executados.

Ainda temos alguns pontos para melhorar antes de aplicarmos esse ambiente em produção:

  • Personalização da imagem.
  • Registro de logs fora do filesystem do container
  • Variáveis de ambiente em arquivos .env.
  • Cluster swarm.

Pretendo abordar esses tópicos nos meus próximos artigos sobre Docker. Fique de olho.

--

--