Baking a Docker image that contains the Ampersand Compiler
If you need an Ampersand compiler in a Docker image, use the one on Docker hub. It sits there ready for you to use. However, if you want to know how it is baked, carry on reading.
The magic
To get a docker container I took the file Dockerfile and built an image called "myampersand", using the following command:
It took 45 minutes to build, but I got an image called myampersand in the docker repository on my laptop.
To see it work, I executed the newly created image on a little file in my working directory, hello.adl from the command line with the following command:
The same command in the Windows command line is:
Do you want to reproduce this?
The Ampersand repository contains a file, , that contains a recipe for building an Ampersand compiler and put it in your Ampersand repository. You need the following ingredients to run it:
A machine to run docker, for building your docker image with. I ran it on my MacBook.
Docker, which you need .
Docker needs least 5G of memory to build Ampersand, which is more than the standard 2G. I used to increase Docker's memory on my Macbook.
To run it, I cloned the Ampersand repository, into ~/Ampersand/, and built the image with:
It runs on my Mac for over half an hour, so some patience is required. If you don't have that patience, consider using the image from docker hub. It was built for your convenience.
The resulting docker image sits in the docker repository on you laptop (placed there when docker was installed).
So which steps does Docker take?
If you want a slightly different image (for reasons of your own), you may want to repeat this process yourself. For that purpose, let us walk through the different steps described in Dockerfile.
Let us discuss the steps one-by-one. (Please check the , just in case it is inconsistent with this documentation.) All of these steps happen automatically, as they are in the docker file.
The first statement states that the compiler is built on a well-defined Haskell image.
This building stage is called buildstage because we want to use a to obtain a small Ampersand image without excess-software.
We decide to work in the build-container from a working directory called /Ampersand.
Normally we want to generate Ampersand from the source code on GitHub. For this purpose we clone the Ampersand-repository into the (working directory in the) build environment.
In this case I wanted to build from a specific feature, so I checked it out.
Now everything is in place to compile Ampersand. Running stack install results in a full-fledged Ampersand compiler in /root/.local/bin. Mind you, this takes a while...
If we were to stop here, we get an image larger than 4GB. We can do better than that by starting over with a clean machine. So we introduce a second FROM-line in the Dockerfile which starts with a clean slate. We use an empty ubuntu machine (form some reason yet unknown, the smaller alpine image doesn't work)
Now we must copy the ampersand executable to /bin, from where we can run it as though it were a normal ubuntu-command. It is the only software we will copy into this image. (Haskell and the intermediate files are all absent). This results in an image that is slightly over 220MB.
When compiling, we will work in a directory called scripts. When using this container, we will volume-map this directory to the actual working directory that contains the ampersand-files we want to compile.
The program to be called when running the container is of course ampersand (residing in /bin/). If called without arguments it will use --verbose.
If you must do things on your own, you might want to reproduce parts of the builds.
The Dockerfile for the Ampersand compiler resides in the root of the Ampersand repository. So from the command line, if you are at the root of the Ampersand repository, you can call docker build . to create the image. See for more details.
The package.yaml file for the Ampersand compiler resides in the root of the Ampersand repository. So from the command line, if you are at the root of the Ampersand repository, you can call stack install to create the image. See for more details.
This chapter describes how and why the various items are built.
Item
build tool
Purpose
Stack
build a binary on MacOS or Windows
Docker
build a Docker image for the Ampersand compiler
Application
Docker
Testing with Docker on your own laptop
If you want to test your application on your own laptop, you need to configure localhost to let it behave like a regular top-level domain.
Requirement
The proper use of Docker ensures that your application will run on any location on the internet. Yet, when testing your application on your laptop, you may discover that your laptop is not configured as a domain on the internet. To run any Ampersand application locally without changes, your laptop must behave like an ordinary top-level domain: localhost. Your computer must believe that localhost is like com, or edu
build a Docker image for an application generated by Ampersand.
When the following experiments are successful on your computer, you may consider this requirement to be fulfilled
First demonstrate that an arbitrary internet domain (here: nu.nl) is visible.
> ping -c 1 nu.nl
PING nu.nl (99.86.122.115): 56 data bytes 64 bytes from 99.86.122.115: icmp_seq=0 ttl=232 time=24.367 ms
--- nu.nl ping statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 24.367/24.367/24.367/0.000 ms
Now demonstrate that localhost is routed to IP-address 127.0.0.1.
> ping -c 1 localhost
PING localhost (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.040 ms
--- localhost ping statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.040/0.040/0.040/0.000 ms
Then demonstrate that an arbitrary subdomain of localhost is routed to IP-address 127.0.0.1.
> ping -c 1 rap.localhost
PING rap.localhost (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.029 ms
--- rap.localhost ping statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.029/0.029/0.029/0.000 ms
Finally, show that this works recursively on an arbitrary sub-subdomain.
> ping -c 1 foo.rap.localhost
PING foo.rap.localhost (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.032 ms
--- foo.rap.localhost ping statistics --- 1 packets transmitted, 1 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.032/0.032/0.032/0.000 ms
Complications
So why should this NOT work?
Your machine might not be connected to the internet. And if it is connected, it needs access to a domain name server to find locations on the internet. For most laptops this is the case, so you have no problems here. Some corporate laptops are connected only to the local corporate network. This means that you cannot let your application communicate with the outside world, or you have to organize that your laptop gains access (e.g. through a proxy).
You cannot run your application locally if localhost is not configured. On some laptops there is a file called hosts or .hosts, which contains the redirection from localhost to IP-address 127.0.0.1. However, this redirection does not cater for subdomains. Consider this to partially fulfill the requirement, which is sufficient if your application works without subdomains.
If your application works with subdomains, localhost must behave like a top-level domain. For this purpose you must install and configure a domain name server on your laptop (which is typically not there).
To build your own Ampersand compiler is something to avoid as a user. As a developer, however, you may have reasons to do this yourself. For instance to verify what happens in older versions.
The Ampersand compiler is a Haskell program built with stack. Stack is a build tool for Haskell projects such as Ampersand. We have automated the building process (using stack) for the following purposes:
to prevent mistakes such as dependency conflicts inside and between Haskell packages, for an uninterrupted compilation process (robust building);
to generate ampersand compilers for different platforms (platform independence);
to provide a reproducible and reliable build process to developers with diverse development tools, operating systems, and working environments (uniform building);
to allow for generating images for docker containers (containerization);
to accellerate the build process to increase the release frequency of Ampersand.
Installation
comes as part of , so there is no need to install Haskell separately.
The are pretty clear for the various platforms. Make sure you read the part about the STACK_ROOT environment variable.
To compile Ampersand you need a file , which sits in the Ampersand repository. Fetch it and put it in you working directory. From the command-line, call command stack install and after a while (go get coffee!) your ampersand compiler exists! NB: If you want to build Rieks' preprocessor as well, the magic spell is stack install --flag ampersand:buildAll