Using C++ with Docker Engine

Although some other alternatives are available, such as the rkt container engine, Docker Engine has become the de facto containerization platform in the past 2-3 years. In "Using Java with Docker Engine," we discussed creating a Java application with Docker Engine. Docker Engine makes better use of the operating system kernel in comparison to a virtualization platform such as VirtualBox or VMWare because a single Docker container does not make use of a whole OS kernel, whereas a single virtual machine does. Each Docker container includes its own filesystem and networking, which makes it an isolated process on the Docker Engine. A single Docker Engine with multiple Docker containers running in isolation makes it feasible to run different applications and even have some containers make use of other containers. One of the main benefits of Docker Engine is the ease of installation and configuration for software. In this tutorial, we shall discuss using C++ on Docker Engine. This tutorial has the following sections:

  • Setting the Environment
  • Creating a C++ Application
  • Creating and Running a Docker Image with the g++ Compiler
  • Creating and Running a Docker Image with the gcc Compiler
  • Compiling and Running C++ Applications Separately
  • Removing Docker Containers and Images

Setting the Environment

Docker is pre-installed on some OSes, such as CoreOS, and needs to be installed if some other OS—such as Ubuntu, Amazon Linux, or Redhat Linux—is used. We shall be using CoreOS. We shall use the CoreOS Linux (Stable) on EC2, which may be accessed at https://aws.amazon.com/marketplace/pp/B01H62FDJM?qid=1478625912213&sr=0-1&ref_=srh_res_product_title. Click Continue. Select 1-Click Launch and the default Version, which is the latest available. Select a Region and a EC2 Instance Type.

Dock01
Figure 1: Launching

Select the "default" security group, which provides access from all Source IPs. Select a Key Pair, which may have been created previously.

Dock02
Figure 2: Selecting a security group

Click Launch with 1-click.

Dock03
Figure 3: Launching with 1-click

A single instance of CoreOS Linux gets started on EC2. Obtain the Public DNS or the Public IP address for the CoreOS instance from the Console.

Dock04
Figure 4: Obtaining the public information

Using the Key Pair and the Public IP (or Public DNS) SSH, log in into the CoreOS instance.

ssh -i "coreos.pem"  core@54.197.150.238

The CoreOS instance gets logged into and the command prompt gets displayed.

Dock05
Figure 5: Displaying the command prompts

Creating a C++ Application

We shall use a Hello World C++ application to demonstrate the use of C++ on Docker, and the application HelloWorld.cpp is listed:

#include <iostream>
using namespace std;

int main()
{
   cout << "Hello world" << endl;
   cout << "From a C++ Program" << endl;
   return 0;
}

Create a file called HelloWorld.cpp in a vi editor and copy the listing to the file.

Dock06
Figure 6: Creating the HelloWorld file

Two options are available to run the C++ application:

  • Create a Docker image and subsequently run a Docker container.
  • First, compile the Docker application and subsequently run the application.

Creating and Running a Docker Image with the g++ Compiler

We shall be using the Docker image "gcc" available on the Docker Hub. The "gcc" Docker image is the GNU Compiler Collection with support for several languages, including C and C++. Two of the main commands that could be used for C/C++ application are gcc and g++. The differences between the two are discussed in the following table.

gcc g++
GNU C Compiler GNU C++ Compiler
Compiles *.c and *.cpp files as C and C++, repectively Compiles *.c and *.cpp, but they are treated as C++ files
Does not link in the C++ libraries Automatically links in the C++ libraries
Should be used with C applications Should be used with C++ applications

Next, we shall use the g++ command to run a C++ application. Create a Dockerfile (in a vi editor) in the same directory as the HelloWorld.cpp file. A Dockerfile contains instructions to build a Docker image that could be used to run a Docker container. Copy the following listing to the Dockerfile.

FROM gcc:4.9
COPY . /HelloWorld
WORKDIR /HelloWorld
RUN g++ --o HelloWorld HelloWorld.cpp
CMD ["./HelloWorld"]

The Dockerfile instructions are as follows.

Dockerfile Instruction Description
FROM gcc:4.9 The Docker image to use as the base image is gcc with tag 4.9.
COPY . /HelloWorld Copy the files in the current directory to the /HelloWorld directory.
WORKDIR /HelloWorld Set the /HelloWorld directory as the working directory.
RUN g++ --o HelloWorld HelloWorld.cpp Run the gcc command g++ with output as "HelloWorld" and input as "HelloWorld.cpp". The command generates a runnable application called "HelloWorld"
CMD ["./HelloWorld"] Run the compiled, runnable application ./HelloWorld

The Dockerfile is shown in the vi editor.

Dock07
Figure 7: The Dockerfile

The root directory should list two files: Dockerfile and HelloWorld.cpp.

Dock08
Figure 8: The two files in the root directory

Before creating a Docker image, create the directory /HelloWorld and set its permissions to global (777).

sudo mkdir /HelloWorld
chmod 777 /HelloWorld

Run the docker build command to create a Docker image called helloworld:v1 from the Dockerfile.

docker build -t  helloworld:v1 .

The Docker image gets created.

Dock09
Figure 9: The newly created Docker image

Subsequently, list the Docker images.

docker images

The helloworld image tag v1 gets listed.

