diff --git a/www/htdocs/index.html b/www/htdocs/index.html index 138cee58..1f19ab31 100644 --- a/www/htdocs/index.html +++ b/www/htdocs/index.html @@ -314,8 +314,8 @@ Now we can stop the generator. .icon[![Warning](warning.png)] Again, pay attention to the port mapping! -The container log says that it's listening on port 80, -but it's mapped to port 8002 on the host. +The container log says that it's listening on port 80, +but it's mapped to port 8002 on the host. You can see the mapping in `docker-compose.yml`. @@ -352,14 +352,14 @@ The invocation of `ab` will be slightly more complex as well. .exercise[ - Execute 100 requests in a row: - + ``` ab -n 100 -T application/octet-stream \ -p /tmp/random localhost:8002/ ``` - Execute 100 requests with 10 requests in parallel: - + ``` ab -c 10 -n 100 -T application/octet-stream \ -p /tmp/random localhost:8002/ @@ -658,7 +658,7 @@ docker run -d -p 80 jpetazzo/hamba 80 www1 1234 www2 2345 - The good - We scaled a service, added a load balancer - + We scaled a service, added a load balancer -
without changing a single line of code - The bad @@ -1192,7 +1192,7 @@ class: title - Dynamic - the system decides what goes where - + - requires extra components (HA KV...) - scaling can be finer-grained, more efficient @@ -1360,23 +1360,77 @@ class: pic # Setting up our Swarm cluster -- This is usually done by **Docker Machine** -
( or by custom deployment scripts) +- This can be done manually or with **Docker Machine** -- We will do a simplified version here (without TLS), -
to give you an idea of what's involved +- Manual deployment: + + - with TLS: certificate generation is painful +
(needs dual-use certs) + + - without TLS: easier, but insecure +
(unless you run on your internal/private network) + +- Docker Machine deployment: + + - generates keys, certificates, and deploys them for you + + - can also create VMs + +--- + +# The Way Of The Machine + +- Install `docker-machine` (single binary download) + +- Set a few environment variables (cloud credentials) + +- Create one or more machines: +
`docker-machine create -d digitalocean node42` + +- List machines and their status: +
`docker-machine ls` + +- Select a machine for use: +
`eval $(docker-machine env node42)` +
(this will set a few environment variables) + +- Execute regular commands with Docker, Compose, etc. +
(they will pick up remote host address from environment) + +--- + +# Docker Machine `generic` driver + +- Most drivers work the same way: + + - use cloud API to create instance + + - connect to instance over SSH + + - install Docker + +- The `generic` driver skips the first step + +- It can install Docker on any machine, +
as long as you have SSH access + +- We will use that! + +--- + +# Swarm deployment - Components involved: - service discovery mechanism
(we'll use Docker's hosted system) - - swarm agent -
(runs on each node, registers it with service discovery) - - swarm manager
(runs on `node1`, exposes Docker API) + - swarm agent +
(runs on each node, registers it with service discovery) + --- ## Service discovery @@ -1393,8 +1447,8 @@ class: pic .exercise[ -- Run `docker run swarm create` -- Save the output carefully: it's your token +- Run `TOKEN=$(docker run swarm create)` +- Save `$TOKEN` carefully: it's your token
(it's the unique identifier for your cluster) ] @@ -1410,74 +1464,234 @@ class: pic - Every 20s (by default), tells to the discovery system:
"Hello, there is a Swarm node at A.B.C.D:EFGH" +- Must know the node's IP address +
(sorry, it can't figure it out by itself, because +
it doesn't know whether to use public or private addresses) + - The node continues to work even if the agent dies ---- - -## Join the cluster - -.exercise[ - -- Connect to `node2` - -- Start the swarm agent: -
`docker run -d swarm join \` -
` --advertise A.B.C.D:55555 token://XXX` -
.small[(`A.B.C.D` is the IP address of `node2`, `XXX` is the token generated earlier)] - -- Check that the node registered successfully: -
`docker swarm list token://XXX` - -- Repeat on nodes 3, 4, 5 - -] - -Note: the Docker daemon on your VMs listens on port 55555 +- Automatically started by Docker Machine +
(when the `--swarm` option is passed) --- ## Swarm manager -- Today: must run on the "master" node +- Today: must run on the leader node -- Later: can run on multiple nodes, with master election +- Later: can run on multiple nodes, with leader election + +- Automatically started by Docker Machine +
(when the `--swarm-master` option is passed) .exercise[ - Connect to `node1` -- Start the swarm manager: -
`docker run -d -p 10000:2375 swarm manage token://XXX` +- "Create" a node with Docker Machine + + .small[ + ``` + docker-machine create node1 --driver generic \ + --swarm --swarm-master --swarm-discovery token://$TOKEN \ + --generic-ssh-user docker --generic-ip-address 1.2.3.4 + ``` + ] ] -- Remember to replace XXX with your token! -- The Swarm manager listens on port 2375 -- We're telling Docker to expose that on port 10000 +(Don't forget to replace 1.2.3.4 with the node IP address!) --- -## First contact with Swarm +## Check our node -- We must setup our CLI to talk to the Swarm master +Let's connect to the node *individually*. .exercise[ -- From any machine, set the environment variable: -
`export DOCKER_HOST=tcp://node1:10000` +- Select the node with Machine -- Check the output of `docker version` and `docker info` + ``` + eval $(docker-machine env node1) + ``` + +- Execute some Docker commands + + ``` + docker version + docker info + docker ps + ``` ] -- Remember to set the environment variable if you open another SSH session! - -- With Docker Machine, you would do a command like: -
`eval $(docker-machine env my-swarm-master)` +Two containers should show up: the agent and the manager. --- -# Running on Swarm +## Check our (single-node) Swarm cluster + +Let's connect to the manager instead. + +.exercise[ + +- Select the Swarm manager with Machine + + ``` + eval $(docker-machine env node1 --swarm) + ``` + +- Execute some Docker commands + + ``` + docker version + docker info + docker ps + ``` + +] + +The output is different! Let's review this. + +--- + +## `docker version` + +Swarm identifies itself clearly: + +``` +Client: + Version: 1.8.2 + API version: 1.20 + Go version: go1.4.2 + Git commit: 0a8c2e3 + Built: Thu Sep 10 19:19:00 UTC 2015 + OS/Arch: linux/amd64 + +Server: + Version: swarm/0.4.0 + API version: 1.16 + Go version: go1.4.2 + Git commit: d647d82 + Built: + OS/Arch: linux/amd64 +``` + +--- + +## `docker info` + +Swarm gives cluster information, showing all nodes: + +``` +Containers: 3 +Images: 6 +Role: primary +Strategy: spread +Filters: affinity, health, constraint, port, dependency +Nodes: 1 + node: 52.89.117.68:2376 + └ Containers: 3 + └ Reserved CPUs: 0 / 2 + └ Reserved Memory: 0 B / 3.86 GiB + └ Labels: executiondriver=native-0.2, + kernelversion=3.13.0-53-generic, + operatingsystem=Ubuntu 14.04.2 LTS, + provider=generic, storagedriver=aufs +CPUs: 2 +Total Memory: 3.86 GiB +Name: 2ec2e6c4054e +``` + +--- + +## `docker ps` + +- This one should show nothing at this point. + +- The Swarm containers are hidden. + +- This avoids unneeded pollution. + +- This also avoids killing them by mistake. + +--- + +## Add other nodes to the cluster + +- Let's use *almost* the same command line +
(but without `--swarm-master`) + +.exercise[ + +- Stay on `node1` (it has keys and certificates now!) + +- Add another node with Docker Machine + + .small[ + ``` + docker-machine create node2 --driver generic \ + --swarm --swarm-discovery token://$TOKEN \ + --generic-ssh-user docker --generic-ip-address 1.2.3.4 + ``` + ] +] + +Remember to update the IP address correctly. + +Repeat for all 4 nodes. + +Pro tip: look for name/address mapping in `/etc/hosts`. + +--- + +## Scripting + +To help you a little bit: + +``` +grep node[2345] /etc/hosts | grep -v ^127 | +while read IPADDR NODENAME +do docker-machine create $NODENAME --driver generic \ + --swarm --swarm-discovery token://$TOKEN \ + --generic-ssh-user docker \ + --generic-ip-address $IPADDR \ + + +--- + +# Running containers on Swarm + +Try to run a few `busybox` containers. + +Then, let's get serious: + +.exercise[ + +- Start a Redis service: +
`docker run -dP redis` + +- See the service address: +
`docker port $(docker ps -lq) 6379` + +] + +This can be any of your five nodes. + +--- + +# Running our app on Swarm - Swarm doesn't support builds (yet) @@ -1704,7 +1918,7 @@ Some Redis commands: `"SET key value"` `"GET key"` ## Notes - If you want to scale up or down, you have to re-do - the whole plumbing + the whole plumbing - This is not a design issue; just an implementation detail of the `connect-services.py` script