Skip to content
This repository has been archived by the owner on Jun 13, 2021. It is now read-only.

Demonstrate docker app build using dockercoins sample app #684

Merged
merged 1 commit into from
Oct 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/dockercoins/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2015 Jérôme Petazzoni

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
11 changes: 11 additions & 0 deletions examples/dockercoins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# dockercoins

This is the demo application originally used in Jérôme Petazzoni's [orchestration workshop](https://github.com/jpetazzo/container.training).

[Kubernetes Hands-on Workshop](https://training.play-with-kubernetes.com/kubernetes-workshop/)
```
rng = web service generating random bytes
hasher = web service computing hash of POSTed data
worker = background process using rng and hasher
webui = web interface to watch progress
```
24 changes: 24 additions & 0 deletions examples/dockercoins/coins.dockerapp/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
version: "3.7"

services:
rng:
build: rng
ports:
- "${rng.port}:80"

hasher:
build: hasher
ports:
- "${hasher.port}:80"

webui:
build: webui
ports:
- "${webui.port}:80"

redis:
image: redis

worker:
build: worker

9 changes: 9 additions & 0 deletions examples/dockercoins/coins.dockerapp/metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Version of the application
version: 0.1.0
# Name of the application
name: coins
# A short description of the application
description:
# List of application maintainers with name and email for each
maintainers:
- name: Jérôme Petazzoni
6 changes: 6 additions & 0 deletions examples/dockercoins/coins.dockerapp/parameters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
webui:
port: 8000
rng:
port: 8001
hasher:
port: 8002
10 changes: 10 additions & 0 deletions examples/dockercoins/hasher/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM ruby:alpine
RUN apk add --update build-base curl
RUN gem install sinatra
RUN gem install thin
ADD hasher.rb /
CMD ["ruby", "hasher.rb"]
EXPOSE 80
HEALTHCHECK \
--interval=1s --timeout=2s --retries=3 --start-period=1s \
CMD curl http://localhost/ || exit 1
18 changes: 18 additions & 0 deletions examples/dockercoins/hasher/hasher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require 'digest'
require 'sinatra'
require 'socket'

set :bind, '0.0.0.0'
set :port, 80

post '/' do
# Simulate a bit of delay
sleep 0.1
content_type 'text/plain'
"#{Digest::SHA2.new().update(request.body.read)}"
end

get '/' do
"HASHER running on #{Socket.gethostname}\n"
end

5 changes: 5 additions & 0 deletions examples/dockercoins/rng/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM python:alpine
RUN pip install Flask
COPY rng.py /
CMD ["python", "rng.py"]
EXPOSE 80
32 changes: 32 additions & 0 deletions examples/dockercoins/rng/rng.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from flask import Flask, Response
import os
import socket
import time

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):
# Simulate a little bit of delay
time.sleep(0.1)
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)

7 changes: 7 additions & 0 deletions examples/dockercoins/webui/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:4-slim
RUN npm install express
RUN npm install redis
COPY files/ /files/
COPY webui.js /
CMD ["node", "webui.js"]
EXPOSE 80
5 changes: 5 additions & 0 deletions examples/dockercoins/webui/files/d3.min.js

Large diffs are not rendered by default.

111 changes: 111 additions & 0 deletions examples/dockercoins/webui/files/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<!doctype html>
<html>
<head>
<title>DockerCoin Miner WebUI</title>
<link rel="stylesheet" type="text/css" href="rickshaw.min.css">
<style>
#graph {
background-color: #eee;
width: 800px;
height: 400px;
}
#tweet {
color: royalblue;
}
</style>
<script src="jquery.js"></script>
<script src="d3.min.js"></script>
<script src="rickshaw.min.js"></script>
<script>

String.prototype.format = function () {
var args = arguments;
return this.replace(/\{(\d+)\}/g, function (m, n) { return args[n]; });
};

var series = [];
var points = []
var graph = null;

