Post

Guia Completo de Docker Images: Conceitos, Criação e Práticas Avançadas

Guia Completo de Docker Images: Conceitos, Criação e Práticas Avançadas

Introdução Geral

Docker Images são a base da tecnologia de containers, permitindo criar ambientes de execução leves e consistentes para aplicações. Este tutorial cobre todos os aspectos fundamentais e avançados do uso de Docker Images, desde o entendimento de conceitos básicos e criação de imagens até estratégias de otimização, segurança e automação. Ao longo deste guia, você aprenderá a construir, versionar e compartilhar imagens Docker de forma eficiente e segura, além de configurar pipelines de CI/CD para integrar o uso de imagens em fluxos automatizados de deploy.


Sumário

Sumário

  1. Introdução às Docker Images
  2. Buscando e Baixando Imagens do Docker Hub
  3. Criando Docker Images com Dockerfile
  4. Dockerfile: Instruções Essenciais e Práticas de Organização
  5. Build de Imagens com docker build e Parâmetros
  6. Otimização de Imagens para Eficiência e Tamanho Reduzido
  7. Multi-Stage Builds: Reduzindo Tamanho e Isolando Dependências
  8. Tagging e Versionamento de Imagens
  9. Publicando Imagens em Registries (Docker Hub, Amazon ECR, GitLab Container Registry)
  10. Escaneamento de Vulnerabilidades em Imagens
  11. Gerenciamento de Imagens Locais
  12. Manipulação de Camadas e Cache em Docker Images
  13. Exportando e Compartilhando Imagens Sem Registry
  14. Configuração de Segurança e Boas Práticas para Imagens
  15. Casos de Uso Avançados e Melhores Práticas para Docker Images

1. Introdução às Docker Images

Objetivo

Apresentar o conceito de Docker Images, explicar sua função no processo de containerização, e fornecer uma visão da estrutura básica das imagens Docker e seu armazenamento eficiente em camadas.

Conteúdo

  • O que são Docker Images?
  • Diferença entre Docker Images e Containers
  • Estrutura das Docker Images: Sistema de Arquivos em Camadas (UnionFS)
  • Armazenamento e Compartilhamento de Imagens com Eficiência

O que são Docker Images?

As Docker Images são arquivos imutáveis que contêm tudo o que é necessário para executar uma aplicação em um container. Elas incluem o sistema operacional, dependências, bibliotecas e configurações de ambiente. As imagens são essencialmente os “moldes” a partir dos quais os containers são criados. Quando uma imagem é executada, ela se transforma em um container, que é uma instância em tempo de execução da imagem.

Diferença entre Docker Images e Containers

Docker Image Container
Um blueprint (modelo) estático Instância em execução de uma imagem
Imutável, não sofre alterações Mutável, pode ser modificado durante a execução
Usada para criar múltiplos containers É criado a partir de uma imagem

Em resumo:

  • Uma imagem é o arquivo de modelo, e um container é a instância gerada a partir dessa imagem.
  • A partir de uma imagem, você pode criar quantos containers desejar, todos com a mesma configuração inicial.

Estrutura das Docker Images: Sistema de Arquivos em Camadas (UnionFS)

As Docker Images são construídas em camadas, uma característica central para a eficiência e flexibilidade no Docker. Cada camada representa uma mudança ou uma adição ao sistema de arquivos e é criada por meio de comandos no Dockerfile. As imagens utilizam o sistema de arquivos UnionFS para empilhar camadas, permitindo que cada uma compartilhe ou modifique arquivos das camadas anteriores.

Exemplo:

  • Uma imagem pode começar com uma camada base Ubuntu.
  • Em seguida, uma camada adicional pode instalar o Python.
  • Outra camada adiciona as bibliotecas necessárias para o aplicativo específico.

Essa estrutura de camadas oferece dois benefícios principais:

  1. Reutilização e Eficiência: Camadas comuns entre diferentes imagens são compartilhadas, economizando espaço de armazenamento e acelerando o processo de build.
  2. Cache de Camadas: Se uma camada não muda, o Docker pode reutilizá-la em builds futuros, acelerando a criação de imagens.

Armazenamento e Compartilhamento de Imagens com Eficiência

O Docker armazena imagens localmente e usa registries (como o Docker Hub) para compartilhar imagens de maneira centralizada e eficiente. As imagens armazenadas localmente podem ser listadas com docker images e removidas quando não forem mais necessárias. Para compartilhar uma imagem, basta carregá-la em um registry, onde outras pessoas podem baixá-la para uso em seus próprios ambientes.


Conclusão

Docker Images são a base da containerização. Compostas por camadas empilháveis e reutilizáveis, elas garantem que os containers sejam rápidos e eficientes. Entender a estrutura e o funcionamento das imagens é o primeiro passo para dominar o Docker, permitindo que você crie e gerencie containers de maneira flexível e otimizada. No próximo tópico, Buscando e Baixando Imagens do Docker Hub, exploraremos como procurar e baixar imagens existentes de registries públicos para iniciar seu ambiente Docker rapidamente.


2. Buscando e Baixando Imagens do Docker Hub

Objetivo

Ensinar como buscar e baixar imagens existentes a partir de registries como o Docker Hub, fornecendo orientações para encontrar e escolher imagens confiáveis.

Conteúdo

  • Introdução ao Docker Hub e Registries Públicos
  • Uso do Comando docker pull para Baixar Imagens
  • Como Navegar e Buscar Imagens Confiáveis no Docker Hub
  • Exemplo Prático de Busca e Verificação de Imagens

Introdução ao Docker Hub e Registries Públicos

O Docker Hub é o registry público padrão do Docker, oferecendo milhares de imagens prontas para uso, incluindo imagens oficiais e versões personalizadas de várias aplicações. Os registries, como o Docker Hub, facilitam o compartilhamento e o armazenamento centralizado de imagens, permitindo que desenvolvedores de todo o mundo colaborem e compartilhem imagens Docker.

Além do Docker Hub, outros registries populares incluem:

  • Amazon Elastic Container Registry (ECR): para armazenar e gerenciar imagens Docker na AWS.
  • GitLab Container Registry: integrado ao GitLab CI/CD para gerenciar imagens de projetos.

Uso do Comando docker pull para Baixar Imagens

O comando docker pull baixa uma imagem específica de um registry. A estrutura básica é:

1
docker pull <nome-da-imagem>:<tag>
  • <nome-da-imagem>: nome da imagem que deseja baixar (ex.: nginx, mysql).
  • <tag>: versão específica da imagem (ex.: latest, 1.19).

Se a tag não for especificada, o Docker automaticamente baixa a tag latest.

Exemplo:

1
docker pull nginx:latest

Este comando baixa a imagem nginx com a tag latest do Docker Hub.

Como Navegar e Buscar Imagens Confiáveis no Docker Hub

  1. Acessando o Docker Hub: Visite o site do Docker Hub e use a barra de pesquisa para encontrar imagens.
  2. Verificar Imagens Oficiais: As imagens oficiais, como nginx, mysql, e python, são mantidas pela comunidade Docker e passam por verificações rigorosas. Elas possuem um selo de verificação que as distingue das imagens personalizadas.
  3. Verificar a Quantidade de Downloads e Estrelas: Imagens amplamente usadas e com muitas estrelas geralmente são mais confiáveis e bem mantidas.
  4. Ler a Documentação: As páginas de cada imagem geralmente incluem instruções de uso e configuração, além de variáveis de ambiente e portas expostas.

Exemplo Prático de Busca e Verificação de Imagens

1. Pesquisando uma Imagem no Docker Hub

Imagine que você deseja usar o MySQL em um container. No Docker Hub:

  • Pesquise por “mysql”.
  • Identifique a imagem oficial com o selo OFFICIAL IMAGE.

2. Baixando a Imagem do MySQL

Depois de encontrar a imagem, você pode baixá-la pelo terminal:

1
docker pull mysql:8.0

