Add multi-stage builds to the C++ guide (#21562)

## Description

Having a multi-stage build is an essential thing to learn for
containerizing a compiled language.

## Related issues or tickets

N/A

## Reviews

- [ ] Technical review
- [ ] Editorial review
- [ ] Product review
This commit is contained in:
Mohammad-Ali A'RÂBI 2025-02-27 18:24:01 +01:00 committed by GitHub
parent b4efa8117d
commit 25d4796019
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 218 additions and 8 deletions

View File

@ -12,19 +12,21 @@ aliases:
- /guides/language/cpp/
languages: [cpp]
params:
time: 10 minutes
time: 20 minutes
---
The C++ getting started guide teaches you how to create a containerized C++ application using Docker. In this guide, you'll learn how to:
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) for his contribution to this guide.
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) and [Mohammad-Ali A'râbi](https://twitter.com/MohammadAliEN) for their contribution to this guide.
- Containerize and run a C++ application
- Containerize and run a C++ application using a multi-stage Docker build
- Build and run a C++ application using Docker Compose
- Set up a local environment to develop a C++ application using containers
- Configure a CI/CD pipeline for a containerized C++ application using GitHub Actions
- Deploy your containerized application locally to Kubernetes to test and debug your deployment
- Use BuildKit to generate SBOM attestations during the build process
After completing the C++ getting started modules, you should be able to containerize your own C++ application based on the examples and instructions provided in this guide.

View File

@ -1,9 +1,9 @@
---
title: Containerize a C++ application
linkTitle: Containerize your app
linkTitle: Build and run a C++ application using Docker Compose
weight: 10
keywords: C++, containerize, initialize
description: Learn how to containerize a C++ application.
description: Learn how to use Docker Compose to build and run a C++ application.
aliases:
- /language/cpp/containerize/
- /guides/language/cpp/containerize/
@ -15,17 +15,17 @@ aliases:
## Overview
This section walks you through containerizing and running a C++ application.
This section walks you through containerizing and running a C++ application, using Docker Compose.
## Get the sample application
Clone the sample application to use with this guide. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
We're using the same sample repository that you used in the previous sections of this guide. If you haven't already cloned the repository, clone it now:
```console
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git
```
You should now have the following contents in your `c-plus-plus-docker`
You should now have the following contents in your `c-plus-plus-docker` (root)
directory.
```text

View File

@ -0,0 +1,112 @@
---
title: Create a multi-stage build for your C++ application
linkTitle: Containerize your app using a multi-stage build
weight: 5
keywords: C++, containerize, multi-stage
description: Learn how to create a multi-stage build for a C++ application.
aliases:
- /language/cpp/multistage/
- /guides/language/cpp/multistage/
---
## Prerequisites
- You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
## Overview
This section walks you through creating a multi-stage Docker build for a C++ application.
A multi-stage build is a Docker feature that allows you to use different base images for different stages of the build process,
so you can optimize the size of your final image and separate build dependencies from runtime dependencies.
The standard practice for compiled languages like C++ is to have a build stage that compiles the code and a runtime stage that runs the compiled binary,
because the build dependencies are not needed at runtime.
## Get the sample application
Let's use a simple C++ application that prints `Hello, World!` to the terminal. To do so, clone the sample repository to use with this guide:
```bash
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git
```
The example for this section is under the `hello` directory in the repository. Get inside it and take a look at the files:
```bash
$ cd c-plus-plus-docker/hello
$ ls
```
You should see the following files:
```text
Dockerfile hello.cpp
```
## Check the Dockerfile
Open the `Dockerfile` in an IDE or text editor. The `Dockerfile` contains the instructions for building the Docker image.
```Dockerfile
# Stage 1: Build stage
FROM ubuntu:latest AS build
# Install build-essential for compiling C++ code
RUN apt-get update && apt-get install -y build-essential
# Set the working directory
WORKDIR /app
# Copy the source code into the container
COPY hello.cpp .
# Compile the C++ code statically to ensure it doesn't depend on runtime libraries
RUN g++ -o hello hello.cpp -static
# Stage 2: Runtime stage
FROM scratch
# Copy the static binary from the build stage
COPY --from=build /app/hello /hello
# Command to run the binary
CMD ["/hello"]
```
The `Dockerfile` has two stages:
1. **Build stage**: This stage uses the `ubuntu:latest` image to compile the C++ code and create a static binary.
2. **Runtime stage**: This stage uses the `scratch` image, which is an empty image, to copy the static binary from the build stage and run it.
## Build the Docker image
To build the Docker image, run the following command in the `hello` directory:
```bash
$ docker build -t hello .
```
The `-t` flag tags the image with the name `hello`.
## Run the Docker container
To run the Docker container, use the following command:
```bash
$ docker run hello
```
You should see the output `Hello, World!` in the terminal.
## Summary
In this section, you learned how to create a multi-stage build for a C++ application. Multi-stage builds help you optimize the size of your final image and separate build dependencies from runtime dependencies.
In this example, the final image only contains the static binary and doesn't include any build dependencies.
As the image has an empty base, the usual OS tools are also absent. So, for example, you can't run a simple `ls` command in the container:
```bash
$ docker run hello ls
```
This makes the image very lightweight and secure.

View File

@ -0,0 +1,96 @@
---
title: Supply-chain security for C++ Docker images
linkTitle: Supply-chain security
weight: 60
keywords: C++, security, multi-stage
description: Learn how to extract SBOMs from C++ Docker images.
aliases:
- /language/cpp/security/
- /guides/language/cpp/security/
---
## Prerequisites
- You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
- You have a Docker Desktop installed, with containerd enabled for pulling and storing images (it's a checkbox in **Settings** > **General**). Otherwise, if you use Docker Engine:
- You have the [Docker SBOM CLI plugin](https://github.com/docker/sbom-cli-plugin) installed. To install it on Docker Engine, use the following command:
```bash
$ curl -sSfL https://raw.githubusercontent.com/docker/sbom-cli-plugin/main/install.sh | sh -s --
```
- You have the [Docker Scout CLI plugin](https://docs.docker.com/scout/install/) installed. To install it on Docker Engine, use the following command:
```bash
$ curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
```
- You have [containerd enabled](https://docs.docker.com/engine/storage/containerd/) for Docker Engine.
## Overview
This section walks you through extracting Software Bill of Materials (SBOMs) from a C++ Docker image using the Docker SBOM CLI plugin. SBOMs provide a detailed list of all the components in a software package, including their versions and licenses. You can use SBOMs to track the provenance of your software and ensure that it complies with your organization's security and licensing policies.
## Generate an SBOM
Here we will use the Docker image that we built in the [Create a multi-stage build for your C++ application](/guides/language/cpp/multistage/) guide. If you haven't already built the image, follow the steps in that guide to build the image.
The image is named `hello`. To generate an SBOM for the `hello` image, run the following command:
```bash
$ docker sbom hello
```
The command will say "No packages discovered". This is because the final image is a scratch image and doesn't have any packages.
Let's try again with Docker Scout:
```bash
$ docker scout sbom --format=list hello
```
This command will tell you the same thing.
## Generate an SBOM attestation
The SBOM can be generated during the build process and "attached" to the image. This is called an SBOM attestation.
To generate an SBOM attestation for the `hello` image, first let's change the Dockerfile:
```Dockerfile
ARG BUILDKIT_SBOM_SCAN_STAGE=true
FROM ubuntu:latest AS build
RUN apt-get update && apt-get install -y build-essential
WORKDIR /app
COPY hello.cpp .
RUN g++ -o hello hello.cpp -static
# --------------------
FROM scratch
COPY --from=build /app/hello /hello
CMD ["/hello"]
```
The first line `ARG BUILDKIT_SBOM_SCAN_STAGE=true` enables SBOM scanning in the build stage.
Now, build the image with the following command:
```bash
$ docker buildx build --sbom=true -t hello:sbom .
```
This command will build the image and generate an SBOM attestation. You can verify that the SBOM is attached to the image by running the following command:
```bash
$ docker scout sbom --format=list hello:sbom
```
Note that the normal `docker sbom` command will not load the SBOM attestation.
## Summary
In this section, you learned how to generate SBOM attestation for a C++ Docker image during the build process.
The normal image scanners will not be able to generate SBOMs from scratch images.