Deploying a remote Docker server using cloud-init

It can be very handy to have a remote Docker server instead of the default local configuration from our workstation because of bandwidth issues, testing a production environment, maybe a customer demonstration, or distant team collaboration. Being able to send the usual Docker commands to a remote server has a multitude of advantages. For speed and comfort, we'll deploy a basic CoreOS system, add one user (Jane) and its public key. Docker will be modified to listen to the network through a socket kind of systemd service, and we'll configure the server time zone to be in New York.

Getting ready

To step through this recipe, you will need:

  • Access to a cloud-config enabled infrastructure

How to do it...

Let's start by simply calling this server "docker":

#cloud-config
hostname: "docker"

In the final system, this will set the hostname to the correct value:

$ hostname
docker
$ cat /etc/hostname
docker

Now let's create the Jane user, so she can log in to the instance to remotely help us. She needs to be in the docker group, so she can manipulate the containers, and she gave us her SSH public key. This is how it translates in the cloud-config file:

#cloud-config
users:
  - name: "jane"
    gecos: "Jane Docker"
    groups:
      - "docker"
    ssh-authorized-keys:
      - "ssh-rsa AAAAB[...] jane"

In the final system, Jane is able to log in using her private key, and interact with the docker daemon as she's a member of the docker group:

jane@docker ~ $ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

The SSH public key ends up in the following file:

jane@docker ~ $ cat .ssh/authorized_keys.d/coreos-cloudinit
ssh-rsa AAAAB [..] jane

Setting the timezone on CoreOS using cloud-init

CoreOS uses a system built around NTP (short for Network Time Protocol), controlled by the timedatectl command. We won't find the usual /etc/timezone on CoreOS, so the default timezone directive from cloud-init we've seen earlier in this book won't work. To set the time zone to New York on CoreOS, we would set it like this:

$ /usr/bin/timedatectl set-timezone America/New_York

Easy! So let's launch that command through a systemd unit in the cloud-config file, so we're sure the time zone is set. In-depth knowledge of systemd is out of the scope of this book, but to do that, we'll have to add two options to the unit: one that tells systemd to not think the unit has crashed because the command exited (RemainAfterExit=yes), and one that tells the unit type is not executing a long running process, but instead a short one that should exit before continuing (Type=oneshot).

Here's the unit in the cloud-config.yml file:

coreos:
  units:
  - name: settimezone.service
    command: start
    content: |
      [Unit]
      Description=Setting the timezone

      [Service]
      ExecStart=/usr/bin/timedatectl set-timezone America/New_York
      RemainAfterExit=yes
      Type=oneshot

Enabling Docker TCP socket for network access

Our final objective is to be able to use a Docker Engine remotely from our workstation. The default Docker configuration is to listen to the Unix socket (/var/run/docker.sock)—and we want it to listen to a TCP socket on port 2375 (the default unencrypted port, it's highly recommended to configure TLS encryption; this will use the TCP/2376 by convention). To configure this, we'll use a systemd feature—socket activation. To make it short, this creates a systemd service that listens on port 2375, and spawns the regular docker.service unit along with the socket description. This way, this particular Docker Engine will answer to requests on the TCP socket and not on the Unix socket (while keeping the possibility to activate more TCP sockets, or keeping the default docker.service clean). Here's how it looks:

coreos:
  units:
  - name: docker-tcp.socket
    command: start
    enable: true
    content: |
      [Unit]
      Description=Docker Socket for the API

      [Socket]
      ListenStream=2375
      BindIPv6Only=both
      Service=docker.service

      [Install]
      WantedBy=sockets.target

Let's start a remote server with this whole configuration and use it a little for the demonstration (in this example, the Docker remote host is 52.211.117.98, and we'll launch an nginx container with HTTP port forwarding). Refer to the Docker section of this book for more information on the command-line options used:

user@workstation $ docker -H 52.211.117.98 run -it --rm -p 80:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
6a5a5368e0c2: Pull complete
4aceccff346f: Pull complete
c8967f302193: Pull complete
Digest: sha256:1ebfe348d131e9657872de9881fe736612b2e8e1630e0508c354acb0350a4566
Status: Downloaded newer image for nginx:latest  
1.2.3.4 - - [25/Sep/2016:16:06:30 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36" "-"

Make some requests on the remote Docker host HTTP port and it will answer. We now have a full on-demand CoreOS host, capable of giving us control over a Docker Engine remotely, using a nifty systemd configuration feature!

There's more...

When connecting to various remote Docker Engines, we will sooner or later connect to a server not using the same version of the server as our client. In this case, we'll get the following error:

Error response from daemon: client is newer than server (client API version: 1.24, server API version: 1.22)

The easy workaround is to override the DOCKER_API_VERSION environment variable and set it to the same value as the server (1.22 in this example):

$ DOCKER_API_VERSION=1.22 docker -H 52.211.117.98 ps

Note

Docker 1.13 greatly improved this situation, by managing the version/feature negotiation between the client and the server directly in the CLI.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.62.122