Durante muito tempo, tarefas como configurar um ótimo ambiente de desenvolvimento foram consideradas um grande desafio para desenvolvedores de todos os níveis. Softwares, compiladores, IDEs, banco de dados e principalmente: A compatibilidade com os ambientes de produção.
Nesse guia rápido trataremos essencial do Docker, uma ferramenta que definitivamente mudou completamente a forma que todos nós, desenvolvedores, trabalhamos. Através de isolamento de namespaces, utilização de cgroups e um sistema de arquivos baseado em camadas, o Docker possibilita que subamos em questão de segundos um ambiente completo e idêntico ao de produção.
Vamos então colocar a mão na massa.
O que é Docker?
Docker é uma plataforma Open Source que possibilita o empacotamento de uma aplicação dentro de um container. Uma aplicação consegue se adequar e rodar em qualquer máquina que tenha essa tecnologia instalada.
De acordo com o www.docker.com, um container é uma unidade padrão de software que empacota o código e todas as suas dependências para que o aplicativo seja executado de maneira rápida e confiável de um ambiente de computação para outro. Uma imagem de container do Docker é um pacote de software leve, autônomo e executável que inclui tudo o que é necessário para executar um aplicativo: código, tempo de execução, ferramentas do sistema, bibliotecas do sistema e configurações.
Disponível para aplicativos baseados em Linux e Windows, o software conteinerizado sempre será executado da mesma maneira, independentemente da infraestrutura. Os containeres isolam o software de seu ambiente e garantem que ele funcione de maneira uniforme, apesar das diferenças, por exemplo, entre desenvolvimento e preparação.
O Docker, especificamente, foi feito para ser trabalhado com o Linux, porém, é totalmente possível trabalharmos com o Docker no MAC e no Windows, já que o MAC possui um sistema de virtualização próprio e o Windows, pelo menos na versão Professional, possui o Hyper V.
No Windows, temos duas opções para rodar o Docker: se você possui o Windows na versão Professional, basta ativar o Hyper V, em outras versões, porém, essa opção de ativação do Hyper V não está disponível, dessa forma, portanto, deveremos utilizar Docker Toolbox. Resumidamente, o Docker Toolbox sobe uma máquina virtual em seu sistema, instala uma versão do Linux e o seu Docker irá “conversar” com essa máquina virtual.
E agora, preparados para a prática?
Não iremos abordar a instalação do Docker, pois podemos partir do pressuposto de que somos todos desenvolvedores e que nós todos temos a capacidade de instalar o Docker.
Vamos resolver um problema pontual de muitos desenvolvedores: Configuraremos um ambiente de desenvolvimento utilizando o Docker e o Docker Compose. Para isso, utilizaremos como exemplo o setup de uma aplicação baseada no framework PHP Laravel.
Mãos à obra: Projeto Laravel
Para iniciar o processo, criaremos um simples projeto Laravel. Esse projeto será chamado de laraveldocker. Para isso, faça o download do “composer” (gerenciador de pacotes do PHP. Para isso acesse: getcomposer.org).
Em seu terminal digite o comando:
composer create-project --prefer-dist laravel/laravel laravel-docker
O Laravel será instalado em sua máquina e em seguida será criado o projeto laravel-docker. ( esse processo poderá levar alguns minutos.
Após a instalação, acessaremos o projeto:
cd laravel-docker
ls
Note que o projeto já está rodando em nossa máquina. Se dermos o comando à seguir, poderemos comprovar isso:
php artisan serve
Acessando o localmente de nosso navegador, poderemos ver a aplicação rodando:
Por que utilizar o Docker?
Nesse momento você deve estar se perguntando: “Mas é tão fácil criar um projeto Laravel, localmente, pra que eu preciso do Docker”
A resposta é bem simples: Para garantir que outros desenvolvedores, que poderão trabalhar em seu projeto, de máquinas diferentes, possam trabalhar exatamente no mesmo ambiente que você, independente da máquina utilizada, todos terão os mesmo recursos, por exemplo, mesma versão do PHP, MySQL, recursos computacionais e etc…
Com isso, aquela história de “Na minha máquina funciona”, com certeza vai acabar.
Primeiros passos com Docker
Agora que já temos nosso projeto instalado, vamos checar rapidamente se o Docker já está disponível em nosso ambiente, caso não, faça a instalação em: www.docker.com.
Digite o comando docker em seu terminal. Você poderá notar que uma lista de outros comandos aparecerão. Isso significa que ele está corretamente instalado:
$ docker
Fixando alguns conceitos básicos do Docker: Containeres e Imagens.
Container: é o local onde a sua aplicação ficará rodando.
Imagem: É como um snapshot. Outros desenvolvedores com acesso a esta imagem, terão os mesmos recursos que você utiliza e configurou em seu container.
Para que você possa trabalhar com o Docker, é extremamente necessário que você conheça seus principais comandos. Vamos lá!
O primeiro comando é o
, esse comando irá lhe mostrar quais o conteineres foram criados e estão rodando:docker ps
Um segundo comando, muito importante, é o
, esse comando mostra quais imagens foram criadas:docker images
Note que ainda não criamos nenhum container e, consequentemente, nenhuma imagem, por isso nenhuma informação é apresentada.
Vamos abrir esse projeto utilizando nossa IDE. Neste artigo iremos trabalhar com o Visual Studio Code.
Dockerfile e Docker Compose
Dockerfile
Agora, iremos criar um arquivo chamado Dockerfile.
“O Dockerfile é um arquivo de texto que contém as instruções necessárias para criar uma nova imagem de contêiner. Essas instruções incluem a identificação de uma imagem existente a ser usada como uma base, comandos a serem executados durante o processo de criação da imagem e um comando que será executado quando novas instâncias da imagem de contêiner forem implantadas.” (Fonte: www.docker.com)
Vamos então criar um arquivo chamado Dockerfile.
Por padrão, utilizaremos uma imagem Docker que nos trará o PHP-FPM e o Nginx já configurados. Você poderá encontrar essa imagem acessando https://hub.docker.com e pesquisando por nginx php fpm:
Em nossa IDE, no arquivo Dockerfile que criamos, inserimos o seguinte código:
FROM wyveo/nginx-php-fpm:latest
A instrução FROM
define a imagem de container que será usada durante o processo de criação de nova imagem,
é o endereço da imagem e wyveo/nginx-php-fpm
indica que queremos a versão mais atual dessa imagem.latest
É necessário explicar que esse código traz uma instalação crua do nginx com PHP-FPM. Por padrão, o nginx, quando instalado dessa forma, mantém seu Document Root no seguinte caminho:
/usr/share/nginx/html
Docker Compose
O docker-compose é uma ferramenta do Docker que, a partir de diversas especificações, permite subir diversos containeres e relacioná-los através de redes internas.
Para isso, vamos iniciar criando um arquivo chamado de docker-compose.yaml.
No arquivo docker-compose, declaramos a seguinte estrutura:
: declara a versão do docker composeversion
: declara quais serviços serão rodados, nesse caso, chamaremos de laravel-app. services
: declara o nome da imagem, ou, no caso, se declararmos o build
, ele irá “chamar” a imagem declarada no Dockerfile..
: realiza a liberação das portas. Na minha máquina eu quero que libere a porta ports
, porém, lá no meu container eu quero que seja liberada a porta 8080
, ou seja, toda vez que eu acessar o meu localhost com a porta 80
8080
o Docker irá redirecionar para a porta
o nginx criado no container.80
Acessando o nosso terminal, subiremos o container com o comando:
$ docker-compose up -d
Note que após o comando aparecerá as seguintes informações:
O
irá rodar o docker compose, baseado em nosso docker-compose.yaml e com o docker-compose up
o container é inicializado em segundo plano e podemos utilizar o nosso terminal para outros comandos.-d
Acessamos o nosso browser e já podemos ver o nosso nginx rodando:
Lembrando que, em nosso docker-compose.yaml, indicamos que acessaremos a porta
de nossa máquina e essa acessará a porta 8080
do nosso container.80
Nosso container rodando:
Volumes
O Docker possui um mecanismo de gerenciamento de volumes que com ele é possível compartilharmos um volume da nossa máquina com o container.
Em nosso docker-compose.yaml iremos declarar
volumes:
- ./:/usr/share/nginx
Quando criamos esse volume, tudo o que estiver em nossa pasta será montado dentro do nosso container, ou seja, tudo o que modificarmos em nossa pasta será compartilhado com o container, porém, caso “matarmos” o container, ainda teremos os arquivos em nossa máquina.
E assim fica o nosso docker-compose.yaml:
Vamos testar?
Com o comando
, subiremos as modificações realizadas em nosso docker-compose.yaml:docker-compose up -d --build
Para evitar que tenhamos um erro 404 no nginx (pois ele está buscando por padrão a pasta html), criaremos um link simbólico apontando a pasta public de nosso projeto Laravel para html.
Esse link simbólico é criado rodando um
em seu terminal. O link simbólico, na verdade, funciona como um atalho, pois toda vez que acessarem a página html na verdade estarão acessando a pasta public: ln -s public html
Note a pasta html:
Agora, finalmente podemos visualizar a imagem do Laravel sendo executada.
Conectando o Banco de Dados
Agora que temos o nosso Laravel rodando, iremos realizar algumas declarações em nosso docker-compose.yaml.
Criaremos um serviço chamado:
mysql-app:
Nesse serviço vamos declarar que utilizaremos uma imagem MySQL. Essa imagem pode ser facilmente encontrada no https://hub.docker.com.
image: mysql:5.7.22
O nosso MySQL também utilizará portas:
ports:
- "3306:3306"
Com essa declaração estamos dizendo que, tanto a porta de nossa máquina quanto a porta de nosso container serão as mesmas.
A imagem do MySQL foi preparada para que possamos trabalhar com variáveis de ambiente. Utilizaremos uma variável de ambiente que cria o banco de dados com uma senha, facilitando todo o trabalho.
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: laravel
Dando prosseguimento, para que essas máquinas possam conversar entre si, é necessário que compartilhem uma rede interna:
networks:
-app-network
Esse serviço deve ser criado em nosso
e em nosso laravel-app
.mysql-app
Declaramos, também, fora dos serviços a criação da rede propriamente dita:
networks:
app-network:
driver: bridge
Esse é o resultado final.
Prontos para testar?
Primeiro, vamos derrubar nosso container:
Em seguida, subimos novamente:
Agora, para que o Laravel possa se conectar com o container do MySQL, vamos rapidamente editar o arquivo .env de nosso projeto. Ele é responsável por todas as configurações desse framework. Nesse caso, vamos alterar as credenciais de acesso ao banco de dados de acordo com o que foi informado no docker-compose.yaml:
Iremos alterar o nome de nossa conexão:
, deve ter o mesmo nome de nossa conexão, ou seja: DB_HOST=127.0.0.1
DB_HOST=mysql-app
Alteramos, também:
para DB_DATABASE=homestead
e DB_DATABASE=laravel
para DB_USERNAME=homestead
e DB_USERNAME=root
para DB_PASSWORD=secret
DB_PASSWORD=laravel
Vamos testar a conexão:
Agora, deveremos criar o volume no
, para que o nosso banco não seja perdido caso “matarmos” o nosso container:mysql-app
Criaremos uma pasta oculta chamada
quando declararmos o nosso volume:.docker
volumes:
- .docker/dbdata:/var/lib/mysql
Na prática, ficará assim em nossa IDE:
Se pararmos o nosso container e depois subirmos novamente, poderá verificar que um novo aquivo foi adicionado em nossa IDE:
Novo arquivo adicionado:
Se dermos novamente um
, aparacerá a informação de que não temos novos arquivos, pois já estarão salvos em nossa máquina.php artisan migrate
É importante explicar que, caso esteja utilizando o Windows, recomenda-se uma declaração específica em nosso docker-compose.yaml:
Sem essa declaração, para usuários do Windows, provavelmente o volume do nosso
não será montado da forma correta.mysql-app
Enfim, nossa aplicação Laravel já está pronta, totalmente disponível para desenvolvermos os nossos projetos.
Declarações Adicionais Dockerfile
WORKDIR
“A instrução
define um diretório de trabalho para outras instruções Dockerfile, como WORKDIR
, RUN
e também o diretório de trabalho para executar instâncias da imagem do container.” (Fonte: www.docker.com).CMD
Em nosso Dockerfile, ficará assim:
FROM wyveo/nginx-php-fpm:latest
WORKDIR /usr/share/nginx/
RUN
“A instrução
especifica os comandos a serem executados e capturados na nova imagem de contêiner. Esses comandos podem incluir itens como a instalação de software, a criação de arquivos e diretórios e a criação da configuração do ambiente.” (Fonte: www.docker.com)RUN
Como exemplo, em nossa aplicação:
FROM wyveo/nginx-php-fpm:latest
WORKDIR /usr/share/nginx/
RUN rm -rf /usr/share/ngix/html
RUN ln -s public html
A declaração
elimina a pasta htmlRUN rm -rf /usr/share/ngix/html
A declaração
cria automaticamente o link simbólico.RUN ln -s public html
COPY
“A
é uma instrução que copia os arquivos e diretórios para o sistema de arquivos do container. Os arquivos e diretórios devem estar em um caminho relativo ao Dockerfile.” (Fonte: www.docker.com).COPY
Iremos abordar essa declaração de forma detalhada, em nosso projeto, quando realizarmos o build da imagem para o nosso Docker Hub.
ADD
“A instrução
é como a instrução de cópia, mas com ainda mais recursos. Além de copiar arquivos do host para a imagem de contêiner, a instrução ADD
também pode copiar arquivos de um local remoto com uma especificação de URL.” (Fonte: www.docker.com).ADD
CMD
“A instrução
, define o comando padrão a ser executado durante a implantação de uma instância da imagem do contêiner. Por exemplo, se o contêiner estiver hospedando um servidor Web NGINX, o CMD
pode incluir instruções para iniciar o servidor Web com um comando como nginx.exe. Se várias instruções CMD
forem especificadas em um Dockerfile, somente a última será avaliada.” (Fonte: www.docker.com).CMD
Em nosso projeto, o resultado será:
Build da imagem no Docker Hub
Para finalizar esse nosso guia rápido, iremos realizaremos o build de nossa imagem no Docker Hub, dessa forma, outros desenvolvedores poderão utilizar a mesma imagem que criamos.
Nessa etapa, iremos declarar o
:COPY
COPY . /usr/share/nginx
Em seguida utilizaremos, novamente o
:RUN
RUN chmod -R 775 /usr/share/nginx/storage/*
Em nossa IDE ficara dessa maneira:
Em nosso terminal, rodaremos o seguinte comando:
docker build -t rafatrevisani/laravel-image:latest .
Sendo
o nome de nossa imagem.seulogin/laravel-image: latest .
O comando digitado fará com que seja realizado o build com todas as alterações que fizemos em nosso
e, feito o build, poderemos publicar em nosso Docker Hub.Dockerfile
Após o build, faremos o login em nosso Docker Hub:
Feito o login, faremos o push da imagem com o comando
:docker push + nome da nossa tag
docker push seulogin/laravel-image:latest
Acessando o nosso Docker Hub, poderemos ver a nossa imagem:
Agora a nossa imagem está disponível a outros desenvolvedores e dessa forma, os mesmos poderão trabalhar exatamente com a essa imagem.
Conclusão
Como todos pudemos verificar, trabalhar com o Docker e o Docker Compose não foi nenhum bicho de sete cabeças.
Lembre-se que esse processo não serve somente para o Laravel, mas sim para qualquer linguagem e framework de sua escolha.
Que tal trabalhar em sua própria imagem agora?
E se você curtiu esse conteúdo e quer aprender mais sobre Docker e Docker Composer, solicite contato clicando aqui e nós te ajudamos.