Ansible. Docker. Vagrant. Bringing together
Giving the challenges of building and maintaining a complex software it’s really hard to manage the provisioning, orchestration, build and deployment of applications easily. Fortunately there are tools and engines coming for help.
In the following article we’ll see how Ansible, Docker and Vagrant can be used to provision and install necessary software on environment where you can build and deploy an application. Having the setup it will be possible to run the application in any environment where the prerequisites are installed.
Here is a quick overview about the tools we are going to use:
Ansible
Ansible is an IT automation engine written in Python. With Ansible it is possible to automate provisioning, orchestration, configuration management and deployment of applications.
Ansible Playbooks are written using YAML syntax, so that you have it in human-readable format and no complex knowledge is required to understand what it does. In practice, you can pass your Ansible Playbooks to a third person and in couple of minutes he/she will have an idea how you manage provisioning for your product.
Docker
Docker is a nice toy to build and deploy any kind of application into lightweight Linux containers. It’s important to understand that Docker is not a VM. Unlike VM’s, Docker is based on AUFS. It shares the same kernel and filesystem of the machine where it is hosted. It comes with a great CLI which makes interaction with Docker engine really easy and supports versioning of the images.
Vagrant
Vagrant is a virtual machine manager. It is easy to configure, and by default comes with support of the providers such as Docker, VirtualBox and VMware. The great thing about Vagrant is that you can use all modern provisioning tools (e.g Chef, Puppet, Ansible) to install and configure software on the virtual machine.
The goal
- Write a RESTfull API which exposes resource to say hello to the world.
- Package, build and deploy an application using Ansible.
- Write a docker image to be used as provider for Vagrant.
- Run Vagrant VM, provision it with Ansible using Docker container as a provider.
- Expose the HelloWorld endpoint to the host from VM.
Step 1 (pre-requisite): Install Vagrant
Installing Vagrant is easy, check out the download page and follow the instructions.
In addition we need to install a plugin that manages the hosts
file in guest machine.
vagrant plugin install vagrant-hostmanager
Step 2: Building a Hello World resource
The API needs to be as simple as possible and for the sake of purpose we use Spring Boot and write the code in Kotlin. As our goal is to demonstrate the power of Ansible, Docker and Vagrant, we won’t go into the details of building the API; the source code is available here.
The endpoint has the following specification
URL: /hello/:name
HTTP Method: GET
Step 3: Writing Dockerfile
The Dockerfile is going to copy the project sources in order to build and deploy it. In addition we install OpenSSH and expose 8080 port so that it can be accessed by VM.
# Version 1.0.0
FROM ubuntu:latest
MAINTAINER vtor
RUN echo 'root:root' | chpasswd
RUN DEBIAN_FRONTEND=noninteractive apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y aptitude sudo openssh-server python2.7
ADD kotlin-hello-world /tmp/kotlin-hello-world
WORKDIR /tmp/kotlin-hello-world
RUN mkdir /var/run/sshd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
EXPOSE 22 8080
CMD ["/usr/sbin/sshd", "-D"]
The kotlin-hello-world project used in the docker file is our application source which we built in Step 1.
Step 4: Writing Vagrantfile
The following things are included in the Vagrantfile
- Build a Docker image and use it as VM provider
- Forward the 8080 to the 7000 it available to the host
- Provision the machine with Ansible
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'
Vagrant.configure("2") do |config|
config.ssh.username = 'root'
config.ssh.password = 'root'
config.hostmanager.enabled = true
config.hostmanager.manage_guest = true
config.vm.provider "docker" do |d|
d.build_dir = "."
d.has_ssh = true
d.remains_running = true
end
config.vm.hostname = "ansible"
config.vm.network "forwarded_port", guest: 8080, host: 7000, host_ip: "127.0.0.1", auto_correct: true
config.vm.provision :hostmanager
config.vm.provision :ansible do |ansible|
ansible.playbook = "ansible/run.yml"
ansible.sudo = true
end
end
Step 5: Creating Ansible Playbook
The Playbook consists of three roles
- Install and configure Maven
- Install and configure Java
- Build and deploy hello-world application
---
- name: Setup environment to run the sample
hosts: all
remote_user: root
become: yes
roles:
- role: maven
- role: java
java:
version: java8
apt_repository: ppa:webupd8team/java
- role: hello-world
Role to install java
---
- name: Install Java repository
apt: >
name=software-properties-common
state=latest
tags: java
- name: Add Java Repository
apt_repository: >
repo='ppa:webupd8team/java'
tags: java
- name: Accept java8 License
debconf: >
name='oracle-java8-installer'
question='shared/accepted-oracle-license-v1-1'
value='true'
vtype='select'
tags: java
- name: Install Oracle java8
apt: >
name=
state=latest
with_items:
- oracle-java8-installer
- ca-certificates
- oracle-java8-set-default
tags: java
Role to install Maven
---
- name: Installing maven
apt: >
pkg=
state=latest
update_cache=yes
cache_valid_time=3600
with_items:
- maven
tags: maven
Role to build and deploy hello-world application
---
- name: Build the hello-world project
command: >
chdir=/tmp/kotlin-hello-world mvn clean package spring-boot:repackage
tags: hello-world
- name: Add the executable jar into init.d
file: src=/tmp/kotlin-hello-world/target/kotlin-hello-world-1.0-SNAPSHOT.jar
dest=/etc/init.d/hello
owner="root" group="root" mode=0755 state=link
become: yes
become_user: root
tags: hello-world
- name: Run the hello-world
become: yes
become_user: root
command: /etc/init.d/hello start
tags: hello-world
ignore_errors: yes
That’s it! Open the Terminal/Command Line and go to the root directory of the project and run
vagrant up
It will take a couple of minutes before Vagrant boots and installs the software and deploys the app. Once Vagrant is up and running, open your favourite web browser and try the following URL:
http://127.0.0.1:7000/hello/<yourname>
As you can see it’s really easy to put Ansible, Docker and Vagrant together and use the power of each to have consistent, easily maintainable configuration management, provisioning, build and deployment of your projects.
Check the Github Repo for the full source code.