Merge branch 'master' into kube-2019-11

This commit is contained in:
Jerome Petazzoni
2019-11-12 04:41:08 -06:00
8 changed files with 455 additions and 27 deletions

View File

@@ -9,7 +9,7 @@ spec:
name: haproxy
containers:
- name: haproxy
image: haproxy
image: haproxy:1
volumeMounts:
- name: config
mountPath: /usr/local/etc/haproxy/

View File

@@ -1,13 +1,13 @@
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: kibana
name: whatever
spec:
rules:
- host: kibana.185.145.251.54.nip.io
- host: whatever.A.B.C.D.nip.io
http:
paths:
- path: /
backend:
serviceName: kibana
servicePort: 5601
serviceName: whatever
servicePort: 1234

View File

@@ -0,0 +1,8 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-without-volume
spec:
containers:
- name: nginx
image: nginx

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-volume
spec:
volumes:
- name: www
containers:
- name: nginx
image: nginx
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html/

View File

@@ -1,7 +1,7 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-volume
name: nginx-with-git
spec:
volumes:
- name: www

View File

@@ -0,0 +1,20 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-init
spec:
volumes:
- name: www
containers:
- name: nginx
image: nginx
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html/
initContainers:
- name: git
image: alpine
command: [ "sh", "-c", "apk add --no-cache git && git clone https://github.com/octocat/Spoon-Knife /www" ]
volumeMounts:
- name: www
mountPath: /www/

View File

@@ -14,7 +14,27 @@
## Rolling updates
- With rolling updates, when a resource is updated, it happens progressively
- With rolling updates, when a Deployment is updated, it happens progressively
- The Deployment controls multiple Replica Sets
- Each Replica Set is a group of identical Pods
(with the same image, arguments, parameters ...)
- During the rolling update, we have at least two Replica Sets:
- the "new" set (corresponding to the "target" version)
- at least one "old" set
- We can have multiple "old" sets
(if we start another update before the first one is done)
---
## Update strategy
- Two parameters determine the pace of the rollout: `maxUnavailable` and `maxSurge`
@@ -225,6 +245,137 @@ If you didn't deploy the Kubernetes dashboard earlier, just skip this slide.
---
## Rolling back to an older version
- We reverted to `v0.2`
- But this version still has a performance problem
- How can we get back to the previous version?
---
## Multiple "undos"
- What happens if we try `kubectl rollout undo` again?
.exercise[
- Try it:
```bash
kubectl rollout undo deployment worker
```
- Check the web UI, the list of pods ...
]
🤔 That didn't work.
---
## Multiple "undos" don't work
- If we see successive versions as a stack:
- `kubectl rollout undo` doesn't "pop" the last element from the stack
- it copies the N-1th element to the top
- Multiple "undos" just swap back and forth between the last two versions!
.exercise[
- Go back to v0.2 again:
```bash
kubectl rollout undo deployment worker
```
]
---
## In this specific scenario
- Our version numbers are easy to guess
- What if we had used git hashes?
- What if we had changed other parameters in the Pod spec?
---
## Listing versions
- We can list successive versions of a Deployment with `kubectl rollout history`
.exercise[
- Look at our successive versions:
```bash
kubectl rollout history deployment worker
```
]
We don't see *all* revisions.
We might see something like 1, 4, 5.
(Depending on how many "undos" we did before.)
---
## Explaining deployment revisions
- These revisions correspond to our Replica Sets
- This information is stored in the Replica Set annotations
.exercise[
- Check the annotations for our replica sets:
```bash
kubectl describe replicasets -l app=worker | grep -A3
```
]
---
class: extra-details
## What about the missing revisions?
- The missing revisions are stored in another annotation:
`deployment.kubernetes.io/revision-history`
- These are not shown in `kubectl rollout history`
- We could easily reconstruct the full list with a script
(if we wanted to!)
---
## Rolling back to an older version
- `kubectl rollout undo` can work with a revision number
.exercise[
- Roll back to the "known good" deployment version:
```bash
kubectl rollout undo deployment worker --to-revision=1
```
- Check the web UI or the list of pods
]
---
class: extra-details
## Changing rollout parameters

View File

