Criando sua própria imagem docker

techfree.com.br

Criando sua própria imagem docker

Esse artigo tem como objetivo explicar de forma detalhada, e com exemplos, como funciona o processo de criação de imagens docker.

docker-600x400

Esse texto tem como público alvo pessoas que já sabem um pouco sobre docker, mas ainda não sabiam como criar imagens docker. Caso não sabia nada sobre docker ainda, veja esse link.

Antes de explicarmos como criar sua imagem, vale a pena tocarmos em uma questão que normalmente confunde iniciantes do docker: “Imagem ou container?”

Qual diferença de Imagem e Container?

Fazendo um paralelo com o conceito de orientação a objeto, a imagem é a classe e o container o objeto, ou seja, a imagem é a abstração da infraestrutura em um estado somente leitura, que é de onde será instanciado o container.

layer04

Todo container é iniciado a partir de uma imagem, dessa forma podemos concluir que nunca teremos uma imagem em execução.

Um container só pode ser iniciado a partir de uma única imagem, ou seja,  caso deseje um comportamento diferente será necessário customizar a imagem.

Anatomia de uma imagem

As imagens podem ser oficial ou não oficial.

Imagens oficiais e não oficiais

As imagens oficiais da docker são aquelas que não tem usuário em seu nome, ou seja, a imagem “ubuntu:16.04″ é oficial, por outro lado a imagem nuagebec/ubuntu” não é oficial. Essa segunda imagem é mantida pelo usuário nuagebecque mantém muitas outras imagens não oficiais.

As imagens oficiais são mantidas pela empresa docker e são disponibilizadas na nuvem docker.

O objetivo das imagens oficiais é prover um ambiente básico (ex. debian, alpine, ruby, python) que serve de ponto de partida para criação de imagens pelos usuários, que é o que explicaremos mais adiante ainda nesse capítulo.

As imagens não oficiais são mantidas pelos usuários que as criaram. Falaremos sobre envio de imagens para nuvem docker em outro tópico.

Nome da imagem

O nome de uma imagem oficial é composta de duas partes. A primeira é o que a documentação chama de “repositório” e a segunda é a “tag”. No caso da imagem “ubuntu:14.04”, ubuntu é o repositório e 14.04 é a tag.

Para o docker o “repositório” é uma abstração de conjunto de imagens, ou seja, não confunda com o local de armazenamento das imagens, que detalharemos mais a frente.

Para o docker a “tag” é uma abstração para criar uma unidade dentro do conjunto de imagens definidas no “repositório”.

Um “repositório” pode conter mais de uma “tag” e cada conjunto repositório:tag representa uma imagem diferente.

Execute esse comando abaixo para visualizar todas as imagens que se encontram localmente na sua estação nesse momento:

docker images

Como se cria imagens

Há duas formas de criar imagens customizadas: Com commit e com Dockerfile.

Criando imagens com commit

É possível criar imagens executando o comando commit relacionado a um container, ou seja, esse comando pegará o status atual desse container escolhido e criará uma imagem com base nele.

Vamos ao exemplo. Primeiro vamos criar um container qualquer:

docker run -it --name containercriado ubuntu:16.04 bash

Agora que estamos no bash do container, vamos instalar o nginx nele:

apt-get update
apt-get install nginx -y
exit

Vamos parar o container com o comando abaixo:

docker stop containercriado

Agora vamos efetuar o commit desse container em uma imagem:

docker commit containercriado meuubuntu:nginx

No exemplo do comando acima, containercriado é o nome do container que criamos e modificamos nos passos anteriores e o nome meuubuntu:nginx é a imagem resultante do commit, ou seja, o estado do containercriado será armazenado em uma imagem chamada meuubuntu:nginx que nesse caso a única modificação que temos da imagem oficial do ubuntu na versão 16.04 é um pacote nginx instalado.

Para visualizar a lista de imagens e encontrar a que acabou de criar, execute novamente o comando abaixo:

docker images

Para testar sua nova imagem, vamos criar um container a partir dela e verificar se o nginx está instalado:

docker run -it --rm meuubuntu:nginx dpkg -l nginx

Se quiser validar, pode executar o mesmo comando na imagem oficial do ubuntu:

docker run -it --rm ubuntu:16.04 dpkg -l nginx

