mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-02-14 17:49:59 +00:00
Save a bunch of things
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.swp
|
||||
*~
|
||||
ips.txt
|
||||
ips.html
|
||||
115
README.md
Normal file
115
README.md
Normal 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
|
||||
|
||||
|
||||
|
||||
10
cadvisor/docker-compose.yml
Normal file
10
cadvisor/docker-compose.yml
Normal 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"
|
||||
|
||||
29
dockercoins/docker-compose.yml
Normal file
29
dockercoins/docker-compose.yml
Normal 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
|
||||
|
||||
5
dockercoins/hasher/Dockerfile
Normal file
5
dockercoins/hasher/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM ruby
|
||||
RUN gem install sinatra
|
||||
ADD hasher.rb /
|
||||
CMD ["ruby", "hasher.rb"]
|
||||
EXPOSE 80
|
||||
16
dockercoins/hasher/hasher.rb
Normal file
16
dockercoins/hasher/hasher.rb
Normal 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
|
||||
|
||||
5
dockercoins/rng/Dockerfile
Normal file
5
dockercoins/rng/Dockerfile
Normal 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
29
dockercoins/rng/rng.py
Normal 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)
|
||||
|
||||
6
dockercoins/webui/Dockerfile
Normal file
6
dockercoins/webui/Dockerfile
Normal 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"]
|
||||
51
dockercoins/webui/files/index.html
Normal file
51
dockercoins/webui/files/index.html
Normal 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>
|
||||
5
dockercoins/webui/files/jquery-1.11.3.min.js
vendored
Normal file
5
dockercoins/webui/files/jquery-1.11.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dockercoins/webui/files/jquery.js
vendored
Symbolic link
1
dockercoins/webui/files/jquery.js
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
jquery-1.11.3.min.js
|
||||
44
dockercoins/webui/webui.js
Normal file
44
dockercoins/webui/webui.js
Normal 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');
|
||||
});
|
||||
|
||||
4
dockercoins/worker/Dockerfile
Normal file
4
dockercoins/worker/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM python
|
||||
RUN pip install redis
|
||||
COPY worker.py /
|
||||
CMD ["python", "worker.py"]
|
||||
71
dockercoins/worker/worker.py
Normal file
71
dockercoins/worker/worker.py
Normal 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()
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
@@ -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
70
prepare-vms/docker-nb.svg
Normal 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
56
prepare-vms/ips-txt-to-html.py
Executable 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
35
prepare-vms/postprep.rc
Executable 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
23
prepare-vms/rc
Normal 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
BIN
prepare-vms/swarm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
@@ -4,5 +4,3 @@ www:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- "htdocs:/usr/share/nginx/html"
|
||||
|
||||
|
||||
193
www/htdocs/index.html
Normal file
193
www/htdocs/index.html
Normal 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
BIN
www/htdocs/keyboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Reference in New Issue
Block a user