1) Run a base docker image.
2) Run the config management tool on/in this image, (ansible playbook, chef cookbook, etc.)
3) Commit the container to the new image
Dockerfiles are very convenient and easy, and are great as far as they go. They also don't have idempotent actions built-in. As a result, a minor change requires one to rebuild the entire image from scratch.
In contrast, the CM systems mentioned above operate by letting you declare the desired system state - i.e., what it is, instead of how to create it. This lets the CM system runtime automatically skip unnecessary steps. For example, in (say) an Ansible playbook, instead of (in the Dockerfile):
RUN mkdir -p /path/to/some/dir
... we'd say something like (in the Ansible playbook): - file:
state: directory
path: /path/to/some/dir
If /path/to/some/dir already exists, and I run this play twice, I do not get the "mkdir: cannot create directory ‘/path/to/some/dir’: File exists" error, because this is designed to be declarative. That means: Ansible first checks whether the directory exists, and if it does, it does nothing. If it doesn't, it recreates it.It also helps a lot with surgical updates. For example, suppose my Dockerfile for a web service container contains the following:
RUN apt-get install -y apache2 php5 libapache2-mod-php5
An analogous Ansible play might include the following: - apt:
name: "{{ item }}"
state: present
with_items:
- apache2
- php5
- libapache2-mod-php5
Now if an Apache security vulnerability is announced, with a fix pushed to the apt sources, I can rapidly modify the image like so:1) Run the previous docker image.
2) Run the config management tool with the surgical-update action.
3) Commit the container to create an updated image.
The Ansible version of the update would be as simple as:
- apt:
update_cache: yes
name: apache2
state: latest
And again, this is a fast no-op if the package is already up-to-date. (It also doesn't needlessly restart apache, though when creating an image that doesn't matter much.)Using a CM system like this doesn't solve all the problems outlined in the article - actually, I don't think it even solves a majority of them. But I can't figure out why so many smart people are focused on reinventing parts of it poorly, or thinking in terms of "docker vs. ansible/chef/puppet/salt". I know they're not idiots. Am I missing something? If so I'd sincerely like to know.