Reduzindo imagens docker com MultiStage

Este post não tem tags.

Compartilhe:

Se você usa linguagens compiladas (Golang, Java) e está buscando uma forma eficiente de reduzir o tamanho das suas imagens docker, está no lugar certo.

Mas antes de decidir utilizar imagens pequenas, precisamos entender o real impacto do uso das imagens grandes.

Esse impacto pode ser maior que o imaginado em ambientes de alta volumetria.

Cenário:

  • Uma aplicação utiliza uma imagem docker de 1GB.
  • Essa aplicação está em um cluster de 100 nós.

No cenário descrito acima, imagine que a aplicação recebe uma volumetria inesperada e vai escalar automaticamente de 1 para 100 containers.

Isso significa que o cluster todo vai trafegar até 99GB de informação, fazendo pull (download) da imagem docker em cada nó que ainda não a tem disponível.

Pra piorar a situação, resolvemos fazer deploy de uma nova versão com a aplicação escalada, ou seja, todas as imagens serão substituídas nesse processo (~100GB).

Resultado:

  • Altas taxas de transferência
  • Concorrência de banda entre pull de imagens e usuários
  • Escalabilidade afetada

Para tentar resolver essa questão, vamos falar de Docker multistage, que apesar de ser uma funcionalidade bastante conhecida na comunidade, ainda gera dúvidas em alguns dos nossos clientes.

Antes da prática, vamos entender a teoria do uso de Multi Stage para o nosso caso:

imagine que o processo de build de uma aplicação precise atender uma série de dependências. Essas dependências criam camadas que fazem a imagem docker ficar cada vez maior.

Com o uso de Multi Stage, temos a possibilidade de utilizar imagens diferentes entre o processo de build e o processo de execução do binário. O resultado disso é uma imagem significativamente menor, já que as camadas anteriores são ‘descartadas’, restando somente o binário para execução em uma imagem enxuta.

Dockerfile:

FROM golang:1.7.3 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY -–from=builder /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]

O exemplo acima, ilustra o uso da imagem golang:1.7.3 com a tag builder, para o processo de build
da aplicação.

Em seguida, a imagem alpine:latest, é utilizada como imagem de execução, onde copiamos somente o
binário da imagem anterior: COPY –from=builder /go/src/github.com/alexellis/href-counter/app .

Isso traz resultados relevantes, já que a imagem final precisa somente do binário compilado.

Mão na Massa

Para o nosso laboratório prático, vamos utilizar um projeto opensource mantido pelo Luizalabs
chamado Teresa, onde tive a chance de colaborar para uma redução significativa da imagem docker.

A ideia do passo a passo é fazer o build da imagem antes do commit com Multi Stage, e depois do
commit pra fazermos a comparação.

Antes do Multi Stage

1 – Vamos começar clonando o projeto

$git clone https://github.com/luizalabs/teresa.git

2 – Em seguda acesse a pasta teresa

$cd teresa

3 – Voltando para o commit antes da alteração

$git checkout 70da95bbe2197ce1db3b46e8945ab990b28ebd8a

4 – Visualizando dockerfile

$cat Dockerfile


FROM golang:1.8
RUN mkdir -p /go/src/github.com/luizalabs/teresa
WORKDIR /go/src/github.com/luizalabs/teresa
COPY . /go/src/github.com/luizalabs/teresa
RUN make build-server
ENTRYPOINT ["./teresa-server"]
CMD ["run"]
EXPOSE 50051

5 – Fazendo build da imagem antiga

$docker build -t teresa-old .

6 – Listando imagens existentes

$docker images

Reduzindo imagens docker com MultiStage 1

Observe que a imagem tinha o tamanho de 823MB antes da alteração.

Depois do Multi Stage

1 – Indo para o commit depois da alteração

$git checkout 15de6e124ac1d081479320259c106f34628b989f

2 – Visualizando dockerfile novo

$cat Dockerfile

FROM golang:1.8 AS builder
WORKDIR /go/src/github.com/luizalabs/teresa
COPY . /go/src/github.com/luizalabs/teresa
RUN make build-server

FROM debian:9-slim
RUN apt-get update && \
apt-get install ca-certificates -y &&\
rm -rf /var/lib/apt/lists/* &&\
rm -rf /var/cache/apt/archives/*
WORKDIR /app
COPY –from=builder /go/src/github.com/luizalabs/teresa .
ENTRYPOINT [“./teresa-server”]
CMD [“run”]
EXPOSE 50051

3 – Fazendo build da imagem nova

$docker build -t teresa-new .

4 – Listando imagens existentes

$docker images

Reduzindo imagens docker com MultiStage 2

Pós alteração, a imagem chegou a 172MB, com possibilidade de melhoras.

Se você ainda não conhecia Multi Stage, agora já conhece e pode utilizar na busca por imagens menores.
Se você já utiliza, compartilhe conosco o seu case também. 🙂

Sobre o autor(a)

Função não encontrada

Sysadmin, evangelista devops, agile expert e desenvolvedor nas horas vagas.

Artigos relacionados

Um pouco do que foi o evento Product to Rescue em 9 de Julho 2024   Foco no problema Manter o foco no problema pode ser Old School mas ainda está em alta. Ficamos muito presos em problemas inexistentes ou…

Após terminar de ler o livro Ruído de Daniel Kahneman, decidi reler alguns clássicos que não olhava há algum tempo. Dentre eles, Rápido e Devagar do mesmo autor e Pensando em Sistemas de Daniela Meadows. Não pude deixar de perceber…

O Guia do Scrum fala sobre o refinamento do Product Backlog: “O Product Backlog é refinado conforme necessário” (p. 9). Todavia ele não descreve exatamente o que é o refinamento. Uma reunião, uma atividade, um processo. Neste artigo vamos jogar…

Marcos Garrido, Sócio-fundador e Trainer na K21

Existem muitas formas de organizar as métricas de seu produto / empresa. Aqui neste blog já escrevemos sobre as Métricas do Pirata, Fit For Purpose (F4P) e Métricas nas Quatro Áreas de Domínio da Agilidade. Todavia, agora, queremos falar sobre…