More complex Hello World in C++, automated builds

July 29, 2018

Back to Tips and Tricks Table of Contents

Back to Page 1 of the tutorial

This is page 2 of the tutorial, where I’ll put together several of the baby steps from page 1 into something that mirrors the final application. I’ll also put the Docker image on the Docker hub using the automated build technique, which has several advantages over other methods.

Contents

Hello World With Args, Access Host, Demo Option, layered directory, and other pitfalls

This final example in the ‘Hello World’ category closely mirrors what I want to do:

This is found in the DockerHelloWorldProject3 folder, from the Github repository accompanying these pages here.

First, the Dockerfile:

FROM amytabb/docker_ubuntu16_essentials
ENV NAME VAR1
ENV NAME VAR2
ENV NAME VAR3
ENV NAME DO_DEMO
RUN mkdir /write_directory
ARG DIRECTORY=/write_directory
ENV VAR_DIR=$DIRECTORY

#grab the repo from github.
RUN git clone https://github.com/amy-tabb/docker-tutorial-hello.git
COPY run_tutorial.sh /run_tutorial.sh
COPY build_tutorial.sh /build_tutorial.sh
WORKDIR /docker-tutorial-hello/

#compile and link
RUN /bin/sh ./../build_tutorial.sh
WORKDIR /
CMD ["/bin/sh", "/run_tutorial.sh"]

Then the build_tutorial.sh script:

#!/bin/sh
#Throwing in OpenMP, we don't need it, to see if it will compile.

g++ src/*.cpp -o hello3 -fopenmp -std=gnu++11 -Wall -lgomp 

And the run_tutorial.sh script:

#!/bin/sh
#Sanity check
echo $DO_DEMO

if [ "$DO_DEMO" = "1" ] 
then
   # need to copy to $VAR_DIR		
   cp  /docker-tutorial-hello/demo_files/read.txt /write_directory/read.txt
fi

./docker-tutorial-hello/hello3 $VAR_DIR $VAR1 $VAR2 $VAR3

In this script, if the DO_DEMO environment variable is selected, then an input file to demonstrate the code is copied over into /write_directory, which is bindmounted to the user’s machine.

Then the C++ code is on publically on Github, and a little more involved, but just reads the read.txt and writes it to write.txt, with some “Hello world!” messages.

#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
using namespace std;

int main(int argc, char **argv) {
	ifstream in;
	ofstream out;
	string directory, str;
	string filename_in, filename_out;
	if (argc >= 2){
			directory = argv[1];
			cout << "Directory is : " << directory << endl;

			filename_in = directory + "/read.txt";

			in.open(filename_in.c_str());

			if (!in.good()){
				cout << "You forgot the read.txt file in the bindmount directory, quitting." << endl;
				exit(1);
			}


			filename_out = directory + "/write.txt";
			out.open(filename_out.c_str());


			while(getline(in, str)) {
				out << str << endl;
			}

			out << endl << " Hello world from the final program!  Here were the arguments!" << endl;
			cout << endl << " Hello world from the final program!  Here were the arguments!" << endl;
		for (int i = 2; i < argc; i++){
			cout << "Argument " << i << " " << argv[i] << endl;
			out << "Argument " << i << " " << argv[i] << endl;
		}
		out.close();
	} else
		return 0;
}

Building is now simple,

docker build -t  hello3 .

I will mention that if the Github repository changes, typically during the Docker build the cached version of the Github repository will be used, and it will not be re-cloned. To prevent this behavior, you can use the --no-cache flag.

docker build --no-cache -t  hello3 .

Now, you can run in similar ways to hello2.

$ sudo docker run -it -v /home/atabb/docker/HelloWorldMount:/write_directory -e VAR1=15 -e DO_DEMO=1 hello3 
1
Directory is : /write_directory

 Hello world from the final program!  Here were the arguments!
Argument 2 15

And the write.txt file returns:

Hello from the demo!

 Hello world from the final program!  Here were the arguments!
Argument 2 15

Put the container on Docker hub with an automated build

Now, at this stage you have a Docker container that works great on your local machine. But the point of Docker is deployment – and getting your awesome stuff to work on other people’s machines. It is possible to push your container to your Docker hub account (I do assume you have signed up for at least a free community edition Docker account), some documentation is here.

However, my experience is that push is slow, and likely to time out on certain internet connections. The cool kids are all using automated builds. The way this works is that you put everything from the folder where the Dockerfile resides in a repository, either Github or Bitbucket, link from Docker hub, and then Docker pulls from the repository and builds in Docker land. Confusingly, the basket where your items live in Docker land is also called a repository. So there’s no upload from your machine.

Automated builds are just as slow for large images, but you don’t have to pull and push images, so you save that time babysitting the command line, and there’s a convenient email notification when the build fails or is successful. Since we have extensively tested the Docker container in the DockerHelloWorldPRoject3 folder, we’ll use that as a test for automated builds.

Step 1. Create repository

Create a Github (or Bitbucket) repository with the files. Mine is https://github.com/amy-tabb/docker-hello-tutorial-automated, which you can clone or fork to play around with.

Github Repository

Step 2. Create automated build on Docker

From the Create tab, select the Create Automated Build option.

Create Docker Container

Step 3. Select the repository name

If you haven’t already linked Github or Bitbucket, you will be asked to do so. Then, select the repository name after selecting Github or Bitbucket. Then, there are some self-explanatory prompts as you set up the project.

Grab from Github

Step 4. Trigger the build.

Under build settings, select the Trigger button to trigger the build process.

Trigger build

Step 5. Wait. Or find something else to do. Seriously!

This screen will display the build process, but not auto-update. I refresh the screen every so often. This process takes quite a while, for one’s own sanity while getting Docker containers set up, it is useful to have another project you can work on as well. There are a lot of 1-2 hour build times – especially in the next section of the tutorial. Once you see the following screen, with that magical green Success text and green checkmark, everything is ready to roll! If not, you will get some error messages.

Build success

Step 6. Pull Docker repository and test

Now, our Docker image is on the Docker hub, in its own repository, and it is time to test. First, pull. Like Github, there’s a handy copy icon on the right-hand side of the page, from Repo info.

docker pull amytabb/docker-hello-tutorial-automated

Then I test using some of the arguments from before, but now the tag of this image is one from the automated build,amytabb/docker-hello-tutorial-automated, instead of hello3:

docker run -it -v /home/atabb/docker/HelloWorldMount:/write_directory -e VAR1=15 -e DO_DEMO=1 amytabb/docker-hello-tutorial-automated
1
Directory is : /write_directory

 Hello world from the final program!  Here were the arguments!
Argument 2 15

The output is as expected, so we’re all done here.

Back to Tips and Tricks Table of Contents

Onward to Page 3!

© Amy Tabb 2018-2020. All rights reserved. The contents of this site reflect my personal perspectives and not those of any other entity.