Dock10
Figure 10: The new helloworld image tag

Having created the Docker image, run the a Docker container with the docker run command. The Docker container may optionally be named, "HelloWorld" for example, with the --name option. If the --name option is not used, a random name is used for the Docker container. The --rm option is called the "Clean up" option and removes the Docker container and the filesystem & volumes associated with the container after it has run. Run the following docker run command for the Docker image helloworld:v1.

docker run -it --rm --name HelloWorld helloworld:v1

The C++ application in the Docker image runs to produce an output.

Dock11
Figure 11: The Docker image producing output

Creating and Running a Docker Image with the gcc Compiler

It was mentioned previously that the g++ command is used for C++ applications and the gcc command is used for C applications. The main difference between the two is that gcc does not link the standard C++ libraries. But, the standard C++ libraries could be linked explicitly when using the gcc commnd; this is what we shall discuss in this section. Before creating a Docker image using the gcc command, remove the Docker image helloworld:v1 because we will create the same name Docker image with gcc.

docker rmi helloworld:v1

The standard C++ libraries could be linked when using the gcc command with the --lstdc++ option. Modify the Dockerfile to replace the g++ command with the gcc command as in following listing.

FROM gcc:4.9
COPY . /HelloWorld
WORKDIR /HelloWorld
RUN gcc --o HelloWorld HelloWorld.cpp --lstdc++
CMD ["./HelloWorld"]

The modified Dockerfile is shown in the vi editor.

Dock12
Figure 12: The modified Dockerfile

The same two files, Dockerfile and HelloWorld.cpp, should get listed.

Dock13
Figure 13: Listing the same two files

Run the same docker build command to create the Docker image helloworld:v1.

docker build -t  helloworld:v1

A Docker image gets generated, but contains a different command, the gcc command instead of the g++ command to run the C++ application. List the Docker images, and the helloworld:v1 Docker image should get listed in addition to the gcc Docker image.

Dock14
Figure 14: Listing the Docker images

Next, run the same docker run command to run a Docker container for the Docker image helloworld:v1.

docker run --it --rm --name HelloWorld helloworld:v1

The same output get generated.

Dock15
Figure 15: Generating the same output

The Docker containers get removed when using the --rm option. List the running and exited Docker containers with the following commands, respectively:

docker ps
docker ps -a

Because the Docker containers have been removed no Docker container should get listed running or exited.

Dock16
Figure 16: No Docker container is listed

In the previous two sections, we compiled the Docker application into a Docker image with docker build and subsequently ran a Docker container with docker run. In the next section, we shall not create a Docker image but instead only compile the HelloWorld.cpp file into a runnable application with docker run with the g++ command being invoked as a command arg to the docker run command. Subsequently, we shall run the application binaries HelloWorld, separately.

Compiling and Running C++ Applications Separately

To compile only the HelloWorld.cpp application into HelloWorld runnable application, run the following command that invokes the g++ GNU C++ compiler.

docker run --rm --v "$PWD":/HelloWorld
                --w /HelloWorld gcc:4.9 g++
                --o HelloWorld HelloWorld.cpp

The --rm option removes the container after it has run, but does not remove the application binaries generated. The --v option adds the current directory as a volume and the --w option sets the working directory to the volume.

Dock17
Figure 17: Removing the container

Subsequently, listing the files lists the HelloWorld application generated.

Dock18
Figure 18: Listing the files to see HelloWorld

Next, run the HelloWorld application.

./HelloWorld

The C++ application output gets generated.

Dock19
Figure 19: Generating the C++ output

We used the g++ compiler with the docker run command to generate the application binaries, but the gcc command with the --lstdc++ option may be used just as well.

docker run --rm --v  /HelloWorld
           --w /HelloWorld gcc:4.9 gcc
           --o HelloWorld HelloWorld.cpp
           --lstdc++

Removing Docker Containers and Images

The Docker images and containers, if any, may be removed after the C++ application has been run. Remove all Docker containers that have exited.

sudo docker rm $(sudo docker ps --a --q)

All exited Docker container should get removed.

Dock20
Figure 20: The Docker containers are removed

Remove the Docker image helloworld:v1 with the docker rmi command.

docker rmi helloworld:v1

The Docker image gets removed.

Dock21
Figure 21: The Docker images are removed

Listing the Docker images may still list some images and some images could be called <none>.

docker images

The <none> images are called dangling images. These are just some images that did not get downloaded properly or built properly.

Dock22
Figure 22: Showing the dangling images

Remove all the dangling images.

sudo docker rmi $(sudo docker images --f
   "dangling=true" --q)

All the dangling images should get removed.

Dock23
Figure 23: The dangling images are now gone

Listing the images lists only the gcc:4.9 Docker image, which could be kept for subsequent use.

Dock24
Figure 24: The remaining gcc:4.9 Docker image

Conclusion

In this tutorial, we introduced using C++ with Docker Engine.



About the Author

Deepak Vohra

Deepak Vohra is an O'Reilly technical reviewer, who reviewed the book WebLogic: The Definitive Guide. He's also a NuBean consultant and web developer, and is a Sun Certified Java 1.4 Programmer and Sun Certified Web Component Developer. Deepak has published two books on Docker.

Related Articles

Comments

  • There are no comments yet. Be the first to comment!

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date