Docker - O que é, o que não é, e alguns detalhes a mais


Logotipo do Docker

No último post, eu falei um pouco sobre o Vagrant,  que é uma ferramenta que permite criar e distribuir máquinas virtuais voltadas especificadamente para desenvolvimento de software. Pois bem, quem já é mais antenado nas últimas novidades, ao ler o último post, deve ter pensado algo como "nossa, mas já temos o Docker, e containers são muito melhores que máquinas virtuais!!!!!". E bem, na verdade, tempos atrás, eu mesmo teria dito o mesmo sobre quem ousasse comentar sobre Vagrant, máquinas virtuais e tal. Por isso, hoje, vou falar sobre o Docker, o que ele faz, o que ele não faz, seus recursos, uma breve comparação com o Vagrant e todo o contexto das máquinas virtuais e também um breve tutorial de uso.

O que é o Docker, afinal?

Bom, para quem já experimentou o Docker, a plataforma realmente parece ser mil maravilhas e aplicável a qualquer caso de uso. Mas, em termos práticos, o Docker nada mais é do que um wrapper turbinado (ele acrescenta alguns recursos a mais, que vou falar mais abaixo) em torno de um sub-sistema do kernel do Linux que até algum tempo atrás era considerada meio obscura, chamada LXC (abreviação para Linux Containers, sacou a semelhança? hein? hein?). Esse sub-sistema implementa uma porrada coleção de ferramentas, templates, bibliotecas e ligações de linguagens que fornece, esses sim, os famosos containers, que são bem pouco comparáveis em relação a máquinas virtuais mais parrudas, como as fornecidas por hypervisors como VMWare (normalmente usado para virtualizar servidores) e Virtualbox (que é mais ideal para desenvolvimento) e afins. Mas..

Mas, o que são esses containers?

Containers são uma forma de virtualização a nível de sistema operacional que permite rodar múltiplos "sistemas" isolados em um único sistema operacional real. Esses sistemas isolados conseguem ser, a partir da proteção dos containers, efetivamente isolados e limitados tanto em uso de disco, quanto memória RAM e CPU. Só que, embora num momento pareçam ser iguais às máquinas virtuais fornecidas por VMWare e Virtualbox, eles não são: Containers usam um truque de compartilhamento de Kernel para "poupar" recursos, e daí vem o fato de serem uma forma de virtualização a nível de sistema operacional.

Como o kernel é compartilhado entre os vários containers, o container acaba por não poder rodar sistemas que tenham kernel diferente do da máquina hospedeira em containers. Isso traz dois pontos importantes para o jogo:

  • Na virtualização a nível de sistema operacional, você não possui um hardware emulado/virtualizado, mas sim um acesso mais limitado ao hardware. O que isso significa? Significa que, no VMWare ou Virtualbox, que implementam a chamada virtualização "completa", a virtualização ocorre efetivamente a baixo nível, e em teoria mesmo chamadas associadas do sistema operacional diretamente ao processador passam e são atendidas pelo hypervisor, que então aloca o recurso real ou nega o acesso, conforme os limites definidos, enquanto que, com o uso da virtualização a nível de sistema operacional, o programa usa as APIs do kernel normalmente, e, através desse uso, é limitado conforme os limites definidos para o container em questão. Ou seja, é o kernel quem "mente" para o programa quando diz que não possui acesso à memória RAM ou disco, por exemplo;
  • Além disso, o compartilhamento do kernel se reflete numa limitação básica que a virtualização completa não possui: O kernel precisa ser o mesmo da máquina hospedeira. Ou seja, a menos que dê a louca na Microsoft e ela resolva adotar o kernel do Linux no Windows (eita), você nunca vai ver algo como o LXC rodando containers do Windows, ou vice-versa (Windows rodando containers do Linux, quando a Microsoft resolver criar uma tecnologia de containers pro Windows também..);

Vendo essas duas limitações fundamentais dos containers, você deve estar se perguntando algo como:

Ué, mas se eu posso rodar "máquinas virtuais" do Linux de boas, por qual motivo não posso substituir Vagrant pelo Docker de boas também??

