Docker’da C++ uygulaması derleyip test etmek
Düzenlendi · Kapsam: Multi-stage Dockerfile, BuildKit cache mounts, CMake/Ninja, CTest ve Distroless çalışma zamanı.
C++ projelerini Docker konteynerlerinde derlerken karşılaşılan en büyük iki sorun:
- Derleme araçlarının (GCC/Clang, CMake, Ninja, vcpkg/Conan) son imajı birkaç gigabayta şişirmesi ve güvenlik açığı yüzeyini genişletmesi.
- Kaynak kodda yapılan tek satırlık bir değişiklikte tüm kütüphanelerin ve bağımlılıkların saatlerce baştan derlenmesi (katman önbelleğinin kırılması).
Bu sorunların modern çözümü; Çok Aşamalı Derleme (Multi-Stage Build), BuildKit Önbellek Bağlamaları (--mount=type=cache) ve CTest entegrasyonu ile oluşturulan izole boru hattıdır.
1. Çok aşamalı mimarinin yapısı
Boru hattı mantıksal olarak 4 aşamadan oluşur:
[ 1. Derleme Ortamı ] ──► Derleyici araçlar (GCC/Clang, CMake, Ninja, Ccache)
│
[ 2. Bağımlılık Katmanı ] ──► vcpkg.json ile harici kütüphaneler (vcpkg cache)
│
[ 3. Kod Derleme ] ──► Kaynak kod derlemesi (Ccache önbelleği ile saniyeler içinde)
│
[ 4. Test Koşucusu ] ──► CTest ile birim testler (Başarısız olursa imaj üretimi durur)
│
[ 5. Minimal Çalışma ] ──► Yalnızca ikili dosya (Distroless / Scratch - ~25 MB)
2. Üretime hazır çok aşamalı Dockerfile
Projenizin kök dizininde Dockerfile dosyasını oluşturun:
# syntax=docker/dockerfile:1.4
# ==============================================================================
# AŞAMA 1: Temel Derleme Ortamı
# ==============================================================================
FROM debian:bookworm-slim AS temel-araclar
ENV DEBIAN_FRONTEND=noninteractive \
VCPKG_ROOT=/opt/vcpkg \
VCPKG_FORCE_SYSTEM_BINARIES=1
# APT paketlerini BuildKit önbelleği ile kur (tekrar indirilmez)
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y --no-install-recommends \
build-essential \
cmake \
ninja-build \
git \
curl \
zip \
unzip \
tar \
pkg-config \
ca-certificates \
ccache
# vcpkg aracını kur
RUN git clone --depth 1 https://github.com/microsoft/vcpkg.git /opt/vcpkg && \
/opt/vcpkg/bootstrap-vcpkg.sh -disableMetrics
# ==============================================================================
# AŞAMA 2: Bağımlılıkların Önbelleklenmesi
# ==============================================================================
FROM temel-araclar AS bagimlilik-derleyici
WORKDIR /proje
# Yalnızca bağımlılık listesini kopyala (Kaynak kod değiştiğinde bu katman bozulmaz)
COPY vcpkg.json ./
# vcpkg ikili önbelleği ile bağımlılıkları derle
RUN --mount=type=cache,target=/root/.cache/vcpkg \
${VCPKG_ROOT}/vcpkg install --triplet x64-linux
# ==============================================================================
# AŞAMA 3: Projeyi Derleme
# ==============================================================================
FROM bagimlilik-derleyici AS derleyici
WORKDIR /proje
# Kaynak kodları kopyala
COPY CMakeLists.txt CMakePresets.json ./
COPY src/ ./src/
COPY tests/ ./tests/
# Ccache ve vcpkg önbelleklerini bağlayarak derle
ENV CCACHE_DIR=/root/.cache/ccache
RUN --mount=type=cache,target=/root/.cache/vcpkg \
--mount=type=cache,target=/root/.cache/ccache \
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake \
-DBUILD_TESTING=ON && \
cmake --build build -j
# ==============================================================================
# AŞAMA 4: Testleri Koşma (CI/CD Kapısı)
# ==============================================================================
FROM derleyici AS test-kosucu
WORKDIR /proje
# Testlerden herhangi biri başarısız olursa Docker build hata verir ve durur
RUN ctest --test-dir build --output-on-failure
# ==============================================================================
# AŞAMA 5: Minimal Üretim İmajı (Distroless)
# ==============================================================================
# Google Distroless: Kabuk (sh), paket yöneticisi içermez; yalnızca glibc ve libstdc++ içerir
FROM gcr.io/distroless/cc-debian12:nonroot AS calisma-zamani
WORKDIR /app
COPY --from=derleyici /proje/build/bin/uygulama /app/uygulama
USER nonroot:nonroot
ENTRYPOINT ["/app/uygulama"]
3. Örnek CMakeLists.txt ve test tanımı
CMakeLists.txt:
cmake_minimum_required(VERSION 3.21)
project(DockerCppProje LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Çıktı ikili dizini
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# Harici kütüphane
find_package(fmt CONFIG REQUIRED)
# Ana uygulama
add_executable(uygulama src/main.cpp)
target_link_libraries(uygulama PRIVATE fmt::fmt)
# Testler
include(CTest)
if(BUILD_TESTING)
enable_testing()
add_executable(birim_test tests/test_main.cpp)
target_link_libraries(birim_test PRIVATE fmt::fmt)
add_test(NAME TemelTest COMMAND birim_test)
endif()
Örnek test dosyası tests/test_main.cpp:
#include <iostream>
#include <cassert>
int topla(int a, int b) { return a + b; }
int main() {
assert(topla(2, 3) == 5);
std::cout << "Tüm testler başarıyla geçti.\n";
return 0;
}
4. Derleme, test ve hedef seçimi
Docker BuildKit’in gelişmiş önbellek özelliklerinden yararlanmak için derlemeyi başlatın:
DOCKER_BUILDKIT=1 docker build -t cpp-uygulama:latest .
CI/CD Boru Hattında Hedef Aşama Seçimi
Bütün adımları tek seferde çalıştırmak yerine CI adımlarını aşamalara bölebilirsiniz:
- Yalnızca testleri çalıştırmak için:
docker build --target test-kosucu -t test-raporu .Eğer kodunuzdaki bir test kırılırsa derleme hemen sonlanır ve hata logları konsola basılır.
- Yalnızca son üretim imajını üretmek için:
docker build --target calisma-zamani -t cpp-uygulama:prod .
5. İmaj boyutlarının karşılaştırılması
Geleneksel tek katmanlı imaj ile multi-stage Distroless imaj arasındaki fark:
Geleneksel GCC + CMake İmajı: ~1.85 GB
Multi-Stage Distroless İmajı: ~28.4 MB
Son imajda gereksiz derleyiciler, başlık dosyaları (.h/.hpp), paket yöneticisi ve
kabuk bulunmadığı için konteyner saniyeler içinde ayağa kalkar ve saldırı yüzeyi minimuma iner.
Kaynaklar ve doğrulama ortamı
- Docker Multi-Stage Builds Resmi Kılavuzu
- Google Container Tools - Distroless İmajları
- BuildKit Cache Mounts Belgesi
Bu kılavuzdaki adımlar, Docker Engine 26.1, BuildKit ve Debian 12 tabanında GCC 12, CMake 3.25 ve Ninja ile test edilerek doğrulanmıştır.