---
# System prepended metadata

title: 'Kubernetes, cas pràctic.'
tags: [' M15', ' kubernetes', daw, ' dam', ' M8']

---

---
title: Kubernetes, cas pràctic.
tags: daw, kubernetes, M8, dam, M15
---

<div style="width: 30%; margin-left: auto;">
    
![](https://hackmd.io/_uploads/HJiR4eGJT.png)    
    
</div>

<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Llicència de Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />Aquesta obra està subjecta a una llicència de <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Reconeixement-CompartirIgual 4.0 Internacional de Creative Commons</a>

<div style="width: 200px;margin: 0 auto;">
    
![kubernetes](https://i.imgur.com/BiRTyF9.png "kubernetes" =200x120)    

</div>


# Kubernetes, cas pràctic.
## Habilitant l'entorn.
Kubernetes és especialment útil quan treballem amb plataformes al núvol però no farem les proves de desenvolupament directament sobre la plataforma de terceres parts (o si).
Tenim disponibles dues solucions de programari que ens permeten desplegar i provar sistemes kubernetes en local:

- [minikube](https://minikube.sigs.k8s.io/docs/): per a ús de desenvolupament, ens recreat tota la arquitectura kubernetes al nostre portàtil.
- [microk8s](https://microk8s.io/): solució multiplataforma que permet creat _master nodes_ i _worker nodes_ que treballin junts com a un únic sistema kubernetes.

En aquests apunts ens limitarem a treballar amb __minikube__.

### Instal·lació de minikube.
Abans de l'instal·lació, és important recordar, sobre tot per a aquells que no treballin directament sobre un sistema Linux, que minikube necessita  un [driver](https://minikube.sigs.k8s.io/docs/start/) que pot ser un programari de contenidors, de màquines virtuals, o la pròpia màquina local, aquesta darrera opció només es recomana per usuaris experimentats i només està disponible pels usuaris d'algunes versions de Linux.

Seguiu les instruccions de la [pàgina oficial](https://minikube.sigs.k8s.io/docs/start/).

Engegueu el servei de minikube indicant el driver dessitjat:
```bash=
isard@isard:~$ minikube start --driver docker
😄  minikube v1.30.1 en Ubuntu 22.10 (amd64)
✨  Using the docker driver based on user configuration
📌  Using Docker driver with root privileges
👍  Starting control plane node minikube in cluster minikube
🚜  Pulling base image ...
💾  Descargando Kubernetes v1.26.3 ...
    > preloaded-images-k8s-v18-v1...:  397.02 MiB / 397.02 MiB  100.00% 135.65 
    > gcr.io/k8s-minikube/kicbase...:  373.53 MiB / 373.53 MiB  100.00% 28.67 M
🔥  Creando docker container (CPUs=2, Memory=2200MB) ...
🐳  Preparando Kubernetes v1.26.3 en Docker 23.0.2...
    ▪ Generando certificados y llaves
    ▪ Iniciando plano de control
    ▪ Configurando reglas RBAC...
🔗  Configurando CNI bridge CNI ...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🔎  Verifying Kubernetes components...
🌟  Complementos habilitados: storage-provisioner, default-storageclass
💡  kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

isard@isard:~$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
```

Minikube instala la seva pròpia versió de kubectl, per aquells que treballin amb Linux i no tinguin instal·lada cap versió de kubectl, és una bona idea, tal i com expliquen a la pàgina de minikube, crear el següent alias:
```
alias kubectl="minikube kubectl --"
```
Per aturar el sistema i esborrar tots els clusters creats:
```
isard@isard:~$ minikube delete --all
🔥  Eliminando "minikube" en docker...
🔥  Eliminando /home/isard/.minikube/machines/minikube...
💀  Removed all traces of the "minikube" cluster.
🔥  Successfully deleted all profiles
isard@isard:~$ 

```
## Desplegant la calculadora
Ara que ja tenim el nostre entorn funcional podem passar a la segona fase: desplegar la nostra calculadora web en un entorn kubernetes.
Recordem el codi de la nostra calculadora:
```python=
#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Servei API-REST implementat en Flask per realitzar operacions matemàtiques bàsiques.
  - suma
  - resta
  - multiplica
  - divideix

Els serveis estan disponibles al port 5000  
Dependències: flask ($ pip3 install flask)
"""
from flask import Flask, jsonify
app = Flask(__name__)


@app.route('/')
def hello_world():
    return jsonify({'name': 'Calculadora'})


@app.route('/suma/<op1>/<op2>')
def suma(op1, op2):
    n_op1 = float(op1)
    n_op2 = float(op2)
    resultat = {'operador': 'suma', 'resultat': n_op1 + n_op2}
    return jsonify(resultat), 200


@app.route('/resta/<op1>/<op2>')
def resta(op1, op2):
    n_op1 = float(op1)
    n_op2 = float(op2)
    resultat = {'operador': 'resta', 'resultat': n_op1 - n_op2}
    return jsonify(resultat), 200


@app.route('/multiplica/<op1>/<op2>')
def multiplica(op1, op2):
    n_op1 = float(op1)
    n_op2 = float(op2)
    resultat = {'operador': 'multiplicacio', 'resultat': n_op1 * n_op2}
    return jsonify(resultat), 200


@app.route('/divideix/<op1>/<op2>')
def divisio(op1, op2):
    n_op1 = float(op1)
    n_op2 = float(op2)
    resultat = {'operador': 'divisio', 'resultat': n_op1 / n_op2}
    return jsonify(resultat), 200


if __name__=='__main__':
    app.run(host='0.0.0.0', port='5000')
```
El primer pas consiteix en crear un contenidor per a la nostra aplicació:

- Contingut del fitxer Dockerfile:
```yaml=
FROM python:latest
RUN pip install flask
WORKDIR /calculadora
COPY ./calc.py /calculadora/
CMD ["python", "calc.py"]
EXPOSE 5000
```
- Compilar i pujar a DockerHub:
```bash=
docker build -t jdaxavi/calculadora .
docker push jdaxavi/calculadora
```
Ara ja tenim la nostra calculadora preparada per enviar-la al núvol dins del seu contenidor.
El primer pas serà crear un fitxer yaml de deploy. El més còmode és anar a la pàgina oficial de kubernetes [https://kubernetes.io/es/](https://kubernetes.io/es/) clicar al link de documentació [https://kubernetes.io/es/docs/home/](https://kubernetes.io/es/docs/home/) i cercar Deployment al textbox de cerca. La primera entrada ens porta a la documentació dels objectes Deploy [https://kubernetes.io/docs/concepts/workloads/controllers/deployment/](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), i a dins podem trobar un exemple:
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
```
A partir d'aquest exemple podem anar construint el nostre propi fitxer yaml que descrigui el __deploy__ de la nostra app calculadora.
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
  name: calculadora           # nginx-deployment
  labels:
    app: calculadora          # nginx
spec:
  replicas: 5 #3
  selector:
    matchLabels:
      app: calculadora        # nginx
  template:
    metadata:
      labels:
        app: calculadora      # nginx
    spec:
      containers:
      - name: calculadora     # nginx
        image: jdaxavi/calculadora:latest
        ports:
        - containerPort: 5000 # 80
```
necessitarem també un 'Service' per adreçar-nos a la nostra aplicació, seguint el cas anterior, cercarem un exemple a la documentació de kubernetes i l'afegirem al mateix fitxer. Hem de recordar que YAML permet multiples documents si els separem per '---'.
[https://kubernetes.io/es/docs/concepts/services-networking/service/](https://kubernetes.io/es/docs/concepts/services-networking/service/)
Així quedaria el nostre fitxer calculadora.yaml ampliat amb el 'service' a més del 'deploy':
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
  name: calculadora           # nginx-deployment
  labels:
    app: calculadora          # nginx
spec:
  replicas: 5 #3
  selector:
    matchLabels:
      app: calculadora        # nginx
  template:
    metadata:
      labels:
        app: calculadora      # nginx
    spec:
      containers:
      - name: calculadora     # nginx
        image: jdaxavi/calculadora:latest
        ports:
        - containerPort: 5000 # 80
---
apiVersion: v1
kind: Service
metadata:
  name: calculadora-servei
spec:
  type: NodePort # ClusterIP per defecte
  selector:
    app: calculadora
  ports:
    - protocol: TCP
      port: 5000
      targetPort: 5000
      nodePort: 30101 # entre 30.000 i 32.767
```
Parem atenció a que el 'service' pot tenir un port diferent al que hem configurat al 'pod':

 - port: 5000 fa referència al port utilitzat al servei.
 - targetPort: 5000 hem d'utilitzar el mateix que hem declarat al contenidor.
 - nodePort: Port que s'obrirà a tots els nodes on s'executi el nostre servei; ha d'estar dins del rang (30000,32767). Només l'especificarem si hem triat el tipus NodePort.

Ara ja podem passar a crear el nostre ConfigMap, el desarem a un fitxer anomenat calculadora-config.yaml
```yaml=
apiVersion: v1
kind: ConfigMap
metadata:
  name: calculadora-config
data:
  calculadora-url: calculadora-servei
```
Ara desde un terminal i el nostre servei minikube arrencat crearem els objectes que acabem de configurar:
```bash=
# En primer lloc el ConfigMap (tot i que per la nostra app no és necessari):
$ kubectl apply -f calculadora-config.yaml
configmap/calculadora-config created

$ kubectl apply -f calculadora.yaml 
deployment.apps/calculadora created
service/calculadora-servicio created

$ kubectl get all
NAME                               READY   STATUS    RESTARTS   AGE
pod/calculadora-6857984764-5865m   1/1     Running   0          92s
pod/calculadora-6857984764-5bjfh   1/1     Running   0          92s
pod/calculadora-6857984764-9gzbr   1/1     Running   0          92s
pod/calculadora-6857984764-pms65   1/1     Running   0          92s
pod/calculadora-6857984764-z9bsb   1/1     Running   0          92s

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/calculadora-servicio   NodePort    10.97.145.182   <none>        5000:30101/TCP   92s
service/kubernetes             ClusterIP   10.96.0.1       <none>        443/TCP          124m

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/calculadora   5/5     5            5           92s

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/calculadora-6857984764   5         5         5       92s
```
Per poder connectar amb la nostra aplicació, hem de conèixer l'adreça IP del node on està corrent el servei:
```bash=
$ minikube ip
192.168.49.2

$ kubectl get node -o wide
NAME       STATUS   ROLES                  AGE    VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
minikube   Ready    control-plane,master   133m   v1.23.3   192.168.49.2   <none>        Ubuntu 20.04.2 LTS   5.15.0-30-generic   docker://20.10.12

$ curl http://192.168.49.2:30101
{"name":"Calculadora"}

```

## Monitorització dels pods
Un cop arrencats podem veure els logs de cada pod individual amb la següent comanda i forçar el seguiment amb el flag -f:
```
$ kubectl logs -f pod/calculadora-68fdd5dd4f-27r4l
 * Serving Flask app 'calculadora'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://10.244.0.15:5000
Press CTRL+C to quit
127.0.0.1 - - [14/Nov/2023 14:54:34] "GET / HTTP/1.1" 200 -

```