O que é Dockerfile

Olá!

Como mencionado neste post, o Docker possui alguns recursos que permitiram sua popularização pelo mundo a fora, além da API de integração, o Docker permite que possamos criar imagens a partir de um arquivo de definição, esse arquivo chama-se Dockerfile.

Vamos lá. Como explicado anteriormente em alguns posts, uma imagem nada mais é do que um ambiente totalmente encapsulado e pronto para ser replicado onde desejar. Podemos montar esse ambiente através de um container que esteja em execução (Exportando o mesmo), ou através da criação a partir do Dockerfile, que nada mais é do que um arquivo de definição onde é possível realizar ou preparar todo ambiente a partir de um script de execução. Em resumo, o Dockerfile é um arquivo texto com instruções, comandos e passos que você executaria manualmente, basicamente o Docker executa uma receita de bolo.

Através do comando docker build, o Docker realizar a execução desses passos e no final da execução ele encapsula cada layer gerada para dentro da imagem. Mas o Dockerfile deve seguir uma ordem ou formatação correta para que o build seja feito de forma certa, por exemplo, o formato do texto deve respeitar: INSTRUÇÃO argumento, onde INSTRUÇÃO é o comando que o build deve executar, e argumento são as instruções que deve fato serão feitas, por exemplo:

RUN yum update

Onde:

RUN: É a instrução;

yum update: Argumento que será executado.

Abaixo podemos visualizar todas as opções de instruções disponíveis:

  • FROM: Informa a partir de qual imagem será gerada a nova imagem, lembrando que em poucos casos (Veremos em posts futuros), uma imagem será gerada se um imagem base;
  • MAINTAINER: Campo opcional, que informa o nome do mantenedor da nova imagem;
  • RUN: Especifica que o argumento seguinte será executado, ou seja, realiza a execução de um comando;
  • CMD: Define um comando a ser executado quando um container baseado nessa imagem for iniciado, esse parâmetro pode ser sobrescrito caso o container seja iniciado utilizando alguma informação de comando, como: docker run -d imagem comando, neste caso o CMD da imagem será sobrescrito pelo comando informado;
  • LABEL: Adiciona metadados a uma imagem, informações adicionais que servirão para identificar versão, tipo de licença, ou host, lembrando que a cada nova instrução LABEL é criada uma nova layer, o Docker recomenda que você não use muitas LABEL. É possível realizar filtragens posteriormente utilizando essas LABEL.
  • EXPOSE: Expõem uma ou mais portas, isso quer dizer que o container quando iniciado poderá ser acessível através dessas portas;
  • ENV: Instrução que cria e atribui um valor para uma variável dentro da imagem, isso é útil para realizar a instalação de alguma aplicação ou configurar um ambiente inteiro.
  • ADD: Adiciona arquivos locais  ou que estejam em uma url, para dentro da imagem.
  • COPY: Copia arquivos ou diretórios locais para dentro da imagem.
  • ENTRYPOINT: Informa qual comando será executado quando um container for iniciado utilizando esta imagem, diferentemente do CMD, o ENTRYPOINT não é sobrescrito, isso quer dizer que este comando será sempre executado.
  • VOLUME: Mapeia um diretório do host para ser acessível pelo container;
  • USER: Define com qual usuário serão executadas as instruções durante a geração da imagem;
  • WORKDIR: Define qual será o diretório de trabalho (lugar onde serão copiados os arquivos, e criadas novas pastas);
  • ONBUILD: Define algumas instruções que podem ser realizadas quando alguma determinada ação for executada, é basicamente como uma trigger.

Veja abaixo um exemplo de Dockerfile completo:


# VERSION 0.1

FROM ubuntu
RUN echo foo > bar
# Saida parecida com ===> 907ad6c2736f

FROM ubuntu
RUN echo moo > oink
# Saida parecida com ===> 695d7793cbe4

EXPOSE 5900

# Você terá duas imagens, 907ad6c2736f com /bar, e 695d7793cbe4 com
# /oink.


Basta copiar esse código acima em um arquivo chamado Dockerfile e em seguir executar o comando: docker build -t minhaimagem . . E pronto, será criada uma imagem com o nome de minhaimagem, basta usa-la para o que precisar.

Nos próximos posts veremos como criar uma imagem mais complexa, iremos montar um ambiente completo para um site em WordPress, e aprendermos um pouco mais sobre outros recursos do docker build.

Fique atento, e tendo dúvidas já sabe, nos mande uma mensagem, abraço!

Como Funciona o Filesystem no Docker?

Olá pessoal!

Para você que está começando a ler nossos posts agora, sugiro que leia antes esseesse link que explicam o que é o Docker e como ele funciona. Hoje nós abordaremos um dos assuntos mais importantes dentro do Docker: O Filesystem.