@@ -66,7 +66,87 @@ class: extra-details
---
## A simple volume example
## Adding a volume to a Pod
- We will start with the simplest Pod manifest we can find
- We will add a volume to that Pod manifest
- We will mount that volume in a container in the Pod
- By default, this volume will be an `emptyDir`
(an empty directory)
- It will "shadow" the directory where it's mounted
---
## Our basic Pod
```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-without-volume
spec:
containers:
- name: nginx
image: nginx
```
This is a MVP! (Minimum Viable Pod😉)
It runs a single NGINX container.
---
## Trying the basic pod
.exercise[
- Create the Pod:
```bash
kubectl create -f ~/container.training/k8s/nginx-1-without-volume.yaml
```
- Get its IP address:
```bash
IPADDR=$(kubectl get pod nginx-without-volume -o jsonpath={.status.podIP})
```
- Send a request with curl:
```bash
curl $IPADDR
```
]
(We should see the "Welcome to NGINX" page.)
---
## Adding a volume
- We need to add the volume in two places:
- at the Pod level (to declare the volume)
- at the container level (to mount the volume)
- We will declare a volume named `www`
- No type is specified, so it will default to `emptyDir`
(as the name implies, it will be initialized as an empty directory at pod creation)
- In that pod, there is also a container named `nginx`
- That container mounts the volume `www` to path `/usr/share/nginx/html/`
---
## The Pod with a volume
```yaml
apiVersion: v1
@@ -86,30 +166,57 @@ spec:
---
## A simple volume example, explained
## Trying the Pod with a volume
- We define a standalone `Pod` named `nginx-with-volume`
.exercise[
- In that pod, there is a volume named `www`
- Create the Pod:
```bash
kubectl create -f ~/container.training/k8s/nginx-2-with-volume.yaml
```
- No type is specified, so it will default to `emptyDir`
- Get its IP address:
```bash
IPADDR=$(kubectl get pod nginx-with-volume -o jsonpath={.status.podIP})
```
(as the name implies, it will be initialized as an empty directory at pod creation)
- Send a request with curl:
```bash
curl $IPADDR
```
- In that pod, there is also a container named `nginx`
]
- That container mounts the volume `www` to path `/usr/share/nginx/html/`
(We should now see a "403 Forbidden" error page.)
---
## A volume shared between two containers
## Populating the volume with another container
- Let's add another container to the Pod
- Let's mount the volume in *both* containers
- That container will populate the volume with static files
- NGINX will then serve these static files
- To populate the volume, we will clone the Spoon-Knife repository
- this repository is https://github.com/octocat/Spoon-Knife
- it's very popular (more than 100K stars!)
---
## Sharing a volume between two containers
.small[
```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-volume
name: nginx-with-git
spec:
volumes:
- name: www
@@ -147,30 +254,72 @@ spec:
---
## Sharing a volume, in action
## Trying the shared volume
- Let's try it!
- This one will be time-sensitive!
- We need to catch the Pod IP address *as soon as it's created*
- Then send a request to it *as fast as possible*
.exercise[
- Create the pod by applying the YAML file:
- Watch the pods (so that we can catch the Pod IP address)
```bash
kubectl apply -f ~/container.training/k8s/nginx-with-volume.yaml
kubectl get pods -o wide --watch
```
- Check the IP address that was allocated to our pod:
]
---
## Shared volume in action
.exercise[
- Create the pod:
```bash
kubectl get pod nginx-with-volume -o wide
IP=$(kubectl get pod nginx-with-volume -o json | jq -r .status.podIP)
kubectl create -f ~/container.training/k8s/nginx-3-with-git.yaml
```
- Access the web server:
- As soon as we see its IP address, access it:
```bash
curl $IP
```
- A few seconds later, the state of the pod will change; access it again:
```bash
curl $IP
```
]
The first time, we should see "403 Forbidden".
The second time, we should see the HTML file from the Spoon-Knife repository.
---
## Explanations
- Both containers are started at the same time
- NGINX starts very quickly
(it can serve requests immediately)
- But at this point, the volume is empty
(NGINX serves "403 Forbidden")
- The other containers installs git and clones the repository
(this takes a bit longer)
- When the other container is done, the volume holds the repository
(NGINX serves the HTML file)
---
## The devil is in the details
@@ -183,13 +332,100 @@ spec:
- That's why we specified `restartPolicy: OnFailure`
---
## Inconsistencies
- There is a short period of time during which the website is not available
(because the `git` container hasn't done its job yet)
- This could be avoided by using [Init Containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)
- With a bigger website, we could get inconsistent results
(we will see a live example in a few sections)
(where only a part of the content is ready)
- In real applications, this could cause incorrect results
- How can we avoid that?
---
## Init Containers
- We can define containers that should execute *before* the main ones
- They will be executed in order
(instead of in parallel)
- They must all succeed before the main containers are started
- This is *exactly* what we need here!
- Let's see one in action
.footnote[See [Init Containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) documentation for all the details.]
---
## Defining Init Containers
.small[
```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-init
spec:
volumes:
- name: www
containers:
- name: nginx
image: nginx
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html/
initContainers:
- name: git
image: alpine
command: [ "sh", "-c", "apk add --no-cache git && git clone https://github.com/octocat/Spoon-Knife /www" ]
volumeMounts:
- name: www
mountPath: /www/
```
]
---
## Trying the init container
- Repeat the same operation as earlier
(try to send HTTP requests as soon as the pod comes up)
- This time, instead of "403 Forbidden" we get a "connection refused"
- NGINX doesn't start until the git container has done its job
- We never get inconsistent results
(a "half-ready" container)
---
## Other uses of init containers
- Load content
- Generate configuration (or certificates)
- Database migrations
- Waiting for other services to be up
(to avoid flurry of connection errors in main container)
- etc.
---