Este comando baixa a versão 8.0 do MySQL. Após o download, a imagem estará disponível localmente e poderá ser verificada com docker images.

3. Verificando a Imagem Baixada

Para garantir que a imagem foi baixada corretamente e verificar seus detalhes, use o comando:

1
docker images mysql

Este comando lista todas as versões de MySQL baixadas, exibindo a IMAGE ID, o TAG e o SIZE.


Conclusão

Saber como buscar e baixar imagens do Docker Hub é essencial para iniciar rapidamente com containers Docker. Seguir práticas recomendadas, como verificar a origem das imagens e escolher versões bem mantidas, ajuda a garantir que você use imagens seguras e confiáveis. No próximo tópico, Criando Docker Images com Dockerfile, exploraremos como criar suas próprias imagens personalizadas para atender às necessidades específicas dos seus projetos.


3. Criando Docker Images com Dockerfile

Objetivo

Ensinar a criar imagens personalizadas usando um Dockerfile, configurando os serviços e dependências necessários para desenvolver uma imagem sob medida para a aplicação.

Conteúdo

  • O Que é um Dockerfile?
  • Instruções Básicas do Dockerfile
    • FROM, RUN, COPY, CMD
  • Criando uma Imagem Simples com Dockerfile
  • Versionamento e Boas Práticas para Dockerfiles

O Que é um Dockerfile?

Um Dockerfile é um arquivo de texto contendo uma sequência de instruções que define todos os passos para construir uma imagem Docker. Cada instrução no Dockerfile gera uma camada na imagem final, resultando em um arquivo leve e modular que pode ser reproduzido e distribuído.

Instruções Básicas do Dockerfile

Aqui estão algumas das instruções mais comuns e essenciais para escrever Dockerfiles:

1. FROM

Define a imagem base que será utilizada para a construção da nova imagem. A imagem base pode ser um sistema operacional básico, como ubuntu, ou uma imagem com dependências pré-instaladas, como node ou python.

Exemplo:

1
FROM ubuntu:20.04

2. RUN

Executa comandos específicos durante o processo de construção da imagem. Esse comando é geralmente usado para instalar pacotes ou dependências.

Exemplo:

1
RUN apt-get update && apt-get install -y nginx

3. COPY

Copia arquivos ou diretórios do sistema local para o sistema de arquivos do container. É utilizado para incluir o código-fonte da aplicação ou arquivos de configuração na imagem.

Exemplo:

1
COPY ./app /usr/src/app

4. CMD

Define o comando padrão que será executado quando um container criado a partir da imagem for iniciado. Essa instrução pode ser sobrescrita ao rodar o container com outros comandos.

Exemplo:

1
CMD ["nginx", "-g", "daemon off;"]

Criando uma Imagem Simples com Dockerfile

Aqui está um exemplo de um Dockerfile básico para uma aplicação Node.js. Este Dockerfile cria uma imagem que contém o Node.js, copia o código da aplicação para o container e instala as dependências.

Exemplo de Dockerfile para Node.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Usando Node.js como imagem base
FROM node:14

# Criando um diretório de trabalho
WORKDIR /usr/src/app

# Copiando o arquivo package.json e instalando dependências
COPY package*.json ./
RUN npm install

# Copiando o código da aplicação
COPY . .

# Expondo a porta que a aplicação usa
EXPOSE 3000

# Comando para iniciar a aplicação
CMD ["npm", "start"]

Explicação:

  1. FROM node:14: Define uma imagem base com Node.js, versão 14.
  2. WORKDIR /usr/src/app: Define o diretório de trabalho dentro do container.
  3. COPY package*.json ./: Copia os arquivos package.json e package-lock.json.
  4. RUN npm install: Instala as dependências da aplicação.
  5. COPY . .: Copia todos os arquivos da aplicação para o container.
  6. EXPOSE 3000: Expõe a porta 3000, que é a porta utilizada pela aplicação.
  7. CMD ["npm", "start"]: Define o comando que será executado ao iniciar o container.

Versionamento e Boas Práticas para Dockerfiles

  • Manter Dockerfiles Simples: Defina apenas as dependências essenciais para evitar imagens pesadas e complexas.
  • Separar Ambiente de Desenvolvimento e Produção: Crie Dockerfiles específicos para cada ambiente, quando necessário.
  • Usar Versões Específicas de Imagens: Defina versões explícitas, como node:14, para evitar surpresas com atualizações automáticas.

Conclusão

O Dockerfile é a base para criar imagens personalizadas, permitindo configurar e instalar tudo o que é necessário para a execução de uma aplicação. No próximo tópico, Dockerfile: Instruções Essenciais e Práticas de Organização, veremos como explorar outras instruções e organizar Dockerfiles para tornar as imagens mais eficientes e fáceis de manter.


4. Dockerfile: Instruções Essenciais e Práticas de Organização

Objetivo

Explorar instruções adicionais no Dockerfile para maior controle e organização, além de práticas recomendadas para organizar as instruções para eficiência e clareza.

Conteúdo

  • Instruções Essenciais do Dockerfile
    • EXPOSE, ENV, ENTRYPOINT, VOLUME, WORKDIR
  • Organização e Ordem das Instruções
  • Exemplo de Dockerfile Bem Estruturado

Instruções Essenciais do Dockerfile

Além das instruções FROM, RUN, COPY e CMD, há outras instruções úteis para personalizar e estruturar um Dockerfile de maneira eficaz:

1. EXPOSE

A instrução EXPOSE documenta qual porta o container usará para comunicação. Embora o comando não configure o mapeamento de portas (isso é feito ao iniciar o container com docker run), ele indica a porta que será usada pela aplicação.

Exemplo:

1
EXPOSE 8080

2. ENV

A instrução ENV define variáveis de ambiente dentro do container. Essas variáveis podem ser usadas pela aplicação e outras instruções no Dockerfile.

Exemplo:

1
ENV NODE_ENV=production

3. ENTRYPOINT

A instrução ENTRYPOINT configura um comando imutável que será executado sempre que o container iniciar. Essa instrução é útil para definir o processo principal da aplicação.

Exemplo:

1
ENTRYPOINT ["nginx", "-g", "daemon off;"]

4. VOLUME

A instrução VOLUME cria um ponto de montagem para persistir dados, permitindo que os dados permaneçam mesmo que o container seja recriado.

Exemplo:

1
VOLUME /data

5. WORKDIR

Define o diretório de trabalho dentro do container. Ao usar WORKDIR, os comandos RUN, COPY, ADD, entre outros, utilizam esse diretório como ponto de referência.

Exemplo:

1
WORKDIR /usr/src/app

Organização e Ordem das Instruções

A ordem das instruções no Dockerfile pode impactar o desempenho e a manutenção da imagem:

  1. Definir FROM no topo: A imagem base deve ser a primeira instrução do Dockerfile.
  2. Definir ENV antes de RUN: Variáveis de ambiente devem ser definidas antes de instalar dependências, para que elas sejam usadas durante o processo de instalação.
  3. Combinar Comandos: Agrupe comandos RUN para minimizar o número de camadas. Por exemplo:

    1
    2
    3
    
    RUN apt-get update && \
        apt-get install -y nginx && \
        rm -rf /var/lib/apt/lists/*
    
  4. Adicionar EXPOSE e VOLUME ao Final: Essas instruções são informativas e geralmente colocadas no final do Dockerfile para documentar o funcionamento da aplicação.

Exemplo de Dockerfile Bem Estruturado

Aqui está um exemplo de Dockerfile que incorpora as instruções e práticas descritas acima para uma aplicação Node.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Define a imagem base
FROM node:14

# Define variáveis de ambiente
ENV NODE_ENV=production
ENV PORT=3000

# Define o diretório de trabalho
WORKDIR /usr/src/app

# Copia e instala dependências
COPY package*.json ./
RUN npm install && npm cache clean --force

# Copia o código da aplicação
COPY . .

# Define a porta que o container vai expor
EXPOSE 3000

# Configura o ponto de entrada
ENTRYPOINT ["node", "server.js"]

Explicação:

  • Variáveis de ambiente como NODE_ENV e PORT são definidas no início para que possam ser usadas por outros comandos.
  • WORKDIR simplifica o uso de caminhos relativos e organiza o contexto de trabalho da aplicação.
  • Combinação de comandos no RUN minimiza o número de camadas e economiza espaço na imagem.

Conclusão

Organizar bem o Dockerfile e usar as instruções de forma eficiente resulta em imagens mais leves e fáceis de manter. No próximo tópico, Build de Imagens com docker build e Parâmetros, vamos explorar o comando docker build e como utilizar parâmetros avançados para construir imagens flexíveis e reutilizáveis.


5. Build de Imagens com docker build e Parâmetros

Objetivo

Demonstrar como construir imagens Docker usando o comando docker build, incluindo parâmetros úteis para nomear e otimizar builds. Isso inclui o uso de argumentos de build para tornar as imagens mais flexíveis.

Conteúdo

  • Comando docker build para Construção de Imagens
  • Nomeação e Tagging de Imagens com -t
  • Uso de Argumentos de Build com --build-arg
  • Exemplo Prático de Build com Argumentos e Tags

Comando docker build para Construção de Imagens

O comando docker build é utilizado para criar uma imagem a partir de um Dockerfile. Para iniciar o build, o Docker precisa do caminho do Dockerfile e, opcionalmente, de um diretório de contexto que contenha todos os arquivos necessários para a construção da imagem.

Sintaxe Básica:

1
docker build -t <nome_da_imagem>:<tag> <caminho_do_contexto>

Exemplo:

1
docker build -t myapp:1.0 .

Neste exemplo:

  • -t: Nomeia a imagem como myapp e aplica a tag 1.0.
  • .: Define o diretório atual como contexto de build.

Nomeação e Tagging de Imagens com -t

A opção -t permite especificar um nome e uma tag para a imagem gerada. Isso facilita a organização e o versionamento das imagens, especialmente em ambientes de produção, onde você precisa controlar as versões de cada componente.

Exemplo com Nomeação e Tag:

1
docker build -t meuapp:latest .

Aqui, meuapp é o nome da imagem, e latest indica que esta é a versão mais recente.

Uso de Argumentos de Build com --build-arg

O parâmetro --build-arg permite passar variáveis de ambiente durante o processo de build, chamadas de argumentos de build. Isso é útil para ajustar configurações específicas no momento da construção da imagem.

Exemplo de Argumentos no Dockerfile

No Dockerfile, declare o argumento com ARG e utilize-o como uma variável:

1
2
3
4
5
# Define um argumento chamado APP_ENV
ARG APP_ENV=production

# Usa o argumento em uma instrução ENV
ENV NODE_ENV=$APP_ENV

Passando Argumentos Durante o Build

No comando docker build, você pode usar --build-arg para definir o valor do argumento.

Exemplo:

1
docker build -t myapp:1.0 --build-arg APP_ENV=development .

Neste exemplo, o argumento APP_ENV é passado com o valor development, substituindo o valor padrão definido no Dockerfile.

Exemplo Prático de Build com Argumentos e Tags

Suponha que você tenha o seguinte Dockerfile para uma aplicação web:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Dockerfile
FROM node:14

# Argumento de build para configurar o ambiente
ARG APP_ENV=production
ENV NODE_ENV=$APP_ENV

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000
CMD ["npm", "start"]

Para construir a imagem com um ambiente de desenvolvimento e uma tag específica, execute:

1
docker build -t webapp:dev --build-arg APP_ENV=development .

Este comando gera uma imagem com a tag dev, configurando NODE_ENV para development. Essa flexibilidade é essencial para builds específicos de ambiente.


Conclusão

O comando docker build e seus parâmetros são fundamentais para criar imagens Docker com flexibilidade e controle. Usar argumentos de build e tags permite personalizar imagens para diferentes ambientes, facilitando o controle de versão e a eficiência do processo de build. No próximo tópico, Otimização de Imagens para Eficiência e Tamanho Reduzido, vamos explorar técnicas de otimização para garantir que suas imagens sejam leves e performáticas.


6. Otimização de Imagens para Eficiência e Tamanho Reduzido

Objetivo

Explorar técnicas para otimizar imagens Docker, visando reduzir o tamanho, melhorar a performance e garantir que as imagens sejam leves para armazenamento e transporte.

Conteúdo

  • Práticas para Reduzir o Tamanho de Imagens
    • Uso de Imagens Base Minimalistas
    • Limpeza de Cache e Dados Temporários
  • Otimização com Combinação de Comandos para Reduzir Camadas
  • Exemplo Prático de Dockerfile Otimizado
  • Comparação de Tamanho Antes e Depois da Otimização

Práticas para Reduzir o Tamanho de Imagens

Uma imagem Docker otimizada reduz o consumo de armazenamento e melhora a velocidade de deploy e download. Aqui estão algumas práticas para reduzir o tamanho das imagens:

1. Uso de Imagens Base Minimalistas

Escolher uma imagem base minimalista reduz o tamanho final. A imagem alpine é uma versão leve do Linux, com cerca de 5 MB, que inclui apenas os componentes essenciais. Ao usar alpine, você consegue uma base muito menor do que imagens tradicionais, como ubuntu.

Exemplo:

1
FROM node:14-alpine

2. Limpeza de Cache e Dados Temporários

Ao instalar pacotes e dependências, muitos arquivos temporários são gerados e podem ser removidos para economizar espaço. Inclua comandos de limpeza no Dockerfile para remover esses arquivos temporários.

Exemplo:

1
2
3
RUN apt-get update && \
    apt-get install -y build-essential && \
    rm -rf /var/lib/apt/lists/*

Otimização com Combinação de Comandos para Reduzir Camadas

Cada instrução RUN, COPY e ADD no Dockerfile gera uma nova camada na imagem. Para minimizar o número de camadas, combine comandos em uma única instrução RUN. Isso não só reduz o tamanho da imagem como melhora o desempenho.

Exemplo:

1
2
3
RUN apt-get update && \
    apt-get install -y build-essential && \
    rm -rf /var/lib/apt/lists/*

Neste exemplo, apt-get update e apt-get install são executados em uma única camada, e os arquivos de cache são removidos imediatamente, resultando em uma imagem mais enxuta.

Exemplo Prático de Dockerfile Otimizado

Abaixo está um exemplo de Dockerfile otimizado para uma aplicação Node.js. Ele utiliza uma imagem base alpine, combina comandos RUN e remove dados temporários.

Dockerfile Otimizado:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Imagem base minimalista
FROM node:14-alpine

# Define o diretório de trabalho
WORKDIR /usr/src/app

# Instala apenas as dependências de produção
COPY package*.json ./
RUN npm install --only=production && npm cache clean --force

# Copia o restante do código
COPY . .

# Expondo a porta da aplicação
EXPOSE 3000

# Comando para iniciar a aplicação
CMD ["node", "server.js"]

Explicação:

  • Imagem Base Minimalista: Utiliza a versão alpine do Node.js, que é significativamente menor.
  • Limpeza de Cache: npm cache clean --force remove o cache do NPM, reduzindo o tamanho.
  • Instruções Combinadas: A instalação de dependências e a limpeza de cache são feitas na mesma instrução RUN.

Comparação de Tamanho Antes e Depois da Otimização

Aqui está uma comparação hipotética entre uma imagem não otimizada e uma otimizada para a mesma aplicação Node.js:

Imagem Tamanho
Imagem Padrão (Node) ~900 MB
Imagem Otimizada ~200 MB

A otimização reduz o tamanho da imagem em mais de 75%, economizando armazenamento e melhorando a velocidade de deploy e download.


Conclusão

Otimizar imagens Docker é essencial para garantir que elas sejam leves, eficientes e fáceis de transportar. Práticas como o uso de imagens minimalistas, a limpeza de dados temporários e a combinação de comandos ajudam a reduzir significativamente o tamanho das imagens sem sacrificar funcionalidade. No próximo tópico, Multi-Stage Builds: Reduzindo Tamanho e Isolando Dependências, exploraremos uma técnica avançada para otimizar ainda mais o tamanho e a segurança das imagens Docker usando multi-stage builds.


7. Multi-Stage Builds: Reduzindo Tamanho e Isolando Dependências

Objetivo

Demonstrar o uso de multi-stage builds para criar imagens leves e seguras, separando etapas de compilação e runtime. Essa técnica permite que somente os arquivos essenciais sejam incluídos na imagem final, reduzindo o tamanho e melhorando a segurança.

Conteúdo

  • Introdução ao Conceito de Multi-Stage Build e Seus Benefícios
  • Criando Dockerfile com Multi-Stage Build
  • Exemplo Prático de Dockerfile Multi-Stage para Aplicações com Compilação
  • Comparação de Tamanho e Segurança com Multi-Stage Builds

Introdução ao Conceito de Multi-Stage Build e Seus Benefícios

Um multi-stage build permite dividir o processo de criação da imagem em várias etapas (ou “stages”), cada uma executada em um ambiente separado. Isso é particularmente útil em projetos que exigem compilação ou construção de código, pois permite:

  1. Isolar Dependências: Ferramentas e dependências usadas apenas na compilação não são incluídas na imagem final.
  2. Reduzir o Tamanho da Imagem: A imagem final inclui apenas os arquivos e binários necessários, excluindo ferramentas de build.
  3. Melhorar a Segurança: Ao remover etapas e ferramentas de build da imagem final, a superfície de ataque é reduzida.

Criando Dockerfile com Multi-Stage Build

Com um Dockerfile multi-stage, você define múltiplas seções FROM, cada uma representando um stage separado. Os arquivos podem ser copiados de um stage para outro usando a instrução COPY --from=<stage>.

Sintaxe Básica de Multi-Stage Build:

1
2
3
4
5
6
FROM <imagem-base-compilação> AS builder
# Etapas de build e compilação...

FROM <imagem-base-runtime>
# Apenas a execução com os artefatos necessários
COPY --from=builder <diretório-ou-arquivo> <destino>

Exemplo Prático de Dockerfile Multi-Stage para Aplicações com Compilação

Abaixo está um exemplo de Dockerfile multi-stage para uma aplicação Node.js que requer uma etapa de build.

Dockerfile Multi-Stage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Primeiro Stage: Build
FROM node:14 AS builder

# Define o diretório de trabalho
WORKDIR /app

# Copia os arquivos de configuração e instala dependências
COPY package*.json ./
RUN npm install

# Copia o código-fonte e executa o build
COPY . .
RUN npm run build

# Segundo Stage: Runtime
FROM node:14-alpine

# Define o diretório de trabalho no runtime
WORKDIR /app

# Copia apenas os arquivos necessários da etapa de build
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules

# Expor a porta da aplicação
EXPOSE 3000

# Comando para rodar a aplicação
CMD ["node", "dist/server.js"]

Explicação:

  1. Stage 1: Build:
    • Usa a imagem node:14 completa, instala as dependências e executa o comando npm run build para gerar o código final.
    • O diretório /app/dist contém o código gerado.
  2. Stage 2: Runtime:
    • Usa a imagem node:14-alpine, mais leve, adequada para execução.
    • Copia apenas o diretório dist e node_modules do primeiro stage, que são os artefatos necessários para a execução.
    • Exclui ferramentas de build, reduzindo o tamanho e o escopo da imagem final.

Comparação de Tamanho e Segurança com Multi-Stage Builds

O uso de multi-stage builds resulta em uma imagem final mais enxuta, com apenas os arquivos e dependências essenciais para rodar a aplicação, sem incluir ferramentas ou bibliotecas usadas apenas na compilação.

Build Tamanho Inclusão de Ferramentas de Build
Imagem Completa ~900 MB Sim
Multi-Stage ~150 MB Não

Além de reduzir o tamanho, a segurança é melhorada, pois dependências desnecessárias e ferramentas de compilação são removidas.


Conclusão

Multi-stage builds são uma prática recomendada para otimizar e proteger Docker Images, especialmente em aplicações que requerem compilação. Com o uso de múltiplos stages, você pode gerar imagens pequenas, leves e seguras, prontas para produção. No próximo tópico, Tagging e Versionamento de Imagens, veremos como gerenciar versões de imagens com tags para organizar e controlar o ciclo de vida das imagens Docker.


8. Tagging e Versionamento de Imagens

Objetivo

Demonstrar como gerenciar versões de imagens Docker usando tags para facilitar o controle de versões e a consistência entre diferentes ambientes, como desenvolvimento e produção.

Conteúdo

  • Importância do Versionamento de Imagens
  • Uso de Tags com docker tag
  • Boas Práticas de Versionamento e Tags
  • Exemplo Prático de Versionamento de Imagens em Desenvolvimento e Produção

Importância do Versionamento de Imagens

O versionamento de imagens é essencial para garantir que cada ambiente (desenvolvimento, teste, produção) utilize a versão correta da aplicação. Usar um sistema de versionamento padronizado com tags permite:

  1. Consistência entre Ambientes: A mesma versão pode ser testada e promovida para produção.
  2. Controle de Atualizações: Permite fazer rollback facilmente para uma versão anterior se houver problemas.
  3. Organização e Rastreamento: Facilita a identificação de mudanças entre versões e histórico de versões.

Uso de Tags com docker tag

Para nomear uma imagem com uma tag específica, você pode usar a opção -t ao construir a imagem ou o comando docker tag para criar uma nova tag para uma imagem existente.

Sintaxe Básica para Tagging no Build

1
docker build -t <nome_da_imagem>:<tag> <caminho_do_contexto>

Exemplo:

1
docker build -t meuapp:1.0 .

Neste exemplo, a imagem é construída com o nome meuapp e a tag 1.0.

Criando uma Nova Tag para uma Imagem Existente

Você também pode criar uma nova tag para uma imagem existente usando docker tag:

1
docker tag meuapp:1.0 meuapp:latest

Esse comando cria uma nova tag latest para a imagem meuapp:1.0, indicando que esta é a versão mais recente.

Boas Práticas de Versionamento e Tags

Aqui estão algumas práticas recomendadas para o versionamento de imagens Docker:

  1. Usar Nomes e Tags Significativas: Identifique a imagem e a versão de forma clara, como meuapp:1.0, meuapp:dev, ou meuapp:stable.
  2. Usar latest com Cuidado: A tag latest é útil para identificar a versão mais recente, mas em produção é recomendado usar tags de versão específicas para evitar inconsistências.
  3. Versionamento Semântico: Utilize a convenção de versionamento semântico (ex.: 1.0.0, 1.1.0, 2.0.0), especialmente se a imagem representa uma aplicação com releases regulares.
  4. Tags para Ambientes Específicos: Defina tags como dev, staging e prod para identificar versões específicas para cada ambiente.

Exemplo Prático de Versionamento de Imagens em Desenvolvimento e Produção

Vamos supor que você tem uma aplicação meuapp e deseja criar uma imagem para o ambiente de desenvolvimento e outra para produção.

  1. Construindo a Imagem para Desenvolvimento
    1
    
    docker build -t meuapp:dev .
    
  2. Construindo e Versionando a Imagem para Produção
    1
    2
    
    docker build -t meuapp:1.0 .
    docker tag meuapp:1.0 meuapp:latest
    

    Nesse caso:

    • meuapp:1.0 é a versão específica da release.
    • meuapp:latest marca a imagem como a versão mais recente para facilitar a identificação.

Organização de Versionamento no Docker Hub ou em Registries

Ao publicar imagens em um registry como o Docker Hub, é uma boa prática manter as tags organizadas para que os usuários possam identificar facilmente a finalidade e a versão de cada imagem.


Conclusão

O uso de tags e versionamento em imagens Docker é fundamental para o gerenciamento de versões e para manter consistência entre ambientes. Definir uma estratégia de tagging permite um controle preciso sobre as versões em uso, facilitando o processo de desenvolvimento, teste e deploy. No próximo tópico, Publicando Imagens em Registries (Docker Hub, Amazon ECR, GitLab Container Registry), vamos explorar como compartilhar suas imagens com outras equipes e ambientes, publicando-as em registries públicos e privados.


9. Publicando Imagens em Registries (Docker Hub, Amazon ECR, GitLab Container Registry)

Objetivo

Ensinar como publicar e compartilhar imagens Docker em registries públicos e privados, incluindo Docker Hub, Amazon ECR e GitLab Container Registry. Isso permite que outros desenvolvedores e equipes acessem imagens de maneira centralizada.

Conteúdo

  • Registries Públicos e Privados
  • Publicação de Imagens no Docker Hub com docker push
  • Publicação em Registries Privados (Amazon ECR, GitLab Container Registry)
  • Exemplo Prático de Configuração e Upload de Imagens para um Registry

Registries Públicos e Privados

Um Docker Registry é um repositório onde as imagens Docker são armazenadas e compartilhadas. O Docker Hub é o registry público mais usado, mas muitos times preferem usar registries privados, especialmente para imagens de produção e código-fonte sensível. Alguns dos registries mais comuns são:

  • Docker Hub: registry público padrão do Docker, ideal para compartilhar imagens open-source e de uso geral.
  • Amazon ECR (Elastic Container Registry): registry privado integrado à AWS, usado para armazenar imagens em projetos que utilizam serviços de containers da Amazon.
  • GitLab Container Registry: registry privado integrado ao GitLab, útil para projetos de CI/CD e automação de pipelines.

Publicação de Imagens no Docker Hub com docker push

Para publicar uma imagem no Docker Hub, você precisa:

  1. Criar uma conta no Docker Hub.
  2. Fazer login pelo terminal usando o comando docker login.

Exemplo de Login e Publicação no Docker Hub

  1. Login no Docker Hub:
    1
    
    docker login
    

    Insira seu nome de usuário e senha do Docker Hub.

  2. Taggear a Imagem para Docker Hub: Antes de enviar, defina o nome da imagem para incluir seu nome de usuário no Docker Hub. Isso organiza a imagem em seu repositório.

    1
    
    docker tag meuapp:1.0 usuario/meuapp:1.0
    
  3. Publicar Imagem:
    1
    
    docker push usuario/meuapp:1.0
    

    Este comando faz o upload da imagem para o Docker Hub, onde ela fica disponível para download e uso por outros.

Publicação em Registries Privados (Amazon ECR, GitLab Container Registry)

Amazon Elastic Container Registry (ECR)

O Amazon ECR é o registry de containers da AWS, integrado com serviços como ECS e EKS.

  1. Autenticar no ECR: Primeiro, autentique-se usando a CLI da AWS. Substitua <region> pela região da AWS onde o ECR está configurado.
    1
    
    aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <aws_account_id>.dkr.ecr.<region>.amazonaws.com
    
  2. Criar o Repositório no ECR:
    1
    
    aws ecr create-repository --repository-name meuapp
    
  3. Taggear a Imagem para o ECR:
    1
    
    docker tag meuapp:1.0 <aws_account_id>.dkr.ecr.<region>.amazonaws.com/meuapp:1.0
    
  4. Publicar a Imagem no ECR:
    1
    
    docker push <aws_account_id>.dkr.ecr.<region>.amazonaws.com/meuapp:1.0
    

GitLab Container Registry

O GitLab Container Registry é integrado aos projetos GitLab, facilitando o uso de imagens nos pipelines CI/CD.

  1. Autenticação no GitLab Registry:
    • Vá até Settings > Repository no projeto GitLab.
    • No terminal, faça login com o comando abaixo:
      1
      
      docker login registry.gitlab.com
      
  2. Taggear a Imagem para o GitLab Registry:
    1
    
    docker tag meuapp:1.0 registry.gitlab.com/usuario/projeto/meuapp:1.0
    
  3. Publicar a Imagem no GitLab Registry:
    1
    
    docker push registry.gitlab.com/usuario/projeto/meuapp:1.0
    

Exemplo Prático de Configuração e Upload de Imagens para um Registry

  1. Preparar a Imagem:
    • Construa a imagem:
      1
      
      docker build -t meuapp:1.0 .
      
  2. Publicar no Registry (Docker Hub, Amazon ECR, ou GitLab):
    • Docker Hub: docker push usuario/meuapp:1.0
    • Amazon ECR: docker push <aws_account_id>.dkr.ecr.<region>.amazonaws.com/meuapp:1.0
    • GitLab: docker push registry.gitlab.com/usuario/projeto/meuapp:1.0

Cada um desses registries tem um processo de autenticação e tag, mas todos facilitam o upload e acesso centralizado às suas imagens.


Conclusão

Publicar imagens em registries, sejam eles públicos ou privados, é fundamental para compartilhar imagens com outras equipes e ambientes. Ao usar registries como Docker Hub, Amazon ECR ou GitLab Container Registry, você pode distribuir versões de imagens de maneira organizada e segura, integrando-as ao fluxo de CI/CD para maior automação. No próximo tópico, Escaneamento de Vulnerabilidades em Imagens, veremos como garantir a segurança das imagens Docker ao detectar e resolver vulnerabilidades antes do deploy em produção.


10. Escaneamento de Vulnerabilidades em Imagens

Objetivo

Apresentar ferramentas de escaneamento de vulnerabilidades para garantir a segurança das imagens Docker, permitindo identificar e corrigir problemas antes que as imagens sejam implantadas em produção.

Conteúdo

  • Importância do Escaneamento de Vulnerabilidades em Imagens
  • Ferramentas de Escaneamento de Vulnerabilidades (Trivy, Clair)
  • Integração de Escaneamento em Pipelines CI/CD
  • Exemplo Prático de Escaneamento de Imagens

Importância do Escaneamento de Vulnerabilidades em Imagens

Docker Images frequentemente contêm sistemas operacionais e dependências que podem apresentar vulnerabilidades. Identificar e corrigir vulnerabilidades em uma imagem Docker é essencial para evitar que aplicações e dados fiquem expostos a riscos de segurança. Escanear imagens ajuda a:

  1. Detectar Vulnerabilidades Conhecidas: Evita que falhas e exploits conhecidos sejam introduzidos na infraestrutura.
  2. Garantir a Conformidade de Segurança: Algumas normas de segurança exigem escaneamentos regulares para reduzir riscos.
  3. Facilitar a Correção de Problemas de Segurança: Permite que equipes identifiquem e atualizem componentes vulneráveis rapidamente.

Ferramentas de Escaneamento de Vulnerabilidades

Duas das ferramentas mais populares para escanear vulnerabilidades em imagens Docker são Trivy e Clair.

1. Trivy

Trivy é uma ferramenta de escaneamento de vulnerabilidades rápida e fácil de usar, que verifica não apenas o sistema operacional da imagem, mas também as bibliotecas e dependências instaladas.

  • Instalação do Trivy:
    1
    2
    
    brew install trivy  # MacOS
    sudo apt install trivy  # Ubuntu/Debian
    
  • Exemplo de Escaneamento com Trivy:
    1
    
    trivy image meuapp:1.0
    

Esse comando escaneia a imagem meuapp:1.0 e lista vulnerabilidades conhecidas com detalhes, incluindo a criticidade e a versão corrigida.

2. Clair

Clair é uma ferramenta de escaneamento de vulnerabilidades em containers que é altamente configurável e se integra bem com registries, como o Docker Hub e o Quay. Clair analisa camadas individuais da imagem, reportando vulnerabilidades detectadas em cada uma.

  • Configuração do Clair: Por ser uma ferramenta mais avançada, Clair exige a configuração de um servidor. A integração com o Docker Registry é recomendada para projetos de grande escala.

Integração de Escaneamento em Pipelines CI/CD

Integrar o escaneamento de vulnerabilidades em uma pipeline de CI/CD é uma prática recomendada, pois permite que vulnerabilidades sejam detectadas automaticamente durante o desenvolvimento, antes do deploy.

Exemplo de Integração com Trivy em um Pipeline CI/CD

Aqui está um exemplo de como integrar Trivy em um pipeline GitLab CI/CD:

1
2
3
4
5
6
7
8
9
stages:
  - security_scan

security_scan:
  image:
    name: aquasec/trivy
    entrypoint: [""]
  script:
    - trivy image meuapp:1.0

Neste exemplo:

  • Imagem aquasec/trivy: Utiliza a imagem oficial do Trivy no GitLab CI/CD.
  • Comando trivy image: Escaneia a imagem meuapp:1.0 e exibe vulnerabilidades diretamente no pipeline.

Esse tipo de integração permite que o pipeline falhe se vulnerabilidades críticas forem detectadas, evitando que imagens inseguras sejam promovidas para produção.

Exemplo Prático de Escaneamento de Imagens

Para ilustrar o uso de escaneamento de vulnerabilidades, veja um exemplo prático usando Trivy para escanear uma imagem local:

1
2
3
4
5
# Baixe ou construa a imagem primeiro
docker build -t meuapp:1.0 .

# Execute o Trivy para escanear vulnerabilidades
trivy image meuapp:1.0

A saída mostrará uma lista de vulnerabilidades detectadas, com a criticidade (baixo, médio, alto ou crítico), identificador (CVE) e possíveis versões de correção.


Conclusão

Escanear vulnerabilidades em imagens Docker é uma prática essencial para manter a segurança e a conformidade das aplicações. Ferramentas como Trivy e Clair oferecem recursos valiosos para identificar problemas de segurança e prevenir falhas antes do deploy em produção. No próximo tópico, Gerenciamento de Imagens Locais, vamos explorar como organizar e limpar imagens Docker armazenadas localmente para otimizar o uso de recursos e o gerenciamento de armazenamento.


11. Gerenciamento de Imagens Locais

Objetivo

Demonstrar como gerenciar imagens Docker armazenadas localmente, organizando-as e removendo imagens obsoletas para manter o ambiente eficiente e liberar espaço em disco.

Conteúdo

  • Listando Imagens com docker images
  • Removendo Imagens com docker rmi
  • Limpando Imagens Não Utilizadas com docker image prune
  • Automatizando a Limpeza de Imagens Locais

Listando Imagens com docker images

Para visualizar todas as imagens armazenadas localmente, use o comando docker images. Esse comando exibe uma tabela com informações sobre as imagens, incluindo nome, tag, ID e tamanho.

Exemplo de Uso:

1
docker images

Saída: A saída apresenta uma tabela como a seguinte:

REPOSITORY TAG IMAGE ID CREATED SIZE
meuapp 1.0 abc12345 2 days ago 200MB

Cada linha representa uma imagem local, facilitando a identificação das versões e o consumo de armazenamento de cada uma.

Removendo Imagens com docker rmi

O comando docker rmi permite remover uma imagem específica. Para isso, basta informar o nome ou o ID da imagem. Esse comando é útil para liberar espaço ao remover imagens antigas ou desnecessárias.

Exemplo de Remoção:

1
docker rmi meuapp:1.0

Nota: Se uma imagem estiver em uso por um container ativo, você precisará parar e remover o container antes de excluir a imagem.

Limpando Imagens Não Utilizadas com docker image prune

O Docker permite remover automaticamente todas as imagens que não estão em uso com o comando docker image prune. Esse comando remove imagens “dangling” (aquelas sem tags) e outras imagens não referenciadas por nenhum container.

Exemplo de Uso:

1
docker image prune

Opções Adicionais:

  • -a: Remove todas as imagens que não estão em uso, incluindo as com tags, economizando ainda mais espaço.

    1
    
    docker image prune -a
    

Ao utilizar -a, tenha certeza de que todas as imagens removidas realmente não são necessárias, pois imagens com tags também serão excluídas.

Automatizando a Limpeza de Imagens Locais

Para manter o ambiente organizado, é recomendável automatizar a limpeza de imagens periodicamente. Um script simples pode ser criado para rodar o comando de limpeza regularmente, por exemplo, semanalmente.

Exemplo de Script para Automação: Salve o seguinte conteúdo em um arquivo de script, como limpeza_docker.sh:

1
2
3
4
#!/bin/bash

# Limpa imagens que não estão sendo usadas
docker image prune -a -f

Em seguida, configure o script para rodar automaticamente com um agendador, como o cron no Linux.

Exemplo de Agendamento no cron: Para rodar o script de limpeza a cada semana, adicione a seguinte linha no crontab:

1
0 0 * * 0 /caminho/para/limpeza_docker.sh

Esse agendamento limpa as imagens não utilizadas todos os domingos à meia-noite.


Conclusão

O gerenciamento de imagens locais é essencial para manter o ambiente Docker eficiente e com espaço de armazenamento otimizado. Utilizando comandos como docker images, docker rmi e docker image prune, você pode listar, organizar e limpar imagens antigas, garantindo que apenas as versões necessárias estejam ocupando espaço. No próximo tópico, Manipulação de Camadas e Cache em Docker Images, exploraremos como o Docker utiliza camadas e cache para construir imagens mais rapidamente e como gerenciar esses recursos de forma eficiente.


12. Manipulação de Camadas e Cache em Docker Images

Objetivo

Explicar como o Docker utiliza camadas e cache para otimizar o processo de build de imagens e mostrar estratégias para manipular o cache e melhorar a eficiência na criação de imagens.

Conteúdo

  • Como Funcionam as Camadas em Docker Images
  • Uso de Cache de Camadas no Build de Imagens
  • Estratégias para Manipulação do Cache e Forçar Rebuilds
  • Exemplo de Otimização com Cache de Camadas

Como Funcionam as Camadas em Docker Images

Docker Images são compostas por camadas, onde cada instrução no Dockerfile cria uma nova camada. Esse sistema de camadas, conhecido como UnionFS, permite:

  1. Reutilização: Camadas não modificadas podem ser reutilizadas em builds futuros, economizando tempo e recursos.
  2. Armazenamento Eficiente: Como cada camada é independente, múltiplas imagens podem compartilhar camadas comuns, economizando espaço.

Por exemplo, ao construir uma imagem com o Dockerfile abaixo, cada instrução FROM, RUN, COPY e CMD gera uma camada:

1
2
3
4
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y nginx
COPY . /app
CMD ["nginx", "-g", "daemon off;"]

Uso de Cache de Camadas no Build de Imagens

O Docker armazena o resultado de cada camada em cache. Durante o processo de build, ele verifica se a camada já existe no cache e a reutiliza se nenhuma modificação foi feita. Isso pode acelerar builds significativamente.

Comportamento do Cache

  • Instruções Inalteradas: Se o conteúdo das instruções RUN, COPY, ADD, entre outras, for idêntico ao de builds anteriores, o Docker utiliza o cache para essa camada.
  • Invalidando o Cache: Qualquer alteração em uma camada invalida o cache para todas as camadas subsequentes.

Estratégias para Manipulação do Cache e Forçar Rebuilds

  1. Ordenar as Instruções do Dockerfile por Frequência de Mudanças:
    • Coloque instruções que mudam frequentemente, como COPY . . (para copiar o código-fonte), o mais próximo do final do Dockerfile.
    • Coloque instruções mais estáveis, como RUN apt-get install -y nginx, no início para maximizar o uso do cache.
  2. Forçar o Rebuild de Camadas Específicas:
    • Adicione argumentos dinâmicos para invalidar o cache quando necessário. Por exemplo, RUN apt-get update && apt-get install -y nginx pode ser atualizado para forçar uma atualização ao adicionar um argumento de data.
    1
    2
    
    ARG CACHEBUST=1
    RUN apt-get update && apt-get install -y nginx
    
  3. Excluir Dados Temporários e Cache em RUN:
    • Remova dados temporários e arquivos de cache dentro da mesma instrução RUN para evitar o acúmulo de camadas desnecessárias.
    1
    2
    3
    
    RUN apt-get update && \
        apt-get install -y nginx && \
        rm -rf /var/lib/apt/lists/*
    

Exemplo de Otimização com Cache de Camadas

Aqui está um Dockerfile otimizado com as práticas mencionadas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Imagem base
FROM node:14 AS builder

# Define o diretório de trabalho
WORKDIR /app

# Copia e instala dependências (camadas estáveis)
COPY package*.json ./
RUN npm install

# Copia o código e constrói a aplicação
COPY . .
RUN npm run build

# Runtime
FROM node:14-alpine

WORKDIR /app
COPY --from=builder /app/dist ./dist

CMD ["node", "dist/server.js"]

Neste exemplo:

  • As dependências são instaladas antes do código-fonte ser copiado, permitindo que a camada de dependências seja reutilizada se o código-fonte mudar, mas o package.json permanecer o mesmo.
  • A cópia do código e o build ocorrem após a instalação de dependências, garantindo que apenas as camadas finais sejam reconstruídas ao modificar o código.

Conclusão

Compreender o funcionamento das camadas e o uso do cache de build permite criar imagens de forma mais eficiente e rápida. Usar camadas de maneira estratégica e invalidar o cache apenas quando necessário garante builds otimizados, economizando tempo e recursos. No próximo tópico, Exportando e Compartilhando Imagens Sem Registry, vamos ver como exportar imagens Docker para compartilhamento direto, mesmo em ambientes que não têm acesso a registries.


13. Exportando e Compartilhando Imagens Sem Registry

Objetivo

Demonstrar como exportar e compartilhar imagens Docker diretamente, sem a necessidade de um registry. Esse processo é útil para mover imagens entre ambientes isolados ou transferi-las offline.

Conteúdo

  • Exportando Imagens com docker save
  • Importando Imagens com docker load
  • Transferência e Compartilhamento de Imagens Exportadas
  • Exemplo Prático de Exportação e Importação de Imagens

Exportando Imagens com docker save

O comando docker save permite exportar uma imagem Docker para um arquivo .tar, que pode ser compartilhado e transferido. Esse arquivo contém todas as camadas e metadados da imagem, permitindo que ela seja restaurada exatamente como foi exportada.

Sintaxe:

1
docker save -o <arquivo_de_saida.tar> <nome_da_imagem>:<tag>

Exemplo:

1
docker save -o meuapp.tar meuapp:1.0

Esse comando cria um arquivo meuapp.tar, que contém a imagem meuapp:1.0. Esse arquivo pode ser armazenado localmente, enviado por rede ou movido para um dispositivo externo.

Importando Imagens com docker load

Para restaurar uma imagem exportada, use o comando docker load. Esse comando importa a imagem a partir do arquivo .tar, tornando-a disponível localmente para uso em containers.

Sintaxe:

1
docker load -i <arquivo.tar>

Exemplo:

1
docker load -i meuapp.tar

Após o carregamento, a imagem meuapp:1.0 estará disponível no ambiente Docker e poderá ser visualizada com o comando docker images.

Transferência e Compartilhamento de Imagens Exportadas

Imagens exportadas podem ser transferidas e compartilhadas de várias maneiras:

  1. Dispositivos Externos: Armazene o arquivo .tar em um pen drive, HD externo, ou outro dispositivo de armazenamento portátil.
  2. Rede Local: Transfira o arquivo .tar para outros sistemas na mesma rede usando protocolos como SCP (em Linux) ou compartilhamento de rede.
    • Exemplo de Transferência via SCP:
      1
      
      scp meuapp.tar usuario@outro-sistema:/caminho/destino
      
  3. Sistemas de Armazenamento em Nuvem: Para ambientes isolados que não permitem conexões diretas ao Docker Hub, o arquivo .tar pode ser enviado a serviços de nuvem (ex.: Google Drive, AWS S3) e baixado posteriormente.

Exemplo Prático de Exportação e Importação de Imagens

Aqui está um exemplo completo do processo de exportação e importação de uma imagem Docker entre dois sistemas:

Sistema de Origem (Exportação)

  1. Construir a Imagem:
    1
    
    docker build -t meuapp:1.0 .
    
  2. Exportar a Imagem para um Arquivo:
    1
    
    docker save -o meuapp.tar meuapp:1.0
    

Transferir a Imagem

  • Transfira o arquivo meuapp.tar para o sistema de destino usando um dispositivo externo, rede local ou sistema de armazenamento.

Sistema de Destino (Importação)

  1. Importar a Imagem:
    1
    
    docker load -i meuapp.tar
    
  2. Verificar a Importação:
    1
    
    docker images
    

    A imagem meuapp:1.0 deve aparecer na lista de imagens disponíveis no sistema de destino.


Conclusão

Exportar e compartilhar imagens sem registry permite que você mova e instale imagens em ambientes isolados e sem conectividade com registries públicos ou privados. Usar os comandos docker save e docker load é uma solução prática para transferência de imagens entre ambientes, especialmente em situações onde o acesso direto a registries é restrito. No próximo tópico, Configuração de Segurança e Boas Práticas para Imagens, exploraremos práticas para garantir a segurança das imagens Docker em ambientes de produção.


14. Configuração de Segurança e Boas Práticas para Imagens

Objetivo

Apresentar práticas de segurança ao criar e utilizar Docker Images, ajudando a mitigar riscos e garantir um ambiente de execução seguro, especialmente em produção.

Conteúdo

  • Minimização de Permissões e Uso de Usuário Não-Root
  • Limpeza de Dados Temporários e Remoção de Ferramentas Desnecessárias
  • Uso Seguro de Variáveis de Ambiente e Proteção de Dados Sensíveis
  • Exemplo Prático de Dockerfile Seguro para Produção

Minimização de Permissões e Uso de Usuário Não-Root

Uma das melhores práticas de segurança em Docker é evitar o uso do usuário root. Executar containers com permissões mínimas reduz a possibilidade de exploração de vulnerabilidades, pois limita os danos que podem ser causados se um atacante comprometer o container.

Instrução USER no Dockerfile

Para definir um usuário específico no Dockerfile, você pode usar a instrução USER:

1
2
3
4
5
# Cria um novo usuário com permissões limitadas
RUN adduser --disabled-password meuusuario

# Define o usuário não-root como padrão
USER meuusuario

Esse comando cria um usuário meuusuario sem privilégios de root e define-o como o usuário que será utilizado para executar o container.

Limpeza de Dados Temporários e Remoção de Ferramentas Desnecessárias

Ao instalar dependências e ferramentas, muitos arquivos temporários são gerados e armazenados no cache, o que pode representar um risco de segurança. Além disso, ferramentas de build ou compilação usadas apenas durante a criação da imagem devem ser removidas.

Exemplo de Limpeza de Dados Temporários:

1
2
3
RUN apt-get update && \
    apt-get install -y build-essential curl && \
    rm -rf /var/lib/apt/lists/*

Esse comando remove os caches de pacotes (/var/lib/apt/lists/*) após a instalação, reduzindo o tamanho da imagem e o risco de segurança.

Uso Seguro de Variáveis de Ambiente e Proteção de Dados Sensíveis

Ao armazenar dados sensíveis, como senhas e tokens, evite incluir essas informações diretamente no Dockerfile. Em vez disso:

  1. Use arquivos .env: Armazene variáveis de ambiente em um arquivo .env e carregue-as dinamicamente no ambiente de execução.
  2. Utilize docker secret (no Docker Swarm): Para clusters, o Docker Swarm oferece o recurso docker secret para gerenciar informações sensíveis de maneira segura.

Exemplo com Variáveis de Ambiente

No Dockerfile, você pode definir variáveis genéricas, mas dados confidenciais devem ser gerenciados fora do Dockerfile:

1
2
# Definindo uma variável de ambiente genérica
ENV APP_ENV=production

E no terminal, defina as variáveis sensíveis no momento da execução:

1
docker run -e DB_PASSWORD='minhasenha' meuapp:1.0

Exemplo Prático de Dockerfile Seguro para Produção

Aqui está um exemplo de Dockerfile que incorpora várias práticas de segurança:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Usando uma imagem base mínima
FROM node:14-alpine

# Criando e usando um usuário não-root
RUN adduser -D meuusuario
USER meuusuario

# Definindo o diretório de trabalho
WORKDIR /app

# Copiando e instalando dependências de produção
COPY package*.json ./
RUN npm install --only=production

# Copiando o código da aplicação
COPY . .

# Expondo a porta da aplicação
EXPOSE 3000

# Configurando variáveis de ambiente genéricas
ENV NODE_ENV=production

# Definindo o comando de execução
CMD ["node", "server.js"]

Explicação:

  • Imagem Base Leve: node:14-alpine reduz o tamanho da imagem e a superfície de ataque.
  • Usuário Não-Root: meuusuario é criado e configurado para reduzir riscos.
  • Dependências de Produção: npm install --only=production garante que apenas dependências essenciais sejam instaladas, reduzindo o tamanho da imagem e minimizando o risco de vulnerabilidades.

Conclusão

Implementar práticas de segurança em Docker Images ajuda a manter ambientes de execução protegidos contra ameaças. Configurações como uso de usuário não-root, limpeza de dados temporários e gerenciamento seguro de variáveis de ambiente tornam a imagem mais resistente a ataques, especialmente em produção. No próximo e último tópico, Casos de Uso Avançados e Melhores Práticas para Docker Images, vamos explorar como aplicar essas práticas e outras avançadas em casos de uso específicos.


15. Casos de Uso Avançados e Melhores Práticas para Docker Images

Objetivo

Explorar casos de uso avançados para Docker Images e apresentar melhores práticas que garantem a eficiência, segurança e escalabilidade das imagens Docker, especialmente em ambientes de produção.

Conteúdo

  • Docker Images para Microserviços e Aplicações Distribuídas
  • Estratégias de Versionamento e Atualização Contínua em CI/CD
  • Boas Práticas para Imagens Duráveis e Preparadas para Produção
  • Exemplo Prático de Pipeline CI/CD com Docker Images

Docker Images para Microserviços e Aplicações Distribuídas

Em arquiteturas de microserviços e aplicações distribuídas, Docker Images permitem isolar componentes e criar ambientes de execução padronizados para cada serviço. Cada microserviço pode ter uma imagem dedicada, que inclui apenas as dependências necessárias para o serviço em questão. Isso oferece benefícios como:

  1. Isolamento Completo: Cada serviço roda de maneira independente, facilitando o desenvolvimento e a manutenção.
  2. Escalabilidade Individual: Microserviços podem ser escalados de forma independente, utilizando Docker Swarm, Kubernetes ou outras ferramentas de orquestração.
  3. Ciclo de Vida Independente: As imagens de cada microserviço podem ser versionadas e atualizadas separadamente, permitindo maior flexibilidade.

Estratégias de Versionamento e Atualização Contínua em CI/CD

Para manter consistência e rastreabilidade, é importante implementar uma estratégia de versionamento robusta para Docker Images. Além disso, a atualização contínua das imagens em pipelines CI/CD automatiza o processo de build, teste e deploy.

Boas Práticas de Versionamento e Automação em CI/CD:

  1. Versionamento Semântico: Use tags como 1.0.0, 1.1.0, etc., e implemente tags latest, stable para identificar versões de desenvolvimento e produção.
  2. Automação com Pipelines CI/CD: Configure pipelines que automatizem o build de imagens em cada push de código, especialmente em branches principais (main, master), usando ferramentas como Jenkins, GitLab CI/CD ou GitHub Actions.
  3. Implementação de Tests: Inclua etapas de testes automatizados no pipeline para garantir que a imagem é funcional e segura antes do deploy.

Boas Práticas para Imagens Duráveis e Preparadas para Produção

Para que uma imagem seja confiável e robusta em produção, algumas práticas avançadas devem ser aplicadas:

  • Imagens Base Leves: Opte por imagens minimalistas (ex.: alpine) para reduzir o tamanho e a superfície de ataque.
  • Ambientes Específicos: Crie Dockerfiles distintos para desenvolvimento, teste e produção. Isso ajuda a evitar incluir dependências desnecessárias na imagem final de produção.
  • Aplicação de Patches e Atualizações: Mantenha as imagens atualizadas, aplicando patches de segurança em intervalos regulares.
  • Limpeza de Build Artifacts: Exclua dependências, arquivos temporários e cache ao final da build para reduzir o tamanho da imagem.
  • Configuração para Escalabilidade e Monitoramento: Para serviços em produção, configure logs, healthchecks e limites de recursos, como CPU e memória, diretamente no Dockerfile ou nas configurações do container.

Exemplo Prático de Pipeline CI/CD com Docker Images

Abaixo está um exemplo básico de um pipeline CI/CD em YAML, que pode ser usado com GitLab CI/CD. O pipeline executa as seguintes etapas:

  • Construção da Imagem: Constrói uma nova imagem sempre que há um novo commit.
  • Testes: Executa testes automatizados para validar a funcionalidade.
  • Escaneamento de Segurança: Verifica a imagem em busca de vulnerabilidades antes do deploy.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
stages:
  - build
  - test
  - scan
  - deploy

# Etapa de construção
build_image:
  stage: build
  script:
    - docker build -t usuario/meuapp:$CI_COMMIT_SHA .
    - docker tag usuario/meuapp:$CI_COMMIT_SHA usuario/meuapp:latest
  only:
    - main

# Etapa de testes
test_image:
  stage: test
  script:
    - docker run --rm usuario/meuapp:latest npm test
  dependencies:
    - build_image

# Etapa de escaneamento de segurança
scan_image:
  stage: scan
  image: aquasec/trivy
  script:
    - trivy image usuario/meuapp:latest
  dependencies:
    - build_image

# Etapa de deploy
deploy_image:
  stage: deploy
  script:
    - docker push usuario/meuapp:latest
  dependencies:
    - build_image
  only:
    - tags

Explicação:

  • build_image: Constrói a imagem e aplica tags baseadas no SHA do commit.
  • test_image: Executa testes unitários e de integração.
  • scan_image: Realiza um escaneamento de vulnerabilidades com a ferramenta Trivy.
  • deploy_image: Publica a imagem somente quando há uma nova tag (indicando uma versão de produção).

Conclusão

Implementar práticas avançadas para Docker Images garante que suas imagens sejam leves, seguras e preparadas para produção. Ao aplicar uma estratégia de versionamento, usar microserviços e configurar pipelines CI/CD robustos, você obtém um ciclo de desenvolvimento e deploy automatizado e confiável, adaptado a ambientes modernos e escaláveis.

Este foi o último tópico do nosso guia completo sobre Docker Images! Esse material deve oferecer a base necessária para criar, gerenciar e otimizar imagens Docker em qualquer fase de desenvolvimento e produção.


Conclusão Geral

Ao dominar a criação e o gerenciamento de Docker Images, você ganha controle e flexibilidade para construir ambientes de execução consistentes, independentemente do estágio de desenvolvimento ou produção. Com as práticas e estratégias discutidas neste tutorial, é possível manter um ciclo de desenvolvimento ágil, seguro e escalável. Seja em arquiteturas de microserviços ou aplicações monolíticas, o uso eficiente de Docker Images facilita a criação de ambientes leves e seguros, tornando sua infraestrutura mais robusta e gerenciável.


This post is licensed under CC BY 4.0 by the author.