O sistema de arquivos do Docker é chamado de layered, ou seja, é um sistema de arquivo em camadas, o que isso quer dizer?

Um sistema de arquivo comum, possui basicamente duas camadas:

bootfs: Onde ficam o sistema de Boot do sistema e o Kernel.

rootfs: Inclui o sistema de arquivo do sistema, incluindo a arquitetura de diretório, em sistemas unix-like: /dev, /proc, /bin, /etc, /lib, /usr, e /tmp assim como os arquivos de configuração e binários do sistema.

Quando o sistema é iniciado ele carrega o rootfs primeiramente em modo somente leitura, verifica sua integridade e em seguida remonta-o como leitura/escrita e assim fica disponível para o usuário/aplicação.

No Docker temos essa arquitetura também, mas com um diferencial, a camada de escrita que o processo/aplicação visualiza não é o mesmo rootfs base, e sim uma camada de abstração do rootfs, isso é o que faz com que um container torne-se portável, pois as modificações realizadas não são aplicadas ao sistema origem do container, e sim na camada a qual o sistema visualiza.

Para ficar mais claro, veja na figura abaixo como é um sistema tradicional:

    docker-filesystems-generic1

 

Agora veja como é o filesystem no docker:

 

docker-filesystems-multiroot

 

 

Como podem notar o bootfs em vez de ser único por sistema/container, é compartilhado entre eles, mas o rootfs é isolado por camadas, ou seja, o que deve ser em comum entre o host e container é compartilhado via AUFS, que monta uma camada de leitura/escrita em cima do filesystem em somente leitura, isso garante que modificações feitas dentro do container não afetem o sistema de arquivos do host.

A imagem abaixo ilustra melhor como funciona essas camadas:

docker-filesystems-busyboxrw

Um detalhe nessa arquitetura é que a cada modificação e commit do container é gerada uma nova camada, ou seja, digamos que eu inicie um container a partir de uma imagem do Debian, e instale o serviço apache dentro desse container, quando eu for transformar esse container em uma imagem, essa imagem possuirá a primeira camada que é do sistema Debian, e uma camada adicional que refere-se a instalação do serviço apache. Na imagen abaixo podemos visualizar melhor esse ambiente.

 

docker-filesystems-multilayer-update

Lembrando que uma imagem pode ser utilizada diversas vezes, ou seja, há compartilhamento da imagem entre os containers, mas os containers depois de iniciados são isolados uns dos outros, na imagem abaixo podemos visualizar essa arquitetura.docker-filesystem

Como podemos notar, há o compartilhamento das camadas inferiores, pois elas fazem parte da imagem que originou o container, e a camada de escrita, que faz parte do container rodando, é isolada para cada container.

Por hoje é isso, veremos em breve um pouco mais sobre filesystem no Docker, e algumas outras questões relacionadas a essa arquitetura. Ficou com dúvida? Gostaria de saber mais? Algum feedback a nos dar? Deixe sua mensagem e vamos conversando.

Abraço!

O que é Docker?

Olá!

Iniciamos agora uma série de posts técnicos que lhe ajudarão a entender o funcionamento do Docker, e como cada componente é utilizado dentro desta plataforma.

Primeiro temos que definir o que não é Docker. Docker não é um sistema de virtualização tradicional. Enquanto em um ambiente de virtualização tradicional nós temos um S.O. completo e isolado, dentro do Docker nós temos recursos isolados que utilizando bibliotecas de kernel em comum (entre host e container), isso é possível pois o Docker utiliza como backend o nosso conhecido LXC.

Abaixo podemos ver uma figura que ilustra essa diferença.

lxc-vm

 

Docker é uma plataforma Open Source escrito em Go, que é uma linguagem de programação de alto desempenho desenvolvida dentro do Google, que facilita a criação e administração de ambientes isolados.

Mas por que que o Docker é tão legal?

O Docker possibilita o empacotamento de uma aplicação ou ambiente inteiro dentro de um container, e a partir desse momento o ambiente inteiro torna-se portável para qualquer outro Host que contenha o Docker instalado.

Isso reduz drasticamente o tempo de deploy de alguma infraestrutura ou até mesmo aplicação, pois não há necessidade de ajustes de ambiente para o correto funcionamento do serviço, o ambiente é sempre o mesmo, configure-o uma vez e replique-o quantas vezes quiser.

Outra facilidade do Docker é poder criar suas imagens (containers prontos para deploy) a partir de arquivos de definição chamados Dockerfiles (veremos isso melhor em posts futuros).

Não podemos nos esquecer também de que o Docker utiliza como backend default o LXC, com isso é possível definir limitações de recursos por container (memória, cpu, I/O, etc.)

Para ficar um pouco mais claro, podemos ver na imagem abaixo a diferença em se utilizar o LXC puro e o Docker.

