NEW! Mirantis Academy -   Learn confidently with expert guidance and On-demand content.   Learn More

< BLOG HOME

How do I build a containerized app on Mirantis OpenStack with native Docker tools?

Last month, we talked about the pros and cons of some of the different ways to handle containers in OpenStack, including native tools, Murano applications, and Magnum-based operations.  Before we get too deep into how to create different types of applications using OpenStack tools, we thought we'd take a look at what's really going on behind the scenes by building a containerized application on OpenStack using native Docker tools.
Docker has soared in popularity, but while there are some huge applications running on it, very few of the millions of developers and organizations using it are doing so in production, despite the fact that there are now multiple ways to create a reliable and robust infrastructure.
At present, the most common way to deploy container “hypervisors” is to first provision a virtual machine, and then install Docker and the appropriate containers on that VM. The drawback of this method is latency while the VM spins up, but the advantage is 100% isolation and security.  OpenStack, of course, lends itself to this approach of creating Docker hosts on a private cloud, so let's see how that works.

Deploy a Docker hypervisor on OpenStack

Before you can run a single Docker container, you will need to install a Docker host.  You can do this manually, or with tools such as Puppet or Ansible, but why reinvent the wheel or recycle configuration management code and adapt it, when Docker has already released a tool that does this?  It's called Docker Machine.
Machine is a single binary which can create Docker hosts on a variety of providers -- including OpenStack -- and eventually link them in order to create distributed Docker infrastructures with hosts running on different providers at the same time. (If you're thinking, "Hey, that's hybrid cloud," yes, you're right.)
Using Machine is as straightforward as downloading the binary and launching it with the right parameters. The only requirements are:
  • An OpenStack tenant.  You'll need to have access to an OpenStack tenant, or project, in which you can launch a medium instance.
  • The Docker engine.  The simplest way to install Docker is to simply type:
sudo apt-get install docker
  • Exact configuration of the tenant security options.  We'll create the security group in a moment.
For the purposes of this tutorial, you will also want:
  • A clean installation of Ubuntu.  This can be a tiny VM running on openStack or even VirtualBox, rather than actual metal.  (This isn't a strict requirement, but if you're having issues, this may clear them up.)
  • A Ubuntu Trusty Tahr image with a 3.13+ kernel
You can easily install a docker client on your favourite operating system with yum, apt-get or brew.
As for machine, you just pull and execute the binary, verify the version and list the current machines list. (Adapt the operating system version to yours; here we're using amd64 for linux.) Follow these steps:
$ sudo su
$ curl -L https://github.com/docker/machine/releases/download/v0.5.6/docker-machine_linux-amd64 > /usr/local/bin/docker-machine
$ chmod +x /usr/local/bin/docker-machine
$ docker-machine --version
docker-machine version 0.5.6, build 61388e9
If we check the current setup:
$ docker-machine ls
NAME   ACTIVE   URL   STATE   URL   SWARM   DOCKER   ERRORS
Of course, no machines exist yet.
Docker-machine uses port tcp/2376 for the Docker daemon to listen, and port tcp/22 (SSH) to configure the host. It can operate on internal networks or on floating IP, preferring the latter if present. Some security options must be configured. You can add a special security group “machine” for machine, enabling incoming ports 22 and 2376, in Horizon
image1
Once you've created the groups, create the rules:
image2
After sourcing the OpenStack credentials of a non administrator user, but with the tenant privileges, with the environment variables OS_AUTH_URL, OS_TENANT_ID, OS_TENANT_NAME, OS_USERNAME, OS_PASSWORD, from an openrc file, we can easily create an OpenStack Docker machine with a self-explanatory command like:
$ docker-machine create \
--driver openstack \
--openstack-image-id 98011e9a-fc46-45b6-ab2c-cf6c43263a22 \
--openstack-flavor-id 3 \
--openstack-floatingip-pool public \
--openstack-net-id 44ead515-da4b-443b-85cc-a5d13e06ddc85 \
--openstack-sec-groups machine \
--openstack-ssh-user ubuntu \
u1
We are creating a Docker host named u1 based on Ubuntu 14.04 Trusty (http://releases.ubuntu.com/trusty/) on a medium size flavor, attaching to it a floating ip, and booting the instance in the security group machine.
$ docker-machine ls
NAME   ACTIVE   DRIVER   STATE URL                     SWARM
u1 -     openstack   Running   tcp://172.18.186.56:2376   
What Machine does is boot and wait for the instance availability, then inject some values with cloud-init, configure security, certificates and keys, SSH to the instance to update packages, install Docker and finally, launch the daemon. You can check the progress from the instance logs:
image3
After installation, which may require a few seconds, this host is immediately usable, if you import the environment variables with the command
$ eval "$(docker-machine env u1)"
Now you can launch any container on it:
$ docker run busybox echo “Hello from OpenStack”
Hello from OpenStack
$ docker images
REPOSITORY       TAG              IMAGE ID         CREATED          VIRTUAL SIZE
busybox          latest           2c5ac3f849df     15 hours ago     1.113 MB
You can even launch the DockerUI, for example. Just make sure you open the required port in the security group. Usually the DockerUI runs on tcp/9000, so add the rule to the security group.  Once you've done that, you can run the UI:
$ docker run -d -p 9000:9000 --privileged -v /var/run/docker.sock:/var/run/docker.sock dockerui/dockerui
image4
Your first Docker host running on OpenStack is ready!  You can tell by running the docker info command:
$ docker info
Containers: 4
Images: 6
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 14
Dirperm1 Supported: false
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 3.13.0-55-generic
Operating System: Ubuntu 14.04.2 LTS
CPUs: 2
Total Memory: 3.861 GiB
Name: u1
ID: QTYT:CLJH:RVZW:KHRJ:QEGW:OGSJ:3VXV:LZ6D:Z6BN:2HAJ:ZEV6:CWDX
WARNING: No swap limit support
Labels:
provider=openstack
Now that you know how to use Machine to spin things up, let's look at the Docker Compose tool.

Design an app with Compose

For the purpose of this blog post, we’ll install a simple containerized app running ownCloud.
To accomplish this, we’ll demonstrate the usage of another tool from the Docker ecosystem: Compose. For those who know Dockerfiles, Compose adds some nice features with some syntactic sugar. The task of Compose is to set up a set of containers depending on a local configuration written in YAML.
First, install locally Compose:
$ sudo su
$ curl -L https://github.com/docker/compose/releases/download/1.4.2/docker-compose-`uname -s`-`uname -m` > /usr/bin/docker-compose
$ chmod +x /usr/bin/docker-compose
$ docker-compose --version
docker-compose version: 1.4.2
Now, with the sourced environment variables to use the remote Docker host running on, OpenStack, we can create the app environment.
There are tons of tutorials on the Internet on how to setup microservices in seconds, with Compose (for example here, here, here). We’ll demonstrate the usage of Compose by using a ready YAML configuration installing Owncloud. Let’s clone the following github repo and set up the app accordingly:
$ git clone https://github.com/sameersbn/docker-owncloud.git
$ cd docker-owncloud
Now we’re ready to set up this app. The structure is fairly simple: 3 containers, one with the Nginx webserver, one with the Postgres database server, and one with the Owncloud code. They are composed automatically starting from the configuration in the docker-compose.yml file:
$ docker-compose up -d
The -d option specifies that you want to run containers in daemon mode. Compose now downloads the images, creates containers, links them, and does some other operations. When the command finishes, if we check, we’ll see that our Docker host now runs the containers:
$ docker ps
CONTAINER ID     IMAGE                      COMMAND               CREATED          STATUS           PORTS                                NAMES
e29ac6f6a394     sameersbn/nginx            "/sbin/entrypoint.sh "   7 minutes ago    Up 7 minutes     443/tcp, 0.0.0.0:80->80/tcp, 1935/tcp   dockerowncloud_nginx_1
91ffba8739fd     sameersbn/owncloud:latest "/sbin/entrypoint.sh "   7 minutes ago    Up 7 minutes     9000/tcp                             dockerowncloud_owncloud_1
2d08e6679161     sameersbn/postgresql:latest   "/sbin/entrypoint.sh" 8 minutes ago    Up 8 minutes     5432/tcp                             dockerowncloud_postgresql_1
On the docker host, a port redirection is active. So, if OpenStack security groups allow incoming traffic to ports tcp/80 and tcp/443, we can login to the new Owncloud instance:
$ docker-machine ip u1
172.18.186.56
Once you have the IP address, pull it up in the browser.
image5
As you can see, it's working.

Next steps

So at this point you should understand how to set up a minimal infrastructure capable of hosting Docker containers on OpenStack by using the standard Docker ecosystem tools. You saw how to provision a Docker host, how to configure it, and finally how to deploy a sample 3-container application on it.
In upcoming articles, we'll look at other methods of running containerized applications in OpenStack, such as OpenStack Magnum or OpenStack Murano and Kubernetes.

Choose your cloud native journey.

Whatever your role, we’re here to help with open source tools and world-class support.

GET STARTED
NEWSLETTER

Subscribe to our bi-weekly newsletter for exclusive interviews, expert commentary, and thought leadership on topics shaping the cloud native world.

JOIN NOW