5

Docker Engine 1.12 Local Development Environment

Engine

In this post we are going to build  a three node development environment to look at the new features in the Docker 1.12 engine. The first thing that we will need is to make sure that we have Vagrant and virtualbox installed. For the instructions from Virtualbox please see https://www.virtualbox.org/wiki/Downloads and for Vagrant https://www.vagrantup.com/

Once we have both those products installed we will go to my GitHub page and clone the following repo https://github.com/scotty-c/vagrant-template. Once we have git cloned the repo we will make a few changes to a couple of files. The first file we will change is the Vagrantfile. We will comment out the section of code that uses Puppet as a provider, as we won’t be needing that. So our Vagrantfile should look like the following

# -*- mode: ruby -*-
# # vi: set ft=ruby :

# Specify minimum Vagrant version and Vagrant API version
Vagrant.require_version ">= 1.6.0"
VAGRANTFILE_API_VERSION = "2"

# Require YAML module
require 'yaml'

# Read YAML file with box details
servers = YAML.load_file('servers.yaml')

# Create boxes
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  # Iterate through entries in YAML file
servers.each do |servers|


  config.vm.define servers["name"] do |srv|

    srv.vm.hostname = servers["name"]

    srv.vm.box = servers["box"]

    srv.vm.network "private_network", ip: servers["ip"]


   servers["forward_ports"].each do |port| 
     srv.vm.network :forwarded_port, guest: port["guest"], host: port["host"]
  end

   srv.vm.provider :virtualbox do |v|
        v.cpus = servers["cpu"]
        v.memory = servers["ram"]
  end

    srv.vm.synced_folder "./", "/home/vagrant/#{servers['name']}"

    servers["shell_commands"].each do |sh|
      srv.vm.provision "shell", inline: sh["shell"]
    end

    #srv.vm.provision :puppet do |puppet|
    #    puppet.temp_dir = "/tmp"
    #    puppet.options = ['--pluginsync', '--modulepath=/tmp/modules', '--verbose', '--debug']
    #    puppet.hiera_config_path = "hiera.yaml"  

    #    end
     end
   end
end

The next file we will change is the servers.yaml file. This is the file that contains all the configuration for the three nodes we are going to build. The three nodes will be called docker-1, docker-02 and docker-03. Docker-01 will be our swarm master and we will also create an overlay network called swarm_private. Docker-02 and docker-03 will be worker nodes. So add the following code to the servers.yml

--- 
- 
  box: scottyc/ubuntu-14-04-puppet-kernel-4-2 
  cpu: 2
  ip: "172.17.10.101"
  name: docker-01
  forward_ports:
      - { guest: 443, host: 8443}

  ram: 4096
  shell_commands:
      - { shell: 'apt-get update -y' }
      - { shell: 'apt-get install -y wget git' }    
      - { shell: 'curl -fsSL https://test.docker.com/ | sh'} 
      - { shell: 'echo -e "172.17.10.101 docker-01\n172.17.10.102 docker-02\n172.17.10.103 docker-03">>/etc/hosts'}
      - { shell: 'docker swarm init --listen-addr 172.17.10.101:2377'} 
      - { shell: 'docker network create -d overlay swarm_private'}   

- 
  box: scottyc/ubuntu-14-04-puppet-kernel-4-2 
  cpu: 2
  ip: "172.17.10.102"
  name: docker-02
  forward_ports:
      - { guest: 443, host: 8444}
  ram: 4096
  shell_commands:
      - { shell: 'apt-get update -y' }
      - { shell: 'apt-get install -y wget git' }    
      - { shell: 'curl -fsSL https://test.docker.com/ | sh'}       
      - { shell: 'echo -e "172.17.10.101 docker-01\n172.17.10.102 docker-02\n172.17.10.103 docker-03">>/etc/hosts'} 
      - { shell: 'docker swarm join --listen-addr 172.17.10.102:2377 172.17.10.101:2377'}  


- 
  box: scottyc/ubuntu-14-04-puppet-kernel-4-2 
  cpu: 2
  ip: "172.17.10.103"
  name: docker-03
  forward_ports:
      - { guest: 443, host: 8445}
  ram: 4096
  shell_commands:
      - { shell: 'apt-get update -y' }
      - { shell: 'apt-get install -y wget git' }    
      - { shell: 'curl -fsSL https://test.docker.com/ | sh'} 
      - { shell: 'echo -e "172.17.10.101 docker-01\n172.17.10.102 docker-02\n172.17.10.103 docker-03">>/etc/hosts'}
      - { shell: 'docker swarm join --listen-addr 172.17.10.103:2377 172.17.10.101:2377'}

Now we have all our code set up. let’s build our cluster. We will do so by issuing the command vagrant up from the same directory that the Vagrantfile lives. This will take a few minutes to build. Once the build is finished we log into docker-01, we will do this by issuing the command vagrant ssh docker-01 from our terminal in the same directory that we ran vagrant up. Once we are logged in we should change to root sudo -i, then we can check that our network was created successfully by issuing the docker network ls command. We should get the following output.

root@docker-01:~# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
4d0103a20826        bridge              bridge              local
7f7187f73cae        docker_gwbridge     bridge              local
10792ed96dc9        host                host                local
0j28z8zihzyv        ingress             overlay             swarm
41a0cf0f8c39        none                null                local
0g3ep77kf7bj        swarm_private       overlay             swarm 

No we have setup our cluster let’s add a service, in this example we are going to use a demo web application that I created for Dockercon 16 called scottyc/webapp. It’s a really lightweight golang application running in a Alpine linux container. To create the service we will use the new docker service command that was released in the 1.12 engine. So logged into our machine docker-01 we will issue docker service create --name simpleweb --replicas 1 --network swarm_private --publish 3000/tcp scottyc/webapp simpleweb as root. This will create a service called simple web with a single replica. To make sure our service is up and running we can use the docker service tasks command, passing the service name as an argument.

root@docker-01:~# docker service tasks simpleweb
ID                         NAME         SERVICE    IMAGE           LAST STATE         DESIRED STATE  NODE
6nbs09w5kv6ubo6bg1rqf0lu6  simpleweb.1  simpleweb  scottyc/webapp  Running 3 minutes  Running        docker-03

As you can see we have our service running a single container on docker-03. As we didn’t expose a port to the outside world the docker load balancer will default to the port 30000. So if now the application is up and running we can curl docker-03 on the ip address 172.17.10.103 that we specified in our servers.yaml earlier.

root@docker-01:~# curl http://172.17.10.103:30000
<!DOCTYPE html>
<html>
<head>
<title>
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
body {background-color:ffffff;background-repeat:no-repeat;background-position:top left;background-attachment:fixed;}
h1{text-align:center;font-family:Impact;color:000000;}
p {text-align:center;font-family:Verdana;font-size:14px;font-style:normal;font-weight:normal;color:000000;}
</style>
</head>
<body>


Awesome Web App !!!!

....and the demo worked :) gif </body> </html>

and as you see we got a response, now what happens if we try to curl to docker-01 172.17.10.101

root@docker-01:~# curl http://172.17.10.101:30000
<!DOCTYPE html>
<html>
<head>
<title>
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
body {background-color:ffffff;background-repeat:no-repeat;background-position:top left;background-attachment:fixed;}
h1{text-align:center;font-family:Impact;color:000000;}
p {text-align:center;font-family:Verdana;font-size:14px;font-style:normal;font-weight:normal;color:000000;}
</style>
</head>
<body>


Awesome Web App !!!!

....and the demo worked :) gif </body> </html>

We got the same result. The reason for this is this is that the mesh routing in the engine 1.12 routed our request to the node docker-03 that was hosting the container that was hosting the service. So as you can see there are a lot of great new features in the Docker engine 1.12.

Now if you want to destroy this development environment and start from a fresh new one, just issue the command vagrant destroy -f && vagrant up

scottyc

Linux geek, Docker Captain and Retro Gamer

5 Comments

  1. Thanks Scott..Got it working..
    Only issue I noticed was. I had to remove the first line in all my dockers where the hostnames was getting associated to 127.0.0.1.

    vagrant@docker-01:~$ more /etc/hosts
    127.0.0.1 docker-01 docker-01
    127.0.1.1 localhost.vm localhost

    The following lines are desirable for IPv6 capable hosts

    ::1 localhost ip6-localhost ip6-loopback
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    172.17.10.101 docker-01
    172.17.10.102 docker-02
    172.17.10.103 docker-03

  2. Thanks for great guide! BTW I got…

    curl: (7) Failed to connect to 172.17.10.103 port 30000: Connection refused

    Any hint? Thanks

  3. After exit and getting in again, it’s just working…weird! working now!

  4. Thanks for the post. The swarm init did not work on my master until after adding –advertise-addr option:
    $ docker swarm init –listen-addr 172.17.10.101:2377 –advertise-addr 172.17.10.101:2377′

    Also the worker joining with –listen-addr did not work, had to use token option.

    Another observation was docker-01 (master) seemed always the 1st to host the app, if replicas=1, the 1 container ran on docker-01, if replicas=3, the 3 containers one ran on each of the vms. Feel like the master itself acted as a worker as well.
    $ sudo docker node ls
    ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
    45nvnypb66j30ugmb4c4lq729 docker-02 Ready Active
    bpxi35cb53swp7etgdvizyvz4 docker-03 Ready Active
    e8y6n789mzvwgjg5zozzq3hd8 * docker-01 Ready Active Leader

    • Hey @Luke C

      When this post was written Docker 1.12 was still rc4, the flags got changed on the final version. For example the token functionality had not been added yet.
      Now the offical documentation is out please follow that https://docs.docker.com/engine/swarm/
      So swarm init would be
      docker swarm init –advertise-addr :2377
      Join would be
      docker swarm join \
      –token SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-1awxwuwd3z9j1z3puu7rcgdbx \
      :2377

Leave a Reply

Your email address will not be published. Required fields are marked *

15 − six =