The Zerofox Syndicate

The process of writing a Docker file

2019-11-09

Here I will walk through my process for creating a Dockerfile. I recently wanted to dockerize ngircd to test IRC over TLS. This is how I went about that.

Reading the build instructions

I started with reading the INSTALL file that is included with the ngircd source. Here I noted the following simple steps.

  1. Satisfy prerequisites
  2. ./autogen.sh [only necessary when using Git]
  3. ./configure
  4. make
  5. make install

Ok so first I needed to satisfy the pre-requisites. The readme also provides an example command on how this can be achieved in debian.

apt-get install autoconf automake build-essential expect libgnutls-dev libident-dev libpam-dev pkg-config libwrap0-dev libz-dev telnet

Try it out

I started by creating a minimal Dockerfile with the instructions from the INSTALL file.

FROM docker.io/library/debian:bullseye-slim

RUN apt-get install -y \
        autoconf automake build-essential expect libgnutls-dev \
        libident-dev libpam-dev pkg-config libwrap0-dev libz-dev telnet

I attempted to build.

docker build --tag=ngircd .

This failed because it cannot find the lib libgnutls-dev package. I decided to search for this package in the debian repositories. I don’t run Debian so I spun up another container to do so.

docker run --rm -it debian:bullseye-slim bash

After looking around I saw that there’s a libgnutls28-dev package that seems to install fine.

Now I followed the rest of the instructions to build my first version and run ngircd from the command line. This worked. I did get an error when I tried to configure SSL. I needed to rebuild with openssl support.

Build with openssl support

To build with openssl support I added the --with-openssl flag.

./configure --prefix=/opt/ngircd --with-openssl

This fails because I didn’t meet the pre-requisites. The proposed pre-requisites use gnutls but I really want to use openssl here. To fix this I went back and swapped libgnutls28-dev for openssl and libssl-dev.

RUN apt-get update && apt-get install -y \
    autoconf automake build-essential expect openssl libssl-dev \
    libident-dev libpam-dev pkg-config libwrap0-dev libz-dev telnet

(Yes, I wasted time looking for the wrong package earlier. It happens.)

With this the pre-requisites were met and I was able to build ngircd with openssl support.

WORKDIR /src
ADD https://github.com/ngircd/ngircd/releases/download/rel-24/ngircd-24.tar.gz /src
RUN tar -xvzf ngircd-24.tar.gz && \
    cd ngircd-24 && \
    chmod +x autogen.sh configure && \
    mkdir /opt/ngircd && \
    ./configure --prefix=/opt/ngircd --with-openssl && \
    make && make install

The resulting container has a lot of bloat. It contains all the build tools for compilation but none of those are necessary to run the software.

Moving to a multi-stage build

To build a multi-stage container I started by naming the build container.

FROM docker.io/library/debian:bullseye-slim as ngircdbuilder

I installed the dependencies and compiled the software as before.

RUN apt-get update && apt-get install -y \
    autoconf automake build-essential expect openssl libssl-dev \
    libident-dev libpam-dev pkg-config libwrap0-dev libz-dev telnet

WORKDIR /src
ADD https://github.com/ngircd/ngircd/releases/download/rel-24/ngircd-24.tar.gz /src
RUN tar -xvzf ngircd-24.tar.gz && \
    cd ngircd-24 && \
    chmod +x autogen.sh configure && \
    mkdir /opt/ngircd && \
    ./configure --prefix=/opt/ngircd --with-openssl && \
    make && make install

In the same docker file I created a new container and installed the runtime dependency.

FROM docker.io/library/debian:bullseye-slim
RUN apt-get update && apt-get install -y libssl1.1

This is the important step. Moving the files from the ngircdbuilder to the new container.

COPY --from=ngircdbuilder /opt/ngircd /opt/ngircd

Generally it is best practice not to run software as root. Even within a container. I try to follow best practice.

RUN useradd --comment "ngircd user" --no-create-home --system ngircd
USER ngircd

Finally the command to start ngircd.

CMD ["/opt/ngircd/sbin/ngircd", "--nodaemon", "--config", "/opt/ngircd/etc/ngircd.conf"]

I build and run the container with the following commands.

docker build --tag=ngircd .
docker run -it -v $(pwd)/etc:/opt/ngircd/etc/ -p 6667:6667 -p 6697:6697 ngircd

The $(pwd)/etc directory containing my configuration files.

The full Dockerfile

Here is the full Dockerfile I ended up with. I hope this helps you build your own containers.

FROM docker.io/library/debian:bullseye-slim as ngircdbuilder

RUN apt-get update && apt-get install -y \
    autoconf automake build-essential expect openssl libssl-dev \
    libident-dev libpam-dev pkg-config libwrap0-dev libz-dev telnet

WORKDIR /src
ADD https://github.com/ngircd/ngircd/releases/download/rel-24/ngircd-24.tar.gz /src
RUN tar -xvzf ngircd-24.tar.gz && \
    cd ngircd-24 && \
    chmod +x autogen.sh configure && \
    mkdir /opt/ngircd && \
    ./configure --prefix=/opt/ngircd --with-openssl && \
    make && make install

FROM docker.io/library/debian:bullseye-slim

RUN apt-get update && apt-get install -y libssl1.1
COPY --from=ngircdbuilder /opt/ngircd /opt/ngircd
RUN useradd --comment "ngircd user" --no-create-home --system ngircd

VOLUME /opt/ngircd/etc
EXPOSE 6667 6697
USER ngircd
CMD ["/opt/ngircd/sbin/ngircd", "--nodaemon", "--config", "/opt/ngircd/etc/ngircd.conf"]
Tags: containers