More complex Hello World in C++, automated builds (Page2).
29 Jul 2018This 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.
Back to Tips and Tricks Table of Contents
Back to Page 1 of the tutorial
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:
git clone
an existing repository of C++ code, which I have imported in Eclipse, so that I can easily develop there.- use an image that has the libraries I need already set up
- has a demo option, that copies over files from the Github repository so that user does not have to.
- does all of the things in the previous examples
- building may or may not include cmake, I want to put that in its own script.
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.
Step 2. Create automated build on Docker
From the Create
tab, select the Create Automated Build
option.
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.
Step 4. Trigger the build.
Under build settings, select the Trigger
button to trigger the build process.
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.
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