Push k8s training

main
Your Name 3 months ago
commit e9da09d5f4

@ -0,0 +1,16 @@
# cloud-practical
Skeleton project and files for cloud practicals.
## Configuration
1. Configure a new env for kubernetes
```bash
# sudo needed to install docker
sudo ./setup-env.sh
```
2. Create cluster
```bash
k3d cluster create --config <use_your_conf>
```
3. User kubectl

@ -0,0 +1,13 @@
---
apiVersion: k3d.io/v1alpha5
kind: Simple
metadata:
name: upec
image: docker.io/rancher/k3s:v1.24.4-k3s1
servers: 1
agents: 2
registries:
create:
host: "127.0.0.1"
hostPort: "5000"

@ -0,0 +1,100 @@
## A simple web application
You will manipulate pods and configmaps in order to deploy a microservice in kubernetes.
#### 1. Declare a pod
Complete the following Pod manifest in order to deploy an nginx container with an empty volume attached to
`/usr/share/nginx/html`.
```yaml
# To create: kubectl apply -f pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: simple-pod-nginx
labels:
exo: simple-pod
spec:
volumes:
- emptyDir: {}
name: html
containers: {} # TODO
```
<br>
You can review the results through various kubectl commands.
```bash
# Describe resources and show event logs from Kubernetes controllers
kubectl describe pod/simple-pod-nginx
# Get brief of a pod
kubectl get pod/simple-pod-nginx
# Get brief of resources filtered by label in the yaml format
kubectl get all -l "exo=simple-pod" -o yaml
# Get a specific field value from a resource (here the pod's IP)
kubectl get pod/simple-pod-nginx -o jsonpath='{.status.podIP}'
```
You can also print the logs from the containered application.
```bash
kubectl logs pod/simple-pod-nginx
```
#### 2. Acces the nginx service
By default, the nginx service is listening on port 80. If not already done, you should expose the container port in the pod declaration (see `pod.spec.containers.ports`).
Then it can be accessed by forwarding your [localhost:8080](http://127.0.0.1:8080) to the pod's port.
```bash
kubectl port-forward pod/simple-pod 8080:80
```
<br>
Surprisingly, the web page shows an error 403.
> Can you hypothesize on why it occurred ? Maybe using the application logs.
<br>
However we notice that the pod is in a ready state and contradicts the real state of our application.
```bash
NAME READY STATUS RESTARTS AGE
pod/simple-pod-nginx 1/1 Running 0 1m
```
#### 3. Evaluate the readiness of a container
Try to add a `readinessProbe` to your container definition that leaves the pod in an unready state until the web page is answering with a 200 response code.
#### 4. Fix the web page
You should update the web content by uploading the `index.html` to the container web root.
> `kubectl cp` can be quite handy
The page should now display correctly and the pod should hop in a ready state. However while its okay to use `cp` in some cases, here changes won't persist after the pod's lifetime.
#### 5. Storing configuration data
A ConfigMap is a very handy resource that can hold configuration data for an application.
You can use the CLI and `kubectl create` to generate the configuration from the index.html file.
Also you can choose to adjust the following manifest :
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: simple-pod-html
data: {}
```
Finaly modify the pod declaration in order to mount this configmap at `/usr/share/nginx/html`.
The application should serve its html content from the configmap and it will allow the configuration to survive reboots.

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>OK</title>
</head>
<body>
<main>
<div style="
text-align: center;
background: green;
color: white;
">
<h1>Nice ! Have some pod-ing 🥞</h1>
</div>
</main>
</body>
</html>

@ -0,0 +1,6 @@
---
apiVersion: v1
kind: Pod
metadata:
name: simple-pod-html
spec: {}

@ -0,0 +1,90 @@
## Resiliency of pods
#### 1. Simulate a node failure
A pod is the smallest unit of compute in kubernetes. It is tied to a single node runtime and does not come with a lot of workload logic.
To ensure that controle plan no schedule pod run this command
```bash
kubectl taint node/k3d-upec-server-0 node-role.kubernetes.io/master:NoSchedule
```
This command prints the node running our simple-pod.
```bash
kubectl get pod/simple-pod-nginx -o jsonpath='{.spec.nodeName}{"\n"}'
```
<br>
We will observe the behaviour of this pod in the event of a node failure.
1. Stop the node where the pod is running with `docker stop <node>`
2. Check the state of the pod. Is it still running ?
> Don't forget to run `docker start <node>` before pursuing.
#### 2. Create replicas
A naive solution to this problem is to create replicas of this pod spread across multiple nodes.
You will create a `ReplicationController` resource that adds workload logic to our application by maintaining 3 replicas of our pod.
> The `spec.template` object describes the pod that will be created in the case of insufficient replicas. It is the same as the pod declaration.
```yaml
---
apiVersion: v1
kind: ReplicationController
metadata:
name: simple-rc-nginx
spec: {}
```
> Be careful in the usage of labels with selectors. Read the documentation.
<br>
As usual, you can monitor the state of the controller and the numbers of ready replicas.
```bash
kubectl get rc/simple-rc-nginx
NAME DESIRED CURRENT READY AGE
simple-rc-nginx 3 3 3 21s
```
<br>
If you delete one pod, the controller should detect it and schedule a new pod to replace it.
<br>
Additionally you can scale replicas up and down, either by modifying the resource/manifest or with kubectl.
```bash
kubectl scale --replicas=5 rc/simple-rc-nginx
```
#### 3. Create a service
Port forwarding to a pod is not very convenient with multiple replicas. Ideally we need a way to address them in a load balanced manner.
A `Service` resource is the standard way of exposing an application inside the cluster. It uses selectors to distribute traffic amongst selected pods.
Create a `svc.spec.type.clusterIP` service to expose the replicas inside the cluster.
> You should consider using labelled selectors as you did for the RC.
```yaml
apiVersion: v1
kind: Service
metadata:
name: simple-rc-nginx
spec: {}
```
You can then access this service through a forwarded port.
```bash
kubectl port-forward svc/simple-rc-nginx 8080:80
```

@ -0,0 +1,6 @@
---
apiVersion: v1
kind: ReplicationController
metadata:
name: simple-rc-nginx
spec: {}

@ -0,0 +1,6 @@
---
apiVersion: v1
kind: Service
metadata:
name: simple-rc-nginx
spec: {}

@ -0,0 +1,48 @@
## Publication of our microservice
We will create a Deployment resource that provides declarative updates for Pods along with other useful features.
#### 1. Declare a deployment
First, the Deployment declaration will be quite similar to the one of our ReplicationController.
```yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple-deploy-nginx
spec:
```
Once it is running, we will modify the manifest in order to add a basic authentication flow. Deployments can detect changes and perform hot reloads of pods configuration.
Precisely, it must present some additional elements :
- a ConfigMap containing the file `auth-nginx.conf` and mounted on `/etc/nginx/conf.d`
- a Secret containing the file `.htpasswd` and mounted on `/secrets`
Both ConfigMaps and Secrets store the data the same way (in key/value pairs), but ConfigMaps are meant for plain text data. Secrets values on the other hand, are `base64` encoded as they can contain binary data.
> `htpasswd -c .htpasswd alice` create a new credential file that contains the MD5 hash of alice's password.
```yaml
---
apiVersion: v1
kind: Secret
data: {}
```
<br>
Don't forget to create a service to expose your deployment inside the cluster.
> You can also scale replicas up and down in a deployment.
The application should prompt you to enter a login and password before serving the page.
#### 2. Expose your deployment
Once again, expose your deployment through a ClusterIP that makes it reachable from __inside__ the cluster.

@ -0,0 +1,12 @@
# mount this file to /etc/nginx/conf.d
server {
listen 80;
root /usr/share/nginx/html;
location / {
index index.html;
auth_basic "Basic Auth from Kubernetes secret";
auth_basic_user_file /secrets/.htpasswd;
}
}

@ -0,0 +1,6 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple-deploy-nginx
spec: {}

@ -0,0 +1,57 @@
## Scale workload to match demand
Horizontal scaling means that the response to increased load is to deploy more Pods.
#### 1. Setup a server-side web app
We will deploy a simple php webapp that performs the sum of all square roots from 0 to 100000.
Therefore, you must complete the following manifest :
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple-hpa-app
spec:
template:
metadata:
name: app
spec:
containers:
- name: php-apache
image: php:7.2-apache
```
You will need to mount the following `index.php` file to `/var/www/html` (preferably as a configmap).
```php
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
echo "OK! Sum is $x";
?>
```
This script is very simple but it can also be quite intense to compute when forked multiple times.
#### 2. Set compute requirements
You will update the deployment in order to define CPU requirements for each pods. They allow to both reserve and limit the amount of compute resources used by each pod.
Set the correct values so that each pod c i always between `200m` and `500m`
> It is also possible to set RAM requirements
#### 3. Testing
This

@ -0,0 +1,6 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple-hpa-app
spec: {}

@ -0,0 +1,6 @@
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: simple-hpa-app
spec: {}

@ -0,0 +1,7 @@
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
echo "OK! Sum is $x";
?>

@ -0,0 +1,17 @@
---
apiVersion: v1
kind: Pod
metadata:
name: simple-hpa-test
spec:
restartPolicy: Never
containers:
- name: test
image: busybox:latest
command:
- /bin/sh
- -c
- |
while sleep 0.01; do
wget -q -O- http://simple-hpa-app
done

@ -0,0 +1,31 @@
## Objectif:
Créer une application web avec plusieurs microservices et exposer ces services via un seul Ingress, en utilisant des chemins d'URL différents pour chaque service.
#### 1. Tâches:
Créer plusieurs Déploiements:
Déployer trois applications Node.js distinctes :
Un service "frontend" qui sert une page HTML de base.
Un service "api" qui fournit une API REST simple (a vous de la definir).
Un service "admin" qui contient une interface d'administration sécurisée.
#### 2. Créer des Services:
Exposer chacun des services via un Service de type ClusterIP.
Créer un Ingress:
Configurer un Ingress pour router le trafic HTTP vers les différents services en fonction des chemins d'URL :
/ : route vers le service "frontend"
/api : route vers le service "api"
/admin : route vers le service "admin"
#### 3. Tester:
Accéder à chaque service en utilisant les chemins d'URL correspondants.
#### 4. Securiser:
Ajouter une authentification pour la partie admin.

@ -0,0 +1,59 @@
#!/usr/bin/env bash
[ -n "$DEBUG" ] && set -e
#exec 3>&1 &>/dev/null
VENV="${1:-.venv}"
ACTIVATE="$VENV/bin/activate"
if grep -qEi 'debian|ubuntu|mint' /etc/*release; then
PKGMANAGER="apt"
PKGMANAGER_CACHE="apt update"
elif grep -qEi 'fedora|centos|redhat' /etc/*release; then
PKGMANAGER="yum"
PKGMANAGER_CACHE="yum makecache"
else
echo "OS is not supported."
exit
fi
pkg_exist () {
$PKGMANAGER list --installed 2>/dev/null | grep -qi "^$1" || command -v "$1" &>/dev/null
}
install_deps () {
if ! pkg_exist docker; then
apt-get -y install ca-certificates gnupg lsb-release
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
usermod -a -G docker etudiant
else
echo "[Ok] $(which docker)"
fi
if ! pkg_exist k3d; then
wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
else
echo "[Ok] $(which k3d)"
fi
BIN=$(echo ${PATH%%:*})
mkdir -p "$BIN"
if ! pkg_exist kubectl; then
curl -Ls "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -o "$BIN/kubectl"
chmod +x "$BIN/kubectl"
else
echo "[Ok] $(which kubectl)"
fi
}
install_deps
echo "######################################################"
echo "Use kubectl ..."
Loading…
Cancel
Save