Introdução ao Docker Como Ambiente de Desenvolvimento Web — Parte 2

Esron Silva
sysvale
Published in
11 min readOct 17, 2018

Como utilizar o Docker como plataforma de desenvolvimento para aplicações Web com orquestramento de contêineres.

Esta é a segunda parte (e final) de uma série de artigos. Para ler a primeira parte acesse este link:

Lembrando que esta é uma abordagem em constante construção, sugestões e correções são sempre bem vindas.

No Artigo Anterior…

Na primeira parte aprendemos um pouco sobre o Docker, suas imagens e contêineres. Construímos nossa primeira imagem utilizando um Dockerfile e executamos um contêiner baseado nessa imagem.

$ docker run -it --rm vaquinha
________________________________
/ Never look up when dragons fly \
\ overhead. /
--------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
$ docker run -it --rm vaquinha "Mooo"
______
< Mooo >
------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||

Também aprendemos alguns comandos básicos utilizados no dia-a-dia do desenvolvimento com Docker.

## Listar Comandos Docker
docker
docker container --help

## Mostrar a versão do Docker e informações do sistema
docker --version
docker version
docker info

## Executar um contêiner
docker run hello-world

## Listar imagens
docker image ls

## Listar contêineres (rodando, todos)
docker ps
docker ps -a

Com a posse desses conhecimentos podemos, neste artigo, criar um ambiente para desenvolvimento Web utilizando contêineres.

Próximos Passos

Primeiro devemos criar uma imagem com os softwares necessários para desenvolver uma aplicação Web. Escolhemos, para este artigo, o framework Laravel pois, além de poderoso e versátil, é o que utilizamos na maioria dos projetos na Sysvale.

Na documentação do Laravel, são listadas as bibliotecas e a versão do PHP necessárias para que framework funcione. Também é necessário ter o npm e o Node.js, para compilar os arquivos JavaScript do nosso front-end.

Utilizaremos o servidor Apache para servir nossa aplicação compilada e realizar o balanço de carga.

Apenas por questões didáticas, juntaremos todos esses softwares em um único contêiner.

Depois da criação do contêiner da aplicação, vamos aprender um pouco sobre orquestramento de contêineres. A ferramenta oficial e recomendada pela documentação do Docker é o Docker Compose, que, de acordo com a documentação, é uma ferramenta para definição e execução de aplicações multi-contêineres.

Vamos utilizar as imagens oficiais do MySQL e Adminer (para diferentes configurações consulte a documentação neste link) para servir o banco de dados da nossa aplicação. Dessa forma, você pode facilmente trocar de banco de dados utilizando uma imagem diferente, uma instalação local, ou um serviço de banco de dados remoto.

Nosso Novo Dockerfile

Não se assuste, explicaremos em detalhes cada parte. Em resumo, estamos utilizando a imagem base ubuntu:16.04, e a partir dela, instalando todos os softwares necessários para executar uma aplicação Laravel. Além disso, configuramos o servidor Apache neste mesmo arquivo.

Nas primeiras linhas, estamos apenas atualizando as bibliotecas padrões para garantir que tenhamos um contêiner seguro:

FROM ubuntu:16.04LABEL Author="Esron Silva esron.silva@sysvale.com"ENV PATH ${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/binRUN apt-get update && apt-get upgrade -y

A linha ENV PATH ... configura uma a variável de ambiente do nosso contêiner.

Em seguida, instalamos um utilitário para adicionar e remover repositórios de pacotes de softwares (software-properties-common ), o servidor Apache, um utilitário para fazer requisições HTTP e um pacote de linguagem necessário para baixar a versão correta do PHP.

RUN apt-get install -y software-properties-common \ 
apache2 \
curl \
language-pack-en-base

Logo depois adicionamos o repositório do PHP, instalamos o próprio PHP e todas as bibliotecas recomendadas na documentação do Laravel:

# Add PHP ondrej repository
RUN LC_ALL=en_US.UTF-8 add-apt-repository ppa:ondrej/php
RUN apt-get update && apt-get upgrade -y
# Install php and its libraries
RUN apt -y install php7.2 \
php7.2-mbstring \
php7.2-xml \
php7.2-curl \
php7.2-mysql \
php7.2-pgsql \
php7.2-imagick \
php7.2-zip \
libxrender1 \
libfontconfig1 \
libxtst6

Este repositório PHP é especial, através dele é possível fazer o download de várias versões do PHP e utilizá-las no mesmo sistema operacional.

Nas linhas seguintes instalamos o nodejs, o npm e o utilitário n:

# Install nodejs and npm
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get install -y nodejs
RUN npm install -g n npm@latest
RUN n 8.*

O utilitário n nos permite transitar entre diferentes versões do npm.

Depois instalamos o composer, que é o gerenciador de pacotes PHP utilizado pelo Laravel:

# Install Composer
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php composer-setup.php --install-dir=/usr/local/bin --filename=composer
RUN php -r "unlink('composer-setup.php');"

Nas próximas linhas copiamos os scripts de configuração do Apache para o sistema de arquivos do nosso contêiner:

# Apachelinker script
COPY apachelinker.sh /usr/local/bin/apachelinker
# Apache config
RUN a2enmod rewrite
COPY apache.conf /etc/apache2/sites-enabled/000-default.conf

O primeiro script, apachelinker.sh , apresentado a seguir, é apenas um atalho para facilitar o link entre a pasta public do projeto Laravel e pasta publicada pelo servidor Apache.

O segundo script é a configuração do servidor Apache:

As linhas finais, abaixo, registram um terceiro script como “entrypoint” do nosso contêiner, ou seja, o script que será executado como padrão quando um contêiner da nossa imagem for instanciado. Esse script apenas registra os logs do servidor Apache e evita que o contêiner baseado em nossa imagem pare sua execução prematuramente. Um contêiner é encerrado quando o processo principal executado nele termina. A linha tail -f /tmp/dev.log mantém um processo ativo no contêiner, que registra na saída padrão os eventos ocorridos no servidor Apache. Esses eventos são úteis quando queremos corrigir algum bug nas requisições do servidor Apache.

Não podemos esquecer de modificar as permissões dos arquivos apachelinker.sh e entrypoint.sh para que eles se tornem executáveis:

$ sudo chmod +x apachelinker.sh entrypoint.sh

Para ter acesso aos logs mencionados acima, execute o comando:

$ docker logs web

Docker Compose

No artigo anterior, construímos nosso contêiner utilizando o comando docker build , porém, neste tutorial faremos algo um pouco diferente e mais elegante. Utilizaremos o Docker Compose. O Docker Compose é um software de orquestramento de contêineres, isso quer dizer que ele cria, destrói, executa e para contêineres a partir de comandos e arquivos de configuração. Escolhemos o Docker Compose por ser a ferramenta oficial do Docker.

As instruções para instalação do Docker Compose podem ser encontradas na documentação do Docker. Ele é compatível com os principais sistemas operacionais.

Sem o Docker Compose, os desenvolvedores seriam obrigados a memorizar os comando de execução dos contêineres, que geralmente dependem de muitos argumentos. Esta prática pode produzir erros ao executar comandos com argumentos errados.

Por exemplo, um comando Docker que executa um contêiner chamado web, mapeando sua porta 80 para a porta 8000 da máquina host e cria um volume no sistema de arquivos do contêiner seria assim:

$ docker run --name web -v /home/project/app/:/home/project-folder -p 80:8080

Neste tutorial, utilizaremos o arquivo descrito a seguir, chamado docker-compose.yml , que é um arquivo de configuração utilizado pelo Docker Compose para criar, executar e parar os contêineres.

Cada entrada no objeto services é a descrição de um contêiner. Isso nos permite conectar contêineres ao sistema de arquivo da máquina host, realizar o redirecionamento de portas, entre outras configurações. Tudo isso sem intermédio de comandos Docker grandes e complexos. Por exemplo, a primeira entrada em services , web , descreve nosso contêiner da aplicação Laravel, a instrução build diz que se a imagem do contêiner não existir, então existe um Dockerfile que deve ser usado para compilar essa imagem no mesmo diretório que o arquivo docker-compose.yml , descrito pelo valor . . A instrução volumes descreve os volumes que devem ser criados e mapeados para o sistema de aquivos do contêiner. A instrução ports descreve quais portas devem ser mapeadas, em nosso caso, a porta 80 do contêiner será mapeada para a porta 8000 da máquina host, ou seja, requisições que chegarem à porta 8000 da máquina host serão redirecionadas para a porta 80 do contêiner.

A segunda entrada, mysql , descreve o contêiner que estará executando nossa base de dados em MySQL. A instrução image informa ao Docker Compose em qual imagem será baseado esse contêiner. Caso ele não encontre a imagem localmente, automaticamente ele tentará baixá-la via docker pull . Na instrução command são passados argumentos para a inicialização do processo a ser executado no contêiner, em nosso caso, o servidor de banco de dados. A instrução restart: always informa ao Docker Compose que esse contêiner deve ser reiniciado sempre, ou seja, mesmo que ele já esteja executando ele será reiniciado. A instrução environment cria variáveis de ambiente no contêiner, nesse caso é configurada uma senha para o servidor de banco de dados MySQL através da variável MYSQL_ROOT_PASSWORD .

A ultima entrada, adminer , descreve o contêiner que será utilizado como SGDB (Software Gerenciador de Banco de Dados) do nosso projeto. Em resumo, é executado um serviço local na porta 8080 que disponibiliza o software SGDB Adminer.

Juntando as Partes

Você deve estar se perguntando, “Como eu vou iniciar um projeto Laravel sem ter o Composer instalado em minha máquina?”. Apesar de existir uma imagem oficial do Composer ela não é simples de ser utilizada, então, tomaremos um caminho mais simples, iremos baixar o projeto direto do repositório do Laravel no GitHub.

Localização do botão de download em formato zip do código do Laravel.

Copiamos o arquivo laravel-master.zip para o diretório onde queremos guardar nosso projeto. Agora vamos descomprimir o arquivo:

$ unzip laravel-master.zip

e renomear a pasta criada para o nome que desejarmos, neste tutorial chamaremos de dolamy (Docker + Laravel + MySQL):

$ mv laravel-master dolamy
$ cd dolamy

Agora copie os aquivos Dockerfile , docker-compose.yml , entrypoint.sh , apache.conf e apachelinker.sh para a pasta recém criada dolamy .

Falta pouco. Vamos compilar nossa imagem utilizando o Docker Compose. Dentro da pasta dolamy execute o seguinte comando:

$ docker-compose build

Este comando pode demorar mais ou menos, dependendo da velocidade da sua internet, já que o processo de compilação baixa todos os softwares listados no Dockerfile . Uma alternativa, no caso de você estar impaciente, é utilizar a imagem já compilada esron/ubuntu-web-server disponível no Docker Hub. Para tal, substitua o arquivo docker-compose.yml pelo seguinte:

O Docker Hub é o repositório oficial de imagens Docker. Todas as imagens que não foram compiladas neste artigo são baixadas do Docker Hub automaticamente via Docker Compose.

Agora vamos iniciar nosso projeto utilizando o comando abaixo:

$ docker-compose up -d

Se tudo tiver ocorrido bem, em seu browser acesse localhost:8080 e faça login, com as seguintes credenciais:

servidor: mysql
usuário: root
senha: example

Na tela seguinte, clique em criar Criar Base de dados e insira um nome, você pode inserir o nome que quiser para sua base de dados, neste tutorial iremos utilizar homestead . Depois clique em Salvar

Criando uma nova base de dados no Adminer

Agora vamos inicializar nosso projeto Laravel. Primeiro lançaremos mão de um script simples (cortesia do amigo Leonardo Cavalcante) que nos economizará algum tempo digitando ):

