Get started Part3 : services

Prerequisites

Be sure your image works as a deployed container. Run this command, slotting in your info for username, repo, and tag:

docker run -p 80:80 id3pvergain/get-started:part2

then visit http://localhost/.

Introduction

In part 3, we scale our application and enable load-balancing.

To do this, we must go one level up in the hierarchy of a distributed application: the service.

  • Stack
  • Services (you are here)
  • Container (covered in part 2)

About services

In a distributed application, different pieces of the app are called “services.” For example, if you imagine a video sharing site, it probably includes a service for storing application data in a database, a service for video transcoding in the background after a user uploads something, a service for the front-end, and so on.

Services are really just “containers in production.” A service only runs one image, but it codifies the way that image runs—what ports it should use, how many replicas of the container should run so the service has the capacity it needs, and so on.

Scaling a service changes the number of container instances running that piece of software, assigning more computing resources to the service in the process.

Luckily it’s very easy to define, run, and scale services with the Docker platform – just write a docker-compose.yml file.

Your first docker-compose.yml file

A docker-compose.yml file is a YAML file that defines how Docker containers should behave in production.

Save this file as docker-compose.yml wherever you want. Be sure you have pushed the image you created in Part 2 to a registry, and update this .yml by replacing username/repo:tag with your image details.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: id3pvergain/get-started:part2
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"
    networks:
      - webnet
networks:
  webnet:

This docker-compose.yml file tells Docker to do the following:

  • Pull the image we uploaded in step 2 from the registry.
  • Run 5 instances of that image as a service called web, limiting each one to use, at most, 10% of the CPU (across all cores), and 50MB of RAM.
  • Immediately restart containers if one fails.
  • Map port 80 on the host to web’s port 80.
  • Instruct web’s containers to share port 80 via a load-balanced network called webnet. (Internally, the containers themselves will publish to web’s port 80 at an ephemeral port.)
  • Define the webnet network with the default settings (which is a load-balanced overlay network).

docker swarm init

Before we can use the docker stack deploy command we’ll first run:

docker swarm init
PS Y:\projects_id3\P5N001\XLOGCA135_tutorial_docker\tutorial_docker\tutoriels\get_started\part3> docker swarm init
Swarm initialized: current node (pnbte8079jvn6eceltf17kysp) is now a manager.

To add a worker to this swarm, run the following command:

        docker swarm join --token SWMTKN-1-24yfg27ko4ma40mgips1yn5syhcs6fmcc7jesi7rwq56a9volj-4152plyrb8p3l6fpnbmqaaa7x 192.168.65.3:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

docker stack deploy -c docker-compose.yml getstartedlab

Now let’s run it. You have to give your app a name. Here, it is set to getstartedlab:

docker stack deploy -c docker-compose.yml getstartedlab
PS Y:\projects_id3\P5N001\XLOGCA135_tutorial_docker\tutorial_docker\tutoriels\get_started\part3> docker stack deploy -c docker-compose.yml getstartedlab
Creating network getstartedlab_webnet
Creating service getstartedlab_web

docker service ls

Our single service stack is running 5 container instances of our deployed image on one host. Let’s investigate.

Get the service ID for the one service in our application:

docker service ls
PS Y:\projects_id3\P5N001\XLOGCA135_tutorial_docker\tutorial_docker\tutoriels\get_started\part3> docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                           PORTS
tzjfv6o4bpxb        getstartedlab_web   replicated          5/5                 id3pvergain/get-started:part2   *:80->80/tcp

You’ll see output for the web service, prepended with your app name. If you named it the same as shown in this example, the name will be getstartedlab_web. The service ID is listed as well, along with the number of replicas, image name, and exposed ports.

A single container running in a service is called a task.

Tasks are given unique IDs that numerically increment, up to the number of replicas you defined in docker-compose.yml.

List the tasks for your service:

docker service ps getstartedlab_web

docker service ps getstartedlab_web
PS Y:\projects_id3\P5N001\XLOGCA135_tutorial_docker\tutorial_docker\tutoriels\get_started\part3> docker service ps getstartedlab_web
ID                  NAME                  IMAGE                           NODE                    DESIRED STATE       CURRENT STATE            ERROR               PORTS
qx6cvv7knp0m        getstartedlab_web.1   id3pvergain/get-started:part2   linuxkit-00155d280a10   Running             Running 31 minutes ago
z9m5tsjo75pz        getstartedlab_web.2   id3pvergain/get-started:part2   linuxkit-00155d280a10   Running             Running 31 minutes ago
kv05oigiytuf        getstartedlab_web.3   id3pvergain/get-started:part2   linuxkit-00155d280a10   Running             Running 31 minutes ago
as0f73cwv5l8        getstartedlab_web.4   id3pvergain/get-started:part2   linuxkit-00155d280a10   Running             Running 31 minutes ago
w4qqxjhsqxw3        getstartedlab_web.5   id3pvergain/get-started:part2   linuxkit-00155d280a10   Running             Running 31 minutes ago

docker container ls -q

Tasks also show up if you just list all the containers on your system, though that will not be filtered by service:

docker container ls -q
c31e71b41bdb
8780b68999cf
4ead2b07d319
473d75fd76f2
cae7ae5c659b
f45453da50cf
b47fd081642e

Sous WSL (Windows Subsystem Linux)

pvergain@uc026:/mnt/c/Users/pvergain/Documents$ which curl
/usr/bin/curl
pvergain@uc026:/etc/apt$ curl http://localhost
<h3>Hello World!</h3><b>Hostname:</b> f45453da50cf<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>

Scale the app

You can scale the app by changing the replicas value in docker-compose.yml, saving the change, and re-running the docker stack deploy command:

docker stack deploy -c docker-compose.yml getstartedlab

Docker will do an in-place update, no need to tear the stack down first or kill any containers.

Now, re-run docker container ls -q to see the deployed instances reconfigured. If you scaled up the replicas, more tasks, and hence, more containers, are started.

Take down the app (docker stack rm getstartedlab)

Take the app down with docker stack rm:

docker stack rm getstartedlab
Removing service getstartedlab_web
Removing network getstartedlab_webnet

Take down the swarm (docker swarm leave –force)

docker swarm leave --force
Node left the swarm.

It’s as easy as that to stand up and scale your app with Docker. You’ve taken a huge step towards learning how to run containers in production. Up next, you will learn how to run this app as a bonafide swarm on a cluster of Docker machines.

To recap, while typing docker run is simple enough, the true implementation of a container in production is running it as a service.

Services codify a container’s behavior in a Compose file, and this file can be used to scale, limit, and redeploy our app.

Changes to the service can be applied in place, as it runs, using the same command that launched the service: docker stack deploy.

Some commands to explore at this stage:

docker stack ls                                            # List stacks or apps
docker stack deploy -c <composefile> <appname>  # Run the specified Compose file
docker service ls                 # List running services associated with an app
docker service ps <service>                  # List tasks associated with an app
docker inspect <task or container>                   # Inspect task or container
docker container ls -q                                      # List container IDs
docker stack rm <appname>                             # Tear down an application
docker swarm leave --force      # Take down a single node swarm from the manager