First Hands-on Experience with Docker 1.12 Swarm Mode

First Hands-on Experience with Docker 1.12 Swarm Mode

Recently, Docker released the official version 1.12, introducing several new features, including the official version of Docker Native. One significant update is the addition of Swarm Mode, providing native cluster support. I tried it as soon as possible and am writing this blog post to record my experience.

It’s important to note that despite the similar names, Swarm Mode and Docker Swarm are not the same thing and are not seamlessly compatible. Their main differences are:

  • Docker Swarm runs inside a Docker Engine container, offering the same API as the standard Docker Engine, thus allowing tools that support standalone Docker to operate (e.g., docker-compose).
  • Swarm Mode is integrated directly within Docker Engine, providing native cluster support. However, it’s not compatible with the standalone Docker Engine, managed by a separate docker service command, and cannot use tools and APIs for standalone Docker.

Although not officially stated in the documentation, it can be considered that Swarm Mode is the successor and replacement for Docker Swarm, which seems to be deprecated.

While Docker’s approach this time seems somewhat underhanded, given that Docker Swarm was released just over a year ago and hadn’t achieved a very stable status before being abandoned, followers like Alibaba Cloud’s container service might be disappointed. However, I still believe it was the right choice. The original Docker Swarm was too focused on compatibility with the standalone Docker environment, neglecting the fundamental differences between a single-host environment and a cluster environment (I encountered countless pitfalls when using it). Abandoning it in a timely manner and designing a set of APIs specifically for the cluster environment is the right way to go.

Overview

Here, I translate and introduce the main features, interspersed with some of my own comments on the old swarm version.

Cluster Management System Integrated within Docker Engine

Docker 1.12 introduced a new command, docker swarm, for managing clusters. Due to the integration of the Discovery service internally, setting up a cluster has become exceptionally simple. Essentially, you only need docker swarm init + docker swarm join to easily establish a cluster; it just works (although there are still some minor issues, like the --listen-addr problem).

Decentralized Design

Unlike determining the relationships between nodes at deployment, the new Swarm Mode dynamically handles these relationships during runtime. Thus, the roles of manager and worker can be swapped in real-time, and nodes can be added dynamically.

Declarative Service Model

You can declare a series of services, and the Docker cluster is responsible for expanding the microservices to the corresponding state.

Easy Control Over Cluster Scale

With the docker service scale command, you can easily increase or decrease the number of containers for a service, much like the docker-compose command for standalone use. Compared to standalone compose, scaling in a cluster environment is undoubtedly much more useful.

Automatic State Maintenance

The Swarm cluster automatically maintains the entire service’s state. For instance, if we declare that we need 10 worker containers, Docker will create and attempt to reallocate new Containers to ensure the number of worker containers meets the expectation.

Cross-Host Networking

You can define networks across hosts, which is transparent to the internal containers, as if they were in their own LAN. This feature existed in Docker Swarm mode, but the new load balancing mechanism introduced in Swarm Mode significantly enhances the utility of this network.

Service Discovery

Docker 1.12 offers a built-in Discovery service, eliminating the need for external Discovery services like consul or etcd for cluster setup.

Load Balancing

I think this is the most important new feature in Swarm Mode. When we use an internal domain name to access another container, we’re not just accessing the first container of the service; instead, we’re accessing a virtual IP with load balancing. This is particularly useful when deploying clusters, eliminating concerns about how to distribute load among containers, such as multiple nginx containers exposing ports to cgi containers, making it much easier for cluster services to integrate into the container environment.

In addition to virtual IPs (VIP), Docker also provides a DNS Round-Robin (dnsrr) load balancing mode.

Default TLS Encryption

I think there’s not much to say about this.

Rolling Updates

Another important feature, docker service, allows you to customize the update interval and sequentially update your containers. docker service update lets you update almost anything, including images. Docker will update your containers according to the set interval. If an error occurs, you can roll back to the previous state.

Some Personal Impressions

The above essentially translates the official feature introduction. Below, I also share some of my personal experiences:

  • mode=replicated|global is a particularly useful parameter, with the default being replicated, meaning the service can be scaled freely. Docker will arrange where these containers run, while global allows us to declare a global service, meaning one container per server, no more, no less.

This means we can set our cgi containers as replicated, scaling whenever the load capacity is insufficient, while globally exposed ports are ensured by nginx in global mode. This way, even if we add worker nodes, nginx will automatically expand to the new machines, making ports immediately accessible (and with internal load balancing, it seems haproxy might not be needed anymore).

The original Docker Swarm lacked this mode, which was my most significant dissatisfaction. Ensuring every machine in a node exposes the same ports, a seemingly fundamental task in a cluster, was quite challenging.

  • The -v --volume parameter is gone, but don’t think mounting the local filesystem is no longer possible. It’s just that the format has changed, and it’s completely unmentioned in the documentation. I found it in an issue, with the following format:
docker service create --mount type=volume,target=<container file/directory>,source=<host file/directory>,volume-driver=<driver>,volume-opts=<k0>=<v0>,volume-opts=<k1>=<v1>

For example, mounting local direcotry:

docker service create --mount type=volume,target=/container_data/,source=/host_data/,volume-driver=local

This also shows Docker’s reliability issues with updates. The official release of a major version happens, but the documentation isn’t thoroughly clear, highlighting the need for caution when updating.

At the moment (2016-08-04), version 1.12 still has quite a few serious bugs, such as the unreliability of container internal load balancing, sometimes making containers inaccessible, especially after using the docker service scale command. Also, the previously available function of resolving container addresses through hostname is temporarily unavailable. These issues have been listed in the milestone for version 1.12.1, awaiting fixes.

  • Currently, Swarm Mode is not compatible with docker-compose. I believe it will be in the future, but it’s not for now. However, most swarm syntax can be converted into parameters for docker service create, and docker-compose 1.8.0 provided a docker-compose bundle command to generate dab files for use with docker deploy to deploy services. However, this command wasn’t provided in the official 1.12 release, and the docker-compose bundle command still lacks support for many syntaxes, so it’s essentially unusable for now. Service creation commands need to be written manually. Fortunately, we have the docker service update command, which rarely necessitates service recreation after its creation.

  • Like with Docker Swarm, Swarm Mode requires pushing images to a registry when using custom-built images.

  • Every time a service is created, each node checks the registry for image updates, even if the tag remains the same (such as latest). This avoids the trouble of docker-compose pull, but if your application doesn’t have released versions and always uses latest, using docker service update --image won’t have any effect. However, there’s a trick: you can switch between docker service update --image someimage and docker service update --image someimage:latest to force the service to re-pull the image.

  • The --env-file parameter is not currently supported, requiring each environment variable to be passed in with the -e parameter. This also avoids the hassle in Docker Swarm where each machine had to have the envfile at the same path.

comments powered by Disqus