Bom, teoricamente, poder você pode. MAS, isso é uma baita "desrespeito" ao paradigma que o Docker prega, e por desrespeito ao paradigma eu to me referindo que isso é bem..gambiarra.

O que eu estou querendo dizer é que, no Vagrant, com uma máquina virtual, você pode chegar e simplesmente instalar Nginx, MySQL, PHP, NodeJS e o que mais precisar instalar para sua aplicação rodar decentemente. No Docker, a filosofia prega que cada container deve ter uma responsabilidade única, ou seja, Nginx é um container, MySQL é outro container, PHP é outro container e NodeJS é ainda outro container. A principio, isso é bom, pois facilita o teste, atualização, deploy e tudo mais de containers e serviços (inclusive, este blog roda dentro de dois containers), mas... Eventualmente isso torna tudo um bocadinho mais complicado, pois:

  • Você precisa lidar com toda a conexão entre todos os containers (afinal, eles são isolados, se lembra?);
  • Alguns containers eventualmente precisam lidar com os mesmos arquivos (e aí acontece de se perder em permissões de leitura, escrita, acesso e etc);
  • Você precisa dar algum jeito de lidar com logs;
  • Você precisa tomar cuidado com aplicações que precisam armazenar dados permanentemente, pois containers são stateless (ou seja, não salvam nenhum dado internamente) e por isso compartilhamento de arquivos são necessários;
  • E por fim você precisa tomar cuidado manualmente para fazer tarefas que normalmente o sistema operacional faria por você (como lidar com processos zumbis, iniciar syslog, etc. etc. etc.);

Só os dois primeiros são características que, por padrão, usando máquinas virtuais só seriam enfrentados se você efetivamente estivesse lidando com um sistema DISTRIBUÍDO. E é daí que vem o ponto: O Docker pode ser usado para quase toda aplicação? Pode. Mas, ele deve? Não necessariamente, visto que, para muitas coisas, usar Docker direito tende a ser mais trabalhoso do que configurar uma boa máquina virtual que atende as suas necessidades.

Mas, se configurar o Docker direito tende a ser mais trabalhoso do que configurar uma boa máquina virtual, então não devo usá-lo?

Não necessariamente. Os maiores problemas do Docker, às vezes, são suas maiores virtudes. Alguns exemplos disso são os próprios usos que eu já fiz do Docker e ao qual ele atende muito bem:

  • Permitir o uso de versões específicas de linguagens/interpretadores/compiladores/bancos de dados/etc. sem que você precise instalar/compilar tudo manualmente;
  • Testes de novos softwares, pois é mais rápido do que o boot de uma máquina virtual e não polui a sua máquina;
  • Permitir a execução de softwares sem instalar nada na máquina principal;

Esse blog que vos fala, por exemplo, está rodando sob dois containers do Docker, um para o php-fpm, outro para o MySQL. Onde está o Nginx? Está fora, instalado na máquina principal, e aí o Nginx se conecta com o php-fpm para poder renderizar essa página da forma que você vê. Parece complicado? Bom, pode até ser um pouquinho, mas..

  • Eu não preciso instalar PHP no VPS;
  • Eu posso usar diferentes versões do PHP para diferentes projetos (já aconteceu de eu rodar um projeto antigo de um cliente numa versão mais antiga do PHP, e isso em nada interferiu aqui no blog, por exemplo);
  • Eu consigo rodar outros softwares em containers e, todos o que precisam de conexão com o mundo real (porta 80) podem facilmente passar pelo proxy do Nginx, que tem todas as configurações, centralizadas;
  • E assim vai..

Hoje, nesse servidor, eu preferencialmente executo as coisas novas dentro de containers. Isso permite que minha lista de pacotes seja mínima e eu não precise ficar me preocupando com arquivos de configuração aqui e ali. Claaaaro que isso dificulta as coisas quando eu quero instalar algo novo (pois, afinal, sempre quero rodar as coisas dentro de um container) mas no fim as vantagens compensam, como quando eu resolvi instalar um projeto em NodeJS e esse acabar instalando 3812098390182908 dependências, que eu pude apagar simplesmente deletando o container do projeto e recriando apenas com as coisas que eu realmente precisava.

