Docker and Ansible

in anger



Docker and Ansible

in anger
the devil is in the details


A Presentation by

Jamie McCrindle
VP of Product Engineering
Brand Networks



Why Docker


  • Most of the benefits of Virtual Machines
    • Isolated applications
    • Portable
  • Far more lightweight than Virtual Machines
    • Faster development
    • Less resource intensive in production
  • Compatibility layer for the cloud
  • Easily hosted outside of the cloud

Why Ansible

  • All of the benefits of configuration management
    • Automated
    • Reliable
    • Describes an environment
  • Simple
    • Agentless
    • Uses SSH

Docker Misconceptions

https://devopsu.com/blog/docker-misconceptions/



Misconception: If I learn Docker then I don't have to learn the other systems stuff!

Dev Ops


Creating a MariaDB cluster docker



Skip to the end



docker run \
-v "/mysql/etc:/etc/mysql" \
-v "/mysql/lib:/var/lib/mysql" \
-p "3306:3306" \
jamiemccrindle/mariadb  --wsrep-new-cluster 

What is happening under the covers

  • Check to see if we have a data directory
  • If we don't, we need to configure the database
    • Run mysql_install_db
    • Run mysql_safe in the background
    • Wait for mysql to come up by polling
    • Run an init script to create an admin user
    • Shut the database down (because we want it running in the foreground)
  • Start up the database in the foreground

Entrypoint

if [ ! -f /var/lib/mysql/ibdata1 ]; then
    mysql_install_db
    /usr/bin/mysqld_safe $@ &
    sleep 2
    while : ; do
        echo 'select 1' | mysql
        if [ $? -eq 0 ] ; then
          break
        fi
        sleep 1
    done
    cat /etc/mysql/init.sql | mysql
    /usr/bin/mysqladmin shutdown  
fi
/usr/bin/mysqld_safe $@  

Docker Misconceptions

https://devopsu.com/blog/docker-misconceptions/



Misconception: If I use Docker then I don't need a configuration management (CM) tool!

Sample Project


  • https://github.com/jamiemccrindle/docker_ansible_build
  • https://github.com/jamiemccrindle/docker_ansible_app


What it is doing

  1. Installs the latest version of Docker
  2. Installs Ansible
  3. Installs Java
  4. Installs a Private Docker Repository
  5. Installs and configures Jenkins
  6. Adds Jenkins Job to build our application
  7. The Jenkins Job
    1. Compiles the application
    2. Builds a docker image
    3. Pushes the docker image to the docker repository
    4. Runs and tests the new docker

App main.go

package main

import (
    "fmt"
    "net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintf(w, "Hello World!")
		})
	http.ListenAndServe(":8000", nil)
}







update the code!

App Dockerfile

FROM google/golang

WORKDIR /gopath/src/app
ADD . /gopath/src/app/
RUN go get app

EXPOSE 8000

CMD []
ENTRYPOINT ["/gopath/bin/app"]

Builder Layout

.
├── Vagrantfile
├── ansible.cfg
├── build.yml
├── build_docker_ansible_app.yml
├── deploy.yml
├── inventory
│   └── vagrant_build
│       └── hosts
└── roles
    ├── ansible
    ├── build_docker_ansible_app
    ├── docker_environment
    ├── docker_registry
    ├── java
    ├── jenkins
    ├── jenkins_deploy_keys
    ├── jenkins_jobs
    └── known_hosts_github

Builder build.yml

- hosts: builder
  sudo: yes
  connection: ssh

  pre_tasks:
    - lineinfile: line='127.0.0.1 docker-registry.example.com' dest=/etc/hosts

  roles:
    - role: docker_environment
    - role: known_hosts_github
    - role: ansible
    - role: docker_registry
    - role: java
    - role: jenkins
      tags: ['jenkins']
    - role: jenkins_jobs
      tags: ['jenkins_jobs']

Ansible docker commands

---

- command: docker build -t docker-registry.example.com:5000/docker_ansible_app ../docker_ansible_app

- command: docker push docker-registry.example.com:5000/docker_ansible_app

- docker: image=docker-registry.example.com:5000/docker_ansible_app ports="8000:8000" name="docker_ansible_app" state=running 

It's possible to automate Jenkins!





https://github.com/ICTO/ansible-jenkins is awesome 

Use Ansible to provision Jenkins Jobs

---
- name: check if job exists
  action: command java -jar {{ jenkins.cli_dest }} -s http://localhost:8080 list-jobs
  register: tasks_installed

- name: copy config
  copy: src="{{ job_name }}.xml" dest=/tmp/config.xml

- name: install task
  action: shell java -jar {{ jenkins.cli_dest }} -s http://localhost:8080 create-job {{ job_name }} < /tmp/config.xml
  when: tasks_installed.stdout.find(job_name) == -1

- name: update task
  action: shell java -jar {{ jenkins.cli_dest }} -s http://localhost:8080 update-job {{ job_name }} < /tmp/config.xml
  when: tasks_installed.stdout.find(job_name) != -1

did it work?

Some things I have learned along the way


Docker






ONBUILD can be used to run commands in child containers

Docker Debugging



docker logs docker_ansible_app
docker inspect docker_ansible_app
nsenter

Docker files





ADD will decompress tar.gz files

Ansible Inventory





group_vars/all can be a directory






thank you

Docker and ansible

By jamiemccrindle

Docker and ansible

Using Docker and Ansible in anger

  • 3,058