# Começando com Docker
Por Fernando Furtado (Alura)
21/06/2017
Quando falamos em desenvolvimento de software é comum ter diversos ambientes, por exemplo:
- Desenvolvimento
- Teste
- Homologação
- Produção
E outra coisa comum no mundo de desenvolvimento é ter divergências entre estes ambientes.
Quem nunca ouviu a frase:
*"Na minha máquina funciona!"?*
Nesse post vamos abordar o [Docker](https://www.docker.com/) como uma alternativa para minimizar essa divergência.
## Mas o que é o Docker?
O Docker é um sistema de virtualização não convencional. Mas o que isso quer dizer? Em virtualizações convencionais temos um software instalado na máquina Host que irá gerenciar as máquinas virtuais (ex.: VirtualBox, VMWare, Parallels e etc...).
Para cada máquina virtual temos uma instalação completa do S.O. que queremos virtualizar, além de ter o próprio hardware virtualizado.
Se por exemplo eu precisar de uma biblioteca comum para todas as máquinas virtuais, preciso instalar em cada uma delas.
O Docker usa uma abordagem diferente, ele utiliza o conceito de container. Como assim [container](https://pt.wikipedia.org/wiki/Container_(transporte))?
## Compreendendo o conceito de containers
Se pensarmos em transporte de cargas, container foi uma revolução nessa área. Pois antes deles o tempo de carregar e descarregar um navio era gigantesco e o trabalho era feito manualmente. Sem contar perdas (devido a quebras ou deterioração), desvio e outros problemas.
Com a chegada dos containers foi possível transportar mercadorias de uma forma segura, de fácil manipulação e com pouco, ou nenhum, trabalho braçal no carregamento ou descarregamento. E é justamente isso que o Docker tenta fazer com nossos softwares.
## Ganhos ao usar containers do Docker
Imagine nosso software como uma mercadoria a ser transportar como por exemplo, do ambiente de Desenvolvimento para Produção.
Para fazer isso precisamos garantir que nosso ambiente de Produção tenha todos os pré-requisitos instalados, de preferência uma versão do S.O. parecida com a do ambiente de Desenvolvimento entre outros cuidados que devem ser tomados (relacionados a permissionamento, serviços dependentes e etc...).
Com o Docker temos um container com nosso software. Esse container é levado inteiro para o outro ambiente.
Com isso não precisamos nos preocupar com pré-requisitos instalados no outro ambiente, versão do S.O., permissionamento e se quisermos podemos ter containers para os serviços dependentes também. Dessa forma minimizamos muito a divergência entre os ambientes.
## Mas como o Docker faz isso?
Essa ideia de container já é bem antiga e a princípio o Docker usava internamente um projeto chamado [LXC](https://linuxcontainers.org/) (Linux Container).
O projeto LXC usa por baixo dos panos diversas funcionalidades presentes no Kernel do Linux. Abaixo vou listar algumas dessas funcionalidades:
- **chroot** - Reponsavel por mapear os diretórios do S.O. e criar o ponto de montagem (/, /etc, /dev, /proc entre outros).
- **cgroup** - Reponsável por controlar os recursos por processo. Com ele podemos por exemplo limitar o uso de memória e/ou processador para um processo específico.
- **kernel namespace** - Com ele podemos isolar processos, ponto de montagem entre outras coisas. Com esse isolamento, conseguimos a sensação de estar usando uma máquina diferente da máquina host. Pois enxergamos somente o ponto de montagem especifico e processos especificos, inclusive nossos processos começam com PID baixo.
- **kernel capabilities** - Entre outras coisas, conseguimos rodar alguns comandos de forma privilegiada.
## Mão na massa
Agora que temos uma noção do que é e para que serve o Docker, vamos fazer o download da ferramenta e começar nesse mundo de containers.
### Instalando o Docker
Atualmente Docker está disponível em duas versões [Docker Community Edition(CE)](https://www.docker.com/community-edition) e [Docker Enterprise Edition(EE)](https://www.docker.com/enterprise-edition).
Em ambas as versões temos acesso a toda a API, basicamente a diferença entre as duas versões é o perfil desejado de aplicações. No EE temos um ambiente homologado pela Docker com toda infraestrutura certificada, segura pensada para o mundo enterprise. Já na versão CE podemos chegar ao mesmo nível que EE porém de uma forma manual.
Nesse [link](https://www.docker.com/community-edition#/download) você pode encontrar as distribuições para downloads em cada sistema operacional disponível e os passos para instalação.
Feito a instalação, execute esse comando no terminal ```docker --version```. Se a instalação ocorreu com sucesso deve ser impresso algo semelhante a isso ```Docker version 17.03.1-ce, build c6d412e```.
### Imagens
O Docker trabalha com o conceito de images, ou seja, para colocar um container em funcionamento o Docker precisa ter a imagem no host.
Essas imagens podem ser baixadas de um repositório (a nomenclatura para esse repositório é registry) ou criadas localmentes e compiladas. Esse é o [link](https://hub.docker.com/) para o registry do Docker.
Nesse registry podemos ter imagens oficiais e não oficiais. Além de podermos criar nossas próprias imagens, também é possível fazer upload dela em um registry.
### Baixando Imagens
Para baixar uma imagem podemos usar o comando ```docker pull``` e o nome da imagem que queremos baixar. Vamos baixar a imagem do Ubuntu, para isso execute o seguinte comando no terminal: ```docker pull ubuntu```.

Aqui o Docker baixou nossa imagem. Percebam que uma imagem é composta de várias camadas, por esse motivo teve que fazer vários Downloads/Pulls.
### Listando imagens baixadas
Para listar todas as imagens podemos usar o comando ```docker images```. O retorno desse comando é algo semelhante a isso:

O nome da imagem é exibido na coluna REPOSITORY, cada imagem tem um identificador único que é exibido na coluna IMAGE ID. A coluna TAG indica a "versão" da imagem do ubuntu. O latest quer dizer que é a última "versão" da imagem (a mais recente).
### Executando Containers
A partir da imagem podemos iniciar quantos containers quisermos através do comando ```docker run```.
Para acessarmos um terminal do Ubuntu podemos usar o comando ```docker run -i -t ubuntu``` ou ```docker run -it ubuntu```. O parâmetro -i indica que queremos um container interativo, o -t indica que queremos anexar o terminal virtual tty do container ao nosso host.
### Listando containers em execução
Para ver os containers em execução podemos usar o comando docker ps (em outro terminal ou aba), e ele exibirá um retorno parecido com esse:

Aqui temos informações sobre os containers em execução, como id, imagem base, comando inicial, há quanto tempo foi criado, status, quais portas estão disponíveis e/ou mapeadas para acesso e o nome do mesmo. Quando não especificamos um nome ao iniciá-lo, será gerado um nome aleatóriamente.
Quando encerramos um container ele não será mais exibido na saida do comando docker ps, porém isso não significa que o container não existe mais. Para verificar os containers existentes que foram encerrados podemos usar o comando ```docker ps -a``` e teremos uma saída parecida com essa:

Como o próprio status do container informa, o mesmo já saiu de execução e no nosso caso saiu com status 0 (ou seja saiu normalmente).
### Removendo containers
Para remover o container podemos usar o comando ```docker rm``` e informar o id do container ou o nome dele. Para nosso caso poderíamos executar o comando ```docker rm 43aac92b4c99``` ou ```docker rm dreamy_bassi``` para remover o container por completo.
Caso tenhamos a necessidade de remover todos os container (em execução ou encerrados) podemos usar o comando ```docker rm $(docker ps -qa)```. A opção -q do comando docker ps tem como saída somente os ids dos containers, essa lista de ids é passado para o docker rm e com isso será removido todos os containers.
Só será possível remover um container caso o mesmo não esteja em execução, do contrário temos que encerrar o container para removê-lo.
### Como são feitas as imagens?
Nesse momento podemos pensar que o Docker é meio mágico (e é...kkk). Dado uma imagem ele pode rodar um ou mais containers com pouco esforço, mas como são feitas as images?
Uma imagem pode ser criada a partir de um arquivo de definição chamado de Dockerfile, nesse arquivo usamos algumas diretivas para declarar o que teremos na nossa imagem. Por exemplo se olharmos a definição da imagem do Ubuntu podemos ver algo semelhante a isso:
```
FROM scratch ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz / . . . RUN mkdir -p /run/systemd && echo 'docker' > /run/systemd/container
CMD \["/bin/bash"\]
```
Para ver o Dockerfile completo consulte [aqui](https://github.com/tianon/docker-brew-ubuntu-core/blob/1a5cb40f41ac4829d8c301ccd2cf3b7a13687a8b/xenial/Dockerfile).
Com um arquivo *Dockerfile* podemos compilá-lo com o comando ```docker build```. Ao compilar um arquivo Dockerfile temos uma imagem. Mas isso é um assunto para um próximo post.
Não deixe de conferir nosso curso de [docker](https://www.alura.com.br/curso-online-docker) na Alura.
Leia também:
[Criando um repositório local de imagens Docker](https://www.alura.com.br/artigos/criando-um-repositorio-local-de-imagens-docker)
[Docker Compose para compor uma aplicação](https://www.alura.com.br/artigos/compondo-uma-aplicacao-com-o-docker-compose)
[Criando volumes com Docker](https://www.alura.com.br/artigos/criando-volumes-com-docker)
[Replicando ambientes com Docker](https://www.alura.com.br/artigos/replicando-ambientes-com-docker)
[Desvendando o DockerFile](https://www.alura.com.br/artigos/desvendando-o-dockerfile)
### PODCAST [aqui](https://cursos.alura.com.br/hipsterstech-containers-e-docker-hipsters-75-a511)
[ToC]