How to build a project inside a Docker container

I wanted to participate in the Hacktoberfest 2018, but one thing kept worrying me. I had to download someone’s code from the Internet and run it on my machine. I don’t have time to review a vast project to check if nothing fishy happens while running tests.

Of course, I could choose to work only on well-known projects with many respected contributors. In this case, I could safely assume that there is no harmful code in the repository. What about other projects?

Docker

I decided that the best available option is building and testing the projects inside a Docker container. I did not want to copy the code to a Docker image and download all dependencies every time I want to run tests. So I needed a way to cache them between the runs.

I wanted to contribute to Scala projects, so I needed to run SBT inside Docker. I ended up with this Dockerfile:

FROM openjdk:8-jre-alpine
ENV SCALA_VERSION 2.12.7
ENV SBT_VERSION 1.2.3

RUN \
apk add bash && \
apk add --no-cache curl && \
cd /tmp && \
curl -fsSOL https://piccolo.link/sbt-$SBT_VERSION.tgz && \
tar -xvzf sbt-$SBT_VERSION.tgz && \
mv /tmp/sbt /usr/lib && \
rm /tmp/sbt-$SBT_VERSION.tgz && \
ln -s /usr/lib/sbt/bin/* /usr/local/bin && \
sbt sbtVersion

It downloads the necessary dependencies and SBT, extracts the files, removes redundant files and sets symbolic links to the sbt tools.

User

Almost good. Such a Dockerfile runs the code as the root user. Still not a good idea, even inside Docker. So I added more code to Dockerfile:

RUN addgroup -g 12345 appuser && \
    adduser -u 12345 -D -G appuser appuser
USER appuser

WORKDIR /home/appuser

Build the image

What now? Now I have to build the image and set its name to something meaningful, so later I can run it.

To build the Docker image you have to run the following command in terminal:

docker build -t sbt .

Run the container

When the image is ready, all I need is to run it in the interactive mode and mount the project directory as one of the directories in the Docker container. I must also mount the .ivy2 directory, so I have a place to cache dependencies between runs of the Docker image.

The next command does the job:

docker run -v $(pwd .):/home/appuser -v $(pwd .)/.packages:/home/appuser/.ivy2 -it sbt:latest

Now nothing stops me from contributing to someone else’s projects ;)

Older post

[book review] Dichotomy of leadership

The follow-up to “Extreme ownership”

Newer post

A "known bug" is still a bug

What does a "known bug" or an update say our users?