Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker image generation #1484

Merged
merged 15 commits into from Apr 30, 2015
6 changes: 6 additions & 0 deletions .dockerignore
@@ -0,0 +1,6 @@
# Copyright (c) 2015 Martin Stumpf
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/.git
16 changes: 16 additions & 0 deletions Dockerfile
@@ -0,0 +1,16 @@
# Copyright (c) 2015 Martin Stumpf
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

FROM stellargroup/build_env:debian_clang

ADD . /hpx

RUN cd /hpx/build && make install && cd /
RUN rm -rf /hpx

RUN ldconfig

CMD bash
WORKDIR /
20 changes: 20 additions & 0 deletions circle.yml
Expand Up @@ -8,6 +8,7 @@ machine:
- docker
environment:
IMAGE_NAME: stellargroup/build_env:debian_clang
TARGET_IMAGE_NAME: stellargroup/hpx:dev

general:
branches:
Expand All @@ -26,9 +27,28 @@ dependencies:
- docker run -v $PWD:/hpx -w /hpx/build ${IMAGE_NAME} make -j2 -k tests.unit
- docker run -v $PWD:/hpx -w /hpx/build ${IMAGE_NAME} make -j2 -k tests.regressions
- docker run -v $PWD:/hpx -w /hpx/build ${IMAGE_NAME} make -j2 -k tests.performance
# TODO replace this line with "docker build" once docker managed to
# introduce temporal file copies that don't show in the resulting image
# size.
# The problem is the "ADD/COPY" and "RUN rm" in Dockerfile. Those count
# as seperate steps and keep the temporal files stored as part of the
# image, expanding it by about 500 MB.
# docker-compile.pl is a dirty workaround, and shall be removed ASAP.
- ./tools/docker/docker-compile.pl ${TARGET_IMAGE_NAME}

test:
override:
- docker run -v $PWD:/hpx -w /hpx/build ${IMAGE_NAME} ./bin/hello_world --hpx:bind=none
#- docker run -v $PWD:/hpx -w /hpx/build ${IMAGE_NAME} ctest -D ExperimentalTest -R tests.unit --output-on-failure
#- docker run -v $PWD:/hpx -w /hpx/build ${IMAGE_NAME} ctest -D ExperimentalTest -R tests.regressions --output-on-failure
- sudo rm -rf build && mkdir build
- docker run -v $PWD:/hpx -w /hpx/build ${TARGET_IMAGE_NAME} hello_world --hpx:bind=none
- docker run -v $PWD:/hpx -w /hpx/build ${TARGET_IMAGE_NAME} hpxcxx --exe=hello_world_test_build ../examples/quickstart/hello_world.cpp -liostreams
- docker run -v $PWD:/hpx -w /hpx/build ${TARGET_IMAGE_NAME} ./hello_world_test_build --hpx:bind=none

deployment:
hub:
branch: master
commands:
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- docker push ${TARGET_IMAGE_NAME}
142 changes: 142 additions & 0 deletions tools/docker/docker-compile.pl
@@ -0,0 +1,142 @@
#!/usr/bin/env perl

# copyright: Maciej Pasternacki
# http://3ofcoins.net/2013/09/22/flat-docker-images/
#
# TODO: replace with something homemade

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the Boost License header

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

U sure? We don't even have the copyright for this file, I pulled it in from that dude. He published it via gist without copyright note

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

He added his copyright but published it without a license (which means it's in the public domain). That entitles us to relicense it under the Boost license, I don't see a problem with that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, technically he didn't even add his name in, I did that ;)
Should I strip his name out? Or is it polite to leave that in

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd leave his copyright in place, credit where credit is due...


use feature 'switch';
use strict;
use warnings;

no if $] >= 5.018, warnings => "experimental::smartmatch";

use Data::Dumper;
use File::Basename;
use File::Copy;
use File::Path qw/make_path/;
use File::Temp qw/tempdir/;

use JSON;

if ($#ARGV != 0) {
print "\nUsage: docker-compile.pl commit-tag\n";
exit;
}

our ( $from, $author, %metadata, @commands, $tmpdir, $tmpcount, $prefix );


$tmpdir = tempdir(CLEANUP => !$ENV{LEAVE_TMPDIR});
$tmpcount = 0;
$prefix = '';

print "*** Working directory: $tmpdir\n" if $ENV{LEAVE_TMPDIR};

open DOCKERFILE, '<Dockerfile' or die;
while ( <DOCKERFILE> ) {
chomp;

# handle long lines
$_ = "$prefix$_";
$prefix = '';
if ( /\\$/ ) {
s/\\$//;
$prefix="$_\n";
next;
}

s/^\s*//;
/^#/ and next;
/^$/ and next;

my ($cmd, $args) = split(/\s+/, $_, 2);
given ( uc $cmd ) {
# building the image
when ('FROM') { $from = $args }
when ('RUN') { push @commands, $args }
when ('ADD') {
$tmpcount++;
my ( $src, $dest ) = split ' ', $args, 2;

if ( $src =~ /^https?:/ ) {
my $basename = basename($src);
my $target = "$tmpdir/dl/$tmpcount/$basename";
make_path "$tmpdir/dl/$tmpcount";
system('wget', '-O', $target, $src) == 0 or die;
$src = $target;
}

my $local = "$tmpdir/$tmpcount";

given ( $src ) {
when ( /\.(tar(\.(gz|bz2|xz))?|tgz)$/ ) {
mkdir $local;
system('tar', '-C', $local, '-xf', $_) == 0 or die;
push @commands, "mkdir -p '$dest'", "( cd /.data/$tmpcount ; cp -a . '$dest' )";
}
when ( -f $_ ) {
$dest .= basename($_) if ( $dest =~ /\/$/ );
system('cp', '-a', $_, $local) == 0 or die;
push @commands, "mkdir -p '".dirname($dest)."'", "cp -a /.data/$tmpcount '$dest'";
}
when ( -d $_ ) {
# Handle trailing slash combinations properly:
# - `$src=/dir, $dest=/foo -> /foo`
# - `$src=/dir, $dest=/foo/ -> /foo/dir`
# - `$src=/dir/, $dest=/foo -> /foo`
# - `$src=/dir/, $dest=/foo/ -> /foo`
$dest .= basename($_) if ( $_ !~ /\/$/ && $dest =~ /\/$/ );

system('cp', '-a', $_, $local) == 0 or die;
push @commands, "mkdir -p '$dest'", "( cd /.data/$tmpcount ; cp -a . '$dest' )";
}
default { die }
}
}

# image metadata
when ('MAINTAINER') { $author = $args }
when ('CMD') { $metadata{Cmd} = eval { decode_json($args) } || ['sh', '-c', $args] }
when ('ENTRYPOINT') { $metadata{Entrypoint} = eval { decode_json($args) } || ['sh', '-c', $args] }
when ('WORKDIR') { $metadata{WorkingDir} = $args }
when ('USER') { $metadata{User} = $args }
when ('EXPOSE') { push @{ $metadata{PortSpecs} ||= [] }, split(' ',$args); }
when ('ENV') {
my ( $k, $v ) = split(/s+/, $args, 2);
push @commands, "export $k='$v'";
push @{ $metadata{Env} ||= [] }, "$k=$v";
}
when ('VOLUME') {
# This seems to be a NOP in `docker build`.
# push @{ $metadata{VolumesFrom} ||= [] }, $args
}
}
}
close DOCKERFILE;

open SETUP, ">$tmpdir/setup.sh" or die;
print SETUP join("\n", "#!/bin/sh", "set -e -x", @commands), "\ntouch /.data/FINI\n";
close SETUP;
chmod 0755, "$tmpdir/setup.sh";

our @run = ('docker', 'run', "-cidfile=$tmpdir/CID", '-v', "$tmpdir:/.data", $from, "/.data/setup.sh");
print "*** ", join(' ', @run), "\n";
system(@run) == 0 or die;

die "unfinished, not committing\n" unless -f "$tmpdir/FINI";

sleep 15; # docker container is not always immediately up to a commit, let's give it time to cool off.

open CID, "<$tmpdir/CID" or die;
our $cid = <CID>;
close CID;

our @commit = ( 'docker', 'commit' );
push @commit, "-author=$author" if defined $author;
push @commit, "-run=" . encode_json(\%metadata) if %metadata;
push @commit, $cid;
push @commit, $ARGV[0];
print "*** ", join(' ', @commit), "\n";
exec(@commit);