Salve esse script com o nome on-server.sh na pasta dolamy .

Vamos agora instalar os pacotes padrões do Laravel. Dentro da pasta dolamy execute o seguinte comando:

$ ./on-server.sh composer install

Isso pode demorar um pouco dependendo da velocidade da sua conexão.

Se tudo tiver ocorrido bem, execute o comando a seguir para copiar o arquivo de ambiente do Laravel.

$ cp .env.example .env

Abra o arquivo .env e substituas os valores das variáveis de configuração de banco de dados como explicado abaixo:

# Valores antes
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
# Valores depois
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=root
DB_PASSWORD=example

Graças ao Docker Compose, a variável DB_HOST pode receber o valor mysql que é o endereço do contêiner executando o processo do MySQL que definimos no arquivo docker-compose.yml .

Agora executaremos os seguintes comandos para inicializar nossa base de dados homestead criada anteriormente:

$ ./on-server.sh php artisan key:generate
Application key set successfully.
$ ./on-server.sh php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table

Acessando o Adminer e atualizando a página veremos as tabelas migrations, users e password_resets, criadas.

Tabelas criadas vistas no Adminer

Nossa aplicação Web está sendo executada em localhost:8000 , no entanto, ainda não é possível acessá-la. Segundo a documentação do Laravel, quando se está utilizando um servidor Web é necessário dar permissão de escrita a esse servidor nas pastas bootstrap/cache e storage para que o projeto funcione corretamente.

