O Docker é uma forma de abstração da nossa infraestrutura que nos beneficia tanto em tempo de desenvolvimento quanto em produção.
- O que é o Docker?
- Docker para Desenvolvedores
- Requisitos
- Versões do Docker
- Criando a Conta
- Instalando o Docker
- Executando o Docker
- Testando a Instalação
- Listando as Imagens
- Listando os Contêineres
- Publicando uma API
- Criando uma Imagem
- Rodando o Contêiner
- Acessando os Logs
Com certeza você já ouviu uma famosa frase 'Na minha máquina funciona'... então se na sua máquina funciona, por que não enviar ela para produção?
Pois bem, o que o Docker faz é parecido com isto. Em termos gerais ele abstrai a infraestrutura das aplicações através de imagens prontas.
O que temos são basicamente 'máquinas virtuais' de baixo custo rodando somente com a infraestrutura das nossas aplicações.
Por exemplo, uma das imagens mais famosas que temos no Docker é a Alpine, que contém apenas 5MB.
Esta imagem contém apenas o Core do sistema operacional, no caso Linux, que a maioria das aplicações precisam para serem executadas.
A ideia é que a partir dela, você possa adicionar o que mais precisar, como a SDK do .NET, Node, PHP e depois fazer um pacote disto.
Com este pacote montado, você envia ele completo, do jeito que está, para produção, assim não corre o risco de dar algo errado.
Embora o Docker seja voltado para infraestrutura, um dos seus grandes usos também são ambientes de desenvolvimento.
Hoje trabalhamos com diversos bancos de dados, diversas tecnologias e serviços, isto tudo gera um acúmulo de instalações muito grandes.
Imagina instalar o SQL Server, MySQL e MongoDb, todos na sua máquina, sendo executados como serviços do Windows. É complicado.
Neste caso, o que podemos fazer é utilizar imagens prontas de máquinas com SQL Server, MySQL e Mongo e simplesmente executá-las quando quisermos.
Quer criar um projeto com SQL Server? Só fazer o download da imagem oficial dele para Docker, executar e pronto, temos o serviço rodando.
O Docker funciona para Mac, Windows e Linux, e no caso do Windows, recomendamos utilizar a versão 10, pois ela tem suporte à subsistemas Linux, que são a base do Docker.
Aqui vem a parte mais chata do Docker, os requisitos. Embora as questões de memória e CPU variem de acordo com a quantidade de images que você tem executando, o disco sempre será necessário.
Embora você possa fazer o download da imagem que quiser a qualquer momento, é muito mais prático manter as imagens locais.
Desta forma você economiza banda e tempo, porém perde em disco. Fica a seu critério manter ou baixar novamente as imagens.
Não são recomendações oficiais, mas preferencialmente tenha pelo menos um processador Dual Core, e 8GB de Ram.
Quanto mais disco você tiver melhor, em casos de discos de 128GB, com pouco espaço, você pode excluir as imagens sempre que não estiver mais utilizando.
A instalação inicial do Docker vai tomar por volta de 2GB de disco.
WINDOWS ONLY
Caso esteja utilizando sistema operacional Windows, recomendamos fortemente o uso do Windows 10 pois ele possui suporte a subsistemas Linux, que são a base do Docker.
Atualmente, o Docker é divido em dois produtos, Community Edition (CE) e Enterprise Edition (EE).
Como os nomes sugerem, o Community é gratuito e voltado a comunidade, enquanto o Enterprise é recomendado para uso empresarial.
Mas não se preocupe com isto neste momento, tudo que precisamos para trabalhar com Docker é fornecido pela versão Community que é gratuita.
A primeira coisa que precisamos fazer é criar uma conta no Docker Hub, ela vai ser utilizada tanto para ativação do Docker em nossa máquina quanto para gerenciar nossas imagens.
Caso já tenha uma conta criada, pode prosseguir para o passo seguinte, do caso contrário, navegue até o site oficial do Docker, clique em Sign In e em seguida em Sign Up.
Preencha todas as informações necessárias e pronto. É importante lembrar que eles verificarão sua conta via E-mail, então não esqueça este passo também.
O Docker possui uma versão para Desktop que irá facilitar nossa vida. Se você gosta de linha de comando, não se preocupe pois ele também fará a instalação do CLI.
Vamos então acessar a página de início do Docker e clicar em Download Desktop and Take a Tutorial. Isto vai nos levar a página de Downloads.
Selecione a versão que atende seu sistema operacional, como Docker for Windows ou Docker for Mac e na tela seguinte selecione Get Docker.
Siga a instalação dos pacotes para realizar todo o processo. Recomendamos que ao término do mesmo reinicie seu computador.
WINDOWS ONLY
Durante a instalação do Docker para Windows, você será questionado sobre utilizar contêineres Windows ao invés de Linux.
Fique à vontade em testar esta opção, mas para utilização do Docker em nossos cursos, recomendamos que NÃO DEIXE-A MARCADA. Nos cursos **sempre vamos utilizar contêineres Linu**x como padrão.
Após reiniciar o computador, inicie o Docker caso o mesmo não tenha sido iniciado. O nome da aplicação no sistema ficará como Docker mesmo.
Você saberá que ele está em execução caso o ícone do Docker (uma baleia) esteja próximo ao relógio (System Tray).
No primeiro acesso você será indagado para autenticar utilizando seu Docker ID criado previamente neste artigo.
Recomendamos fortemente que faça o login, e caso tenha perdido esta primeira tela, basta clicar novamente no ícone do Docker (baleia) e selecionar a opção Sign In.
Isto é tudo que precisamos para ter o Docker rodando em nossa máquina. Em adicional recomendamos que clique novamente no ícone do Docker e vá até a opção Settings.
Na aba General, desmarque a opção Start Docker for Desktop when you Login.
Isto fará com que o Docker não seja iniciado junto com o sistema operacional, tornando a inicialização mais rápida.
Caso tenha uma máquina mais poderosa e queira deixar esta opção marcada, fique à vontade.
Ao instalar o Docker automaticamente fazemos a instalação do seu CLI, que disponibiliza o comando docker em nosso terminal.
Desta forma, abra um terminal e digite o seguinte comando para ver a versão do Docker instalada.
docker --version
Se estiver no Windows, recomendamos fortemente o Windows Terminal ou Power Shell.
Vamos então executar nosso famoso Hello World, que vai baixar e executar um contêiner para testarmos se tudo está funcionando corretamente.
docker run hello-world
Ao executar o comando, veremos a mensagem 'Unable to find image hello-world:latest locally', o que significa que ele não conseguiu encontrar nenhuma imagem chamada hello-world localmente.
Faz todo sentido, afinal não fizemos download de nada ainda, mas mesmo assim, ele fará uma busca online e encontrará esta imagem.
Seguindo adiante ele fará o download e execução da imagem, exibindo a mensagem 'This message shows that your installation appears to be working correctly.' caso tudo tenha dado certo.
Durante a execução destes primeiros comandos, duas coisas muito importante aconteceram, o download da imagem e a criação do contêiner.
Uma imagem é a informação crua que temos enquanto o contêiner é uma representação desta imagem local.
Os contêineres se baseiam nas imagens, mas nunca executamos as imagens, sempre os contêineres.
Desta forma, temos uma imagem do hello-world, que é uma base que temos para construir diversos contêineres.
Para listar as imagens que temos localmente é só executar o comando abaixo.
docker image ls
Como você deve imaginar, estas imagens ocupam espaço em disco, e podemos removê-las e baixá-las novamente a qualquer momento.
No caso, para remover uma imagem baixada, podemos utilizar o comando abaixo.
docker image rmi ID_DA_IMAGEM
É importante frisar que uma imagem não poderá ser apagada caso esteja em uso.
Para listar os contêineres podemos utilizar o comando abaixo, porém neste caso o hello-world não aparecerá.
docker container ls
Isto ocorre pelo hello-world ser um contêiner de testes apenas, então para vê-lo listado, precisamos executar o comando com --all no final.
docker container ls --all
Desta forma você verá todos os contêineres que estão na máquina.
Para executar ou para um contêiner, podemos usar o comando start/stop.
docker container start ID_DO_CONTAINER
docker container stop ID_DO_CONTAINER
Para ver a lista completa do que podemos fazer com um contêiner basta executar o comando abaixo.
docker container --help
Com o contêiner parado, podemos removê-lo utilizando o comando abaixo. Em seguida podemos também executar o comando para remover a imagem baixada.
docker container rm ID_DO_CONTAINER
Chegou a hora do desafio final, vamos publicar uma API criada utilizando Node/JavaScript em um contêiner e torná-la acessível pelo nosso Browser.
Para executar esta parte do artigo você precisará do Git e do Visual Studio Code instalados em sua máquina.
Abra um terminal e navegue para uma pasta segura, sem caracteres especiais ou com caminho muito longo e execute o seguinte comando.
git clone https://github.com/andrebaltieri/docker-sample-api.git
Este comando fará o download do código fonte de uma API de exemplo que está no nosso GitHub, gerando assim uma nova pasta chamada docker-sample-api.
Com o código baixado, precisamos gerar um contêiner para nossa aplicação, e neste processo informar alguns detalhes.
O Docker File é o arquivo de instruções que o Docker utilizará para saber como publicar nossa aplicação em um contêiner, bem como qual imagem ele deve utilizar.
Abra pasta docker-sample-api com o Visual Studio Code e vamos criar um arquivo chamado Dockerfile na raiz.
Note que este arquivo não tem extensão alguma, é apenas Dockerfile mesmo.
O primeiro passo que precisamos fazer neste arquivo é definir qual imagem vamos utilizar em nossa aplicação.
Lembre-se que a imagem é a base para construção, contendo apenas o necessário do SO para execução da nossa aplicação.
Neste caso, vamos utilizar a imagem oficial do Node para Docker. Você pode encontrar imagens oficiais de diversas empresas no Docker Hub.
Para definir que estamos utilizando uma imagem como base, utilizamos a palavra FROM, seguida da imagem que queremos utilizar.
FROM node:current-slim
Note que após o nome da imagem temos dois pontos e current-slim. Na verdade o que vem depois dos dois pontos é a TAG da imagem.
As tags são utilizadas para definir versões destas imagens e no caso, current diz que estamos pegando a versão mais atual do Node (LTS - Long Term Support) e slim diz que é a versão enxuta.
Cada imagem tem suas tags, então você deve sempre olhar no Docker Hub pela versão que precisa utilizar.
A segunda definição que iremos fazer em nosso arquivo será o caminho, dentro da imagem, onde ficará o código fonte da nossa aplicação.
Isto é feito utilizando a palavra WORKDIR, como mostrado abaixo.
WORKDIR /usr/src/app
Agora precisamos copiar o arquivo Package.json, que contém os pacotes necessários para execução da nossa API.
Lembre-se que no caso do Node, não precisamos instalar uma SDK ou algo do tipo, porém toda aplicação tem a pasta node_modules com as bibliotecas que utilizamos durante a construção do App.
Para executar esta cópia vamos utilizar a palavra COPY, como mostrado abaixo.
COPY package.json .
Note que no fim do comando há um '.', definindo que o arquivo será copiado para raiz da nossa aplicação definido no WORKDIR.
Com tudo pronto, vamos executar o comando NPM INSTALL para instalar todos os pacotes que precisamos, e isto é feito utilizando a palavra RUN.
RUN npm install
Até o momento temos o código da nossa aplicação sendo copiado para a imagem e em seguida sendo instalados os pacotes que a API precisa para rodar.
Porém, precisamos definir em qual porta esta API irá rodar, e isto é feito pela palavra EXPOSE, como mostrado abaixo.
EXPOSE 8080
Neste caso, estamos expondo a API na porta 8080, porém fique à vontade em alterar esta porta.
É importante lembrar que nossa API, internamente (Dentro da imagem) roda na porta 3000. Isto está definido na linha 15 do arquivo bin/www.
Embora tenhamos copiado os arquivos e instalado os pacotes, nossa API ainda não está executando, e para isto precisamos de fato executar o comando NPM START.
Desta forma, vamos utilizar a palavra CMD que nos permite passar uma lista de comandos a serem executados.
CMD ['npm', 'start']
Por fim, vamos executar mais um COPY para copiar o resto da nossa aplicação para a imagem.
COPY . .
Note que utilizamos o mesmo esquema anterior, copiando os arquivos da raiz ('.') da nossa aplicação para a raiz ('.') da imagem.
O arquivo final Dockerfile fica com o seguinte conteúdo.
# Copy the file from your host to your current location
COPY package.json .
# Run the command inside your image filesystem
RUN npm install
# Inform Docker that the container is listening on the specified port at runtime.
EXPOSE 8080
# Run the specified command within the container.
CMD [ "npm", "start" ]
# Copy the rest of your app's source code from your host to your image filesystem.
COPY . .
Nosso desafio agora é criar uma imagem customizada a partir desta API/'Dockerfile que criamos. Vamos juntar a imagem padrão definida no Dockerfile com o restante da execução do script.
Dentre os comandos que podemos executar, temos o docker image build, para criar uma imagem, e vamos utilizá-lo para gerar o que precisamos aqui.
Certifique-se que você está na raiz da API, a pasta docker-sample-api e execute o seguinte comando.
docker image build -t dockerapi:1.0 .
Para facilitar futuras execuções, vamos dar um nome para esta imagem, adicionando o parâmetro -t, seguido pelo nome:versão da imagem.
Por fim, devemos especificar o diretório onde está nosso Dockerfile, que no caso é a raiz da nossa API, definido no comando pelo ".".
Para verificar se tudo deu certo, basta executar o comando docker image ls para listar as imagens que temos na máquina.
A última coisa que precisamos fazer é pegar esta imagem gerada e executar ela como um contêiner, e isto é feito pelo comando docker container run.
Novamente, certifique-se que você está na raiz da API, a pasta docker-sample-api e execute o seguinte comando.
docker container run --publish 8080:3000 --detach --name api dockerapi:1.0
O primeiro parâmetro que temos no comando é o --publish, que vai fazer o redirecionamento do tráfego para a porta onde nossa API está rodando.
Neste caso, vamos rodar nosso contêiner na porta 8080, ou seja, acessaremos nossa API no Browser pela URL http://localhost:8080, porém, internamente nossa API está rodando na porta 3000.
O --publish cuidará exatamente deste redirecionamento de tráfego para nós. Você também pode alterar a porta de execução para outra qualquer, diferente da 8080 se quiser.
O --detach diz para o Docker executar este contêiner em background, e não vai travar o processo do nosso terminal ou Visual Studio Code que acabamos de executar.
O --name especifica o nome do contêiner, e fica a seu critério colocar qualquer nome que quiser, desde que não tenha espaços ou caracteres especiais.
Neste momento você pode abrir o browser no endereço http://localhost:8080 para ver a mensagem 'Docker Node API Running' na tela, o que significa que nossa API está rodando.
Por fim temos o nome da imagem especificado, que no caso é a que acabamos de criar. Agora você pode usar os comandos docker container ls para ver este contêiner em execução, além do docker container start ID e docker container stop ID para iniciar ou parar ele.
Para visualizar os logs de execução da API você pode clicar no ícone do Docker e ir na opção Dashboard. Uma nova tela se abrirá listando o contêiner que acabamos de criar.
Clique sobre o contêiner e em seguida clique na opção LOGS para visualizar tudo que está sendo executado neste contêiner.
Criar e executar imagens e contêineres no Docker não é uma tarefa difícil. Neste artigo vimos a instalação e primeiros passos para 'conteinerizar' nossas aplicações, mas ainda há muito mais a se aprender sobre Docker.