Vale salientar que o método commit não é a melhor opção para criar imagens, pois como pudemos verificar, o processo de modificação da imagem é completamente manual e apresenta certa dificuldade para rastrear as mudanças que foram efetuadas, uma vez que o que foi modificado manualmente não é registrado automaticamente na estrutura do docker.

Criando imagens com Dockerfile

Quando se utiliza Dockerfile para gerar uma imagem, basicamente é apresentado uma lista de instruções que serão aplicadas em uma determinada imagem para que outra seja gerada com base nessas modificações.

dockefile_imagem

Podemos resumir que o arquivo Dockerfile na verdade representa a exata diferença entre uma determinada imagem, que aqui chamamos de base, e a imagem que se deseja criar, ou seja, nesse modelo temos total rastreabilidade sobre o que será modificado essa nova imagem.

Vamos ao mesmo exemplo da instalação do nginx no ubuntu 16.04.

Primeiro crie um arquivo qualquer para um teste futuro:

touch arquivo_teste

Crie um arquivo chamado Dockerfile e dentro dele coloque o seguinte conteúdo:

FROM ubuntu:16.04
RUN apt-get update && apt-get install nginx -y
COPY arquivo_teste /tmp/arquivo_teste
CMD bash

No arquivo acima eu utilizei quatro instruções:

FROM é usado para informar qual imagem usarei como base, que nesse caso foi a ubuntu:16.04.

RUN é usado para informar quais comandos serão executados nesse ambiente para efetuar as mudanças necessárias na infraestrutura do sistema. São como comandos executados no shell do ambiente, igual ao modelo por commit, mas nesse caso foi efetuado automaticamente e completamente rastreável, já que esse Dockerfile será armazenado no sistema de controle de versão.

COPY é usado para copiar arquivos da estação onde está executando a construção para dentro da imagem. Usamos um arquivo de teste apenas para exemplificar essa possibilidade, mas essa instrução é muito utilizada para enviar arquivos de configuração de ambiente e códigos para serem executados em serviços de aplicação.

CMD é usado informar qual comando será executado por padrão, caso nenhum seja informado na inicialização de um container a partir dessa imagem. No nosso caso colocamos o comando bash, ou seja, caso essa imagem seja usada para iniciar um container e não informamos o comando, ele executará o bash.

Após construir seu Dockerfile basta executar o comando abaixo:

docker build -t meuubuntu:nginx_auto .

O comando acima tem a opção “-t” que serve para informar o nome da imagem que será criada, que no nosso caso será meuubuntu:nginx_auto e o “.” no final informa qual o contexto que deve ser usado nessa construção de imagem, ou seja, todos os arquivos da sua pasta atual serão enviados para o serviço do docker e apenas eles podem ser usados para manipulações do Dockerfile (Exemplo do uso do COPY).

A ordem importa

É importante atentar que o arquivo Dockerfile é uma sequência de instruções que é lido do topo até sua base e cada linha é executada por vez, ou seja, caso alguma instrução dependa de uma outra instrução, essa dependência deve vir mais acima no documento.

O resultado de  cada instrução desse arquivo é armazenado em um cache local, ou seja, caso o Dockerfile não seja modificado na próxima criação da imagem (build) o processo não demorará, pois tudo estará no cache, mas caso algo seja modificado apenas a instrução modificada e as posteriores serão executadas novamente.

A sugestão pra aproveitar bem o cache do Dockerfile é sempre manter instruções que mudem com mais frequência mais próximas da base do documento. Vale lembrar de atender também as dependências entre instruções.

Vamos utilizar um exemplo pra deixar mais claro:

FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install nginx
RUN apt-get install php5
COPY arquivo_teste /tmp/arquivo_teste
CMD bash

Caso modifiquemos a terceira linha do arquivo e ao invés de instalar o nginx mudarmos para apache2, a instrução que faz o update no apt não será executada novamente, mas a instalação do apache2 será instalado, pois acabou de entrar no arquivo, assim como o php5 e a cópia do arquivo, pois todos eles são subsequentes a linha modificada.

Conclusão

Como podem perceber, com posse do arquivo Dockerfile, é possível ter noção exata de quais mudanças foram efetuadas na imagem e assim registrar as modificações no seu sistema de controle de versão.

Comentários