How to Deploy Your App Using Multiple Machines with Docker Swarm

If you are starting to work with Docker, and you have a big application to deploy, you have to learn about Swarm. It allows you to use multiple machines together as an orchestra.

From my experience, you can do it the hard way, or you can use Docker Swarm.

Why Docker?

As part of my internship at the Nearsoft Academy, I contributed to an Open Source project. After some research, I chose to contribute to Docker repositories.

Docker is a really innovative tool to create, deploy, and run applications. It will become an indispensable tool for you as a developer.

The tool I will concentrate in is Docker Swarm. It has plenty of documentation. If you are a Docker enthusiast, you’ll love its features, like I did.

Docker Swarm

In Docker-talk, a swarm is a cluster of machines running and working together,

  • A node refers to a each machine in the Swarm
  • Any node can be a manager or a worker
  • A leader is the top-most manager

The advantage of a cluster is to load-balance. Since the request will be assigned randomly to the nodes and not a single machine. The managers can pass docker commands to workers, and deploy everything as a service to achieve load balance.

Get Started

To use swarm you must do the following,

  • Have Docker installed
  • Have an image to deploy
  • Have a docker-compose.yml file to create the services
  • Be on a Docker Machine

How to Work with Docker Swarm

The three key things you’ll want to do is to Create, Initialize, and Run the Swarm.

1. Create the Swarm

You can use physical or virtual machines to incorporate them in a Swarm. You will need the IP address of each machine and a token generated by Swarm. If you use Virtual Machines, you can use,

docker-machine create --driver virtualbox myvm1

And get a list of your machines using,

docker-machine ls

2. Initialize the Swarm

Once you figure which machine will be the leader, you can initialize the Swarm Mode. At the same time assign that machine as the manager and leader of the swarm.

  • As leader, the machine will have admin rights in the swarm. As manager, it will have rights over the other managers and workers.
  • Workers cannot pass commands, they can only receive them.

To initialize as leader, run the next command,

docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"

If you want to check how this is initialized, look in the [Docker CLI] repository. It will show you how Docker commands work, including the commands for Docker Swarm.

On the init.go file, the Docker CLI code has the method runInit. It invokes swarmInit to initialize the Swarm.

One of the main things I like about Swarm is that the CLI guides you by telling which commands to use next.

For example, in this case, it first tells you how to initialize the swarm using the current node as a manager.

  nodeID, err := client.SwarmInit(ctx, req)
  if err != nil {
     if strings.Contains(err.Error(), "could not choose an IP address to advertise") || strings.Contains(err.Error(), "could not find the system's IP address") {
        return errors.New(err.Error() + " - specify one with --advertise-addr")
     }
     return err
  }

  fmt.Fprintf(dockerCli.Out(), "Swarm initialized: current node (%s) is now a manager.\n\n", nodeID)

  if err := printJoinCommand(ctx, dockerCli, nodeID, true, false); err != nil {
     return err
  }

Then, it tells you how to initialize the rest of the machines as workers or managers, using the Out method of the CLI class.

  fmt.Fprint(dockerCli.Out(), "To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.\n\n")

  if req.AutoLockManagers {
     unlockKeyResp, err := client.SwarmGetUnlockKey(ctx)
     if err != nil {
        return errors.Wrap(err, "could not fetch unlock key")
     }
     printUnlockCommand(dockerCli.Out(), unlockKeyResp.UnlockKey)
  }

  return nil
}

This is what you’ll see in your console,

Swarm initialized: current node <node ID> is now a manager.
To add a worker to this swarm, run the following command:

  docker swarm join \
  --token <token> \
  <myvm ip>:<port>

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

To add a worker or manager use,

docker-machine ssh myvm2 "docker swarm join \
--token <token> \
<ip>:2377"

Use this approach to join machines with the IP and a provided token in the Docker CLI.

On the join.go file, the code has the runJoin method, which uses again the swarmInit method, shown next,

  err := client.SwarmJoin(ctx, req)
  if err != nil {
     return err
  }

  info, err := client.Info(ctx)
  if err != nil {
     return err
  }

  if info.Swarm.ControlAvailable {
     fmt.Fprintln(dockerCli.Out(), "This node joined a swarm as a manager.")
  } else {
     fmt.Fprintln(dockerCli.Out(), "This node joined a swarm as a worker.")
  }
  return nil
}

Note that runJoin has a similar functionality to the runInit method. The difference is that with runJoin, you specify if the node joined will be a manager of a worker.

3. Deploy the Swarm

Once you have the swarm setup, you can deploy it by using,

docker stack deploy -c docker-compose.yml <image file>

Note the new element, called a stack. A stack is a group of interrelated services. This can be the your whole application or a fragment of it.

You use a Docker-compose file to configure the services. It deploys the image of the application you would want to use.

If you use any of the IP addresses for the swarm nodes, you can access the application from a web browser.

TL;DR

  • Docker Swarm allows you to load-balancing by creating a cluster of multiple machines running Docker.
  • By assigning nodes as managers, you can pass Docker commands to other machines.
  • The leader manager can alter the swarm state.
  • Docker Swarm, with the help of the Docker CLI, can guide you showing what commands to use, and what each parameter should contain.

If you have any questions, contact me at [email protected].

Focus Mode

Contact Request

Close

We will call you right away. All information is kept private