There has been much interest recently in the use of microservices to architect large-scale services. Microservices are predicated on the idea of deploying individual applications each of which provides a single service, and linking these microservices together to create a large-scale service. The hope is that the use of microservices simplifies the creation of sophisticated services by making it easier to deploy and upgrade individual applications.
Virtualization has been a core technology that, over the last few years, has enabled both public and private clouds. Virtualization simplifies the task of deploying and configuring new servers. However, since a virtual machine contains an entire OS it is a heavyweight deployment vehicle more suited to the deployment of heavyweight applications than microservices.
Over the years, there have been various attempts to develop lightweight container technology in different UNIX and Linux distributions. The idea with containerization is that many containers can be deployed to a single physical host, with each container hosting an application that is securely isolated from applications hosted in other containers.
Virtualization and containerization can both be used on bare-metal systems, and it would seem that there is no need for virtualization when containerization is used. However, the economics of the public cloud is closely tied to the deployment density and flexibility provided by virtualization. Consequently, in a public cloud containerization is likely to reside on top of virtualization rather than replace it.
An increasingly fashionable solution is the use of Docker to host microservices. Docker provides an integrated application-hosting environment and a packaging mechanism that simplifies the use of Linux containers for microservice deployment. The Docker application-hosting environment is built on several Linux technologies including Linux Containers and Union File Systems.
A Linux Container is a lightweight application-hosting environment that can be used to host a microservice. A single compute node can host many containers. Even on a single host, distinct containers are isolated from each other. Each container has its own filesystem and TCP/IP ports. There are various patterns for connecting containers such as exposing TCP/IP ports and shared directories on the host system. Container technology fits in well with the idea of creating large-scale services out of simple microservices.
In a traditional filesystem hierarchy, new filesystems are mounted as distinct branches into the existing filesystem tree. In a union filesystem, new filesystems are overlaid on the existing filesystem tree so that files in a single branch may come from different filesystems. Typically, all but one filesystem are mounted read-only. Specific rules also apply when two files with the same name are mounted from different filesystems.
Docker provides a CLI allowing Docker images to be built with these images serving as templates for the creation of containers. Images can be stored locally or uploaded to the Docker Hub where they can be made available either privately or publically. An image is typically built from a configuration file, so that images are created in a declarative rather than procedural manner. This configuration file contains information such as: the base operating system for a container; deployment script for the application; TCP/IP ports to be exposed; files to be copied into the file system of the container; and directories in the host system to be made accessible to the container. Docker caches intermediate steps of the build process, which speeds up the iterative development of images by allowing subsequent builds to start from a known good point in the process. The different steps provide different layers to the union file system used by Docker.
The Docker CLI allows Docker containers to be created from an image stored either locally or in the Docker Hub. Container creation is parameterized allowing different containers built from the same image to be hosted in the same server. A single image can be used to deploy containers to any environment hosting a Docker server, thereby supporting the replicable deployment of an identical application-hosting environment.
The Docker website hosts downloads of the Docker software as well as extensive documentation. James Turnbull (@kartar), of Docker, has written an excellent book, The Docker Book, providing many fully-worked examples of deploying applications in Docker. Adrian Cockroft (@adrianco) recently posted a typically interesting take on the sudden popularity of Docker.
The Docker software comprises a daemon, which manages the Docker containers running on the host server. The Docker client provides the API manage Docker, build images and deploy containers. The Docker client can be used to securely manage Docker running on remote hosts.
It is easy to deploy one or more Docker containers into a host and configure them to create an integrated service. However, the management of a cluster of compute nodes each hosting many containers is more difficult – and some means to manage the cluster is needed.
Google is developing Kubernetes, an open-source project, written in Go, to manage clusters of Docker hosts. Kubernetes is a pre-production beta in active development, and hosted in a GitHub repo. Kubernetes can be deployed into a number of environments including Google Compute Engine and Microsoft Azure. Mark Lamourine (@markllama) has a nice post showing how to use Kubernetes to deploy services.
The Kubernetes repo contains a design document. The basic idea is that a Kubernetes deployment comprises one or more Docker hosts, referred to as minions, and a master server to control them. The Kubernetes deployment unit is a pod, which is a group of containers on a single host with shared network and storage volumes. A single compute node may host several pods. Kubernetes comes with an API allowing pods to be created and deleted.
Docker on Azure
Azure Virtual Machines is the IaaS offering in the Microsoft Azure Platform. It supports the deployment of VMs hosting various Linux flavors including Ubuntu, CentOS, OpenSuse, and Oracle Linux. Docker can be deployed easily into an Azure VM in a couple of ways:
- installation of Docker into an existing Azure VM
- deployment of an Azure VM with Docker pre-configured
The Azure cross-platform CLI is documented here, along with download and installation instructions. The azure vm create command can be used to deploy a new VM. Once that is running, an SSH connection can be used to access the VM and perform a standard Docker installation.
The Azure cross-platform CLI can also automate the creation and deployment of a VM in which Docker is pre-installed through the azure vm docker create command. The Docker configuration is setup to require authentication, and the credentials are installed in the ~/.docker directory on the machine where the command isexecuted. Furthermore, a Docker endpoint on port 4243 is exposed on the Azure Load Balancer so that a Docker client can authenticate to and access the Docker server over the public internet. Ross Gardler (@rgardler), of Microsoft OpenTech, has a post going into this in detail.
With the Docker client installed locally and appropriate credentials in the ~/.docker directory, the following command can be used to get information about a remote Docker server hosted in an Azure cloud service:
docker –tls -H tcp://CLOUD_SERVICE_NAME.cloudapp.net:4243 info
A curiosity to be aware of is that the Docker daemon requires root access by default so that docker info on a local Docker server fails while the equivalent command succeeds against a remote Docker server.
Kubernetes on Azure
Kubernetes is an open-source project hosted in the GoogleCloudPlatform repos on GitHub. The core Kubernetes GitHub repo contains extensions allowing it to be deployed into various environments including Azure. The instructions for deploying Kubernetes and using it in Azure are here.
Note that the installation scripts currently use the subscription name to generate an Azure storage account name. This may lead to an error if the subscription name has not been changed from the default. Furthermore, although the documentation indicates the use of the West US Azure region there is nothing intrinsic to that region so that with appropriate modification to the configuration scripts Kubernetes can be deployed in any region. The storage account and region can both be configured in kubernetes/release/azure/config.sh.
The installation script:
- Creates a new storage account named kubeRandomString
- Creates a new cloud service – named kube-SameRandomString
- Deploys a master VM
- Deploys 4 minion VMs and installs Docker on them
The master VM has a public endpoint on 443, and all the VMs have distinct public SSH endpoints exposed. The following example shows how to SSH into the first minion in a cluster:
ssh -i ~/.ssh/azure_rsa CLOUD_SERVICE_NAME.cloudapp.net -p 22001
Once the cluster is up and running, Kubernetes can be used to deploy pods, and the deployment document has examples. Azure endpoints need to be configured manually if the microservices in a pod are to be exposed to the public internet. Kubernetes provides bash scripts to perform other pod-management tasks including the tear down of an entire cluster.
Kubernetes Visualizer is an OSS demonstration from Microsoft OpenTech, that deploys a simple website that provides a basic visual overview of a Kubernetes cluster. It also allows pods to be created. The Kubernetes Visualizer is described here and is documented on and downloadable from the Azure repo on GitHub.