Using Salt to Build Docker Containers

February 16, 2017 - SaltStack Marketing

How docker works now.

When you build docker containers using only docker tools, what you are actually doing is building a bunch of layers. Great. Layers is a good idea. You get to build a bunch of docker images that have a lot of similar layers, so you only have to build the changes when you update containers. But what you end up with is this really hard to read ugly Dockerfile that is hard to leave because it tries to put a bunch of commands on the same line.

# from
FROM php:7.0-apache

RUN a2enmod rewrite

# install the PHP extensions we need
RUN apt-get update && apt-get install -y libpng12-dev libjpeg-dev libpq-dev 
    && rm -rf /var/lib/apt/lists/* 
    && docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr 
    && docker-php-ext-install gd mbstring opcache pdo pdo_mysql pdo_pgsql zip

# set recommended PHP.ini settings
# see
RUN { 
        echo 'opcache.memory_consumption=128'; 
        echo 'opcache.interned_strings_buffer=8'; 
        echo 'opcache.max_accelerated_files=4000'; 
        echo 'opcache.revalidate_freq=60'; 
        echo 'opcache.fast_shutdown=1'; 
        echo 'opcache.enable_cli=1'; 
    } > /usr/local/etc/php/conf.d/opcache-recommended.ini

WORKDIR /var/www/html

ENV DRUPAL_MD5 57526a827771ea8a06db1792f1602a85

RUN curl -fSL "${DRUPAL_VERSION}.tar.gz" -o drupal.tar.gz 
    && echo "${DRUPAL_MD5} *drupal.tar.gz" | md5sum -c - 
    && tar -xz --strip-components=1 -f drupal.tar.gz 
    && rm drupal.tar.gz 
    && chown -R www-data:www-data sites modules themes

Here is a Dockerfile that is used to build a mysqld container. The RUN command in the middle is just really convuluted and I just can’t imagine trying to write a container like this. But what if you could use salt to configure the build of your docker containers to do the same thing.

Using Salt States

NOTE: This is all to be added in the Nitrogen release of salt, but you should be able to drop-in the dockerng state and module from develop once this PR is merged.

It is worth mentioning that this is a contrived example, because one of the requirements to use is to have python installed in the docker container. So for the salt example you will need to build a slightly modified parent container using the following command.

docker run --name temp php:7.0-apache bash -c 'apt-get update && apt-get install -y python' && docker commit temp php:7.0-apache-python && docker rm temp

Now, this shouldn’t be a problem when building images. This just allows for managing the layers. If I were to do this, I would take the debian image, and use salt states to setup apache and the base stuff for building the modules and things and then run the following state.

Build Drupal Image:
    - name: myapp/drupal
    - base: php:7.0-apache-python
    - sls: docker.drupal

Then this would build the image with my salt://docker/drupal.sls state.

{%- set exts = ('gd', 'mbstring', 'opcache', 'pdo', 'pdo_mysql', 'pdo_pgsql', 'zip') %}
{%- set DRUPAL_VERSION = '8.2.6' %}
{%- set DRUPAL_MD5 = '57526a827771ea8a06db1792f1602a85' %}

enable rewrite module:
    - name: rewrite

install extensions:
    - names:
      - libpng12-dev
      - libjpeg-dev
      - libpq-dev
    - names:
      - docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr:
        - prereq:
          - cmd: docker-php-ext-install gd
      {%- for ext in exts %}
      - docker-php-ext-install {{ext}}:
        - creates: /usr/local/etc/php/conf.d/{{ext}}.ini
      {%- endfor %}

configure opcache:
    - name: /usr/local/etc/php/conf.d/opcache-recommended.ini
    - contents: |

get drupal:
    - name: /var/www/html
    - source:{{DRUPAL_VERSION}}.tar.gz
    - source_hash: md5={{DRUPAL_MD5}}
    - user: www-data
    - group: www-data
    - enforce_toplevel: False
    - options: --strip-components=1

And we are done. In my honest opinion, this is significantly easier to read. First we enable the rewrite module. Then we install the packages for compiling the different php extensions. Then we use the built in docker-php-ext-* to build the different php modules. And we put the opcache recommended plugins in place. Lastly we download and extract the drupal tarball and put it in the correct place.

There is one caveat, right now we do not have the ability to build in the WORKDIR and ENV variables, so those will have to be provided when the container is started.

Start Drupal Container:
    - name: drupal
    - image: myapp/drupal:latest
    - working_dir: /var/www/html

I am going to look into adding those for the dockerng.create command that is used to create the starting container for the sls_build so that they can be saved for the image.