Um ponto que eu acho legal no uso de containers é que, como tudo é isolado, em teoria tudo fica mais seguro. O php-fpm, por exemplo, só consegue enxergar que tem uma conexão com o MySQL, e o MySQL não precisa enxergar nada de fora, ou seja, não precisa se conectar a nenhum container, a nenhuma outra máquina ou mesmo à máquina física em questão. Aliás, os outros projetos que eu executo no servidor teoricamente nem sabem que o php-fpm e o MySQL estão rodando na máquina, também, afinal, até a lista de processos é isolada.

Graças a essas características, hoje, containers são usados em muitos serviços da web, como Heroku (que até onde eu saiba foi meio que pioneiro no uso de containers), Travis CI, Codeship, Deis e muitos serviços no qual você parece ter acesso à uma máquina completa, mas, na verdade, está apenas rodando dentro de um container com outras milhares de aplicações rodando na mesma máquina. =)

No fim das contas, o importante é usar containers (e o Docker, portanto) quando este lhe for realmente conveniente, e não ter como regra sempre usá-lo, mesmo quando seu uso pode vir a ser realmente mais difícil do que deveria. Aliás, essa deveria ser a regra pra todo software, mas, deixo para comentar mais sobre isso noutro post. 😀

E, claro, não posso deixar de destacar três coisas que já falei (ou ao menos mencionei) no post e que são bem relacionadas a respeito do uso de containers:

  • Não use containers da mesma forma que usaria uma máquina virtual;
  • PELO AMOR DE DEUS PAI não use/procure/deseje acesso SSH dentro de containers (pois isso super implica em usar containers como máquinas virtuais, o que não é legal);
  • Nada te proíbe de às vezes misturar softwares que estão em containers com softwares que não estão em containers (e às vezes isso pode ser interessante, inclusive);

Agora que você leu mais de 1500 palavras sobre o que o Docker é, o que não é e alguns pontos legais a respeito, vamos ao:

Tutorial básico de uso do Docker

Nesse tutorial, para seguir mais ou menos a base do tutorial básico de uso do Vagrant, vamos criar um container Ubuntu no Docker, instalar o Apache 2 nele, e depois alterar a página inicial padrão do Apache 2 para "Olá Mundo" básico usando o vim, acessando o interior do container (embora essa não seja a melhor prática de todas, vou fazer isso apenas para seguir a mesma ideia do tutorial básico de uso do Vagrant, mesmo).

1) Baixe e instale o Docker (importante ter uma máquina de 64 bits, pois é o único ambiente no qual o Docker efetivamente roda..);
2) Depois, numa pasta vazia, crie um arquivo com o nome "Dockerfile" e com o conteúdo abaixo:

FROM ubuntu:trusty
RUN apt-get update 
RUN apt-get install -y apache2 vim
EXPOSE 80
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

No arquivo acima, estão especificados os comandos que o Docker deverá seguir na criação da imagem do container. Aqui, vale a especificação do que é imagem e do que é container para o docker:

  • Imagem é uma especificação do que o container vai possuir quando for executado. Ela não é uma entidade ativa (uma imagem não pode ser executada), mas sim passiva, pois apenas armazena as instruções e dados que depois serão usadas para criar o container;
  • Container é basicamente uma imagem sendo executada, acompanhado de informações extras adicionais necessárias para o S.O, como segmentos de dados (data e stack), status do processo e dados extras que o S.O pode necessitar para a execução do programa;

Ou seja, para você possuir um container, você precisa ter uma imagem já construída. Portanto, para ter um container rodando a partir do zero, é necessário, além do Dockerfile, da execução de dois comandos: Um para construir a imagem, e outro para criar um container a partir dessa imagem, diferente do Vagrant que a partir de um único comando já faz tudo automagicamente, mesmo na configuração inicial. Esses comandos serão abordados mais abaixo.

