# 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```. ![](https://i.imgur.com/WYnaI8w.png) 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: ![](https://i.imgur.com/YONOjnN.png) 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: ![](https://i.imgur.com/Yx6tAix.png) 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: ![](https://i.imgur.com/36TFes0.png) 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]