Skip to content

Instantly share code, notes, and snippets.

@dmolesUC
Last active January 9, 2016 01:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmolesUC/1cf3e1e451897b552828 to your computer and use it in GitHub Desktop.
Save dmolesUC/1cf3e1e451897b552828 to your computer and use it in GitHub Desktop.
Stash / Docker diary

Creating a Dockerfile for Stash development

Emulating the AWS development environment

It is possible to find Docker images for Amazon Linux, but because the RPM repositories for Amazon Linux are only available within AWS, they only work if the Docker host is also on AWS.

Instead, we're going to try use Centos, which like Amazon Linux is derived from RedHat Enterprise Linux, cross our fingers, and hope.

Getting CentOS

First let's see what we've actually got on uc3-dash2-dev.cdlib.org:

-bash-4.2$ uname -a
Linux uc3-dash2-dev 4.1.13-19.30.amzn1.x86_64 #1 SMP Fri Dec 11 03:42:10
UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

Now, Centos ships with a 3.1 kernel, but since this is Docker, we don't care; all Docker containers share the kernel of the Docker host (which in this case is a VirtualBox VM installed by Docker Toolbox). Let's spin up a temporary Docker container and run uname on that so we can see what we've got.

$ docker run ubuntu:14.04 uname -a
Linux 18f2e96c0abc 4.1.13-boot2docker #1 SMP Fri Nov 20 19:05:50 UTC 2015
x86_64 x86_64 x86_64 GNU/Linux

Excellent, Docker and Amazon are both keeping their kernels up to date.

Network troubleshooting

Now let's find and install Centos on Docker.

$ docker pull centos:7
Pulling repository docker.io/library/centos
Error while pulling image: 
Get https://index.docker.io/v1/repositories/library/centos/images: 
dial tcp: lookup index.docker.io on 128.32.136.9:53: server misbehaving

Okay. This Stack Overflow answer implies it may have something to do with the fact that we started the Docker machine yesterday over at BIDS, and now we're back at CDL. Let's try the answer suggested there:

$ docker-machine restart default && eval "$(docker-machine env default)"
(default) Restarting VM...
Restarted machines may have new IP addresses. You may need to re-run the
`docker-machine env` command.
Error checking TLS connection: Error checking and/or regenerating the
certs: There was an error validating certificates for host
"192.168.99.100:2376": dial tcp 192.168.99.100:2376: getsockopt: connection
refused
You can attempt to regenerate them using 'docker-machine regenerate-certs
[name]'.
Be advised that this will trigger a Docker daemon restart which will stop
running containers.

