Add v2 load balancing technique

This commit is contained in:
Jerome Petazzoni
2016-03-09 15:39:23 -08:00
parent 8a73d85beb
commit 1174845c52
3 changed files with 438 additions and 37 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

View File

@@ -4150,7 +4150,12 @@ Note: good guy ~~Stevedore~~ Docker will start without K/V
.exercise[
- Log into `node1`
- Make sure you're logged into `node1`,
with a clean environment:
```
unset DOCKER_HOST
```
- The first node must be started with the `-bootstrap` flag:
@@ -4160,24 +4165,24 @@ Note: good guy ~~Stevedore~~ Docker will start without K/V
jpetazzo/consul agent -server -bootstrap)
```
- Find the internal IP address of that node
<br/>With This One Weird Trick:
```
IPADDR=$(ip a ls dev eth0 |
sed -n 's,.*inet \(.*\)/.*,\1,p')
```
]
---
## Starting the other Consul nodes
- Other nodes have to be started with the `-join A.B.C.D`
option, where A.B.C.D is the address of an existing node
.exercise[
- The other nodes have to be startd with the `-join IP.AD.DR.ESS` flag:
- Find the internal IP address of our first node:
```
IPADDR=$(ip a ls dev eth0 |
sed -n 's,.*inet \(.*\)/.*,\1,p')
```
- Start the other nodes:
```
for N in 2 3 4 5; do
ssh node$N docker run --name consul_node$N \
@@ -4186,15 +4191,15 @@ Note: good guy ~~Stevedore~~ Docker will start without K/V
done
```
- With your browser, navigate to any instance on port 8500
<br/>(in "NODES" you should see the five nodes)
]
---
## Check that our Consul cluster is up
- With your browser, navigate to any instance on port 8500
<br/>(in "NODES" you should see the five nodes)
- Let's run a couple of useful Consul commands
.exercise[
@@ -4313,7 +4318,7 @@ Note: good guy ~~Stevedore~~ Docker will start without K/V
- Check connectivity:
```
docker exec -ti turquoise ping -c1 navy
docker exec -ti turquiose ping -c1 grass
docker exec -ti turquoise ping -c1 grass
```
(First works; second doesn't)
@@ -4336,7 +4341,7 @@ Note: good guy ~~Stevedore~~ Docker will start without K/V
- Check connectivity:
```
docker exec -ti turquoise ping -c1 navy
docker exec -ti turquiose ping -c1 grass
docker exec -ti turquoise ping -c1 grass
```
(Both commands work now)
@@ -4376,7 +4381,7 @@ Note: good guy ~~Stevedore~~ Docker will start without K/V
- Check connectivity:
```
docker exec -ti turquoise ping -c1 navy
docker exec -ti turquiose ping -c1 grass
docker exec -ti turquoise ping -c1 grass
```
(First command fails, second one works)
@@ -4445,11 +4450,78 @@ Let's examine the `docker-compose.yml` file.
---
FIXME
## Our first Compose v2 file
```
version: "2"
services:
backend:
image: registry:2
frontend:
image: jpetazzo/hamba
command: 5000 backend:5000
ports:
- "127.0.0.1:5000:5000"
depends_on:
- backend
```
- *Backend* is the actual registry.
- *Frontend* is the ambassador that we deployed earlier.
<br/>
It communicates with *backend* using an internal network
and network aliases.
---
## Converting from Compose file v1 to v2
## Starting a local registry with Compose
- We will bring up the registry
- Then we will ensure that one *frontend* is running
on each node by scaling it to our number of nodes
.exercise[
- Make sure that `COMPOSE_FILE` is not set:
```
unset COMPOSE_FILE
```
- Start the registry:
```
docker-compose up -d
```
]
---
## "Scaling" the local registry
- This is a particular kind of scaling
- We just want to ensure that one *frontend*
is running on every single node of the cluster
.exercise[
- Scale the registry:
```
N=1
while docker-compose scale frontend=$N; do
N=$((N+1))
done
```
]
Note: Swarm might do that automatically for us in the future.
---
## Converting the Compose file for DockerCoins
- Services are no longer at the top level,
<br/>but under a `services` section
@@ -4503,44 +4575,358 @@ Copy-paste this into `docker-compose.yml`
---
## Update our Compose file
## Use images, not builds
- If we try to start the app like that, containers will only
run on nodes with the appropriate images
run on nodes which have the images
- We need to replace each `build:` section with an `image:` section
- Like before: we need to replace `build` with `image`
- We can re-use the `build-tag-push.py` script for that
.exercise[
XXX
- Start the application
- Observe that it's running on multiple nodes
- Set `DOCKER_REGISTRY` to use our local registry,
<br/>then build, tag, and push the application:
```
export DOCKER_REGISTRY=localhost:5000
../bin/build-tag-push.py
```
]
---
## Going further
## Run the application
Adding load balancers (difficulty: easy)
- At this point, our app is ready to run
- Replace each service by:
- We don't need ambassadors or extra containers
- multiple copies of itself
.exercise[
- a load balancer
- Start the application:
```
docker-compose up -d
```
- This is what we did with `rng` earlier
- Observe that it's running on multiple nodes:
```
docker ps
```
- Traffic will follow suboptimal paths
]
Each container name is prefixed with the node it's running on.
---
## Going further
## View the performance graph
- Load up the graph in the browser
.exercise[
- Check the `webui` service address and port:
```
docker-compose port webui 80
```
- Open it in your browser
]
---
# Load balancing with overlay networks
- Scaling the `worker` service works out of the box
(like before)
.exercise[
- Scale `worker`:
```
docker-compose scale worker=10
```
]
We will hit the bottleneck caused by the `rng` service.
How can we scale that service?
---
## The manual method
- Replace `rng` with:
- multiple copies `rng1`, `rng2`, `rng3`, ...
- a load balancer taking over the name `rng`,
<br/>and spreading traffic accross all instances
- You should have a sense of *déjà vu*
- We did that in the beginning of the workshop
- Can we do better?
---
## The scripted method
- We could write a script to automate those steps
--
- *Can we do better?*
--
- In a perfect world, we would like to do:
```
docker-compose scale rng=10
```
---
## Naming problem
- Service is called `rng`
- It therefore takes the network name `rng`
- Worker code connects to `rng`
- So `rng` should point to the load balancer
- What do‽
---
## Naming is *per-network*
- Solution: put `rng` on its own network
- That way, it doesn't take the network name `rng`
<br/>(at least not on the default network)
- Have the load balancer sit on both networks
- Add the name `rng` to the load balancer
---
class: pic
## Original DockerCoins
![](dockercoins-single-node.png)
---
class: pic
## Load-balanced DockerCoins
![](dockercoins-multi-node.png)
---
## Declaring networks
- Networks (other than the default one)
*must* be declared
in a top-level `networks` section
.exercise[
- Add the `rng` network to the Dockerfile:
```
version: '2'
networks:
rng:
services:
rng:
image: ...
...
```
]
That section can be placed anywhere in the file.
---
## Putting the `rng` service in its network
- Services can have a `networks` section
- If they don't: they are placed in the default network
- If they do: they are placed only in the mentioned networks
.exercise[
- Change the `rng` service to put it in its network:
```
rng:
image: localhost:5000/dockercoins_rng:…
networks:
rng:
```
]
---
## Adding the load balancer
- The load balancer has to be in both networks:
<br/>`rng` and `default`
- In the `default` network, it must have the `rng` alias
- We will use the `jpetazzo/hamba` image
.exercise[
- Add the `rng-lb` service to the Compose file:
```
rng-lb:
image: jpetazzo/hamba
command: run
networks:
rng:
default:
aliases: [ rng ]
```
]
---
## Load balancer initial configuration
- We specified `run` as the initial command
- This tells `hamba` to wait for an initial configuration
- The load balancer will not be operational
<br/>(until we feed it its configuration)
---
## Start the application
.exercise[
- Bring up DockerCoins:
```
docker-compose up -d
```
- See that `worker` is complaining:
```
docker-compose logs worker
```
]
Note: the workers didn't need to be restarted.
---
## Configure the load balancer
- Multiple solutions:
- lookup the IP address of the `rng` backend
- use the backend's network name
- use the backend's container name (easiest!)
.exercise[
- Configure the load balancer:
```
docker run --rm \
--volumes-from dockercoins_rng-lb_1 \
--net container:dockercoins_rng-lb_1 \
jpetazzo/hamba reconfigure 80 dockercoins_rng_1 80
```
]
The application should now be working correctly.
---
## Scale the application
- Use `docker-compose scale` as planned
.exercise[
- Scale `rng`:
```
docker-compose scale rng=10
```
]
Of course, the graph doesn't change *yet*.
We need to add the new backends to the load balancer
configuration first.
---
## Reconfigure the load balancer
- The command is similar to the one before
- We need to pass the list of all backends
.exercise[
- Reconfigure the load balancer:
```
docker run --rm \
--volumes-from dockercoins_rng-lb_1 \
--net container:dockercoins_rng-lb_1 \
jpetazzo/hamba reconfigure 80 \
$(for N in $(seq 1 10); do
echo dockercoins_rng_$N:80
done)
```
]
---
## Automating the process
- Nobody loves artisan YAML handy craft
- This can be automated very easily
- To make things easier, we can use a label:
*each container behind a load balancer will
have a `loadbalancer` label giving the name
of that loadbalancer*
- This is implemented by two scripts:
- add-load-balancer-v2.py
- reconfigure-load-balancers.py
---
# Going further
Deploying a new version (difficulty: easy)
@@ -4596,12 +4982,14 @@ Harder projects:
- Terminate containers and remove them:
```
docker-compose kill
docker-compose rm -f
docker-compose down
```
]
Note: `docker-compose down` also deletes the
networks that had been created for the application.
---
class: pic
@@ -4643,7 +5031,7 @@ class: pic
---
## Storing files into Consul
## Storing files in Consul
- We will use [Benjamin Wester's consulfs](
https://github.com/bwester/consulfs)
@@ -4780,6 +5168,8 @@ At this point, `ls -l ~/consul` should show `docker` and
]
.icon[![Warning](warning.png)] Go back to node1 after this.
---
## A few words on this strategy
@@ -4788,6 +5178,16 @@ At this point, `ls -l ~/consul` should show `docker` and
<br/>(to be fair: anyone accessing Consul can wreck
serious havoc to your cluster anyway)
- ConsulFS doesn't support *all* POSIX operations,
<br/>so a few things (like `mv`) will not work)
- As a consequence, with Machine 0.6, you cannot
run `docker-machine create` directly on top of ConsulFS
---
## What if Consul becomes unavailable?
- If Consul becomes unavailable (e.g. loses quorum),
<br/>you won't be able to access your credentials
@@ -4797,6 +5197,7 @@ At this point, `ls -l ~/consul` should show `docker` and
- You can still access each Docker Engine over the
local UNIX socket (and repair Consul that way)
---
# Highly available Swarm managers