Impulsojunte-se à Impulso
Docker e Docker Compose com PHP

15/04/21

8 min de leitura

Docker e Docker Compose com PHP

Docker e Docker Compose com PHP

Márcio AlbuquerqueMárcio Albuquerque

Contêineres chegaram para ficar no universo da tecnologia, independentemente da sua especialidade. Para quem não conhece, eles são um conjunto de desenvolvimento de software em que todas as configurações são empacotadas como uma imagem de contêiner. Ou seja, uma unidade pode conter diferentes dependências ou códigos. Isso significa que é muito mais fácil de usa e abre caminho para um processo de configuração mais rápido 😃

E hoje, dentro deste universo, o Docker é a principal tecnologia de contêineres do mercado. Pensando nisso, preparei este artigo para contar mais sobre esse sistema e como usá-lo como ambiente de desenvolvimento de PHP.

Algumas introduções

Como é um assunto longo e complexo, também separei alguns tutoriais para quem nunca teve contato com esses softwares:

E para fazer a instalação correta, basta seguir os links abaixo:

Depois disso, com as ferramentas instaladas, basta rodar esses comandos para verificar se tudo deu certo e para confirmar quais são as versões adquiridas:

$ docker -v
Docker version 17.06.1-ce, build 874a737
$ docker-compose -v
docker-compose version 1.15.0, build e12f3b9

Agora, com tudo preparado, podemos começar e o primeiro arquivo que preciso apresentar é o docker-compose.yml, que define nossos serviços. De início, vamos trabalhar com PHP 7.1.11, Apache e MySQL.

1. docker-compose.yml

version: "3"
services:
    database:
        image: mysql:5.7.20
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: 12345
            MYSQL_DATABASE: usuarios
            MYSQL_USER: dbadmin
            MYSQL_PASSWORD: dbpassword
        volumes:
            - "data:/var/lib/mysql"
    webserver:
        image: webdevops/apache:alpine
        depends_on:
            - php
        ports: 
            - "80:80"
            - "443:443"
        volumes: 
            - ".:/var/www/html"
        environment:
            WEB_PHP_SOCKET: "php:9000"
            WEB_PHP_TIMEOUT: 600
            WEB_DOCUMENT_ROOT: "/var/www/html"
    php:
        image: mlalbuquerque/php:7.1
        build:
            context: ./dockerfiles
            dockerfile: php7.1.dockerfile
            args:
                - "UID=$UID"
                - "GID=$GID"
                - "USER=$USER"
        volumes:
            - ".:/var/www/html"
            - "./dockerfiles/config/php.ini:/usr/local/etc/php/php.ini"
            - "./dockerfiles/config/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini"
        environment:
            PATH: "/root/.composer/vendor/bin:${PATH}"
volumes:
    data:

Explicações sobre database

O principal uso aqui é por meio do MySQL.

  • Image – estou usando a imagem oficial do MySQL (mysql). Também, sempre prefiro especificar a tag em que estou trabalhando, pois assim saberei exatamente a versão do banco;
  • Restart – esta diretiva tem relação com o tratamento do serviço se ele parar abruptamente. Neste caso, ele sempre irá reiniciar. Se for uma parada explícita (por exemplo, você parando o serviço de propósito), ele não reinicia;
  • Environment – nesta entrada definimos variáveis de ambiente do serviço. Normalmente, são variáveis que serão usadas internamente pelo contêiner. Dessas acima, a única obrigatória mesmo é a MYSQL_ROOT_PASSWORD. Todas as outras são opcionais, mas mesmo assim eu configuro por questões de clareza. Assim, sabemos o nome do banco, o usuário e a senha a serem usadas pela infra, respectivamente definidas em MYSQL_DATABASEMYSQL_USER e MYSQL_PASSWORD;
  • Volumes – isso sempre é importante em serviços baseados em contêiner. Caso contrário, os dados se perdem quando o contêiner é parado ou destruído. No caso, esta única entrada em volumes é para definir a persistência dos dados do banco na máquina hospedeira (host). Na documentação da imagem, indica o endereço /var/lib/mysql como o local no contêiner ondes os dados serão guardados. Então, mapeando o volume data para este caminho, os dados serão persistidos no host e tudo ficara a cargo do próprio Docker. Mas lembre-se: quando mapeamos volumes, os dados que existem no contêiner serão apagados e sobrescritos pelos dados encontrados no host.

