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
- Installs the latest version of Docker
- Installs Ansible
- Installs Java
- Installs a Private Docker Repository
- Installs and configures Jenkins
- Adds Jenkins Job to build our application
- The Jenkins Job
- Compiles the application
- Builds a docker image
- Pushes the docker image to the docker repository
- 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,131