Docker and C++: Containerizing Applications from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Docker and C++: Containerizing Applications from A to Z



Containerization has become an integral part of modern software development. Docker allows you to package applications together with their dependencies, ensuring reproducibility and portability. In this article, we will thoroughly examine how to containerize C++ applications using Docker — from basic concepts to advanced optimization techniques.



1. Why Containerize C++ Applications?



Many developers mistakenly believe that Docker is only relevant for interpreted languages (Python, Node.js). However, C++ applications also benefit from containerization:



  • Dependency isolation: libraries, compilers, and system utilities do not conflict with other projects
  • Build reproducibility: identical environment at all stages (dev, CI/CD, production)
  • Simplified deployment: the image contains everything needed to run
  • Scalability: easily run multiple instances via Docker Compose or Kubernetes


Let's examine the process with a practical example.



2. Basic Dockerfile for C++



Let's start with a simple C++ application. Create a file main.cpp:



#include <iostream>

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


Now let's write a Dockerfile for building and running:



# Base image with compilerFROM gcc:latest AS builder

WORKDIR /appCOPY main.cpp .

# CompilationRUN g++ -o hello main.cpp

# Final minimal imageFROM alpine:latest

WORKDIR /appCOPY --from=builder /app/hello .

CMD ["./hello"]


Build and run:



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


Result: Hello, Dockerized C++!



Explanation:

  • The first stage (builder) uses the full gcc image for compilation
  • The second stage uses minimal Alpine Linux for the final image
  • The final image contains only the compiled binary — this saves space


3. Building with CMake and Dependencies



Real projects often use CMake and external libraries. Let's look at an example with the fmt library.



Project structure:



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


CMakeLists.txt:



cmake_minimum_required(VERSION 3.14)project(MyApp)

find_package(fmt REQUIRED)

add_executable(myapp main.cpp)target_link_libraries(myapp fmt::fmt)


main.cpp:



#include <fmt/core.h>

int main() { fmt::println("Hello from {}!", "C++ with Docker"); return 0;}


Dockerfile with multi-stage build:



# Stage 1: Build dependencies and applicationFROM ubuntu:22.04 AS builder

RUN apt-get update && apt-get install -y \ build-essential cmake libfmt-dev \ && rm -rf /var/lib/apt/lists/*

WORKDIR /appCOPY CMakeLists.txt main.cpp ./RUN cmake -B build && cmake --build build

# Stage 2: Final imageFROM ubuntu:22.04

RUN apt-get update && apt-get install -y libfmt9 \ && rm -rf /var/lib/apt/lists/*

WORKDIR /appCOPY --from=builder /app/build/myapp .

CMD ["./myapp"]


Important points:

  • Build dependencies (build-essential, cmake) do not end up in the final image
  • Runtime dependencies (libfmt9) are installed separately
  • The size of the final image is significantly smaller


4. Optimizing Docker Images for C++



Optimization is especially important for C++ applications, as images with compilers can

Blogs

Book Recommendations