Explicações sobre webserver

O servidor de web, neste caso, é o Apache. Estou usando uma imagem não oficial, pois esta oferece variáveis de ambiente interessantes que facilitam a configuração do Apache.

  • Image – a imagem é do grupo WebDevOps. Conta com ótimas configurações, é bem estruturada e possui várias opções. Uso a versão do Alpine por ser bem menor (24MB) em comparação com outras baseadas em Debian (~90MB) ou Ubuntu (~110MB);
  • Depends_on – indica uma dependência deste serviço. Ou seja, o serviço webserver depende do serviço php. É necessário criar uma ordem para iniciar os serviços. Então o início só acontece depois que o serviço do qual ele depende já tiver iniciado;
  • Ports – define as portas mapeadas entre host e contêiner. A marcação é sempre na ordem HOST:CONTEINER. No caso, a porta 80 (http) do host, aponta para a porta 80 do contêiner. O mesmo vale para a porta 443 (https). Assim, podemos acessar este serviço pelo endereço http://localhost/ ou https://localhost/. Se não fizéssemos isso, teríamos que saber qual é o IP do contêiner para poder acessá-lo;
  • Volumes – esta é uma parte bem importante, pois o volume é criado a partir do mapeamento da pasta local (onde o arquivo docker-compose.yml se encontra) para a pasta /var/www/html do contêiner, que é a pasta configurada como Document Root do Apache. Com isso, todos os arquivos dentro da pasta do projeto podem ser servidos pelo Apache;
  • Environment – aqui temos 3 variáveis que nos ajudam a configurar o Apache. Podemos configurar como acessar o PHP via FPM (WEB_PHP_SOCKET), o timeout do PHP (WEB_PHP_TIMEOUT) e o Document Root do Apache (WEB_DOCUMENT_ROOT). Existem outras variáveis para serem usadas, se quiserem.

Explicações sobre php

Este é o serviço que define o PHP usado no ambiente. Neste caso, crio uma imagem nova que ainda não existe. E o Docker Compose sabe como tratar isso de forma bem simples. Fiz assim já para embutir extensões que normalmente uso, o Composer (programador PHP não tem como não saber o que é, né?) e o Git (o Composer depende dele e podemos usar pro projeto também).

Dentro da Image, você pode colocar o nome que quiser. Eu coloquei seguindo a regra do Docker: NAMESPACE/CONTEINER:TAG (mlalbuquerque/php:7.1). Além disso, também é importante mencionar o docker build. Como a imagem não existe localmente ou no Docker Hub, ele usa as informações abaixo para construir a imagem:

  • Context – pasta onde irá procurar pelos arquivos necessários para a build da imagem;
  • Dockerfile – caso o arquivo Dockerfile não tenha este nome, deve ter esta diretiva para dizer qual é o nome do arquivo. No caso, o arquivo é php7.1.dockerfile e ele se encontra dentro da pasta ./dockerfiles;
  • Args – esses são argumentos passados no momento da build (diretivas ARG dentro do Dockerfile). No caso, foram criados 3 argumentos (UIDGID e USER), que usam variáveis de ambiente do host ($UID$GID e $USER) como valores. Mas existe um porém: o Docker não tem acesso às variáveis $UID e $GID, portanto, podemos usar um arquivo .env (um arquivo estilo INI) para definir valores de variáveis de ambiente que não existem.

2. php7.1.dockerfile

ARG PHP_VERSION=7.1.11-fpm-alpine
ARG XDEBUG_VERSION=2.5.5
FROM php:${PHP_VERSION}
ARG UID=root
ARG GID=root
ARG USER