function refresh () {
$.ajax({ url: "json" }).done(function (data) {
series.push(data);
while (series.length < 250) {
data = JSON.parse(JSON.stringify(data));
data.now -= 1;
series.unshift(data);
}
while (series.length > 250) {
series.shift();
}
while (points.length > 0) {
points.pop();
}
var speed;
for (var i=0; i<series.length-1; i++) {
// Compute instantaneous speed
var s1 = series[i];
var s2 = series[i+1];
speed = (s2.hashes-s1.hashes)/(s2.now-s1.now);
points.push({ x: s2.now, y: speed });
}
$("#speed").text("~" + speed.toFixed(1) + " hashes/second");
var msg = ("I'm attending a @docker orchestration workshop, "
+ "and my #DockerCoins mining rig is crunching "
+ speed.toFixed(1) + " hashes/second! W00T!");
$("#tweet").attr(
"href",
"https://twitter.com/intent/tweet?text="+encodeURIComponent(msg)
);
if (graph == null) {
graph = new Rickshaw.Graph({
renderer: "area",
stroke: true,
width: 800,
height: 400,
element: $("#graph")[0],
preserve: true,
series: [
{ name: "Coins",
color: "steelblue",
data: points
}
]
});
graph.render();
var yAxis = new Rickshaw.Graph.Axis.Y({
graph: graph,
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
ticksTreatment: "glow"
});
yAxis.render();
} else {
graph.update();
$("text").css({
"font-size": "15px",
"font-weight": "normal",
"opacity": 0.5,
});
}
});
}

$(function () {
setInterval(refresh, 1000);
});
</script>
</head>
<body>

<h1>DockerCoin Miner WebUI</h1>

<div id="graph"></div>

<h2>
Current mining speed:
<span id="speed">-</span>
<a id="tweet" href="#">(Tweet this!)</a>
</h2>

</body>
</html>
5 changes: 5 additions & 0 deletions examples/dockercoins/webui/files/jquery-1.11.3.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions examples/dockercoins/webui/files/jquery.js
1 change: 1 addition & 0 deletions examples/dockercoins/webui/files/rickshaw.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions examples/dockercoins/webui/files/rickshaw.min.js

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions examples/dockercoins/webui/webui.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
var express = require('express');
var app = express();
var redis = require('redis');

var client = redis.createClient(6379, 'redis');
client.on("error", function (err) {
console.error("Redis error", err);
});

app.get('/', function (req, res) {
res.redirect('/index.html');
});

app.get('/json', function (req, res) {
client.hlen('wallet', function (err, coins) {
client.get('hashes', function (err, hashes) {
var now = Date.now() / 1000;
res.json( {
coins: coins,
hashes: hashes,
now: now
});
});
});
});

app.use(express.static('files'));

var server = app.listen(80, function () {
console.log('WEBUI running on port 80');
});

5 changes: 5 additions & 0 deletions examples/dockercoins/worker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM python:alpine
RUN pip install redis
RUN pip install requests
COPY worker.py /
CMD ["python", "worker.py"]
70 changes: 70 additions & 0 deletions examples/dockercoins/worker/worker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import logging
import os
from redis import Redis
import requests
import time

DEBUG = os.environ.get("DEBUG", "").lower().startswith("y")

log = logging.getLogger(__name__)
if DEBUG:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
logging.getLogger("requests").setLevel(logging.WARNING)


redis = Redis("redis")


def get_random_bytes():
r = requests.get("http://rng/32")
return r.content


def hash_bytes(data):
r = requests.post("http://hasher/",
data=data,
headers={"Content-Type": "application/octet-stream"})
hex_hash = r.text
return hex_hash


def work_loop(interval=1):
deadline = 0
loops_done = 0
while True:
if time.time() > deadline:
log.info("{} units of work done, updating hash counter"
.format(loops_done))
redis.incrby("hashes", loops_done)
loops_done = 0
deadline = time.time() + interval
work_once()
loops_done += 1


def work_once():
log.debug("Doing one unit of work")
time.sleep(0.1)
random_bytes = get_random_bytes()
hex_hash = hash_bytes(random_bytes)
if not hex_hash.startswith('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")


if __name__ == "__main__":
while True:
try:
work_loop()
except:
log.exception("In work loop:")
log.error("Waiting 10s and restarting.")
time.sleep(10)