Installing salt in a docker container and running it in masterless mode, allows you to use your existing salt infrastructure to provision containers. See the following Dockerfile.

FROM debian:jessie

# Give the container an id. Then salt can uniquely identify it.
ARG id

# Install some needed systems libraries
RUN apt-get update && \
    apt-get -y install software-properties-common git wget

# Install salt
RUN wget -q -O- "http://debian.saltstack.com/debian-salt-team-joehealy.gpg.key" | apt-key add -
RUN echo "deb http://debian.saltstack.com/debian jessie-saltstack main" >> /etc/apt/sources.list.d/salt.list

RUN apt-get update && apt-get install -y salt-minion

# Create directory for holding config file to override default salt minion config
RUN mkdir -p /etc/salt/minion.d

# Override the default id with the id passed into the build context
RUN echo "id: ${id}" >> /etc/salt/minion.d/salt.conf

# Run salt in masterless mode in this container 
RUN echo "file_client: local" >> /etc/salt/minion.d/salt.conf

# Add the salt configs
ADD salt /srv/salt 

# Run the high state in this container
RUN salt-call state.highstate

When building the docker images, all we have to do is pass a build-arg for the id. This id is passed to the minion configuration file, which can then be used in salt to match the minion to the provisioning scripts.

In our example salt project, we have the following top.sls file.

base:
  '*':
    - apt 
  'ruby_dev':
    - docker.ruby

It says everyone gets the apt state and salt minons with the id ruby_dev gets the docker.ruby state. By default salt looks for state files in the /srv/salt directory. The state config files need to land there unless you override the config value for file_roots.

To override defaults, which we need to do to run salt in masterless mode, provide another config file in the /etc/salt/minion.d/ directory. It doesn’t matter what this file is called as long as it exists here. In this file give values to the properties we want to override from the /etc/salt/minion config. In our case, we’re overriding file_client: local (to enable masterless) and the id, which is automatically assigned and useless to us if not overridden.

Finally we salt-call state.highstate, which reads the top.sls file to figure out what to install. In this case we’ll install git, vim and some python3 packages. Those are defined the apt state file as well as ruby-dev from the docker.ruby state file.

To run the example, assuming you have installed docker, just clone the repo and execute a docker build from the root directory.

docker build --build-arg=id=ruby_dev -t ruby_container .

When it’s done, salt will have provisioned a docker container with the hostname ruby_container and a tag latest.