This tutorial shows you how to use Docker Machine with the OpenStack driver to provision Docker Engines on Catalyst Cloud compute instances.
Docker Engine is the daemon at the core of the Docker platform. It is responsible for providing the lightweight runtime on which containers are run.
Docker Machine is a tool that allows you to provision Docker Engines either locally or hosted with a cloud provider. Docker Machine has a number of different drivers to facilitate installing the Docker Engine on different cloud providers. On the Catalyst Cloud we will be making use of the OpenStack driver.
Once a Docker Engine has been provisioned on a VM instance, the local docker client can be configured to talk to the remote Docker Engine, rather than talking to the local Docker Engine. This is achieved using environment variables.
This tutorial assumes a number of things:
You are familiar with Docker and its use case and wish to make use of Catalyst Cloud compute instances to run Docker Engines
You already have Docker installed on your machine
You are familiar with basic usage of the Catalyst Cloud (e.g. you have created your first instance as described at Overview)
You have a single private network and subnet within your project
You will be setting up a Ubuntu 14.04 instance
You will be using the ubuntu user
You will be letting the driver create an SSH keypair for you
You have sourced an openrc file, as described at Source an openstack RC file
The first thing you need to do is install Docker Machine locally:
$ curl -L https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-`uname -s`-`uname -m` | \
sudo tee /usr/local/bin/docker-machine > /dev/null && sudo chmod +x /usr/local/bin/docker-machine
Check that Docker Machine is working:
$ docker-machine -v
docker-machine version 0.7.0, build a650a40
Note
Assumptions: your project has a private network, subnet and router set up. Please see consult Overview if you do not have this configured already. It is also assumed that you have spare floating IPs available in your quota.
The next step is to set up a security group for your docker host. You will use the command line clients to achieve this. First create a security group:
$ openstack security group create --description 'network access for docker' docker-security-group
+-------------+---------------------------------------------------------------------------------+
| Field | Value |
+-------------+---------------------------------------------------------------------------------+
| description | network access for docker |
| headers | |
| id | f27b5889-8f43-4e57-ba99-xxxxxxxxxxxx |
| name | docker-security-group |
| project_id | 3d5d40b4a6904e6db4xxxxxxf53d4f39 |
| rules | direction='egress', ethertype='IPv4', id='ffaea025-3511-492f-b8ce-xxxxxxxxxxxx' |
| | direction='egress', ethertype='IPv6', id='00132465-6141-4842-ad5c-xxxxxxxxxxxx' |
+-------------+---------------------------------------------------------------------------------+
Now you need to create three rules:
Inbound access to TCP port 22 for SSH access
Inbound access to TCP port 80 for web access so you can demonstrate Nginx running inside a docker container
Inbound access to TCP port 2376 so your local client can communicate with the Docker Engine daemon
You can issue the openstack security group list
command to find your
SECURITY_GROUP_ID
:
$ openstack security group list
+--------------------------------------+-----------------------+-----------------------------------------+----------------------------------+
| ID | Name | Description | Project |
+--------------------------------------+-----------------------+-----------------------------------------+----------------------------------+
| 87426623-b895-4fa8-bf1b-xxxxxxxxxxxx | default | default | 3d5d40b4a6904e6db4xxxxxxf53d4f39 |
| f27b5889-8f43-4e57-ba99-xxxxxxxxxxxx | docker-security-group | network access for docker | 3d5d40b4a6904e6db4xxxxxxf53d4f39 |
+--------------------------------------+-----------------------+-----------------------------------------+----------------------------------+
$ for port in 22 80 2376; do openstack security group rule create --dst-port $port --ingress \
--protocol tcp --src-ip YOUR_CIDR_NETWORK SECURITY_GROUP_ID; done
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| direction | ingress |
| ethertype | IPv4 |
| headers | |
| id | d988e327-01c7-4c80-8b72-xxxxxxxxxxxx |
| port_range_max | 22 |
| port_range_min | 22 |
| project_id | 3d5d40b4a6904e6db4xxxxxxf53d4f39 |
| protocol | tcp |
| remote_group_id | None |
| remote_ip_prefix | 114.110.38.54/32 |
| security_group_id | f27b5889-8f43-4e57-ba99-xxxxxxxxxxxx |
+-------------------+--------------------------------------+
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| direction | ingress |
| ethertype | IPv4 |
| headers | |
| id | 01fad37d-518f-48f2-93d6-xxxxxxxxxxxx |
| port_range_max | 80 |
| port_range_min | 80 |
| project_id | 3d5d40b4a6904e6db4xxxxxxf53d4f39 |
| protocol | tcp |
| remote_group_id | None |
| remote_ip_prefix | 114.110.38.54/32 |
| security_group_id | f27b5889-8f43-4e57-ba99-xxxxxxxxxxxx |
+-------------------+--------------------------------------+
+-------------------+--------------------------------------+
| Field | Value |
+-------------------+--------------------------------------+
| direction | ingress |
| ethertype | IPv4 |
| headers | |
| id | 3b4e03a7-4d3e-4d88-afc8-xxxxxxxxxxxx |
| port_range_max | 2376 |
| port_range_min | 2376 |
| project_id | 3d5d40b4a6904e6db4xxxxxxf53d4f39 |
| protocol | tcp |
| remote_group_id | None |
| remote_ip_prefix | 114.110.38.54/32 |
| security_group_id | f27b5889-8f43-4e57-ba99-xxxxxxxxxxxx |
+-------------------+--------------------------------------+
If you are unsure of what YOUR_CIDR_NETWORK
should be, ask your network
admin, or visit https://ifconfig.me and get your IP address. Use
“IP_ADDRESS/32” as YOUR_CIDR_NETWORK to allow traffic only from your current
effective IP.
The next step is to provision a compute instance using Docker Machine. Docker
Machine will instantiate a VM, get SSH access to this VM and will then install
the Docker Engine on this host. As this process can take quite a while, it’s
a good idea to use the --debug
flag so you can monitor the installation
progress and see any errors that may occur.
Note
You are making use of OpenStack environment variables in this command. Ensure you have followed the steps described at Source an openstack RC file
$ docker-machine --debug create --driver openstack --openstack-ssh-user ubuntu --openstack-image-name ubuntu-14.04-x86_64 --openstack-flavor-name c1.c1r1 \
--openstack-net-name PRIVATE-NET-NAME --openstack-floatingip-pool public-net --openstack-sec-groups docker-security-group docker-engine-host
Note
If your cloud project only has one private network defined, then the
--openstack-net-name PRIVATE-NET-NAME
can be omitted. If there is more
than one private network defined, then PRIVATE-NET-NAME
should be replaced
with the network you wish to connect the docker-engine-host to
Now you need to tell your local client how to connect to the remote Docker Engine you have created:
$ eval "$(docker-machine env docker-engine-host)"
Now, when you issue docker commands using the local client, you will be interacting with the Docker daemon in the cloud instance:
$ docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 1.12.1
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 0
Dirperm1 Supported: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: null bridge host overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor
Kernel Version: 3.13.0-95-generic
Operating System: Ubuntu 14.04.5 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 993.9 MiB
Name: docker-engine-host
ID: UERI:SGSA:5SDC:W7HF:Z3DC:Y5H3:FOKJ:OQO5:YSYG:BPYR:BOBY:4VDV
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
provider=openstack
Insecure Registries:
127.0.0.0/8
Note
Docker Engine stores configuration parameters including SSL and SSH keys under ~/.docker/machine/
Next, create a test image from which you will instantiate a container running
in the cloud. You will run a simple webserver by basing your image on the
official Nginx image. To create a custom index page and a Dockerfile
for
our image:
$ cat index.html
<html>
<h3>Hello, Docker World!</h3>
</html>
$ cat Dockerfile
FROM nginx
MAINTAINER Yourname Yoursurname <yourname@example.com>
COPY index.html /usr/share/nginx/html/index.html
Now create your image:
$ docker build -t yourname/nginx .
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM nginx
latest: Pulling from library/nginx
8ad8b3f87b37: Pull complete
c6b290308f88: Pull complete
f8f1e94eb9a9: Pull complete
Digest: sha256:aa5ac743d65e434c06fff5ceaab6f35cc8519d80a5b6767ed3bdb330f47e4c31
Status: Downloaded newer image for nginx:latest
---> 4a88d06e26f4
Step 2 : MAINTAINER Yourname Yoursurname <yourname@example.com>
---> Running in 0ec25b1c7689
---> 9e2a7f2166b4
Removing intermediate container 0ec25b1c7689
Step 3 : COPY index.html /usr/share/nginx/html/index.html
---> 11bcf58d424a
Removing intermediate container 642408c201d3
Successfully built 11bcf58d424a
Note
At this point you are referencing a local Dockerfile
but the image is being built on the remote Docker Engine cloud instance.
Now instantiate the image you have just built as a running container:
$ docker run -d -p 80:80 yourname/nginx
3f47ef854fbe7d58b0e14e8ce2407ddb00b0883399aa1ff434c50fcfe1406750
Check you have a running container:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eac317f0642b yourname/nginx "nginx -g 'daemon off" 10 seconds ago Up 9 seconds 0.0.0.0:80->80/tcp, 443/tcp amazing_pike
Now hit the external IP to verify you have everything working:
$ curl $( openstack server show docker-engine-host | grep addresses | awk '{print $(NF-1)}' )
<html>
<h3>Hello, Docker World!</h3>
</html>
Should you wish to log in to the remote instance using SSH you can use the key generated by Docker Machine:
$ ssh -i ~/.docker/machine/machines/docker-engine-host/id_rsa \
ubuntu@$( openstack server show docker-engine-host | grep addresses | awk '{print $(NF-1)}' )
If you wish to interact with the Docker Engine on the cloud instance you will
need to use sudo
:
ubuntu@docker-engine-host:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3f47ef854fbe dojo/nginx "nginx -g 'daemon off" 52 minutes ago Up 52 minutes 0.0.0.0:80->80/tcp, 443/tcp naughty_bell