\[ \definecolor{data}{RGB}{18,110,213} \definecolor{unknown}{RGB}{217,86,16} \definecolor{learned}{RGB}{175,114,176} \]

Ansible-container

Look mom, no Dockerfile!

Vadim Rutkovsky
Red Hat Czech, http://github.com/vrutkovs

Typical case

Grafana - an app to build dashboards and grafs from various sources

Default choice: monitoringartist/grafana-xxl

Why I didn't like default Grafana-XXL image from dockerhub:

  • Bloated: all the grafana plugins installed
  • Bloated: uses gosu to run
  • Has auto-upgrade on by default
  • Doesn't have read-only anonymous access

Dockerfile + shell = hell

ENV GRAFANA_VERSION=3.1.1-1470047149 \
    GF_PLUGIN_DIR=/grafana-plugins \
    UPGRADEALL=true

COPY ./run.sh /run.sh

RUN apt-get update && \
  apt-get -y --force-yes --no-install-recommends install libfontconfig \
      curl ca-certificates git jq && \
  curl https://grafanarel.s3.amazonaws.com/builds/grafana_${GRAFANA_VERSION}_amd64.deb >
      /tmp/grafana.deb && \
  dpkg -i /tmp/grafana.deb && \
  rm /tmp/grafana.deb && \
  curl -L https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64 > \
      /usr/sbin/gosu && \
  chmod +x /usr/sbin/gosu && \
for plugin in $(curl -s https://grafana.net/api/plugins?orderBy=name | 
      jq '.items[] | select(.internal=='false') | .slug' | tr -d '"'); do 
      grafana-cli --pluginsDir "${GF_PLUGIN_DIR}" plugins install $plugin; done

Ansible Container

Ansible Container

https://github.com/ansible/ansible-container

sudo pip install ansible-container

A tool to build Docker images and orchestrate containers using only Ansible playbooks instead of Dockerfile + shell + docker-compose combination.

Ansible Container allows using several ansible features:

  • Vars
  • Templates
  • Roles

Directory structure

ansible-container init creates initial files:

.
└── ansible
    ├── container.yml
    ├── main.yml
    └── requirements.txt
  • main.yml - playbook to build the image
  • container.yml - orchestration
  • requirements.txt - requirements for ansible module

container.yml - orchestration

version: "1"
services:
  grafana:
    image: centos:7
    ports:
      - "3000:3000"
    user: "grafana"
    command: ["/usr/sbin/grafana-server",
              "--homepath=/usr/share/grafana",
              "--config=/etc/grafana/grafana.ini",
              "cfg:default.paths.data=/var/lib/grafana",
              "cfg:default.paths.logs=/var/log/grafana",
              "cfg:default.paths.plugins=/grafana-plugins"]

registries:
  atomicregistry:
    url: atomic-registry.usersys.redhat.com:5000
    namespace: vrutkovs

main.yml - playbook

- hosts: grafana
  vars:
    rpm: https://grafanarel.s3.amazonaws.com/builds/grafana-3.1.1-1470047149.x86_64.rpm
  tasks:
    - name: Upgrade all packages
      yum: name=* state=latest

    - name: Install grafana
      yum: name="{{ rpm }}" state=present
    
    - name: Install plugins
      command: grafana-cli --pluginsDir /grafana-plugins plugins install {{ item }}
      with_items:
        - grafana-piechart-panel
        - alexanderzobnin-zabbix-app
        - mtanda-histogram-panel
    
    - name: Copy config file
      copy: src="grafana.ini" dest=/etc/grafana owner=grafana

    - name: Make sure grafana user is the owner of its dirs
      file: name={{ item }} state=directory owner=grafana recurse=true
      with_items:
        - /grafana-plugins
        - /var/lib/grafana
        - /var/log/grafana
    - name: Clean yum files
      command: yum clean all

Build process

  • ansible-container build creates a build container: "ansible_ansible-container" and containers for services: "ansible_<service name>"
  • Build container adds service container to the inventory
  • Build container runs the playbook
  • The result is committed and the images are exported
  • The image can be 'flattened' into a single layer

Build log

Starting Docker Compose engine to build your images...
Attaching to ansible_ansible-container_1
Attaching to ansible_ansible-container_1, ansible_grafana_1
ansible-container_1  | 
ansible-container_1  | PLAY [grafana] ********************************************
ansible-container_1  | 
ansible-container_1  | TASK [setup] **********************************************
ansible-container_1  | ok: [grafana]
ansible-container_1  | 
ansible-container_1  | TASK [Upgrade all packages] *******************************
ansible-container_1  | ok: [grafana]
ansible-container_1  |

[snip]

ansible-container_1  | PLAY RECAP ************************************************
ansible-container_1  | grafana: ok=7    changed=2    unreachable=0    failed=0   
ansible-container_1  | 
ansible_ansible-container_1 exited with code 0
Aborting on container exit...
Stopping ansible_grafana_1 ... 
Stopping ansible_grafana_1 ... done
Exporting built containers as images...
Committing image...
Exported grafana-xxl-grafana with image ID 
    sha256:c15c6a907eb24e0f2384e0bf7744986e793a699b5741a644fb64ab8613704cec
Cleaning up grafana build container...
Cleaning up Ansible Container builder...

Running and shipping it

run starts services according to their description in container.yml

push pushes the resulting image to a specified registry

shipit kubernetes creates a playbook which deploys the image to a k8s cluster

shipit openshift same for Openshift

Future

A very young project, has lots of plans:

  • Build caching
  • Detached run, stop and restart
  • Custom volumes and build variables
  • rkt and OCI support

Github: https://github.com/ansible/ansible-container

Docs: https://docs.ansible.com/ansible-container

#ansible-container on Freenode

Thanks! Questions?