
Ansible and Docker
Automate you docker containers with ansible
If you're like me and you have a home lab you are constantly changing things, whether that is changing the way your network works or adding new hardware. For me that meant every time I got a new server I had to manually configure things. Some of it was easier than others, however a constant pain has been moving my docker containers from host to host without using any kind of orchestration tools like Kubernetes.
Enter Ansible. Anisble is a configuration management tool that helps lots of Sysadmin and engineers to manage fleets of servers reliably. I use Ansible everyday in my day job to deploy all sorts of things to the very large amount of servers that I'm responsible for, but at home I still "handjam" everything. But after months ( maybe years) of resisting - who wants to come home to do more work - I've finally decided to manage the servers at home the way I manage them at work.
The first project I decided to tackle was to automate some simple tasks, the first one being installing docker. So I created an extremely simple play that just that.
---
- name: install pre-reqs
apt:
name: "{{item}}"
state: present
with_items:
- "ca-certificates"
- "curl"
- "software-properties-common"
- name: docker repo key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: docker repo install
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable
state: present
- name: install docker
apt:
name: docker-ce
state: present
update_cache: yes
- name: start service
service:
name: docker
state: started
enabled: true
- name: ensure docker-py is installed
apt:
name: "{{ item }}"
state: present
with_items:
- "python-docker"
- "python3-docker"
- name: add user to docker group
user:
name: ryan
group: docker
append: yes
With just those few lines of YAML, I'm able to install the pre-reqs, set up the docker repository, install docker, and add myself to the docker group.
Next I decided to tackle mounting my nfs mounts that my Plex server uses to serve my movies.
---
- name:
file:
path: "{{ item }}"
state: directory
with_items:
- ["/config", "/key", "/music", "/movies", "/pics", "/vids", "/tv" , "/weddingg_vids", ]
---
- name: Mount config nfs
mount:
path: /config
src: freenas:/mnt/tank/docker_host
fstype: nfs
state: mounted
- name: Mount key nfs
mount:
path: /key
src: freenas:/mnt/tank/key
fstype: nfs
state: mounted
- name: Mount music nfs
mount:
path: /music
src: freenas:/mnt/tank/music
fstype: nfs
state: mounted
This creates the directories that my nfs shares backed by Freenas would be mounted to. One of the import mount points is /config. This is the directory that does the magic for my docker containers that save state. As long as I mount this share and bind the correct path to the containers my container configs/databases will always be the same regardless of how many times I rebuild my docker hosts
With all of that working I can now use Ansible to spin up my containers
```yaml --- - name: install jwilder-nginx docker_container: name: nginx-proxy image: jwilder/nginx-proxy:latest volumes: - /var/run/docker.sock:/tmp/docker.sock:ro exposed_ports: - "80:80" restart_policy: always ```And that's it, I can keep writing plays similar to the one above and my containers will be created and started automatically with all the correct options. And because Ansible is idempotent I never have to worry about stepping on any running containers, I simply modify my play, run Ansible and off to the races.
One thing to note is that container listed above is excellent . It allows you to declare a wild card DNS A record that points to the container host. Any container with the following env variables, VIRTUAL_HOST and VIRTUAL_PORT are automatically proxied behind the scenes to the mapped URL. For example 192.168.29:9000 can become portainer.foo.bar without having to add more DNS records and manually setting up a reverse proxy.