From b2fc2827f23b6eb32d721bc8cc93f6eecddaf1ff Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Sun, 27 Sep 2015 22:10:32 -0700 Subject: [PATCH] Big update for LISA --- prepare-vms/postprep.rc | 2 +- www/htdocs/delay-hasher.png | Bin 0 -> 15687 bytes www/htdocs/delay-rng.png | Bin 0 -> 27049 bytes www/htdocs/index.html | 589 +++++++++++++++++++++++++++--------- 4 files changed, 448 insertions(+), 143 deletions(-) create mode 100644 www/htdocs/delay-hasher.png create mode 100644 www/htdocs/delay-rng.png diff --git a/prepare-vms/postprep.rc b/prepare-vms/postprep.rc index 0929edf3..98dfb46b 100755 --- a/prepare-vms/postprep.rc +++ b/prepare-vms/postprep.rc @@ -28,7 +28,7 @@ while addresses: os.system("sudo apt-get -qy install python-setuptools pssh apache2-utils httping htop") os.system("sudo easy_install pip") -os.system("sudo pip install docker-compose==1.4.1") +os.system("sudo pip install docker-compose==1.4.2") os.system("docker pull swarm:0.4.0") os.system("docker tag -f swarm:0.4.0 swarm") os.system("sudo curl -L https://github.com/docker/machine/releases/download/v0.4.1/docker-machine_linux-amd64 -o /usr/local/bin/docker-machine") diff --git a/www/htdocs/delay-hasher.png b/www/htdocs/delay-hasher.png new file mode 100644 index 0000000000000000000000000000000000000000..16c71a0430a7f87db1f82928a2feb1e111021d94 GIT binary patch literal 15687 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 literal 0 HcmV?d00001 diff --git a/www/htdocs/delay-rng.png b/www/htdocs/delay-rng.png new file mode 100644 index 0000000000000000000000000000000000000000..d5cdb7e1670f6de07472865a03f08b624150efcd GIT binary patch literal 27049 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 literal 0 HcmV?d00001 diff --git a/www/htdocs/index.html b/www/htdocs/index.html index 8a26e598..414cd0cf 100644 --- a/www/htdocs/index.html +++ b/www/htdocs/index.html @@ -101,27 +101,32 @@ class: title - Pre-requirements - VM environment - Our sample application +- Running services independently - Running the whole app on a single node -- Finding bottlenecks -- Scaling workers on a single node +- Identifying bottlenecks +- Measuring latency under load - Scaling HTTP on a single node +- Put a load balancer on it - Connecting to containers on other hosts -- Abstracting connection details +- Abstracting remote services with ambassadors +- Various considerations about ambassadors --- ## Outline (2/2) +- Docker for ops - Backups - Logs - Security upgrades - Network traffic analysis - Dynamic orchestration -- Introducing Mesos, Kubernetes, Swarm -- PAAS and other tools -- Setting up our Swarm cluster -- Running on Swarm +- Hands-on Swarm +- Deploying Swarm +- Cluster discovery +- Building our app on Swarm - Network plumbing on Swarm +- Going further --- @@ -156,21 +161,21 @@ class: title .exercise[ - Log into the first VM (`node1`) -- Check that you can SSH (without password) to `node2`\* +- Check that you can SSH (without password) to `node2` - Check the version of docker with `docker version` ] -\*Note: from now on, unless instructed, **all commands must -be run from the first VM, `node1`**. +.footnote[Note: from now on, unless instructed, **all commands must +be run from the first VM, `node1`**.] --- ## Brand new versions! -- Docker 1.8.2 +- Engine 1.8.2 -- Compose 1.4.1 +- Compose 1.4.2 - Swarm 0.4 @@ -219,7 +224,7 @@ Next: we will inspect components independently. --- -## Running components independently +# Running services independently First, we will run the random number generator (`rng`). @@ -433,22 +438,24 @@ We have available resources. ## Scaling workers on a single node -- Docker Compose supports scaling -- It doesn't deal with load balancing -- For services that *do not* accept connections, that's OK +- Docker Compose supports scaling.red[*] - Let's scale `worker` and see what happens! .exercise[ - In one SSH session, run `docker-compose logs worker` -- In another, run `docker-compose scale worker=4` +- In another, run `docker-compose scale worker=10` - See the impact on CPU load (with top/htop),
and on compute speed (with web UI) ] +You should see the compute speed increase ~3x (not 10x). + +.footnote[.red[*]With some limitations, as we'll see later.] + --- # Identifying bottlenecks @@ -528,7 +535,32 @@ Let's test and see what happens! ] -Take note of the number of requests/s. +-- + +Whatever we do, we get ~10 requests/second. + +Increasing concurrency doesn't help: +it just increases latency. + +--- + +## Discussion + +- When serving requests sequentially, they each take 100ms + +- When 10 requests arrive at the same time: + + - one request is served in 100ms + - another is served in 200ms + - another is served in 300ms + - ... + - another is served in 1000ms + +- All requests are queued and served by a single thread + +- It looks like `rng` doesn't handle concurrent requests + +- What about `hasher`? --- @@ -605,7 +637,7 @@ Take note of the performance numbers (requests/s). ## Benchmarking the hasher on smaller data -Here we hashed 1 meg. +Here we hashed 1,000,000 bytes. Later we will hash much smaller payloads. @@ -618,12 +650,6 @@ Let's repeat the tests with smaller data. ] -??? - -## Why do `rng` and `hasher` behave differently? - -![Equations on a blackboard](equations.png) - --- # Measuring latency under load @@ -671,27 +697,113 @@ What happens? --- +class: title + +Why? + +--- + +## Why does everything take (at least) 100ms? + +-- + +`rng` code: + +![RNG code screenshot](delay-rng.png) + +-- + +`hasher` code: + +![HASHER code screenshot](delay-hasher.png) + +--- + +class: title + +But ... + +WHY?!? + +--- + +## Why did we sprinkle this sample app with sleeps? + +- Deterministic performance +
(regardless of instance speed, CPUs, I/O...) + +-- + +- Actual code sleeps all the time anyway + +-- + +- When your code makes a remote API call: + + - it sends a request; + + - it sleeps until it gets the response; + + - it processes the response. + +--- + ## Why do `rng` and `hasher` behave differently? ![Equations on a blackboard](equations.png) +-- + +(Synchronous vs. asynchronous event processing) + +--- + +## How to make `rng` go faster + +- Obvious solution: comment out the `sleep` instruction + +-- + +- Real-world solution: use an asynchronous framework +
(e.g. use gunicorn with gevent) + +-- + +- New rule: we can't change the code! + +-- + +- Solution: scale out `rng` +
(dispatch `rng` requests on multiple instances) + --- # Scaling HTTP on a single node -The plan: +- We could try to scale with Compose: + + ``` + docker-compose scale rng=3 + ``` + +- Compose doesn't deal with load balancing + +- We would get 3 instances ... + +- ... But only the first one would serve traffic + +--- + +## The plan - Stop the `rng` service first -- Scale `rng` to multiple containers +- Create multiple identical `rng` containers -- Put a load balancer in front of it +- Put a load balancer in front of them - Point other services to the load balancer -Note: Compose does not support that kind of scaling yet. -
We will have to do it manually for now. - --- ## Stopping `rng` @@ -767,7 +879,9 @@ docker run -d -p 80 jpetazzo/hamba 80 www1 1234 www2 2345 --- -## Add our load balancer to the Compose file +# Put a load balancer on it + +Let's add our load balancer to the Compose file. .exercise[ @@ -839,32 +953,27 @@ If you get errors about port 8001, make sure that - The good We scaled a service, added a load balancer - -
without changing a single line of code +
without changing a single line of code. - The bad - We manually copy-pasted sections in `docker-compose.yml` + We manually copy-pasted sections in `docker-compose.yml`. + + Improvement: write scripts to transform the YAML file. - The ugly - If we scale up/down, we have to restart everything + If we scale up/down, we have to restart everything. ---- - -## Ideas to improve the situation - -- Parse `docker-compose.yml` to automatically replace - services with their scaled counterparts - -- Replace Docker Links with network namespace sharing - -- More on this later + Improvement: reconfigure the load balancer dynamically. --- # Connecting to containers on other hosts -- We want to scale across multiple nodes +- So far, our whole stack is on a single machine + +- We want to scale out (across multiple nodes) - We will deploy the same stack multiple times @@ -892,6 +1001,28 @@ If you get errors about port 8001, make sure that --- +## Making Redis available on its default port + +There are two strategies. + +- `docker run -p 6379:6379 redis` + + - the container has its own, isolated network stack + - Docker creates a port mapping rule through iptables + - slight performance overhead + - port number is explicit (visible through Docker API) + +- `docker run --net host redis` + + - the container uses the network stack of the host + - when it binds to 6379/tcp, that's 6379/tcp on the host + - allows raw speed (no overhead due to iptables/bridge) + - port number is not visible through Docker API + +Choose wisely! + +--- + ## Deploy Redis .exercise[ @@ -984,6 +1115,22 @@ those files are only present locally, not on the remote nodes. --- +## Start the stack on the first machine + +- Nothing special to do here + +- Just bring up the application like we did before + +.exercise[ + +- `docker-compose up -d` + +] + +- Check in the web browser that it's running correctly. + +--- + ## Start the stack on another machine - We will set the `DOCKER_HOST` variable @@ -1040,7 +1187,7 @@ those files are only present locally, not on the remote nodes. --- -# Abstracting connection details +# Abstracting remote services with ambassadors - What if we can't/won't run Redis on its default port? @@ -1114,7 +1261,7 @@ Shortcut: `docker-compose.yml-ambassador` --- -# Discussion about ambassadors +# Various considerations about ambassadors - "But, ambassadors are adding an extra hop!" @@ -1206,6 +1353,14 @@ Shortcut: `docker-compose.yml-ambassador` --- +class: title + +# Interlude
+ +# Docker for ops + +--- + # Backups - Redis is still running (with name `myredis`) @@ -1290,16 +1445,12 @@ Shortcut: `docker-compose.yml-ambassador` - Sorry, this part won't be hands-on -- Two (and a half) strategies: +- Two strategies: - log to plain files on volumes - - log to stdout with the syslog driver - - - log to stdout with the JSON driver - -- The last one doesn't really count -
(but it's the default) + - log to stdout +
(and use a logging driver) --- @@ -1326,28 +1477,25 @@ Shortcut: `docker-compose.yml-ambassador` --- -## Logging to syslog +## Logging to stdout - All containers should write to stdout/stderr -- Change Docker start options to add `--log-driver syslog` +- Docker will collect logs and pass them to a logging driver + +- Available drivers: +
json-file (default), syslog, journald, gelf, fluentd + +- Change driver by passing `--log-driver` option to daemon
(On Ubuntu, tweak `DOCKER_OPTS` in `/etc/default/docker`) -- When you do that, you can't use `docker logs` anymore +- For now, only json-files supports logs retrieval +
(i.e. `docker logs`) ---- +- Warning: json-file doesn't rotate logs by default +
(but this can be changed with `--log-opt`) -## Logging to JSON files - -- That's the default option - -- All containers should write to stdout/stderr - -- You can use `docker logs` - -- But those local JSON files are, well, local - -- ... And they will eventually use up all the space +See: https://docs.docker.com/reference/logging/overview/ --- @@ -1422,19 +1570,23 @@ Shortcut: `docker-compose.yml-ambassador` ## Install and start `ngrep` +Ngrep uses libpcap (like tcpdump) to sniff network traffic. + .exercise[ - Start a container with the same network namespace: -
`docker run --net container:myredis -ti ubuntu` +
`docker run --net container:myredis -ti alpine` - Install ngrep: -
`apt-get update && apt-get install -y ngrep` +
`apk update && apk add ngrep` - Run ngrep:
`ngrep -tpd eth0 -Wbyline . tcp` ] +You should see a stream of Redis requests and responses. + --- class: title @@ -1555,10 +1707,12 @@ class: title - OK for some scenarios (Jenkins, grid...) -- Not OK (yet) for Compose build, links... +- Not OK (yet.red[*]) for Compose build, links... - We'll see it (briefly) in action +.footnote[.red[*]By "not OK" we mean "requires extra elbow grease."] + --- ## PAAS on Docker @@ -1682,7 +1836,7 @@ class: pic --- -## Swarm deployment +# Deploying Swarm - Components involved: @@ -1697,7 +1851,7 @@ class: pic --- -## Service discovery +# Cluster discovery - Possible backends: @@ -1955,7 +2109,7 @@ This can be any of your five nodes. --- -## Building our app on Swarm +# Building our app on Swarm - Swarm has partial support for builds @@ -2011,19 +2165,24 @@ This can be any of your five nodes. ## Build, Tag, And Push +Let's inspect the source code of `build-tag-push.py` and run it. + +.icon[![Warning](warning.png)] It is better to run it against a single node! + +(There are some race conditions within Swarm when building+pushing too fast.) + .exercise[ -- Look at `build-tag-push.py` +- Point to a single node: +
`eval $(docker-machine env node1)` + +- Run the script (from the `dockercoins` directory): +
`../build-tag-push.py` + +- Inspect the `docker-compose.yml-XXX` file that it created -- Run it! ] -- Run it in the directory containing `docker-compose.yml` -
(suggestion: `../build-tag-push.py`) - -- It will create a new `docker-compose.yml` file -
(named `docker-compose.yml-XXX` where `XXX` is a timestamp) - --- ## Can we run this now? @@ -2032,7 +2191,11 @@ Let's try! .exercise[ -- Run `docker-compose -f docker-compose.yml-XXX up` +- Switch back to the Swarm cluster: +
`eval $(docker-machine env node1 --swarm) + +- Bring up the application: +
`docker-compose -f docker-compose.yml-XXX up` ] @@ -2089,11 +2252,15 @@ So, what do‽ - Linking would work -- But seriously, what's the point? +- But all containers would end up on the same node + +-- + +- So having a cluster would be pointless! --- -## Network plumbing on Swarm +# Network plumbing on Swarm - We will use one-tier, dynamic ambassadors
(as seen before) @@ -2126,61 +2293,47 @@ So, what do‽ ``` docker run --rm --volumes-from amba jpetazzo/hamba \ - 80 backend1 port1 backend2 port2 ... + reconfigure 80 backend1 port1 backend2 port2 ... ``` -??? +.footnote[Note: configuration validation and error messages +will be logged by the ambassador, not the `reconfigure` container.] -## Another use of network namespaces +--- -- Two (or more) containers can share a network stack +## Should we use `links` for our ambassadors? -- They will have the same IP address +Technically, we could use links. -- They will be able to connect over `localhost` +- Before starting an app container: + + start the ambassador(s) it needs -- Other containers can be added later +- When starting an app container: -??? + link it to its ambassador(s) -## Connecting over localhost +But we wouldn't be able to use `docker-compose scale` anymore. -.exercise[ +--- -- Start a container running redis: -
`docker run -d --name myredis redis` +## Network namespaces and `extra_hosts` -- Start another container in the same network namespace: -
`docker run -ti --net container:myredis ubuntu` +This is our plan: -- In the 2nd container, install telnet: -
`apt-get update && apt-get install telnet` +- Replace each `link` with an `extra_host`, +
pointing to the `127.127.X.X` address space -- In the 2nd container, connect to redis on localhost: -
`telnet localhost 6379` +- Start app containers normally +
(`docker-compose up`, `docker-compose scale`) -] +- Start ambassadors after app containers are up: -Some Redis commands: `"SET key value"` `"GET key"` + - ambassadors bind to `127.127.X.X` -??? + - they share their client's network namespace -class: hidden - -## Same IP address - -- Let's confirm that our containers share - the same IP address - -.exercise[ - -- Run a couple of times: -
`docker run ubuntu ip addr ls` - -- Now run a couple of times: -
`docker run --net container:myredis ubuntu ip addr ls` - -] +- Reconfigure ambassadors each time something changes --- @@ -2204,20 +2357,19 @@ class: hidden .icon[![Warning](warning.png)] Services should try to reconnect! -??? +--- -## .icon[![Warning](warning.png)] Work in progress +## "Design for failure," they said -- Ideally, we would use `--add-host` - (and Docker Compose counterpart, `extra_hosts`) to populate - `/etc/hosts` +- When the containers are started, the network is not ready -- Unfortunately, this does not work yet -
(See [Swarm issue #908](https://github.com/docker/swarm/issues/908) - for details) +- First connection attempts **will fail** -- We'll populate `/etc/hosts` manually instead -
(with `docker exec`) +- App should try to reconnect + +- It is OK to crash and restart + +- Exponential back-off is nice --- @@ -2241,16 +2393,169 @@ class: hidden --- -## Putting it together +## Convert links to ambassadors -- build-tag-push -- link-to-ambassadors -- up! -- scale! -- create-ambassadors -- configure-ambassadors +- When we ran `build-tag-push.py` earlier, +
it generated a new `docker-compose.yml-XXX` file. -Repeat last 3 steps. +.exercise[ + +- Run the first script to create a new YAML file: +
`../link-to-ambassadors.py docker-compose.yml-XXX a.yml` + +- Look how the file was modified: +
`diff docker-compose.yml-XXX a.yml` + +] + +The script can take one or two file name arguments: + +- two arguments indicate input and output files to use; +- with one argument, the file will be modified in place. + +--- + +## Bring up the application + +The application can now be started and scaled. + +Remember to use the *new* YAML file! + +.exercise[ + +- Start the application: +
`docker-compose -f a.yml up -d` + +- Scale the application: +
`docker-compose -f a.yml scale worker=5 rng=10` + +] + +Note: you can scale everything as you like, *except Redis*, +because it is stateful. + +--- + +## Create the ambassadors + +This has to be executed each time you create new services +or scale up existing ones. + +The script takes the YAML file as its only argument. + +It will scan and compare: + +- the list of app containers, +- the list of ambassadors. + +It will create missing ambassadors. + +.exercise[ + +- Run the script! +
`../create-ambassadors.py a.yml` + +] + +--- + +## Configure the ambassadors + +All ambassadors are created but they still need configuration. + +That's the purpose of the last script. + +It will gather: + +- the list of app backends, +- the list of ambassadors. + +Then it will configure all ambassadors will all found backends. + +.exercise[ + +- Run it! +
`../configure-ambassadors.py a.yml` + +] + +--- + +## Check what we did + +.exercise[ + + +- Find out the address of the web UI: +
`docker-compose ps webui` + +- Point your browser to it + +- Check the logs: +
`docker-compose logs` + +] + +--- + +# Going further + +Scaling the application (easy) + +- Run `docker-compose scale` + +- Re-create ambassadors + +- Re-configure ambassadors + +- No downtime + +--- + +## Going further + +Deploying a new version (easy) + +- Just re-run all the steps! + +- However, Compose will re-create the containers + +- You will have to re-create ambassadors +
(and configure them) + +- You will have to cleanup old ambassadors +
(left as an exercise for the reader) + +- You will experience a little bit of downtime + +--- + +## Going further + +Zero-downtime deployment (medium) + +- Isolate stateful services +
(like we did earlier for Redis) + +- Do blue/green deployment: + + - deploy and scale version N + + - point a "top-level" load balancer to the app + + - deploy and scale version N+1 + + - put both apps in the "top-level" balancer + + - slowly switch traffic over to app version N+1 + +--- + +## Going further + +Try two-tier or three-tier ambassador deployments. + +Try overlay networking instead of ambassadors. ---