From e9da09d5f4d55bd92948cdb11f073925c08ac991 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 11 Dec 2025 07:40:16 +0100 Subject: [PATCH] Push k8s training --- README.md | 16 ++++ cluster.yaml | 13 +++ exercises/01-simple-pod/README.md | 100 +++++++++++++++++++++ exercises/01-simple-pod/index.html | 20 +++++ exercises/01-simple-pod/pod.yaml | 6 ++ exercises/02-simple-rc/README.md | 90 +++++++++++++++++++ exercises/02-simple-rc/rc.yaml | 6 ++ exercises/02-simple-rc/service.yaml | 6 ++ exercises/03-simple-deploy/README.md | 48 ++++++++++ exercises/03-simple-deploy/auth-nginx.conf | 12 +++ exercises/03-simple-deploy/deploy.yaml | 6 ++ exercises/04-simple-hpa/README.md | 57 ++++++++++++ exercises/04-simple-hpa/deploy.yaml | 6 ++ exercises/04-simple-hpa/hpa.yaml | 6 ++ exercises/04-simple-hpa/index.php | 7 ++ exercises/04-simple-hpa/test.yaml | 17 ++++ exercises/05-microservices/README.md | 31 +++++++ setup-env.sh | 59 ++++++++++++ 18 files changed, 506 insertions(+) create mode 100644 README.md create mode 100644 cluster.yaml create mode 100644 exercises/01-simple-pod/README.md create mode 100644 exercises/01-simple-pod/index.html create mode 100644 exercises/01-simple-pod/pod.yaml create mode 100644 exercises/02-simple-rc/README.md create mode 100644 exercises/02-simple-rc/rc.yaml create mode 100644 exercises/02-simple-rc/service.yaml create mode 100644 exercises/03-simple-deploy/README.md create mode 100644 exercises/03-simple-deploy/auth-nginx.conf create mode 100644 exercises/03-simple-deploy/deploy.yaml create mode 100644 exercises/04-simple-hpa/README.md create mode 100644 exercises/04-simple-hpa/deploy.yaml create mode 100644 exercises/04-simple-hpa/hpa.yaml create mode 100644 exercises/04-simple-hpa/index.php create mode 100644 exercises/04-simple-hpa/test.yaml create mode 100644 exercises/05-microservices/README.md create mode 100644 setup-env.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..b310800 --- /dev/null +++ b/README.md @@ -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 +``` +3. User kubectl + diff --git a/cluster.yaml b/cluster.yaml new file mode 100644 index 0000000..f324516 --- /dev/null +++ b/cluster.yaml @@ -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" diff --git a/exercises/01-simple-pod/README.md b/exercises/01-simple-pod/README.md new file mode 100644 index 0000000..a077afa --- /dev/null +++ b/exercises/01-simple-pod/README.md @@ -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 +``` + +
+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 +``` +
+ +Surprisingly, the web page shows an error 403. +> Can you hypothesize on why it occurred ? Maybe using the application logs. + +
+ +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. diff --git a/exercises/01-simple-pod/index.html b/exercises/01-simple-pod/index.html new file mode 100644 index 0000000..d59ce81 --- /dev/null +++ b/exercises/01-simple-pod/index.html @@ -0,0 +1,20 @@ + + + + + + + OK + + +
+
+

Nice ! Have some pod-ing đŸ„ž

+
+
+ + diff --git a/exercises/01-simple-pod/pod.yaml b/exercises/01-simple-pod/pod.yaml new file mode 100644 index 0000000..c3f1752 --- /dev/null +++ b/exercises/01-simple-pod/pod.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +kind: Pod +metadata: + name: simple-pod-html +spec: {} diff --git a/exercises/02-simple-rc/README.md b/exercises/02-simple-rc/README.md new file mode 100644 index 0000000..df13ac8 --- /dev/null +++ b/exercises/02-simple-rc/README.md @@ -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"}' +``` + +
+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 ` + +2. Check the state of the pod. Is it still running ? + +> Don't forget to run `docker start ` 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. + +
+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 +``` + +
+If you delete one pod, the controller should detect it and schedule a new pod to replace it. + +
+ +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 +``` diff --git a/exercises/02-simple-rc/rc.yaml b/exercises/02-simple-rc/rc.yaml new file mode 100644 index 0000000..db65725 --- /dev/null +++ b/exercises/02-simple-rc/rc.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +kind: ReplicationController +metadata: + name: simple-rc-nginx +spec: {} diff --git a/exercises/02-simple-rc/service.yaml b/exercises/02-simple-rc/service.yaml new file mode 100644 index 0000000..4f8118e --- /dev/null +++ b/exercises/02-simple-rc/service.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: simple-rc-nginx +spec: {} diff --git a/exercises/03-simple-deploy/README.md b/exercises/03-simple-deploy/README.md new file mode 100644 index 0000000..4645043 --- /dev/null +++ b/exercises/03-simple-deploy/README.md @@ -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: {} +``` + +
+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. diff --git a/exercises/03-simple-deploy/auth-nginx.conf b/exercises/03-simple-deploy/auth-nginx.conf new file mode 100644 index 0000000..55100b9 --- /dev/null +++ b/exercises/03-simple-deploy/auth-nginx.conf @@ -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; + } +} diff --git a/exercises/03-simple-deploy/deploy.yaml b/exercises/03-simple-deploy/deploy.yaml new file mode 100644 index 0000000..af32c8e --- /dev/null +++ b/exercises/03-simple-deploy/deploy.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: simple-deploy-nginx +spec: {} diff --git a/exercises/04-simple-hpa/README.md b/exercises/04-simple-hpa/README.md new file mode 100644 index 0000000..d7ed277 --- /dev/null +++ b/exercises/04-simple-hpa/README.md @@ -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 + +``` + +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 + + diff --git a/exercises/04-simple-hpa/deploy.yaml b/exercises/04-simple-hpa/deploy.yaml new file mode 100644 index 0000000..5376f8b --- /dev/null +++ b/exercises/04-simple-hpa/deploy.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: simple-hpa-app +spec: {} diff --git a/exercises/04-simple-hpa/hpa.yaml b/exercises/04-simple-hpa/hpa.yaml new file mode 100644 index 0000000..65216e3 --- /dev/null +++ b/exercises/04-simple-hpa/hpa.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: simple-hpa-app +spec: {} diff --git a/exercises/04-simple-hpa/index.php b/exercises/04-simple-hpa/index.php new file mode 100644 index 0000000..fcb2ea4 --- /dev/null +++ b/exercises/04-simple-hpa/index.php @@ -0,0 +1,7 @@ + diff --git a/exercises/04-simple-hpa/test.yaml b/exercises/04-simple-hpa/test.yaml new file mode 100644 index 0000000..9521355 --- /dev/null +++ b/exercises/04-simple-hpa/test.yaml @@ -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 diff --git a/exercises/05-microservices/README.md b/exercises/05-microservices/README.md new file mode 100644 index 0000000..30b6731 --- /dev/null +++ b/exercises/05-microservices/README.md @@ -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. + + diff --git a/setup-env.sh b/setup-env.sh new file mode 100644 index 0000000..b133c95 --- /dev/null +++ b/setup-env.sh @@ -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 ..." +