Docker Swarm For a Docker Swarm cluster I will use in this example: 1 manager node and 2 worker nodes. They will be launched by Vagrant with VirtualBox using the Ubuntu 16.04 image.

First we define the nodes in the Vagrantfile:

manager_ip = "10.0.3.2"

Vagrant.configure(2) do |config|

  config.vm.define "manager" do |manager|
    manager.vm.hostname = "manager"
    manager.vm.box = "ubuntu/xenial64"
    manager.vm.network "private_network", ip: manager_ip

    manager.vm.provider :virtualbox do |v|
      v.cpus = 1
      v.memory = 512
    end
  end

  (1..2).each do |i|
    config.vm.define "worker-#{i}" do |worker|
      worker.vm.hostname = "worker-#{i}"
      worker.vm.box = "ubuntu/xenial64"
      worker.vm.network "private_network", ip: "10.0.3.#{i+2}"

      worker.vm.provider :virtualbox do |v|
        v.cpus = 1
        v.memory = 512
      end
    end
  end
end

Make sure the nodes can reach each other in the same network.

Then we need to provision those nodes with Docker. For this I chose Ansible.

Let’s first create an Ansible play that installs Docker:

- name: docker gpg key
  apt_key: url=https://download.docker.com/linux/ubuntu/gpg

- name: add docker repository
  apt_repository:
    repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable

- name: install docker
  apt: name=docker-ce

Then we need to initialize the Swarm cluster on the manager. For this I defined a separate Ansible play:

- hosts: all
  gather_facts: false
  become: true
  tasks:
    - include: docker.yml

    - name: check swarm is active
      shell: 'docker info | grep "Swarm: active"'
      register: swarm_active
      ignore_errors: true

    - name: swarm init
      when: swarm_active.rc == 1
      shell: docker swarm init --listen-addr :2377 --advertise-addr 

    - name: get swarm token
      shell: docker swarm join-token -q worker > /vagrant/worker_token

The last task in provisioning the master node is to store the “join token” in a shared file so that the workers can join the newly created cluster.

To have the workers join the swarm, create a separate Ansible play for the workers:

- hosts: all
  gather_facts: false
  become: true
  tasks:
    - include: docker.yml

    - name: swarm join
      shell: docker swarm join --token $(cat /vagrant/worker_token) :2377

Finally add the Ansible provisioning to the Vagrantfile:

config.vm.define "manager" do |manager|
    #...

    manager.vm.provision "ansible" do |ansible|
      ansible.playbook = "manager.yml"
      ansible.extra_vars = {
          ansible_python_interpreter: "/usr/bin/python3",
          manager_ip: manager_ip
      }
    end
  end

  (1..2).each do |i|
    config.vm.define "worker-#{i}" do |worker|
      #...

      worker.vm.provision "ansible" do |ansible|
        ansible.playbook = "worker.yml"
        ansible.extra_vars = {
            ansible_python_interpreter: "/usr/bin/python3",
            manager_ip: manager_ip
        }
      end
    end
  end

Note: because Ubuntu 16.04 ships with Python 3 instead of 2.x, we need to explicitly set the ansible_python_interpreter variable.

After this, just run:

$ vagrant up

And it will launch and provision the Docker Swarm cluster for you. When the cluster is running you can connect to the manager node at 10.0.3.2 and start deploying services!