After installing Laravel, you may need to configure some permissions. Directories within the storage and the bootstrap/cache directories should be writable by your web server or Laravel will not run.

O usuário no contêiner que gerencia o Apache é o www-data . Então, vamos executar o comando a seguir para conceder tais permissões:

$ ./on-server.sh chown www-data bootstrap/cache storage -R

Parabéns!! Agora podemos acessar localhost:8000 e veremos esta tela de boas vindas ao seu projeto Laravel funcionando.

Laravel funcionando

Comandos Importantes

Segue abaixo uma lista de comandos importantes que usamos no dia-a-dia do desenvolvimento com Docker Compose. Esses comandos devem ser executados dentro da pasta do projeto e só afetam as imagens e contêineres listados pelo arquivo docker-compose.yml

# Executar o projeto
docker-compose up -d
# Ou
docker-compose start
# Parar todos os contêineres
docker-compose stop
# Remover todos os contêineres
docker-compose rm
# Executar um comando em um serviço ou contêiner
docker-compose exec SERVIÇO COMANDO [ARGUMENTOS]
# Compilar as imagens definidas pelo Dockefile
docker-compose build
# Sem usar a pilha de cache do Docker
docker-compose build --no-cache

Recapitulando…

Neste artigo, aprendemos a utilizar o Docker e o Docker Compose como ambiente de desenvolvimento Web.

Aprendemos como criar uma imagem com os softwares necessários para executar uma aplicação Laravel com servidor Apache.

Aprendemos como compilar, executar e parar contêineres usando o Docker Compose e um arquivo docker-compose.yml . Este arquivo unifica as configurações da execução dos contêineres e possibilita que os desenvolvedores utilizem sempre a mesma configuração. O que evita o travamento das atividades diárias por algum erro ao executar um comando Docker grande e complexo.

Aprendemos a utilizar as imagens oficiais MySQL e Adminer para gerenciar um sistema de banco de dados.

Temos agora, o poder de compartilhar um ambiente de desenvolvimento muito próximo do que acontece em produção. Desta forma a equipe de desenvolvimento e a equipe de operações de um projeto podem trabalhar com maior sinergia. Além disso, todos os desenvolvedores estarão trabalhando no mesmo ambiente, o que tem potencial para eliminar a famigerada frase:

“Na minha máquina funciona”

Não se esqueça de compartilhar este artigo com seus amigos e aplaudir, se tiver gostado.

Se inscreva na Publicação Sysvale para receber as novidades em seu e-mail.

--

--

Esron Silva
sysvale
Writer for

Computer Engineer — Web Developer — Amateur Writer