lxc_vs_docker

 

Como o Docker faz isso?

Como ele trabalha utilizando cliente e servidor (toda a comunicação entre o Docker Daemon e Docker client é realizada através de API), basta apenas que você tenha instalado o serviço do Docker em um lugar, e aponte em seu Docker Client para esse servidor. A plataforma do Docker em si utilizada alguns conjuntos de recursos, seja para a criação ou administração dos containers, entre esses conjuntos podemos destacar a biblioteca libcontainer, que é responsável pela comunicação entre o Docker Daemon e o backend utilizado, é ela a responsável pela criação do container, e é através dela que podemos setar os limites de recursos por container.

Podemos ver na imagem abaixo como é o Workflow dentro do Docker.

libcontainer intro

 

 

Ficou com dúvidas? Ótimo! nos mande suas dúvidas para que possamos conversar mais sobre essa tecnologia. E aguardem, nos próximos posts explicaremos melhor cada um dos componentes do Docker, e claro traremos algumas aplicações práticas dele 😉

Até Mais!

 

O que é Container?

Olá Pessoal,

Este é nosso primeiro post aqui no Blog, antes de começar a falar sobre o que é Docker, Containers, DevOps e afins gostaríamos de agradecer a você que chegou até nós e agora está lendo um pouco sobre o que é esse mundo.

Você já deve ter ouvido falar em Containers ou no mínimo, Docker, bom o que é tudo isso afinal de onde veio essa história de container?

O projeto LXC (Linux Container) nasceu em agosto de 2008, no inicio, o site oficial trazia a seguinte frase: LXC, chroot com esteroides. O objetivo do projeto era ser uma alternativa a já consolidada tecnologia de chroot, sendo um meio termo entre máquina virtual e chroot, possibilitando a criação de um ambiente mais próximo possível de uma instalação Linux sem a necessidade de  um kernel separado.

Através do chroot é possível encapsular um sistema inteiro dentro de uma estrutura de diretório, fazendo com que o sistema hospede não acesse nada além daquilo que é definido dentro dessa arquitetura. Isso é muito útil pois elimina a sobrecarga de uma máquina virtual inteira para executar um processo ou serviço simples.

Voltando ao LXC, algumas das features do LXC são:

Kernel Namespaces:

Possibilita a abstração de processos dentro do kernel, isso quer dizer que um processo ou grupo de processo é isolado dentro do kernel, podendo visualizar os pontos de montagem, id de processos, id de usuário, hostname e fila de processo, isolados de outros processos ou grupo de processo.

Apparmor and SELinux:

Responsável por carregar politicas de acesso no host, isso quer dizer que são definidas regras de acesso a determinados arquivos/diretórios dentro do host, isso garante que em uma possível brecha de segurança, um container não consiga visualizar ou executar algo malicioso no host.

Seccomp policies:

Realiza uma filtragem das chamadas de sistema (syscall) e aceita ou não essa chamada. Como o host e container compartilham do mesmo kernel, é necessário algumas politicas especificas a nível de interface do kernel para que o hóspede não consiga escalar privilégios dentro do sistema host.

Chroots (pivot_root):

Responsável pelo mapeamento de diretórios e ponto de montagem do sistema container, é a chamada de sistema que cria a árvore de diretórios que o container terá acesso.

Kernel Capabilities:

Todos os sistema UNIX dividem os processos em duas grandes categorias, processo privilegiados  (sendo executados como root) e processos não privilegiados (executados com usuário comum), por padrão todo container executa comando não privilegiados, ou seja, um processo dentro de um container é executado como root dentro do host (mesmo que este esteja como root dentro do container). Sendo assim, a partir do kernel 2.2  foram inseridos dispositivos que possibilitam ao container executar de forma privilegiados alguns comandos, para esses dispositivos foi dado o nome de Capabilities ou CAP.

Cgroups:

Ou Control Groups, é responsável pelo controle de uso dos recursos por processo/grupo de processo, podendo assim executar diferentes containers com diferentes limites de uso (memória, cpu, I/O).

Devido a essas características é que chamamos de container todo sistema criado utilizando essa tecnologia, pois o sistema fica “enjaulado” dentro de uma caixa de recursos alocados exclusivamente para ele, e claro limitado a esses recursos. Abaixo há uma imagem ilustrando a diferença entre uma máquina virtual comum e um sistema em containers.

 

 

Ótimo, já sabemos um pouco sobre o que é e de onde vieram os containers, agora temos outras dúvidas:

O que é o docker afinal?

No que os containers podem me ajudar?

Ok, ok, vamos responder a essas e muitas outras dúvidas em nossos próximos posts, fiquem atentos e caso tenham dúvidas ou quiserem conversar um pouco mais sobre esse mundo, deixem suas mensagens!