Agora, vamos à descrição do que cada linha faz:

  1. A primeira linha define em que imagem a nossa imagem final deve ser baseada. No nosso caso, trata-se do Ubuntu Trusty, que é definido lá no repositório oficial do Docker;
  2. A segunda linha instrui o Docker a executar, dentro do Ubuntu Trusty, um simples "apt-get update". Note que, por padrão, os containers já rodam com usuário root, e por isso o "sudo" não é necessário na frente do comando;
  3. A terceira linha o Docker a instalar os pacotes apache2 e vim. O vim não é necessário para a instalação do apache 2, mas vai ser útil para a posterior edição do arquivo HTML padrão do Apache;
  4. A quarta linha instrui o Docker a expor a porta 80 do futuro container por padrão;
  5. A quinta linha instrui o Docker que comando deve ser executado quando o container for iniciado;

3) Agora, na mesma pasta onde você criou o arquivo, execute o comando "docker build -t tutorial-docker .". A saída final do programa deve ser algo similar a isso:

Note que, no comando acima, a imagem é construída e tageada com a tag "tutorial-docker". Se não aplicássemos uma tag na imagem, teríamos que usar o hash que o docker gera automaticamente para ela na construção da imagem, o que não é muito amigável para um tutorial.

Com isso, a nossa imagem tutorial-docker vai ter sido criada com perfeito sucesso, baseada no Ubuntu Trusty e já com os pacotes Apache 2 e vim pré-instalados. Agora, vamos criar o container? =)

4) Para criar o container, execute o comando "docker run --name container-tutorial-docker -p 3000:80 -d tutorial-docker", como visto abaixo:

No comando executado para criar o container, "-t <tag>" define a tag que será usada para comandar o container, "-p 3000:80" faz o docker redirecionar a porta 3000 do seu computador para a porta 80 do container, e "-d" manda o docker mandar a execução do container para o background, permitindo assmi que o fluxo normal do terminal ocorra.

Além disso, como mostrado na imagem, "docker ps" faz o papel de "monitor" dos containers em execução, mostrando o que está rodando, que portas está usando e a quanto tempo está executando, além de outras informações.

Note também que, diferente do Vagrant, aqui precisamos fazer um redirecionamento de portas para que seja possível acessar o Apache 2.

5) Agora, vamos alterar o arquivo HTML de boas vindas do Apache para ter nosso Olá Mundo, como fizemos no tutorial básico do Vagrant. A diferença aqui é que, diferente do Vagrant, o acesso ao container não vai ser feito através de SSH, mas sim a partir de um truque do docker chamado "docker exec".

Outra coisa importante: Como no caso do Vagrant, essa não é a melhor forma de alterar arquivos dentro da máquina, pois todas as alterações serão perdidas caso eventualmente o container seja recriado (o que é necessário quando a imagem recebe uma atualização, por exemplo). Só vamos fazer isso aqui para demonstrar o uso do "docker exec", mesmo. =)

O comando a ser executado neste caso é "docker exec -ti container-tutorial-docker bash". Veja abaixo:

Como que o docker exec faz para acessar o interior do container sem ser por SSH? Bom, eu acho que num primeiro momento dá para considerar que a resposta para esta pergunta é..

Mas, sobre o comando "docker exec -ti container-tutorial-docker bash", basicamente:

  • "-ti" faz o Docker manter a conexão com o terminal aberta (o docker exec por padrão fecha todas as conexões com o seu terminal e apenas executa o programa especificado no container);
  • "container-tutorial-docker" é o nome do nosso container, como esperado;
  • "bash" é o nome do programa (localizado dentro do container) que desejamos executar;

E com isso temos o arquivo HTML alterado corretamente e tudo funcionando usando Docker, de boas. \o/

Uma observação: Nesse exemplo do tutorial, embora o docker exec tenha sido usado apenas de modo ilustrativo, o container, por si só, não quebrou o paradigma do Docker de cada container ter uma responsabilidade única. Isso porque o Apache apenas serve arquivos, e o container executa o Apache, então está tudo certo, assim. =)

