mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-02-14 09:39:56 +00:00
Expand volume section
This commit is contained in:
8
k8s/nginx-1-without-volume.yaml
Normal file
8
k8s/nginx-1-without-volume.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx-without-volume
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
13
k8s/nginx-2-with-volume.yaml
Normal file
13
k8s/nginx-2-with-volume.yaml
Normal 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/
|
||||
@@ -1,7 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx-with-volume
|
||||
name: nginx-with-git
|
||||
spec:
|
||||
volumes:
|
||||
- name: www
|
||||
20
k8s/nginx-4-with-init.yaml
Normal file
20
k8s/nginx-4-with-init.yaml
Normal 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/
|
||||
@@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user