Skip to content

Commit 25d4796

Browse files
authored
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
1 parent b4efa81 commit 25d4796

File tree

4 files changed

+218
-8
lines changed

4 files changed

+218
-8
lines changed

content/guides/cpp/_index.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,21 @@ aliases:
1212
- /guides/language/cpp/
1313
languages: [cpp]
1414
params:
15-
time: 10 minutes
15+
time: 20 minutes
1616
---
1717

1818
The C++ getting started guide teaches you how to create a containerized C++ application using Docker. In this guide, you'll learn how to:
1919

2020
> **Acknowledgment**
2121
>
22-
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) for his contribution to this guide.
22+
> 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.
2323
24-
- Containerize and run a C++ application
24+
- Containerize and run a C++ application using a multi-stage Docker build
25+
- Build and run a C++ application using Docker Compose
2526
- Set up a local environment to develop a C++ application using containers
2627
- Configure a CI/CD pipeline for a containerized C++ application using GitHub Actions
2728
- Deploy your containerized application locally to Kubernetes to test and debug your deployment
29+
- Use BuildKit to generate SBOM attestations during the build process
2830

2931
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.
3032

content/guides/cpp/containerize.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
22
title: Containerize a C++ application
3-
linkTitle: Containerize your app
3+
linkTitle: Build and run a C++ application using Docker Compose
44
weight: 10
55
keywords: C++, containerize, initialize
6-
description: Learn how to containerize a C++ application.
6+
description: Learn how to use Docker Compose to build and run a C++ application.
77
aliases:
88
- /language/cpp/containerize/
99
- /guides/language/cpp/containerize/
@@ -15,17 +15,17 @@ aliases:
1515

1616
## Overview
1717

18-
This section walks you through containerizing and running a C++ application.
18+
This section walks you through containerizing and running a C++ application, using Docker Compose.
1919

2020
## Get the sample application
2121

22-
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:
22+
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:
2323

2424
```console
2525
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git
2626
```
2727

28-
You should now have the following contents in your `c-plus-plus-docker`
28+
You should now have the following contents in your `c-plus-plus-docker` (root)
2929
directory.
3030