Bom, espero que tenham gostado do tutorial. Foram mais de 2600 palavras investido num post que eu precisava fazer a algum tempo, mas que só com as pesquisas recentes permitiram que eu escrevesse de forma mais sábia sobre o assunto. Não é pouca palavra não. 😛

Ah, e quem quiser saber mais sobre o Docker, dá uma estudada na documentação, que é bem organizada e é bem completa, explicando desde como criar um Dockerfile a como usar os vários comandos do Docker de forma fácil e rápida.

Por fim, compartilhe, e deixe seus comentários, sua opinião é muito importante para mim e mesmo dúvidas ou sugestões vão me ajudar a melhorar ainda mais o conteúdo desse e dos futuros posts. Ficam os links relacionados ao Docker:


Posts relacionados


30 respostas para “Docker - O que é, o que não é, e alguns detalhes a mais”

  1. Avatar de Alan Ktquez

    Parabéns pelo post man, se eu tinha dúvidas iniciais, elas foram tiradas somente nesta postagem, obrigado!
    Ele é um excelente Get started, recomendei.
    Vlw

    1. Avatar de Fernando Jorge Mota

      Opa!

      Fico muito feliz que tenha curtido e recomendado. Com toda a certeza isso vai me ajudar a escrever muito mais posts completos como esse no futuro. Valeu pelo apoio!

      Abs.

  2. Avatar de Fernando Paladini

    Muito boa introdução! Parabéns pelo post, Mota 🙂

    1. Avatar de Fernando Jorge Mota

      Opa! Maneiro que você curtiu. Valeu pelo elogio e espero que acompanhe os próximos posts também! o/

      Abs

  3. Avatar de Vicente Martins

    Cara, muito bom o post! Como todos os outros que comentaram, foi a melhor introdução sobre o assunto que encontrei até agora (e olha que procurei viu!). E esses vídeos cara, parecia que você estava aqui do lado dizendo "é assim que faz animal!". Obrigado pela dedicação e abraço!

    1. Avatar de Fernando Jorge Mota

      Opa!

      Fico feliz que essa tenha sido uma das melhores introduções sobre o assunto até agora o/

      Os vídeos deram certo trabalhinho pra fazer, espero que tenham ficado bem explicativos também. 😛

      Valeu, e abs!

  4. Avatar de Matheus Filho
    Matheus Filho

    Assim, bem que você poderia mostrar como montar algo nesse esquema que você usa... Nginx diretamente na maquina e Php/ MySql em containers... Seria MARAVILHOSO... 😀 Brigadão, muito boa introdução.

    1. Avatar de Fernando Jorge Mota

      Opa!

      Valeu pela sugestão! Vou considerá-la para poder usar como base para um post futuro.

      Abs!

    2. Avatar de Fernando

      Ei Matheus! Depois de MUITOS ANOS, eu consegui parar e escrever um tutorial que pode ajudar nisso: https://fjorgemota.com/2024/07/07/docker-networks-ou-como-configurar-php-fpmmysql-no-docker-com-o-nginx-externo/

      Valeu!

  5. Avatar de Nayara Valadares

    Ótimo post cara, tudo explicadinho! muito obrigada pelos esclarecimentos e um grande abraço!

    1. Avatar de Fernando Jorge Mota

      Obrigado pelo comentário, Nayara! Fico muito feliz que você gostou do post 😀 😀 😀

      Abraço!

  6. Avatar de Thiago Elias
    Thiago Elias

    Excelente post, iniciei meus estudos em docker, e seu artigo foi muito esclarecedor. Obrigado e Parabéns leitura muito prazerosa.

    1. Avatar de Fernando Jorge Mota

      Olá Thiago!

      Fico feliz que tenha curtido o post! =D

      Abs.

  7. Avatar de Daniel Albino
    Daniel Albino

    Parabéns pelo post Fernando. Bastante claro, objetivo e com um senso de humor que torna a leitura ainda mais agradável. 🙂

    1. Avatar de Fernando Jorge Mota

      Olá Daniel!

      Valeu! Fico feliz que você tenha curtido o post! 😀

      Abs!

  8. Avatar de alexandredsc
    alexandredsc

    Muito bom o texto!

    1. Avatar de Fernando Jorge Mota

      Valeu Alexandre!

      Fico feliz que tenha curtido! 😀

  9. Avatar de Fabio De Carli
    Fabio De Carli

    Excelente explicações, deixando tudo bem claro!
    Parabéns

  10. Avatar de Mauri Francisco Do Carmo
    Mauri Francisco Do Carmo

    Muito interessante. Sou iniciante nesse mundo de virtualização mas já estou gostando do seu conteúdo hahaha. Agora bora conhecer o Vagrant.

    1. Avatar de Fernando Jorge Mota

      Opa!

      haha..valeu!

      Boa leitura! Qualquer dúvida é só mandar nos comentários. 🙂

      Abs.

  11. Avatar de Rafael Rodrigues Pereira
    Rafael Rodrigues Pereira

    Muito bom. Porém, tem um erro no script de criação de container:

    O script "docker run –name container tutorial-docker -p 3000:80 -d tutorial-docker" não funciona.

    O "–name" tem que ser "--name" (Acredito que foi um problema no corretor...)
    Tem um parâmetro a mais. Acredito que em "container tutorial-docker" deveria ser "container-tutorial-docker".

    No mais, ótimo artigo.
    Obrigado.

    1. Avatar de Sérgio Toledo

      Correto Rafael, o comando certo é:
      docker run --name container-tutorial-docker -p 3000:80 -d tutorial-docker

      1. Avatar de Fernando Jorge Mota

        Opa!

        Desculpem pela demora na resposta, acabei de corrigir o código no tema do WordPress (no editor aparecia a versão certinha em relação ao --, mas aí o WordPress convertia logo antes de mostrar o post). Também corrigi o problema do parâmetro.

        Valeu pelo aviso pessoal!

        Abraço.

  12. Avatar de Daniel Benetti
    Daniel Benetti

    Muito bom tutorial, parabéns.
    Só fiquei algumas duvidas:
    "Outra coisa importante: Como no caso do Vagrant, essa não é a melhor
    forma de alterar arquivos dentro da máquina, pois todas as alterações
    serão perdidas caso eventualmente o container seja recriado (o que é
    necessário quando a imagem recebe uma atualização, por exemplo)"

    Qual seria a melhor forma de alterar arquivos nesse caso?
    Para não perder as alterações a sugestão seria criar uma nova imagem após a alteração do arquivo?

    1. Avatar de Fernando Jorge Mota

      Opa, Daniel!

      Valeu pelo elogio!

      Sobre a sua pergunta, eu acabei me esquecendo de fazer um post extra sobre isso, mas a resposta é basicamente...Docker volumes! Para dar um exemplo básico, é em um volume que os dados que um banco de dados persiste são salvos, de forma que tais dados não sejam perdidos quando o container é recriado.

      Aqui está a documentação excelente sobre o assunto, em inglês: https://docs.docker.com/engine/tutorials/dockervolumes/

      Assim que eu puder voltar com o blog escrevo mais sobre o assunto. =)

      Abs.

  13. […] que implementa um PaaS - Platform as a Service, ou Plataforma como Serviço, em inglês - e usa o Docker - que já apresentamos em outro post - para fazer suas "magias". Sua administração decorre de um simples comando chamado "dokku", que […]

  14. […] inglês (!!!), mas para a surpresa de um total de zero pessoas a vida adulta é bem...caótica, e artigos de sucesso como o que escrevi anos atrás sobre o Docker (que até hoje recebe um razoável … levam MUITO tempo para serem propriamente escrito, testados e revisados. Eu gosto da ideia de […]

  15. […] eu postei o tutorial completo sobre Docker, muitos anos atrás, algumas pessoas comentaram pedindo mais detalhes a respeito desse trecho aqui […]

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.