Conteinerização de aplicações C++ com Docker: guia completo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que containerizar aplicações C++?



O desenvolvimento em C++ é tradicionalmente associado ao problema "funciona na minha máquina". Diferentes versões de compiladores, bibliotecas e dependências do sistema transformam a implantação em uma dor de cabeça. O Docker resolve esse problema: você empacota a aplicação com todo o ambiente em um contêiner leve que é executado da mesma forma em qualquer sistema.



Neste artigo, vamos analisar o processo completo de containerização de uma aplicação C++ — desde um Dockerfile simples até a construção em múltiplos estágios com otimização do tamanho da imagem.



1. Fundamentos: Dockerfile para aplicação C++



Vamos começar com o exemplo mais simples. Suponha que temos um programa em C++ que exibe "Hello, Docker!".



Código-fonte (hello.cpp)



#include <iostream>

int main() { std::cout << "Hello, Docker!" << std::endl; return 0;}


Primeiro Dockerfile



# Usamos a imagem com GCCFROM gcc:13.2

# Definimos o diretório de trabalhoWORKDIR /app

# Copiamos os fontesCOPY hello.cpp .

# CompilamosRUN g++ -o hello hello.cpp

# ExecutamosCMD ["./hello"]


Vamos construir e executar:



docker build -t cpp-hello .docker run cpp-hello


A desvantagem dessa abordagem é que a imagem pesa cerca de 1,2 GB devido ao conjunto completo de ferramentas GCC. Para produção, isso é inaceitável.



2. Construção em múltiplos estágios (Multi-stage build)



A melhor prática é separar a compilação da execução. No primeiro estágio, compilamos a aplicação com o conjunto completo de ferramentas; no segundo, copiamos apenas o binário final para uma imagem mínima e limpa.



Dockerfile otimizado



# Estágio 1: compilaçãoFROM gcc:13.2 AS builder

WORKDIR /app

COPY hello.cpp .

RUN g++ -static -o hello hello.cpp

# Estágio 2: execuçãoFROM alpine:3.19

WORKDIR /app

# Copiamos o binário compilado estaticamenteCOPY --from=builder /app/hello .

CMD ["./hello"]


O ponto-chave é a flag -static. Ela inclui todas as dependências no binário, permitindo executá-lo em um Alpine puro sem bibliotecas adicionais. O tamanho da imagem diminui de 1,2 GB para ~6 MB!



3. Projeto real: CMake + dependências



Vamos considerar um caso mais complexo: uma aplicação que usa a biblioteca Boost e é compilada com CMake.



Estrutura do projeto



myapp/├── CMakeLists.txt├── src/│   └── main.cpp└── Dockerfile


CMakeLists.txt



cmake_minimum_required(VERSION 3.20)project(MyApp LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Boost REQUIRED COMPONENTS system)

add_executable(myapp src/main.cpp)target_link_libraries(myapp Boost::system)


main.cpp



#include <iostream>#include <boost/asio.hpp>

int main() { boost::asio::io_context io; std::cout << "Boost.Asio funciona no contêiner!" << std::endl; return 0;}


Dockerfile com dependências



# Estágio 1: compilaçãoFROM ubuntu:22.04 AS builder

# Instalamos as dependências de compilaçãoRUN apt-get update && apt-get install -y \ build-essential \ cmake \ libboost-system-dev \ && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copiamos os fontesCOPY CMakeLists.txt .COPY src/ src/

# CompilamosRUN mkdir build && cd build && \ cmake .. -DCMAKE_BUILD_TYPE=Release && \ make -j$(nproc)

# Estágio 2: execuçãoFROM ubuntu:22.04

# Instalamos apenas as dependências de runtimeRUN apt-get update && apt-get install -y \ libboost-system1.74.0 \ && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY --from=builder /app/build/myapp .

CMD ["./myapp"]


Observe: no segundo estágio, instalamos apenas a versão de runtime do Boost (libboost-system1.74.0).

Blogs

Book Recommendations