Hmm. Regenerating certs sounds good, but what do I put in for [name]? This answer suggests default (cf. eval "$(docker-machine env default)". Presumably if we had other machines in ~/.docker/machine/machines/ we'd have to worry about which one, but we don't.

$ docker-machine regenerate-certs default
Regenerate TLS machine certs?  Warning: this is irreversible. (y/n): y
Regenerating TLS certificates
Detecting the provisioner...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...

Okay, let's try that pull again.

$ docker pull centos:7
7: Pulling from library/centos

fa5be2806d4c: Pull complete 
2bf4902415e3: Pull complete 
86bcb57631bd: Pull complete 
c8a648134623: Pull complete 
Digest: sha256:db4d91ef365f4716517d5cbdb1be54b6d205912038d67bf687a4c2dad9b85928
Status: Downloaded newer image for centos:7

Much better. And let's check our assumptions about how Docker kernels work:

$ docker run centos:7 uname -a
Linux 96c0898c8ad8 4.1.13-boot2docker #1 SMP Fri Nov 20 19:05:50 UTC 2015 
x86_64 x86_64 x86_64 GNU/Linux

Ok, good.

Creating the Dockerfile

We start with a basic Dockerfile, in a directory we'll call stash-docker:

# image: stash/docker
FROM centos:7
MAINTAINER david.moles@ucop.edu

WORKDIR /home

(According to Titus Brown at the BIDS workshop, /home is more or less the conventional Docker working directory. Note that by default, Docker runs everything as root. This isn't as big a deal as it might seem since root's privilges are confined to this single-purpose Docker container. In a sense the container itself takes the place of the "role account".)

Starting with Scott's "Installing Ruby, Rails and Passenger to Home Directory on Server", let's figure out what we're going to need.

We'll do this interactively first.

$ docker run -it centos:7 /bin/bash
[root@76981257b993 /]#

We're now logged into a Centos 7 Docker container, so we can try following Scott's instructions.

Installing yaml

[root@76981257b993 /]# cd home
[root@76981257b993 /home]# wget http://pyyaml.org/download/libyaml/yaml-0.1.5.tar.gz
bash: wget: command not found

Oops. The centos image must be pretty bare. Let's try curl instead.

[root@76981257b993 home]# curl -O  http://pyyaml.org/download/libyaml/yaml-0.1.5.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  493k  100  493k    0     0   378k      0  0:00:01  0:00:01 --:--:--  378k

So far, so good.

[root@76981257b993 home]# tar -zxvf yaml-0.1.5.tar.gz
yaml-0.1.5/
...
(lots of files here)
...
yaml-0.1.5/tests/test-version.c

Let's add this to the Dockerfile:

RUN curl -O http://pyyaml.org/download/libyaml/yaml-0.1.5.tar.gz &&
    tar -zxvf yaml-0.1.5.tar.gz

(We do this as a single operation, with &&, because reasons.)

Configuring yaml, 1st attempt

And now on to configure:

[root@76981257b993 home]# cd yaml-0.1.5
[root@76981257b993 yaml-0.1.5]# ./configure --prefix=/dash2/local
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... no
checking for gcc... no
checking for cc... no
checking for cl.exe... no
configure: error: in `/home/yaml-0.1.5':
configure: error: no acceptable C compiler found in $PATH
See `config.log' for more details
[root@76981257b993 yaml-0.1.5]# 

OK, the Centos image is really bare. It looks like we need make and gcc, at minimum.

Installing make

Let's check uc3-dash2-dev.cdlib.org to see which RPMs we ought to be installing:

dash2@uc3-dash2-dev:~$ rpm -q --whatprovides `which make`
make-3.82-21.10.amzn1.x86_64

Sensible enough:

[root@76981257b993 yaml-0.1.5]# yum install make
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
 * base: mirrors.usc.edu
 * extras: mirror.vcu.edu
 * updates: mirrors.gigenet.com
Resolving Dependencies
--> Running transaction check
---> Package make.x86_64 1:3.82-21.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=========================================================================================================
 Package              Arch                   Version                          Repository            Size
=========================================================================================================
Installing:
 make                 x86_64                 1:3.82-21.el7                    base                 420 k

Transaction Summary
=========================================================================================================
Install  1 Package

Total download size: 420 k
Installed size: 1.1 M
Is this ok [y/d/N]: y
Downloading packages:
make-3.82-21.el7.x86_64.rpm                                                       | 420 kB  00:00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : 1:make-3.82-21.el7.x86_64                                                             1/1 
  Verifying  : 1:make-3.82-21.el7.x86_64                                                             1/1 

Installed:
  make.x86_64 1:3.82-21.el7                                                                              

Complete!
[root@76981257b993 yaml-0.1.5]# 

Good, now let's add it to the Dockerfile. (We'll make this the first RUN statement since we want it already there when we start messing with pyyaml.) Note the -y so we don't get prompted with Is this ok [y/d/N].

RUN install -y make

Installing gcc

What about gcc?

dash2@uc3-dash2-dev:~$ rpm -q --whatprovides `which gcc`
file /usr/bin/gcc is not owned by any package

...OK, that's slightly disturbing. But let's assume it's gcc and see where that gets us.

[root@76981257b993 yaml-0.1.5]# yum install gcc
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
 * base: mirrors.usc.edu
 * extras: mirror.vcu.edu
 * updates: mirrors.gigenet.com
Resolving Dependencies
--> Running transaction check
---> Package gcc.x86_64 0:4.8.5-4.el7 will be installed
--> Processing Dependency: libgomp = 4.8.5-4.el7 for package: gcc-4.8.5-4.el7.x86_64
--> Processing Dependency: cpp = 4.8.5-4.el7 for package: gcc-4.8.5-4.el7.x86_64
--> Processing Dependency: glibc-devel >= 2.2.90-12 for package: gcc-4.8.5-4.el7.x86_64
--> Processing Dependency: libmpfr.so.4()(64bit) for package: gcc-4.8.5-4.el7.x86_64
--> Processing Dependency: libmpc.so.3()(64bit) for package: gcc-4.8.5-4.el7.x86_64
--> Processing Dependency: libgomp.so.1()(64bit) for package: gcc-4.8.5-4.el7.x86_64
--> Running transaction check
---> Package cpp.x86_64 0:4.8.5-4.el7 will be installed
---> Package glibc-devel.x86_64 0:2.17-106.el7_2.1 will be installed
--> Processing Dependency: glibc-headers = 2.17-106.el7_2.1 for package: glibc-devel-2.17-106.el7_2.1.x86_64
--> Processing Dependency: glibc-headers for package: glibc-devel-2.17-106.el7_2.1.x86_64
---> Package libgomp.x86_64 0:4.8.5-4.el7 will be installed
---> Package libmpc.x86_64 0:1.0.1-3.el7 will be installed
---> Package mpfr.x86_64 0:3.1.1-4.el7 will be installed
--> Running transaction check
---> Package glibc-headers.x86_64 0:2.17-106.el7_2.1 will be installed
--> Processing Dependency: kernel-headers >= 2.2.1 for package: glibc-headers-2.17-106.el7_2.1.x86_64
--> Processing Dependency: kernel-headers for package: glibc-headers-2.17-106.el7_2.1.x86_64
--> Running transaction check
---> Package kernel-headers.x86_64 0:3.10.0-327.4.4.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=========================================================================================================
 Package                    Arch               Version                         Repository           Size
