Key concepts for stateful services in Kubernetes
Kubernetes Boston
Ryan Wallner - Technical Evangelist
@RyanWallner - ryan.wallner@clusterhq.com
Avid outdoorsman, works on containers
Previously at IBM and EMC
Worked on SDN/OpenStack/Containers
Who am i?
Agenda
- Containers
- Sateful / Stateless
- Managing State
- Persistence / Volumes
- Kubernetes Volumes
- Demo
- Q/A
CONTAINERs
- Container = Process and Resource Isolation
- Linux Process (think of as light weight app vm)
- Does not need a hypervisor, shares a linux kernel
- Enables new architectures such as Microservices
http://en.community.dell.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-01-55/lxc_2D00_vm.jpg
"Stateful" Container
- Secrets - public/private keys, password, etc
- Databases - databases, sharded, clustered.
- Logs - to collect support bundles, run analytics for data mining, etc.
- Other - CI repo data, transcoded bits...
"Stateless" Container
- Nothing to Disk
- Web Front-End
- Can stop and start as many containers as you like
- Like http is stateless
- Container is ephemeral
- Does not care about what has happened or changed.
Use Case
Stateless Streaming
Stateless Web
Stateful DB
K8s
Cluster
var Twitter = require('twitter');
var MongoClient = require('mongodb').MongoClient;
Server = require('mongodb').Server;
var client = new Twitter({
consumer_key: process.env.CONSUMER_KEY,
consumer_secret: process.env.CONSUMER_SECRET,
access_token_key: process.env.ACCESS_TOKEN_KEY,
access_token_secret: process.env.ACCESS_TOKEN_SECRET
});
client.stream('statuses/filter', {
track: process.env.TWITTER_TRACK
}, function(stream) {
stream.on('data', function(tweet) {
console.log(tweet.text);
var client = new MongoClient(new Server(process.env.MONGOSERVER, "27017", {
auto_reconnect: true
}, {
numberOfRetries: 10,
retryMilliseconds: 500
}));
client.open(function(err, client) {
if (err) {
console.log(err);
} else {
var db = client.db("test");
db.collection('records', function(err, collection) {
collection.insert({
'tweet': tweet.text
}, {
safe: true
}, function(err, result) {
if (!err) {
console.log(result);
} else {
console.log(err);
}
});
});
}
});
});
stream.on('error', function(error) {
console.log("error getting tweets");
console.log(error);
});
});
Stateless Streaming Service
var express = require('express');
var MongoClient = require('mongodb').MongoClient;
var app = express();
var PORT = 8080;
var fs = require('fs'); // this engine requires the fs module
app.engine('ntl', function(filePath, options, callback) { // define the template engine
fs.readFile(filePath, function(err, content) {
if (err) return callback(new Error(err));
var rendered = content.toString().replace('#tweet#', '<style type="text/css"> body { background-color: #f3f3f3; }</style><div id="twt" style="display: inline-block; position: fixed; top: 0; bottom: 0; left: 0; right: 0; width: 500px; height: 200px; margin: auto; font-size:22pt; font-weight:bold; font-family: Helvetica Neue, sans-serif; letter-spacing: -1px; line-height: 1; background-color: #f3f3f3;"><p>' + options.tweet + '</p></div>');
return callback(null, rendered);
})
});
app.set('views', './views'); // specify the views directory
app.set('view engine', 'ntl'); // register the template engine
app.get('/', function(req, res) {
console.log('Contacting MongoDB');
// Connect to the db
MongoClient.connect("mongodb://" + process.env.MONGOSERVER + ":27017/test", function(err, db) {
if (!err) {
console.log("We are connected to MongoDB");
db.collection('records', function(err, collection) {
if (!err) {
collection.find().toArray(function(err, docs) {
if (!err) {
db.close();
len = docs.length - 1;
res.render('index', {
tweet: docs[len].tweet
});
}
});
}
});
} else {
res.send('Cannot connect to MongoDB\n');
console.log("Cannot connect to MongoDB");
console.log(err);
}
});
});
app.listen(PORT);
Stateless Web Service
var jsonfile = require('jsonfile')
var util = require('util')
var file = '/tmp/data.json'
var obj = {name: 'Ryan'}
//Write file
jsonfile.writeFile(file, obj, function (err) {
console.error(err)
})
//Read File
jsonfile.readFile(file, function(err, obj) {
console.dir(obj)
})
Stateful JSON Service
If the container or node fails, what happens to /tmp/data.json?
Do we care what changes were tracked and what happend/changed during the container lifecycle? Yes. (Stateful)
Managing State
It's important through the entire devops lifecycle
Dev
CI/Test
Production
development:
adapter: postgresql
encoding: unicode
database: myapp_development
pool: 5
username: myapp
password: password1
test:
adapter: postgresql
encoding: unicode
database: myapp_test
pool: 5
username: myapp
password: password1
#!/bin/bash -x
export RAILS_ENV=test
bundle install
read -d '' database_yml <<"EOF"
login: &login
adapter: mysql2
username: builds
password:
encoding: utf8
test: &test
database: my_project_test
<<: *login
EOF
echo "$database_yml" > config/database.yml
rake db:create db:test:prepare
bundle exec rspec spec/
<VirtualHost *:80>
ServerName application_name.rails.local
DocumentRoot "/Users/rails/app/public"
RailsEnv production ## This is the default
</VirtualHost>
Volumes & Kubernetes
PersistentVolume (PV)
storage resource provisioned by admin.
PersistentVolumeClaim (PVC)
user request for persistent volume.
VOLUMES
- emptyDir
- hostPath
- gcePersistentDisk
- awsElasticBlockStore
- nfs
- iscsi
- flocker
- glusterfs
- rbd
- gitRepo
- secret
- persistentVolumeClaim
Volumes & Kubernetes
A "Volume" from the pool
Pool of Volumes
Directly Reference Volumes
Volume: "MyVolume"
Pool of Volumes
Container
POD
volumes:
- name: www-root
flocker:
datasetName: MyVolume
flockerctl create -m name=MyVolume -s 1Tb
User
Admin
Utilize Volume Claims
Pool of Volumes
Container
POD
volumes:
- name: mypd
source:
persistentVolumeClaim:
accessMode: ReadWriteOnce
claimRef:
name: myclaim-1
Persistent
Volume
Claim
PersistentVolume (best match)
POST:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim-1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
POST:
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv0001
spec:
capacity:
storage: 8Gi
persistentDisk:
pdName: "abc123"
fsType: "ext4"
Admin
User
User
Demo
QA & THANK YOU
Thanks to Microsoft NERD
We're Hiring!
@RyanWallner
ryan.wallner@clusterhq.com
@clusterhq
Key concepts for stateful services in Kubernetes
By Ryan Wallner
Key concepts for stateful services in Kubernetes
- 2,993