3131
```text

content/guides/cpp/multistage.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
title: Create a multi-stage build for your C++ application
3+
linkTitle: Containerize your app using a multi-stage build
4+
weight: 5
5+
keywords: C++, containerize, multi-stage
6+
description: Learn how to create a multi-stage build for a C++ application.
7+
aliases:
8+
- /language/cpp/multistage/
9+
- /guides/language/cpp/multistage/
10+
---
11+
12+
## Prerequisites
13+
14+
- 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.
15+
16+
## Overview
17+
18+
This section walks you through creating a multi-stage Docker build for a C++ application.
19+
A multi-stage build is a Docker feature that allows you to use different base images for different stages of the build process,
20+
so you can optimize the size of your final image and separate build dependencies from runtime dependencies.
21+
22+
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,
23+
because the build dependencies are not needed at runtime.
24+
25+
## Get the sample application
26+
27+
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:
28+
29+
```bash
30+
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git
31+
```
32+
33+
The example for this section is under the `hello` directory in the repository. Get inside it and take a look at the files:
34+
35+
```bash
36+
$ cd c-plus-plus-docker/hello
37+
$ ls
38+
```
39+
40+
You should see the following files:
41+
42+
```text
43+
Dockerfile hello.cpp
44+
```
45+
46+
## Check the Dockerfile
47+
48+
Open the `Dockerfile` in an IDE or text editor. The `Dockerfile` contains the instructions for building the Docker image.
49+
50+
```Dockerfile
51+
# Stage 1: Build stage
52+
FROM ubuntu:latest AS build
53+
54+
# Install build-essential for compiling C++ code
55+
RUN apt-get update && apt-get install -y build-essential
56+
57+
# Set the working directory
58+
WORKDIR /app
59+
60+
# Copy the source code into the container
61+
COPY hello.cpp .
62+
63+
# Compile the C++ code statically to ensure it doesn't depend on runtime libraries
64+
RUN g++ -o hello hello.cpp -static
65+
66+
# Stage 2: Runtime stage
67+
FROM scratch
68+
69+
# Copy the static binary from the build stage
70+
COPY --from=build /app/hello /hello
71+
72+
# Command to run the binary
73+
CMD ["/hello"]
74+
```
75+
76+
The `Dockerfile` has two stages:
77+
78+
1. **Build stage**: This stage uses the `ubuntu:latest` image to compile the C++ code and create a static binary.
79+
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.
80+
81+
## Build the Docker image
82+
83+
To build the Docker image, run the following command in the `hello` directory:
84+
85+
```bash
86+
$ docker build -t hello .
87+
```
88+
89+
The `-t` flag tags the image with the name `hello`.
90+
91+
## Run the Docker container
92+
93+
To run the Docker container, use the following command:
94+
95+
```bash
96+
$ docker run hello
97+
```
98+
99+
You should see the output `Hello, World!` in the terminal.
100+
101+
## Summary
102+
103+
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.
104+
In this example, the final image only contains the static binary and doesn't include any build dependencies.
105+
106+
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:
107+
108+
```bash
109+
$ docker run hello ls
110+
```
111+
112+
This makes the image very lightweight and secure.

content/guides/cpp/security.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
title: Supply-chain security for C++ Docker images
3+
linkTitle: Supply-chain security
4+
weight: 60
5+
keywords: C++, security, multi-stage
6+
description: Learn how to extract SBOMs from C++ Docker images.
7+
aliases:
8+
- /language/cpp/security/
9+
- /guides/language/cpp/security/
10+
---
11+
12+
## Prerequisites
13+
14+
- 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.
15+
- 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:
16+
- 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:
17+
18+
```bash
19+
$ curl -sSfL https://raw.githubusercontent.com/docker/sbom-cli-plugin/main/install.sh | sh -s --
20+
```
21+
22+
- You have the [Docker Scout CLI plugin](https://docs.docker.com/scout/install/) installed. To install it on Docker Engine, use the following command:
23+
24+
```bash
25+
$ curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
26+
```
27+
28+
- You have [containerd enabled](https://docs.docker.com/engine/storage/containerd/) for Docker Engine.
29+
30+
## Overview
31+
32+
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.
33+
34+
## Generate an SBOM
35+
36+
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.
37+
The image is named `hello`. To generate an SBOM for the `hello` image, run the following command:
38+
39+
```bash
40+
$ docker sbom hello
41+
```
42+
43+
The command will say "No packages discovered". This is because the final image is a scratch image and doesn't have any packages.
44+
Let's try again with Docker Scout:
45+
46+
```bash
47+
$ docker scout sbom --format=list hello
48+
```
49+
50+
This command will tell you the same thing.
51+
52+
## Generate an SBOM attestation
53+
54+
The SBOM can be generated during the build process and "attached" to the image. This is called an SBOM attestation.
55+
To generate an SBOM attestation for the `hello` image, first let's change the Dockerfile:
56+
57+
```Dockerfile
58+
ARG BUILDKIT_SBOM_SCAN_STAGE=true
59+
60+
FROM ubuntu:latest AS build
61+
62+
RUN apt-get update && apt-get install -y build-essential
63+
64+
WORKDIR /app
65+
66+
COPY hello.cpp .
67+
68+
RUN g++ -o hello hello.cpp -static
69+
70+
# --------------------
71+
FROM scratch
72+
73+
COPY --from=build /app/hello /hello
74+
75+
CMD ["/hello"]
76+
```
77+
78+
The first line `ARG BUILDKIT_SBOM_SCAN_STAGE=true` enables SBOM scanning in the build stage.
79+
Now, build the image with the following command:
80+
81+
```bash
82+
$ docker buildx build --sbom=true -t hello:sbom .
83+
```
84+
85+
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:
86+
87+
```bash
88+
$ docker scout sbom --format=list hello:sbom
89+
```
90+
91+
Note that the normal `docker sbom` command will not load the SBOM attestation.
92+
93+
## Summary
94+
95+
In this section, you learned how to generate SBOM attestation for a C++ Docker image during the build process.
96+
The normal image scanners will not be able to generate SBOMs from scratch images.

0 commit comments

Comments
 (0)