=========================================================================================================
Installing:
 gcc                        x86_64             4.8.5-4.el7                     base                 16 M
Installing for dependencies:
 cpp                        x86_64             4.8.5-4.el7                     base                5.9 M
 glibc-devel                x86_64             2.17-106.el7_2.1                updates             1.0 M
 glibc-headers              x86_64             2.17-106.el7_2.1                updates             661 k
 kernel-headers             x86_64             3.10.0-327.4.4.el7              updates             3.2 M
 libgomp                    x86_64             4.8.5-4.el7                     base                130 k
 libmpc                     x86_64             1.0.1-3.el7                     base                 51 k
 mpfr                       x86_64             3.1.1-4.el7                     base                203 k

Transaction Summary
=========================================================================================================
Install  1 Package (+7 Dependent packages)

Total download size: 27 M
Installed size: 59 M
Is this ok [y/d/N]: y
Downloading packages:
(1/8): kernel-headers-3.10.0-327.4.4.el7.x86_64.rpm                               | 3.2 MB  00:00:00     
(2/8): glibc-devel-2.17-106.el7_2.1.x86_64.rpm                                    | 1.0 MB  00:00:01     
(3/8): glibc-headers-2.17-106.el7_2.1.x86_64.rpm                                  | 661 kB  00:00:01     
(4/8): cpp-4.8.5-4.el7.x86_64.rpm                                                 | 5.9 MB  00:00:02     
(5/8): libgomp-4.8.5-4.el7.x86_64.rpm                                             | 130 kB  00:00:00     
(6/8): libmpc-1.0.1-3.el7.x86_64.rpm                                              |  51 kB  00:00:00     
(7/8): mpfr-3.1.1-4.el7.x86_64.rpm                                                | 203 kB  00:00:00     
(8/8): gcc-4.8.5-4.el7.x86_64.rpm                                                 |  16 MB  00:00:05     
---------------------------------------------------------------------------------------------------------
Total                                                                    5.3 MB/s |  27 MB  00:00:05     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : mpfr-3.1.1-4.el7.x86_64                                                               1/8 
  Installing : libmpc-1.0.1-3.el7.x86_64                                                             2/8 
  Installing : cpp-4.8.5-4.el7.x86_64                                                                3/8 
  Installing : libgomp-4.8.5-4.el7.x86_64                                                            4/8 
  Installing : kernel-headers-3.10.0-327.4.4.el7.x86_64                                              5/8 
  Installing : glibc-headers-2.17-106.el7_2.1.x86_64                                                 6/8 
  Installing : glibc-devel-2.17-106.el7_2.1.x86_64                                                   7/8 
  Installing : gcc-4.8.5-4.el7.x86_64                                                                8/8 
  Verifying  : kernel-headers-3.10.0-327.4.4.el7.x86_64                                              1/8 
  Verifying  : gcc-4.8.5-4.el7.x86_64                                                                2/8 
  Verifying  : cpp-4.8.5-4.el7.x86_64                                                                3/8 
  Verifying  : libgomp-4.8.5-4.el7.x86_64                                                            4/8 
  Verifying  : glibc-devel-2.17-106.el7_2.1.x86_64                                                   5/8 
  Verifying  : mpfr-3.1.1-4.el7.x86_64                                                               6/8 
  Verifying  : glibc-headers-2.17-106.el7_2.1.x86_64                                                 7/8 
  Verifying  : libmpc-1.0.1-3.el7.x86_64                                                             8/8 

Installed:
  gcc.x86_64 0:4.8.5-4.el7                                                                               

Dependency Installed:
  cpp.x86_64 0:4.8.5-4.el7                          glibc-devel.x86_64 0:2.17-106.el7_2.1               
  glibc-headers.x86_64 0:2.17-106.el7_2.1           kernel-headers.x86_64 0:3.10.0-327.4.4.el7          
  libgomp.x86_64 0:4.8.5-4.el7                      libmpc.x86_64 0:1.0.1-3.el7                         
  mpfr.x86_64 0:3.1.1-4.el7                        

Complete!
[root@76981257b993 yaml-0.1.5]#

Looks pretty good. Let's go back to uc3-dash2-dev.cdlib.org and check the gcc version there:

dash2@uc3-dash2-dev:~$ gcc --version
gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

dash2@uc3-dash2-dev:~$ 

4.8.3 vs. 4.8.5. Close enough. Let's add that to the Dockerfile:

RUN yum install -y make &&
    yum install -y gcc

Back to yaml.

Configuring yaml, 2nd attempt

We run ./configure --prefix=/dash2/local again. It looks pretty good this time, except, about halfway through:

./configure: line 6343: /usr/bin/file: No such file or directory

It looks like it completes successfully anyway, but just to be on the safe side, let's yum install file as well, update the Dockerfile appropriately, and re-configure, just to be sure.

[root@76981257b993 yaml-0.1.5]# ./configure --prefix=/dash2/local
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking how to run the C preprocessor... gcc -E
checking whether ln -s works... yes
checking whether make sets $(MAKE)... (cached) yes
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking how to print strings... printf
checking for a sed that does not truncate output... /usr/bin/sed
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking for fgrep... /usr/bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking the maximum length of command line arguments... 1572864
checking whether the shell understands some XSI constructs... yes
checking whether the shell understands "+="... yes
checking how to convert x86_64-unknown-linux-gnu file names to x86_64-unknown-linux-gnu format... func_convert_file_noop
checking how to convert x86_64-unknown-linux-gnu file names to toolchain format... func_convert_file_noop
checking for /usr/bin/ld option to reload object files... -r
checking for objdump... objdump
checking how to recognize dependent libraries... pass_all
checking for dlltool... no
checking how to associate runtime and link libraries... printf %s\n
checking for ar... ar
checking for archiver @FILE support... @
checking for strip... strip
checking for ranlib... ranlib
checking command to parse /usr/bin/nm -B output from gcc object... ok
checking for sysroot... no
checking for mt... no
checking if : is a manifest tool... no
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for dlfcn.h... yes
checking for objdir... .libs
checking if gcc supports -fno-rtti -fno-exceptions... no
checking for gcc option to produce PIC... -fPIC -DPIC
checking if gcc PIC flag -fPIC -DPIC works... yes
checking if gcc static flag -static works... no
checking if gcc supports -c -o file.o... yes
checking if gcc supports -c -o file.o... (cached) yes
checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
checking whether -lc should be explicitly linked in... no
checking dynamic linker characteristics... GNU/Linux ld.so
checking how to hardcode library paths into programs... immediate
checking whether stripping libraries is possible... yes
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... yes
checking whether to build static libraries... yes
checking for doxygen... false
checking for ANSI C header files... (cached) yes
checking for stdlib.h... (cached) yes
checking for an ANSI C-conforming const... yes
checking for size_t... yes
configure: creating ./config.status
config.status: creating yaml-0.1.pc
config.status: creating include/Makefile
config.status: creating src/Makefile
config.status: creating Makefile
config.status: creating tests/Makefile
config.status: creating win32/Makefile
config.status: creating config.h
config.status: config.h is unchanged
config.status: executing depfiles commands
config.status: executing libtool commands

Much better.

compiling yaml

make looks to complete successfully, and so does make install, even helpfully creating /dash2/local for us:

[root@76981257b993 yaml-0.1.5]# find /dash2/local -type f
/dash2/local/include/yaml.h
/dash2/local/lib/libyaml-0.so.2.0.3
/dash2/local/lib/libyaml.la
/dash2/local/lib/pkgconfig/yaml-0.1.pc
/dash2/local/lib/libyaml.a

Installing Ruby

So the first part of this is pretty straightforward:

RUN curl -L https://github.com/postmodern/ruby-install/archive/v0.5.0.tar.gz > \
    ruby-install-0.5.0.tar.gz && 
    tar -zxvf ruby-install-0.5.0.tar.gz &&
    cd ruby-install-0.5.0

The only tricky bits are (1) the -L, telling curl to follow redirects (otherwise you get an HTML file instead of a tarball), and the trailing \ to let us sensibly break that first line. However, Scott then tells us:

# edit PREFIX variable toward the first of the Makefile to have the correct directory such as /dash2/local

Let's look at that line:

PREFIX?=/usr/local

Luckily, the Makefile authors aren't insane, and we should be able to set the environment variable externally (the ?= should mean "set only if absent").

[root@76981257b993 ruby-install-0.5.0]# PREFIX=/dash2/local && make install
for dir in `find bin share -type d`; do mkdir -p /usr/local/$dir; done
for file in `find bin share -type f`; do cp $file /usr/local/$file; done
mkdir -p /usr/local/share/doc/ruby-install-0.5.0
cp -r *.md *.txt /usr/local/share/doc/ruby-install-0.5.0/

Nice try, but nope. It's still stuffing things in /usr/local/.

(To be continued...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment