Andy Repton, Mission Critical Engineer @ Schuberg Philis
@SethKarlo
arepton@schubergphilis.com
What is Kubernetes and why do we care?
Everybody gets a user
Commands cheat sheet: http://bit.ly/2s17Mwo
Install Kubectl
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.6.6/bin/darwin/amd64/kubectl
Install kops
brew update && brew install kops
Clone the workshop repo
git clone git@github.com:Seth-Karlo/intro-to-kubernetes-workshop.git
export KOPS_STATE_STORE=s3://devopsdays-ams
export MYNAME=user1
export NAME=${MYNAME}.sbp-demo.com
export AWS_ACCESS_KEY_ID=$YourID
export AWS_SECRET_ACCESS_KEY=$yourkey
Export the Variables we need
kops create cluster --zones eu-west-1a --node-size t2.medium --master-size t2.medium $NAME && kops update cluster ${NAME} --yes
And build
(This will take a few minutes)
kubectl get cs
Master components are the brains of the cluster. They compose of:
Node components are the brains of the individual nodes. They compose of:
Etcd is a replicated key value store that acts as the state store and clustering manager for kubernetes. Access to this is effectively root access on the cluster, so it should be protected and secured.
When we think of 'Bottom Up', we start with the node:
Then we add the container runtime
And then the containers
When we move from the 'physical' layer to kubernetes, the logical wrapper around containers is a pod
Pods support Health checks and liveness checks. We’ll go through those later
$ kubectl create -f pod/pod.yaml
Check it's running:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
pod 1/1 Running 0 11s
Run a command inside the pod:
$ kubectl exec -it pod bash
[root@pod /]# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=51 time=0.925 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=51 time=0.961 ms
^C
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.925/0.943/0.961/0.018 ms
$ kubectl delete pod pod
pod "pod" deleted
$ kubectl create -f replicaset.yml
replicaset "replica-set" created
Check your pod
$ k get pods
NAME READY STATUS RESTARTS AGE
replica-set-l3zbz 1/1 Running 0 1m
Delete your pod
$ k delete pod replica-set-l3zbz
pod "replica-set-l3zbz" deleted
Check your pods again
$ k get pods
NAME READY STATUS RESTARTS AGE
replica-set-z0pp4 1/1 Running 0 1m
Let's upgrade our replicaset (I've given you an old version of nginx)
$ kubectl edit replicaset replica-set
1 # Please edit the object below. Lines beginning with a '#' will be ignored,
2 # and an empty file will abort the edit. If an error occurs while saving this file will be
3 # reopened with the relevant failures.
4 #
5 apiVersion: extensions/v1beta1
6 kind: ReplicaSet
7 metadata:
8 creationTimestamp: 2017-06-26T10:02:34Z
9 generation: 1
10 labels:
11 app: replica-set
12 name: replica-set
13 namespace: default
14 resourceVersion: "1724"
15 selfLink: /apis/extensions/v1beta1/namespaces/default/replicasets/replica-set
16 uid: 9339e8f5-5a56-11e7-8817-0a75658e3054
17 spec:
18 replicas: 1
19 selector:
20 matchLabels:
21 app: replica-set
22 template:
23 metadata:
24 creationTimestamp: null
25 labels:
26 app: replica-set
27 spec:
28 containers:
29 - image: nginx:latest
30 imagePullPolicy: IfNotPresent
31 name: replica-set
32 ports:
33 - containerPort: 80
34 name: web
35 protocol: TCP
36 readinessProbe:
37 failureThreshold: 3
38 periodSeconds: 10
39 successThreshold: 1
40 tcpSocket:
41 port: 80
42 timeoutSeconds: 1
43 resources: {}
44 terminationMessagePath: /dev/termination-log
45 terminationMessagePolicy: File
46 dnsPolicy: ClusterFirst
47 restartPolicy: Always
48 schedulerName: default-scheduler
49 securityContext: {}
50 terminationGracePeriodSeconds: 30
51 status:
52 availableReplicas: 1
53 fullyLabeledReplicas: 1
54 observedGeneration: 1
55 readyReplicas: 1
56 replicas: 1
Change
- image: nginx:1.12
- image: nginx:1.13
to
Let's check our pod:
$ k get pods
NAME READY STATUS RESTARTS AGE
replica-set-z0pp4 1/1 Running 0 4m
And the image:
$ kubectl delete pod replica-set-z0pp4
pod "replica-set-z0pp4" deleted
$ kubectl describe pod | grep Image:
Image: nginx:1.13
Hmm, that's odd. Let's delete the pod and check the new one
$ kubectl describe pod | grep Image:
Image: nginx:1.12
We'll add Volumes and Secrets to our pods
$ kubectl create -f persistent-disk.yml
persistentvolumeclaim "mysql-pv-claim" created
We will use persistent volumes for our mysql database
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-31415c4d-5a59-11e7-8817-0a75658e3054 20Gi RWO gp2 55s
$ kubectl create secret generic mysql-pass --from-file=password.txt
secret "mysql-pass" created
$ kubectl create -f mysql-deployment.yaml
service "wordpress-mysql" created
deployment "wordpress-mysql" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
wordpress-mysql-1894417608-2k4rm 1/1 Running 0 41s
Now deploy mysql
And check the logs
$ kubectl logs wordpress-mysql-1894417608-2k4rm | tail -1
2017-06-26 10:23:22 0 [Note] mysqld (mysqld 5.6.36) starting as process 1 ...
$ kubectl create -f wordpress-deployment.yaml
service "wordpress" created
persistentvolumeclaim "wp-pv-claim" created
deployment "wordpress" created
Now deploy wordpress
And check the logs
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
wordpress-1595585052-9m5vm 1/1 Running 0 55s
wordpress-mysql-1894417608-2k4rm 1/1 Running 0 6m
$ kubectl logs wordpress-1595585052-9m5vm
WordPress not found in /var/www/html - copying now...
WARNING: /var/www/html is not empty - press Ctrl+C now if this is an error!
+ ls -A
lost+found
+ sleep 10
Complete! WordPress has been successfully copied to /var/www/html
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 100.96.2.8. Set the 'ServerName' directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 100.96.2.8. Set the 'ServerName' directive globally to suppress this message
[Mon Jun 26 10:29:00.980026 2017] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.10 (Debian) PHP/5.6.30 configured -- resuming normal operations
[Mon Jun 26 10:29:00.980053 2017] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
$ kubectl get svc wordpress
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wordpress 100.70.168.153 <none> 80/TCP 3m
Let's edit that and make it type 'LoadBalancer'
$ kubectl edit svc wordpress
service "wordpress" edited
$ kubectl get svc wordpress -o wide
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
wordpress 100.70.168.153 a252b84715a5a11e788170a75658e305-2028720367.eu-west-1.elb.amazonaws.com 80:30867/TCP 4m app=wordpress,tier=frontend
At the moment our service is type 'ClusterIP'
$ kubectl edit deployment wordpress
Change the image from image: wordpress:4.7.3-apache to image: wordpress:4.8.0-apache (the latest)
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
wordpress-1321513498-zjmql 0/1 Terminating 0 3m
wordpress-1595585052-93wzw 1/1 Running 0 4s
We can upgrade our pods automatically
$ kubectl create -f statefulsets/
service "cockroachdb-public" created
service "cockroachdb" created
poddisruptionbudget "cockroachdb-budget" created
statefulset "cockroachdb" created
Watch your pods start up
$ kubectl get pods -w
NAME READY STATUS RESTARTS AGE
cockroachdb-0 0/1 Init:0/1 0 4s
One of the resources created is a 'PodDisruptionBudget'
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: cockroachdb-budget
labels:
app: cockroachdb
spec:
selector:
matchLabels:
app: cockroachdb
minAvailable: 67%
If using the 'eviction' type rather than a 'delete' (which statefulsets use), this will prevent you from deleting too many pods.
$ kubectl run -it --rm cockroach-client --image=cockroachdb/cockroach --restart=Never --command -- ./cockroach sql --host cockroachdb-public --insecure
root@cockroachdb-public:26257/> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| crdb_internal |
| information_schema |
| pg_catalog |
| system |
+--------------------+
(4 rows)
root@cockroachdb-public:26257/> CREATE DATABASE IF NOT EXISTS dodams;
root@cockroachdb-public:26257/> CREATE TABLE IF NOT EXISTS dodams.demo (k STRING PRIMARY KEY, v STRING);
CREATE TABLE
root@cockroachdb-public:26257/> UPSERT INTO dodams.demo VALUES('Devops', 'Days'), ('Amsterdam', 'Loves');
INSERT 2
root@cockroachdb-public:26257/> SELECT * FROM dodams.demo;
$ kubectl delete pod cockroachdb-2
pod "cockroachdb-2" deleted
Will self heal, in the correct order:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
cockroachdb-0 1/1 Running 0 29m
cockroachdb-1 1/1 Running 0 6m
cockroachdb-2 1/1 Running 0 33s