Save a bunch of things

This commit is contained in:
Jerome Petazzoni
2015-06-06 21:07:20 -07:00
parent 5f18fe86ea
commit a94147ca4e
26 changed files with 772 additions and 39 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*.swp
*~
ips.txt
ips.html

115
README.md Normal file
View File

@@ -0,0 +1,115 @@
# Orchestration at scales
Preparation:
- Create VMs with docker-fundamentals script.
- Put `ips.txt` file in `prepare-vms` directory.
- Generate HTML file.
- Open it in Chrome.
- Transform to PDF.
- Print it.
- Make sure that you have SSH keys loaded (`ssh-add -l`).
- Source `rc`.
- Source `postprep.rc`.
(This will install a few extra packages, add entries to
/etc/hosts, generate SSH keys, and deploy them on all hosts.)
- Set one group of machines for instructor's use.
- Remove it from `ips.txt`.
- Log into the first machine.
- Git clone this repo.
- Put up the web server.
- Use cli53 to add an A record for `view.dckr.info`.
# Description
Chaos Monkey.
App: pseudo-cryptocurrency?
- datastore: redis
- rng: microservice generating randomness
- hasher: microservice computing hashes
(really just computing sha256sum)
- worker: microservice using the previous two
to "mine" currency; a coin is a random string whose
hash starts with at least one zero; they are stored
in the datastore
- webui: display statistics
(Details: use map sha256->randorigin; also maintain
a list of length 1000 containing timestamps;
compute hash speed by CARD/(NOW()-oldest_ts))
Initial worker has a bug, and takes only 4 first
bytes of seed
## Intro to the environment
- SSH with password
- SSH with keys
- docker run blahblah
- sudo
- parallel-ssh example
## Intro to the app
## Deploy app on single machine
- Docker Compose
- frontend, backend, worker, datastore
- check CPU usage with docker top; docker stats; top
- cadvisor
- introduce ambassador/balancer
- scale appropriately
- fix bug, redeploy
## Clean up
- Stop all containers
## Get started with Swarm
- Explain that machine would take care of this
- Enable SSL certs everywhere
- Create token
- Start swarm master on node1
- Start swarm agent everywhere
- Point CLI to swarm master
- Check docker info, docker version
- Run a few hello worlds
## Deploy with Swarm
- compose up -> doesn't work because build
- docker-compose-tag + push
- docker-compose-pull
- replace each "linked-to" service by ambassador + single service
- workers: as is
- redis: single service + amba
- backend: scaled + lb; lb is haproxy with net:container
- scale up and see results
- check cadvisor
## Deploy with Mesos
# TODO
+ write pseudo miner
- write deployment scripts
- write chaos monkey
- docker-compose-tag
- docker-compose-pull
- haproxy ambassador
- docker-compose 1.3

View File

@@ -0,0 +1,10 @@
cadvisor:
image: google/cadvisor
ports:
- "8080:8080"
volumes:
- "/:/rootfs:ro"
- "/var/run:/var/run:rw"
- "/sys:/sys:ro"
- "/var/lib/docker/:/var/lib/docker:ro"

View File

@@ -0,0 +1,29 @@
rng:
build: rng
ports:
- "8001:80"
hasher:
build: hasher
ports:
- "8002:80"
webui:
build: webui
links:
- redis
ports:
- "8000:80"
volumes:
- "webui/files/:/files/"
redis:
image: redis
worker:
build: worker
links:
- rng
- hasher
- redis

View File

@@ -0,0 +1,5 @@
FROM ruby
RUN gem install sinatra
ADD hasher.rb /
CMD ["ruby", "hasher.rb"]
EXPOSE 80

View File

@@ -0,0 +1,16 @@
require 'digest'
require 'sinatra'
require 'socket'
set :bind, '0.0.0.0'
set :port, 80
post '/' do
content_type 'text/plain'
"#{Digest::SHA2.new().update(request.body.read)}"
end
get '/' do
"HASHER running on #{Socket.gethostname}\n"
end

View File

@@ -0,0 +1,5 @@
FROM python
RUN pip install Flask
COPY rng.py /
CMD ["python", "rng.py"]
EXPOSE 80

29
dockercoins/rng/rng.py Normal file
View File

