Building docker images with ansible


Docker is something really hot recently. It allows you to run your software with linux container easily. It’s actually kind of OS level isolation rather than hardware simulation nor kernel simulation. So you won’t have too much performance penalty but still have pretty nice virtual machine features. I really like the analog used by Docker community, shipping software should be easier and Docker serves as just like the standard container in shipping industry.

Building docker images is not hard, but …

Although docker provides an easy way to deliver and run your software in linux container, there is still no an obvious and easy way to build a docker image for big projects. For building a large and complex project docker image, you would probably need to

  • Clone your private software repo in to build folder
  • Ensure base images are built before your project image
  • Generate some files dynamically, such as current git commit revision
  • Generate templates
  • Upload image with your credentials

With Dockerfile, you can only have static steps for building the image. Obviously, it was not designed for doing any of these listed above. And since docker uses a kind of layering file system, you probably don’t want to put your Github credentials into the container and pull the repo inside it, because it works pretty similar to git commits, once you commit, then it’s hard to remove it from the history. So you definitely want to do these things outside the container and then put them together.

My first solution - Crane

With these requirements in mind, I actually feel it’s pretty similar to the experience I had with Omnibus - a tool for packing your software into a standalone dep package. So I built a simple tool in Python for building docker images, named Crane. It allows you to define steps for building the image, it also provides template generating with jinja2.

The final solution - ansible

Crane was working fine, but I actually don’t like to make a new wheel and maintain it if there is already an obvious better solution. After I played ansible for a while, I realized it is actually a way better solution for building docker images. So, what is ansible you may ask, well, it’s yet another deployment tool, like Puppet, Chef or SaltStack.

Wait, what? Why you are using a deployment tool for building docker image? It may sound odd to you at very beginning. But ansible is not actually just yet another deployment tool. Its design is pretty different from its predecessors. It uses SSH for pushing commands to target machines, other tools are all pulling based. It also provides many modules for different operations, including creating instances in EC2 or other cloud computing providers. Most importantly, it is able to do orchestration easily.

Of course it meets requirements we mentioned before

  • Clone git repo? Check.
  • Build base image? Check.
  • Generate dynamic file? Check.
  • Generate templates? Check.
  • Upload images? Check.

Moreover, with ansible, you can launch an EC2 instance, build the image inside it, and run a series of tests before you publish the image. Or you can simply build the image in your vagrant machine or in the local machine. It makes building software extremely flexible, since you can run the building process anywhere you want as long as they can be pushed as commands via SSH, you can also provision the whole building environment, or even drive a fleet in cloud for building, that’s pretty awesome huh, isn’t it?

Show me the code

Okay, enough of talking, let’s see the code. The tasks/main.yml looks like this

- assert:
    that:
      - 'hellobaby_version != ""'

- name: install apt packages
  apt: "name='' state=present"
  with_items:
    - git
    - python-pip

- name: install docker-py
  pip: name=docker-py version=0.3.1

- name: create build directory
  file: >
    dest=""
    state=directory

- name: clone hellobaby git repo
  git: >
    repo=""
    dest="/hellobaby"
    version="v"
  register: hellobaby_repo

- name: remove git deploy key
  file: dest=/tmp/github_deploy_key state=absent

- name: archive repo
  shell: >
    cd "/" &&
    git archive -o ../.tar HEAD
  with_items:
    - hellobaby

- name: generate templates
  template: >
    src=""
    dest="/"
  with_items:
    - { src: "Dockerfile", dest: "Dockerfile" }
    - { src: "runapp.sh", dest: "runapp.sh" }

- name: build image
  docker_image: >
    name=""
    tag=""
    path=""
    state=build

- name: tag
  command: >
    docker tag -f
    :
    :
  when: hellobaby_extra_tag != ''

and the playbook looks like this

---
- name: Build Hello baby app image
  hosts: all
  sudo: yes
  vars_prompt:
    - name: hellobaby_version
      prompt: "hellobaby_version"
      default: "1.0.0"
      private: no
    - name: hellobaby_iteration
      prompt: "hellobaby_iteration"
      default: 1
      private: no
  roles:
    - Ansibles.apt
    - hellobaby_image

So, to build with vagrant, you can run something like this

ansible-playbook \
  -i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory \
  -u vagrant --private-key=~/.vagrant.d/insecure_private_key \
  playbooks/hellobaby.yml

You can find the complete example here - ansible-docker-demo.

A tool for deployment but also amazing for building software

Although ansible was not designed for building software, it doesn’t necessary mean you cannot do not it. And surprisingly, it does so well in building software. With its machine provisioning and orchestration capability, you can integrate building and deployment together easily. The building environment itself can also be provisioned before building the software. Cloud computing resource can also be leveraged. I feel there are actually lots more interesting things can be done with ansible. Looking forward to see how people use it not just for deployment but also for building software :P


This article is sponsored by nobody but myself 🤣

Hire me

Interested in hiring a one-person army software engineer to build your next dream product? Do you need an excellent team-player software engineer who can fill almost any role before filling the gap? Check out my work and my GitHub profile to see some of them. I have more than 20 years of experience building software in various fields. I provide one-stop, high-quality, rapid software development services from end to end, be it mobile, front-end, back-end, DevOps, data, or security. You can reach out to me at [email protected].

Contact me
This ad is powered by PolisNetwork

Recent articles:

Two AMD 7900XTX GPUs in a Tinygrad-Based Training Workstation with Peer-to-Peer PCIe Communication
I built an AI-gen video detection model and browser extension in a month
Nvidia GPU on bare metal NixOS Kubernetes cluster explained