# Instalando extensões necessárias do PHP
RUN apk add --update --no-cache \
        alpine-sdk autoconf curl curl-dev freetds-dev \
        libxml2-dev jpeg-dev openldap-dev libmcrypt-dev \
        libpng-dev libxslt-dev postgresql-dev \
    && rm /var/cache/apk/*
RUN docker-php-ext-configure ldap --with-ldap=/usr
RUN docker-php-ext-configure xml --with-libxml-dir=/usr
RUN docker-php-ext-configure gd --with-jpeg-dir=/usr/include --with-png-dir=/usr/include
RUN docker-php-ext-install \
    bcmath calendar curl dom fileinfo gd hash json ldap mbstring mcrypt \
    mysqli pgsql pdo pdo_dblib pdo_mysql pdo_pgsql sockets xml xsl zip

# Instalando o XDebug
RUN pecl install xdebug-${XDEBUG_VERSION}
RUN docker-php-ext-enable xdebug

# Configurando o XDebug
RUN echo "xdebug.remote_enable = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.remote_autostart = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.connect_back = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

# Instalando o Git (Composer usa para baixar alguns pacotes)
RUN apk add --update --no-cache git && rm /var/cache/apk/*

# Instalando o Composer
RUN php -r "copy('http://getcomposer.org/installer', 'composer-setup.php');"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

# Setando o user:group do conteiner para o user:group da máquina host (ver arquivo .env e docker-compose.yml)
# Assim, o Composer passa a usar o mesmo user:group do usuário do host
# Configura também as pastas para o novo usuário
RUN chown -R ${UID}:${GID} /var/www/html
RUN chown -R ${UID}:${GID} /root/.composer
RUN mkdir -p /.composer && chown -R ${UID}:${GID} /.composer
RUN mkdir -p /.config && chown -R ${UID}:${GID} /.config
VOLUME /var/www/html
VOLUME /root/.composer
VOLUME /.composer
VOLUME /.config
USER ${UID}

3. .env

# Para uso no Docker
# USER => seu usuário do host
# UID => ID do seu usuário (para descobrir => $ id -u)
# GID => ID do seu grupo (para descobrir => $ id -g)
UID=1000
GID=888

Perceba que o arquivo .env serve para configurar variáveis de ambiente que não existem ou aqueles que o Docker não pode usar. A variável $USER tem acesso ao Docker, então não precisa setar. As outras precisam e serão substituídas no docker-compose.yml. Para ver o efeito, rode o comando abaixo e veja as substituições:

$ docker-compose config

Como estará na seção args da seção build do serviço php, serão usados como valores dos argumentos do Dockerfile php7.1.dockerfile (diretivas ARG nas linhas 4 a 6). Assim, a imagem será construída usando esses argumentos que estão em .env.

Neste momento, temos um ambiente com Apache 2.4, PHP 7.1 e MySQL 5.7, já com Composer e Git para ajudar no desenvolvimento do projeto. Agora, com tudo no seu lugar, basta rodar o comando abaixo para subir o ambiente:

$ docker-compose up

E caso queira subir apenas um dos serviços, basta seguir esses outros comandos:

$ docker-compose up database
$ docker-compose up webserver
$ docker-compose up php

Nesses casos, o log dos serviços fica no terminal. Se quiser deixar o terminal livre, basta colocar a diretiva -d depois de up:

$ docker-compose up -d

Prontinho!

Próximos passos

Depois de todo esse tutorial, é hora de colocar tudo isso em prática. Se tiver mais dúvidas sobre o assunto, tem um lugar perfeito para tirá-las com especialistas: na nossa comunidade do Discord! Lá você pode conversar com outras pessoas programadoras, conseguir respostas e criar uma rede de contatos devs. Não esqueça também de conferir outros artigos do nosso Blog e aprender mais alguns truques de programação 😉

Nós usamos cookies para melhorar sua experiência no site. Ao aceitar, você concorda com nossa Política de Privacidade

Assine nossa newsletter

Toda semana uma News com oportunidades de trabalho, conteúdos selecionados, eventos importantes e novidades sobre o Mundo da Tecnologia.

Pronto, em breve você vai receber novidades 👍