@@ -0,0 +1,29 @@
from flask import Flask, Response
import os
import socket
app = Flask(__name__)
# Enable debugging if the DEBUG environment variable is set and starts with Y
app.debug = os.environ.get("DEBUG", "").lower().startswith('y')
hostname = socket.gethostname()
urandom = os.open("/dev/urandom", os.O_RDONLY)
@app.route("/")
def index():
return "RNG running on {}\n".format(hostname)
@app.route("/<int:how_many_bytes>")
def rng(how_many_bytes):
return Response(
os.read(urandom, how_many_bytes),
content_type="application/octet-stream")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80)

View File

@@ -0,0 +1,6 @@
FROM node
RUN npm install express
RUN npm install redis
COPY files/ /files/
COPY webui.js /
CMD ["node", "webui.js"]

View File

@@ -0,0 +1,51 @@
<!doctype html>
<html>
<head>
<title>DockerCoin Miner WebUI</title>
<script src="jquery.js"></script>
<script>
String.prototype.format = function () {
var args = arguments;
return this.replace(/\{(\d+)\}/g, function (m, n) { return args[n]; });
};
var stats = [];
function refresh () {
var content = $("#content");
$.ajax({ url: "json" }).done(function (data) {
stats.push(data);
while (stats.length > 20) {
stats.shift();
}
content.empty();
$.each(stats, function (index) {
var stat = stats[index];
content.append("Coins: {0}. ".format(stat.coins));
var s10 = Math.trunc(1000*stat.speed10)/1000;
var s100 = Math.trunc(1000*stat.speed100)/1000;
var s1000 = Math.trunc(1000*stat.speed1000)/1000;
var ago = Math.trunc(1000*stat.ago)/1000;
content.append("Average speed (10/100/1000): {0}/{1}/{2}. ".format(s10, s100, s1000));
content.append("Last result was {0}s ago.<br/>".format(ago));
});
});
}
function loop () {
setInterval(refresh, 3000);
}
</script>
</head>
<body>
<h1>DockerCoin Miner WebUI</h1>
<a href="#" onClick="refresh();">Refresh</a>
<a href="#" onClick="loop();">Every 3s</a>
<div id="content">Statistics will show up here.</div>
</body>
</html>

File diff suppressed because one or more lines are too long

1
dockercoins/webui/files/jquery.js vendored Symbolic link
View File

@@ -0,0 +1 @@
jquery-1.11.3.min.js

View File

@@ -0,0 +1,44 @@
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.redirect('/index.html');
});
app.get('/json', function (req, res) {
redis.lrange('timing', 0, -1, function (err, timing) {
redis.hlen('wallet', function (err, coins) {
timing.reverse();
var speed10 = '?';
var speed100 = '?';
var speed1000 = '?';
if (timing.length >= 10) {
speed10 = 10 / (timing[0]-timing[9]);
}
if (timing.length >= 100) {
speed100 = 100 / (timing[0]-timing[99]);
}
if (timing.length >= 1000) {
speed1000 = 1000 / (timing[0]-timing[999]);
}
var now = Date.now() / 1000;
res.json( {
speed10: speed10,
speed100: speed100,
speed1000: speed1000,
coins: coins,
now: now,
ago: now - timing[0]
});
});
});
});
app.use(express.static('files'));
var redis = require('redis').createClient(6379, 'redis');
var server = app.listen(80, function () {
console.log('WEBUI running on port 80');
});

View File

@@ -0,0 +1,4 @@
FROM python
RUN pip install redis
COPY worker.py /
CMD ["python", "worker.py"]

View File

@@ -0,0 +1,71 @@
import http.client
import logging
import os
from redis import Redis
import time
DEBUG = os.environ.get("DEBUG", "").lower().startswith("y")
log = logging.getLogger(__name__)
level = logging.DEBUG if DEBUG else logging.INFO
logging.basicConfig(level=level)
redis = Redis("redis")
def get_random_bytes():
log.debug("Connecting to RNG")
connection = http.client.HTTPConnection("rng")
log.debug("Sending request")
connection.request("GET", "/4")
response = connection.getresponse()
random_bytes = response.read()
log.debug("Got {} bytes of random data".format(len(random_bytes)))
return random_bytes
def hash_bytes(data):
log.debug("Connecting to HASHER")
connection = http.client.HTTPConnection("hasher")
log.debug("Sending request")
connection.request(
"POST", "/", data, {"Content-Type": "application/octet-stream"})
response = connection.getresponse()
hex_hash = response.read()
log.debug("Got hash: {}...".format(hex_hash[:8]))
return hex_hash
def work_once():
log.debug("Doing one unit of work")
random_bytes = get_random_bytes()
hex_hash = hash_bytes(random_bytes)
if not hex_hash.startswith(b'0'):
log.debug("No coin found")
return
log.info("Coin found: {}...".format(hex_hash[:8]))
created = redis.hset("wallet", hex_hash, random_bytes)
if not created:
log.info("We already had that coin")
return
log.debug("Storing timing information")
now = time.time()
redis.rpush("timing", now)
redis.ltrim("timing", -1000, -1)
log.debug("Getting timing information")
oldest = float(redis.lrange("timing", 0, 0)[0])
total = redis.llen("timing")
if oldest == now:
log.debug("oldest == now, can't compute timing")
return
speed = total / (now - oldest)
log.info("Speed over the last {} coins: {} coins/s".format(total, speed))
if __name__ == "__main__":
while True:
work_once()

View File

@@ -1,7 +0,0 @@
<a href="http://trng.dckr.org:9090">Live slides</a>
<p>
<a href="DockerSlides.pdf">PDF slides</a>
<p>
<a href="slave/fig.yml">fig.yml (mesos slave)</a>
<p>
<a href="token.txt">token swarm</a>

View File

@@ -1,21 +0,0 @@
master:
image: redjack/mesos-master
command: mesos-master --work_dir=/mesos
net: host
volt:
image: volt/volt
command: --master=trng.dckr.org:5050
ports:
- "8081:8080"
zk:
image: jplock/zookeeper
marathon:
image: mesosphere/marathon
command: --master trng.dckr.org:5050 --zk zk://zk:2181/marathon
links:
- zk:zk
ports:
- "8082:8080"

View File

@@ -1,9 +0,0 @@
slave:
image: redjack/mesos-slave
net: host
command: mesos-slave --master=trng.dckr.org:5050 --containerizers=docker,mesos
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/bin/docker

70
prepare-vms/docker-nb.svg Normal file
View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="466px" height="423.891px" viewBox="0 0 466 423.891" enable-background="new 0 0 466 423.891" xml:space="preserve">
<rect x="-43.5" y="37.005" display="none" fill-rule="evenodd" clip-rule="evenodd" fill="#E7E7E7" width="792" height="612"/>
<g>
<path id="outline_7_" fill-rule="evenodd" clip-rule="evenodd" d="M242.133,168.481h47.146v48.194h23.837
c11.008,0,22.33-1.962,32.755-5.494c5.123-1.736,10.872-4.154,15.926-7.193c-6.656-8.689-10.053-19.661-11.054-30.476
c-1.358-14.71,1.609-33.855,11.564-45.368l4.956-5.732l5.905,4.747c14.867,11.946,27.372,28.638,29.577,47.665
c17.901-5.266,38.921-4.02,54.701,5.088l6.475,3.734l-3.408,6.652c-13.345,26.046-41.246,34.113-68.524,32.687
c-40.817,101.663-129.68,149.794-237.428,149.794c-55.666,0-106.738-20.81-135.821-70.197l-0.477-0.807l-4.238-8.621
C4.195,271.415,0.93,247.6,3.145,223.803l0.664-7.127h40.315v-48.194h47.143v-47.145h94.292V74.191h56.574V168.481z"/>
<g display="none">
<path display="inline" fill="#394D54" d="M61.093,319.89c6.023,0,11.763-0.157,17.219-0.464c0.476-0.026,0.932-0.063,1.402-0.092
c0.005-0.002,0.008-0.002,0.012-0.002c13.872-0.855,25.876-2.708,35.902-5.57c0.002-0.002,0.004-0.002,0.006-0.002
c1.823-0.521,3.588-1.07,5.282-1.656c1.894-0.657,2.896-2.725,2.241-4.618c-0.656-1.895-2.722-2.899-4.618-2.24
c-12.734,4.412-29.535,6.842-50.125,7.298c-0.002,0-0.004,0-0.005,0c-10.477,0.232-21.93-0.044-34.352-0.843c0,0,0,0-0.001,0
c-0.635-0.038-1.259-0.075-1.9-0.118c-1.995-0.128-3.731,1.374-3.869,3.375c-0.136,1.999,1.376,3.73,3.375,3.866
c2.537,0.173,5.03,0.321,7.49,0.453c0.392,0.021,0.77,0.034,1.158,0.054l0,0C47.566,319.697,54.504,319.89,61.093,319.89z"/>
</g>
<g id="Containers_8_">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M86.209,179.744h3.227v34.052h-3.227V179.744z M80.02,179.744
h3.354v34.052H80.02V179.744z M73.828,179.744h3.354v34.052h-3.354V179.744z M67.636,179.744h3.354v34.052h-3.354V179.744z
M61.446,179.744H64.8v34.052h-3.354V179.744z M55.384,179.744h3.224v34.052h-3.224V179.744z M51.981,176.338h40.858v40.86H51.981
V176.338z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M133.354,132.598h3.229v34.051h-3.229V132.598z M127.165,132.598
h3.354v34.051h-3.354V132.598z M120.973,132.598h3.354v34.051h-3.354V132.598z M114.781,132.598h3.354v34.051h-3.354V132.598z
M108.593,132.598h3.352v34.051h-3.352V132.598z M102.531,132.598h3.222v34.051h-3.222V132.598z M99.124,129.193h40.863v40.859
H99.124V129.193z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M133.354,179.744h3.229v34.052h-3.229V179.744z M127.165,179.744
h3.354v34.052h-3.354V179.744z M120.973,179.744h3.354v34.052h-3.354V179.744z M114.781,179.744h3.354v34.052h-3.354V179.744z
M108.593,179.744h3.352v34.052h-3.352V179.744z M102.531,179.744h3.222v34.052h-3.222V179.744z M99.124,176.338h40.863v40.86
H99.124V176.338z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M180.501,179.744h3.225v34.052h-3.225V179.744z M174.31,179.744
h3.355v34.052h-3.355V179.744z M168.12,179.744h3.354v34.052h-3.354V179.744z M161.928,179.744h3.354v34.052h-3.354V179.744z
M155.736,179.744h3.354v34.052h-3.354V179.744z M149.676,179.744h3.222v34.052h-3.222V179.744z M146.271,176.338h40.861v40.86
h-40.861V176.338z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M180.501,132.598h3.225v34.051h-3.225V132.598z M174.31,132.598
h3.355v34.051h-3.355V132.598z M168.12,132.598h3.354v34.051h-3.354V132.598z M161.928,132.598h3.354v34.051h-3.354V132.598z
M155.736,132.598h3.354v34.051h-3.354V132.598z M149.676,132.598h3.222v34.051h-3.222V132.598z M146.271,129.193h40.861v40.859
h-40.861V129.193z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,179.744h3.226v34.052h-3.226V179.744z M221.457,179.744
h3.354v34.052h-3.354V179.744z M215.265,179.744h3.354v34.052h-3.354V179.744z M209.073,179.744h3.354v34.052h-3.354V179.744z
M202.884,179.744h3.354v34.052h-3.354V179.744z M196.821,179.744h3.224v34.052h-3.224V179.744z M193.416,176.338h40.861v40.86
h-40.861V176.338z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,132.598h3.226v34.051h-3.226V132.598z M221.457,132.598
h3.354v34.051h-3.354V132.598z M215.265,132.598h3.354v34.051h-3.354V132.598z M209.073,132.598h3.354v34.051h-3.354V132.598z
M202.884,132.598h3.354v34.051h-3.354V132.598z M196.821,132.598h3.224v34.051h-3.224V132.598z M193.416,129.193h40.861v40.859
h-40.861V129.193z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,85.451h3.226v34.053h-3.226V85.451z M221.457,85.451
h3.354v34.053h-3.354V85.451z M215.265,85.451h3.354v34.053h-3.354V85.451z M209.073,85.451h3.354v34.053h-3.354V85.451z
M202.884,85.451h3.354v34.053h-3.354V85.451z M196.821,85.451h3.224v34.053h-3.224V85.451z M193.416,82.048h40.861v40.86h-40.861
V82.048z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M274.792,179.744h3.224v34.052h-3.224V179.744z M268.602,179.744
h3.352v34.052h-3.352V179.744z M262.408,179.744h3.354v34.052h-3.354V179.744z M256.218,179.744h3.354v34.052h-3.354V179.744z
M250.026,179.744h3.354v34.052h-3.354V179.744z M243.964,179.744h3.227v34.052h-3.227V179.744z M240.561,176.338h40.86v40.86
h-40.86V176.338z"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M137.428,283.445c6.225,0,11.271,5.049,11.271,11.272
c0,6.225-5.046,11.271-11.271,11.271c-6.226,0-11.272-5.046-11.272-11.271C126.156,288.494,131.202,283.445,137.428,283.445"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M137.428,286.644c1.031,0,2.015,0.194,2.923,0.546
c-0.984,0.569-1.65,1.635-1.65,2.854c0,1.82,1.476,3.293,3.296,3.293c1.247,0,2.329-0.693,2.89-1.715
c0.395,0.953,0.615,1.999,0.615,3.097c0,4.458-3.615,8.073-8.073,8.073c-4.458,0-8.074-3.615-8.074-8.073
C129.354,290.258,132.971,286.644,137.428,286.644"/>
<path fill="#FFFFFF" d="M167.394,364.677c-27.916-13.247-43.239-31.256-51.765-50.915c-10.37,2.961-22.835,4.852-37.317,5.664
c-5.457,0.307-11.196,0.464-17.219,0.464c-6.942,0-14.26-0.205-21.94-0.613c25.6,25.585,57.094,45.283,115.408,45.645
C158.866,364.921,163.14,364.837,167.394,364.677z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

56
prepare-vms/ips-txt-to-html.py Executable file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python
clustersize = 5
pagesize = 12
###############################################################################
ips = list(open("ips.txt"))
assert len(ips)%clustersize == 0
clusters = []
while ips:
cluster = ips[:clustersize]
ips = ips[clustersize:]
clusters.append(cluster)
html = open("ips.html", "w")
html.write("<html><head><style>")
html.write("""
div {
float:left;
border: 1px solid black;
width: 25%;
padding: 4%;
font-size: x-small;
background-image: url("docker-nb.svg");
background-size: 15%;
background-position-x: 50%;
background-repeat: no-repeat;
}
.pagebreak {
page-break-before: always;
clear: both;
display: block;
height: 8px;
}
""")
html.write("</style></head><body>")
for i, cluster in enumerate(clusters):
if i>0 and i%pagesize==0:
html.write('<span class="pagebreak"></span>\n')
html.write("<div>")
html.write("<p>Here is the connection information to your very own ")
html.write("cluster for this orchestration workshop. You can connect ")
html.write("to each VM with your SSH client.</p>\n")
html.write("<p>login=docker password=training</p>\n")
html.write("<p>IP addresses:<ul>\n")
for ipaddr in cluster:
html.write("<li>%s</li>\n"%ipaddr)
html.write("</ul></p>")
html.write("</div>")
html.close()

35
prepare-vms/postprep.rc Executable file
View File

@@ -0,0 +1,35 @@
pssh -I tee /tmp/postprep.py <<EOF
#!/usr/bin/env python
import os
import sys
import urllib
clustersize = 5
myaddr = urllib.urlopen("http://myip.enix.org/REMOTE_ADDR").read()
addresses = list(l.strip() for l in sys.stdin)
def makenames(addrs):
return [ "node%s"%(i+1) for i in range(len(addrs)) ]
while addresses:
cluster = addresses[:clustersize]
addresses = addresses[clustersize:]
if myaddr not in cluster:
continue
names = makenames(cluster)
for ipaddr, name in zip(cluster, names):
os.system("grep ^%s /etc/hosts || echo %s %s | sudo tee -a /etc/hosts"
%(ipaddr, ipaddr, name))
if myaddr == cluster[0]:
os.system("[ -f .ssh/id_rsa ] || ssh-keygen -t rsa -f .ssh/id_rsa -P ''")
os.system("sudo easy_install pip")
os.system("sudo pip install docker-compose==1.3.0rc1")
os.system("sudo apt-get -qy install pssh")
EOF
pssh -I "chmod +x /tmp/postprep.py && /tmp/postprep.py" < ips.txt
pssh "[ -f .ssh/id_rsa ] || scp -o StrictHostKeyChecking=no node1:.ssh/id_rsa* .ssh"
pssh "grep docker@ .ssh/authorized_keys || cat .ssh/id_rsa.pub >> .ssh/authorized_keys"

23
prepare-vms/rc Normal file
View File

@@ -0,0 +1,23 @@
pssh () {
HOSTFILES="hosts ips.txt /tmp/hosts"
for HOSTFILE in $HOSTFILES; do
[ -f $HOSTFILE ] && break
done
[ -f $HOSTFILE ] || {
echo "No hostfile found (tried $HOSTFILES)"
return
}
parallel-ssh -h $HOSTFILE -l docker \
-O UserKnownHostsFile=/dev/null -O StrictHostKeyChecking=no \
-O ForwardAgent=yes \
"$@"
}
pcopykey () {
ssh-add -L | pssh --askpass --send-input \
"mkdir -p .ssh; tee .ssh/authorized_keys"
ssh-add -L | pssh --send-input \
"sudo mkdir -p /root/.ssh; sudo tee /root/.ssh/authorized_keys"
}

BIN
prepare-vms/swarm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@@ -4,5 +4,3 @@ www:
- "80:80"
volumes:
- "htdocs:/usr/share/nginx/html"

193
www/htdocs/index.html Normal file
View File

@@ -0,0 +1,193 @@
<!DOCTYPE html>
<html>
<head>
<title>Docker Orchestration Workshop</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css">
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
@import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
body { font-family: 'Droid Serif'; font-size: 150%; }
h1, h2, h3 {
font-family: 'Yanone Kaffeesatz';
font-weight: normal;
}
a {
text-decoration: none;
color: blue;
}
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
.red { color: #fa0000; }
.gray { color: #ccc; }
.small { font-size: 70%; }
.big { font-size: 140%; }
.underline { text-decoration: underline; }
.footnote {
position: absolute;
bottom: 3em;
}
.pic {
vertical-align: middle;
text-align: center;
padding: 0 0 0 0 !important;
}
img {
max-width: 100%;
max-height: 450px;
}
.title {
vertical-align: middle;
text-align: center;
}
.title {
font-size: 2em;
}
.title .remark-slide-number {
font-size: 0.5em;
}
.quote {
background: #eee;
border-left: 10px solid #ccc;
margin: 1.5em 10px;
padding: 0.5em 10px;
quotes: "\201C""\201D""\2018""\2019";
font-style: italic;
}
.quote:before {
color: #ccc;
content: open-quote;
font-size: 4em;
line-height: 0.1em;
margin-right: 0.25em;
vertical-align: -0.4em;
}
.quote p {
display: inline;
}
.icon img {
height: 1em;
}
.exercise {
background-color: #eee;
background-image: url("keyboard.png");
background-size: 1.4em;
background-repeat: no-repeat;
background-position: 0.2em 0.2em;
border: 2px dotted black;
}
.exercise::before {
content: "Exercise:";
margin-left: 1.8em;
}
li p { line-height: 1.25em; }
</style>
</head>
<body>
<textarea id="source">
class: title
# Docker <br/> Orchestration <br/> Workshop
---
# Pre-requirements
- Computer with network connection and SSH client
<br/>(on Windows, get [putty](http://www.putty.org/))
- GitHub account
- Docker Hub account
- Basic Docker knowledge
.exercise[
- This is the stuff you're supposed to do!
- Create [GitHub](https://github.com/) and
[Docker Hub](https://hub.docker.com) accounts now if needed
- Go to [view.dckr.info](http://view.dckr.info) to view those slides
]
---
# VM environment
- Each person gets 5 VMs
- They are *your* VMs
- They'll be up until tomorrow
- You have a little card with login+password+IP addresses
- You can automatically SSH from one VM to another
.exercise[
- Log into one of the VMs
- Check that you can SSH to `node1`
- Check the version of docker with `docker version`
]
Note: from now on, unless instructed, all commands have
to be done from the VMs.
---
# Our sample application
- Split into 5 microservices
- `rng` = web service generating random bytes
- `hasher` = web service accepting POST data and
returning its hash
- `worker` = background process using `rng` and `hasher`
- `redis` = data store for the results of the worker
- `webui` = web interface to watch progress
.exercise[
-
---
# Running on a single node
# Finding bottlenecks
# Scaling workers on a single node
# Scaling HTTP on a single node
# Introducing Swarm
# Setting up our Swarm cluster
# Running on Swarm
# Scaling on Swarm
# Cluster metrics
# Introducing Mesos
# Setting up our Mesos cluster
# Running on Mesos
# Network on Mesos
---
class: title
# Thanks! <br/> Questions?
### [@jpetazzo](https://twitter.com/jpetazzo) <br/> [@docker](https://twitter.com/docker)
</textarea>
<script src="https://gnab.github.io/remark/downloads/remark-0.5.9.min.js" type="text/javascript">
</script>
<script type="text/javascript">
var slideshow = remark.create();
</script>
</body>
</html>

BIN
www/htdocs/keyboard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB