Azure kubernetes

Pasos rápidos para crear un servicio kubernetes

  1. Creamos un recurso kubernetes service, a tener en cuenta
    1. Crear un grupo de recursos propios, facilita la gestión y la limpieza (usaremos kubernetes)
    2. Elegimos un nombre, se usará también como DNS (usaremos dummy)
    3. Elegir el tamaño de nodo adecuado, con la restricción de que tenga al menos 2 cores y 4GB de RAM (B2s estándar)
    4. Elegir el número de nodos
  2. Usamos la herramienta Azure CLI
    1. az login
      Logearse dentro de la plataforma
    2. az aks get-credentials –resource-group kubernetes –name dummy
      Actualiza el contexto kubernetes y se conecta al cluster, usando la herramienta de docker desktop se pueden ver todos los contextos de kubernetes activos.
    3. Se puede verificar usando el comando kubectl get nodes donde se pueden ver los nodos que habían sido creados
  3. A partir de este punto se pueden usar los comandos de kubernetes necesarios para desplegar como kubectl create

Creación de disco

Es muy común que se quiera crear un volumen de datos asociado a un cluster kubernetes, un ejemplo sería este:

kind: StorageClass 
apiVersion: storage.k8s.io/v1beta1
metadata: 
    name: azure-disk
provisioner: kubernetes.io/azure-disk 
parameters: 
    storageaccounttype: Standard_LRS 
    kind: Managed

En este caso no hace falta crear un volumen persistente porque Azure Disks soporta aprovisionamiento dinámico. Este es un ejemplo para una base de datos, hay que establecer la contraseña con:
kubectl create secret generic
mssql –from-literal=SA_PASSWORD=»Password_123″

apiVersion: v1 
kind: PersistentVolumeClaim 
metadata: 
    name: azure-volume-claim 
spec: 
    storageClassName: azure-disk 
    accessModes: 
        - ReadWriteOnce 
    resources: 
        requests: 
            storage: 8Gi
spec: 
    containers: 
        - name: myapp-database 
          image: mcr.microsoft.com/mssql/server 
          ports: 
              - containerPort: 1433 
          env: 
              - name: "ACCEPT_EULA" 
                value: "Y" 
              - name: "SA_PASSWORD" 
                valueFrom: 
                    secretKeyRef: 
                        name: mssql 
                        key: SA_PASSWORD 
              - name: "MSSQL_PID"
                value: "Express" 
          volumeMounts: 
              - name: mssqldb 
                mountPath: /var/opt/mssql 
    volumes: 
    - name: mssqldb 
          persistentVolumeClaim: 
              claimName: azure-volume-claim

Podemos crear también un balanceador para acceder a la base de datos.

apiVersion: v1 
kind: Service 
metadata: 
    name: myapp-db-svc 
spec: 
    selector: 
        app: myapp-db 
    ports: 
        - protocol: TCP 
          port: 1433 
          targetPort: 1433 
    type: LoadBalancer

Este script habilitará una IP externa que se puede usar para acceder a la base de datos, cuando no se necesite acceder se puede eliminar este balanceador.

Azure kubernetes

Kubernetes

En el caso de Kubernetes el nodo maestro no ejecuta ningún contenedor, (no es como swarm) solo tiene servicios que son necesarios para la infraestructura de Kubernetes. En el caso de Kubernetes se usan pods, un pod es la mínima unidad de trabajo de Kubernetes que contiene uno o más contenedores.

Kubernetes tiene este ciclo de vida para los pods:

  1. Pending: Se cargan los contenedores
    1. Failed: Error durante la carga
    2. Running: Todos los contenedores creados, al menos uno está funcionando.
      1. Succeded: Todos los contenedores en el pod han terminado correctamente.

Servicios

Kubernetes tiene varios servicios ejecutándose que interesa conocer, unos se ejecutan en el nodo maestro y otros son específicos del resto de nodos.

Maestro

kube-apiserver: Servidor REST API que consume datos JSON a través de archivos de manifiesto para la configuración de Kubernetes.

etcd: Almacenamiento clave/valor para pequeñas cantidades de datos en memoria, una parte principal de kubernetes que se recomienda guardar.

kube-controller-manager: Observa cambios en el sistema y reacciona para asegurar la configuración del sistema.

kube-scheduler: Asigna trabajo a los nodos e inspecciona el servidor API para la creación de nuevos pods.

Nodos

kubelet: Un agente que se comunica con el maestro para arrancar operaciones en el nodo e informar del estado del nodo.

kube-proxy: Componente que habilita el direccionamiento IP en el pod y balancea el tráfico a través de todos los pods del servicio.

Comandos

  • kubectl create -f pod.yml
    Crea un pod en base a un fichero
  • kubectl create -f service.yml
    Crea un servicio en base a un fichero yml
  • kubectl create -f deployment.yml
    Crea un deployment a partir de fichero
  • kubectl create secret generic secreto –from-literal=PASSWORD=»FooPass» –from-file=./<filename> –namespace=app
    Crea un secreto
    • –from-literal lo crea desde el literal de texto indicado
    • –from-file para colocar secretos en ficheros
    • –namespace si se ha creado un namespace para agrupar se puede especificar aquí
  • kubectl create namespace app
    Crea un espacio de nombre para agrupar a todos los elementos del cluster, también es útil para separar tus proyectos y limitar los recursos disponibles para cada uno de ellos. Es como tener un cluster virtual sobre uno físico. El namespace también sirve como DNS servicename.namespace.svc.cluster.local
  • kubectl describe pod
    Muestra toda la información disponible sobre el pod y los contenedores que incluye.
  • kubectl describe service app-rc-service
    Información sobre el servicio
  • kubectl describe deployment app-dpl
    Muestra información sobre el deployment
  • kubectl describe hpa
    Muestra las métricas en el cluster local
  • kubectl get pods
    Permite ver los pods creados y su estado
  • kubectl get pod
    Recupera el nombre del pod, útil para poder referenciarlo luego con otros comandos
  • kubectl get deployment dpl
    Permite ver información sobre el deployment creado, nombre, replica, pods actuales, acutalizados, disponibles…
  • kubectl get persistentvolumes
    Devuelve todos los volúmenes
  • kubectl get persistentvolume volumen
    Devuelve solo el volumen indicado
  • kubectl get pv
    Devuelve información sobre los volúmenes indicando cuales han sido reclamados y cuales siguen disponibles
  • kubectl get persistentvolumeclaims
    Devuelve todos los volúmenes reclamados
  • kubectl get persistentvolumeclaim volumen
    Devuelve solo el volumen reclamado indicado
  • kubectl get secrets
    Saca un listado de los secretos creados
  • kubectl get secret secreto -o yaml
    Devuelve el valor de un secreto
  • kubectl get namespaces
    Obtiene los espacios de nombre disponibles
  • kubectl get hpa
    Sirve para monitorizar HPA
  • kubectl get nodes
    Muestras los nodos del cluster
  • kubectl get service app-svc –watch
    Muestra información de un servicio
    • –watch monitoriza el comando hasta que se asigne una IP pública
  • kubectl run pod –image=autor/imagen –port 80 –restart=Never
    Crea un pod y lo arranca
    • –image la imagen que se usará para el pod
    • –port en que puerto estará escuchando
    • –restart indica que hacer en caso de reinicio, en este caso Never indica que no se recreará, falla o muere.
  • kubectl delete pod pod
    Borra un pod
  • kubectl delete deployment dpl
    Borra el deployment indicado
  • kubectl -n kube-system get secret
    Muestra todos los secretos del cluster. En general interesa el secreto que empieza por deployment-controller-token
  • kubectl -n kube-system describe secret deployment-controller-token-xyz
    Obtener un token
  • kubectl rollout status deployment app-deployment
    Permite ver el progreso de una operación rollout
  • kubectl rollout history deployment app-deployment
    Si se uso el parámetro –record al hacer un kubectl apply permite ver la historia del deployment
  • kubectl rollout undo deployment app-deployment –to-revision=1
    Permite volver a una versión específica
    • –to-revision versión a la que volver
  • kubectl expose rc app-rc –name=app-rc-service –type=NodePort
    Servicio que expone el pod a otros pods o clientes.
    • –name indica el nombre del servicio
    • –type indica el tipo de servicio
      • ClusterIP: Valor por defecto que expone el pod interno al cluster
      • NodePort: Expone el pod con un puerto estático en cada nodo que contiene el pod
      • LoadBalancer: Expone el pod externamente usando un balanceador de carga de un proveedor de cloud
      • ExternalName: Disponible desde la versión 1.7 de kube-dns para exponer los pods a través de los contenidos de el campo externalName
  • kubectl cluster-info
    Muestra información de estado del cluster.
  • kubectl proxy
    Arranca el servidor proxy de Kubernetes
  • kubectl apply -f deployment.yml –record
    Aplica los cambios hechos en el fichero
    • –record Sigue todos los cambios hechos durante el deployment, permite hacer un rollback a una versión previa de la aplicación.
  • kubectl exec -it dpl/bin/bash [–container container]
    Ejecuta un comando
    • -it dpl el deployment que se usará
    • comando el comando a ejecutar
    • –container el container donde se va a ejecutar
  • kubectl cp fichero dpl:fichero
    Copia el fichero al deployment indicado con el nombre dado en fichero
  • kubectl config view
    Muestra información de la configuración
  • kubectl autoscale deployment app-deployment –cpu-percent=50 –min=1 –max=5 –horizontal-pod-autoscaler-sync-period=x
    Este comando configura Horizontal Pod Autoscaler (HPA) , es un controlador que comprueba los recursos definidos en una configuración cada 15 segundos por defecto y los intenta implementar.
    • app-deployment Nombre del deployment a escalar
    • –horizontal-pod-autoscaler-sync-period=x intervalo entre refresco de configuración

Scripts

Ficheros pod

Pod

Ejemplo para crear un pod, generalmente no se usa mucho porque no se querrá tener solo un pod, es más probable querer crear un deployment (ver más abajo) que tiene más características como ReplicaSet y proporciona alta disponibilidad y escalado así como capacidades de monitorización.

apiVersion: v1 # version de la sintaxis del fichero
kind: pod # se va a crear un pod
metadata: 
    name: web-pod # nombre del pod
    labels: # agrega etiquetas personalizadas
        app: app
        zone: prod 
        version: v1 
    spec: # definición del pod
        containers: 
           - name: app-web
             image: autor/imagen
             ports: 
                 - containerPort: 80

ReplicationController

Ejemplo para ReplicationController, necesario cuando se quieren replicar pods específicos, si ya existiera uno del tipo especificado se tiene en cuenta para el total.

apiVersion: v1 
kind: ReplicationController # Tipo necesario para ReplicationController
metadata: 
    name: app-rc 
    spec: 
        replicas: 5 # número de replicas
        selector: 
            app: app # pod a replicar
            zone: prod
            version: v2  
        template: # plantilla con información sobre el pod
            metadata: 
            labels: 
                app: app 
                zone: prod 
                version: v1 
            spec: 
                containers: 
                    - name: app-web
                      image: autor/imagen
                      ports: 
                      - containerPort: 80

Servicio

Script para crear un servicio (kubectl expose rc)

Normalmente un fichero deployment y otro service será lo necesario para crear un cluster kubernetes.

apiVersion: v1 
kind: Service 
metadata: 
    name: app-svc 
spec: 
    selector: 
        app: app # que pods será expuestos
    type: NodePort # diferentes tipos (ver kubectl expose rc) 
    ports: # mapeo de puertos
    - port: 80 # puerto interno
        nodePort: 30001 # puerto del cluster

El selector en este caso está usando una etiqueta, por lo que conectará todos los pods con esa etiqueta, las etiquetas se pueden establecer en un ReplicationController en la sección label la restricción es que se realiza una comparación por igualdad.

Deployment

Fichero para crear un deployment, opción recomendada para generar un cluster.

apiVersion: apps/v1 
kind: Deployment 
metadata: name: app-deployment 
spec: 
    replicas: 3 
    selector: 
        matchLabels: 
            app: myapp 
        matchExpressions:
            - {key: zone, operator: In, values: [prod, test]} # ReplicaSet
        strategy:
            type: RollingUpdate
            minReadySeconds: 5 # Segundos a esperar antes de crear el siguiente pod
            rollingUpdate:
                maxSurge: 1 # % o # de pods que pueden exceder las réplicas solicitadas
                maxUnavailable: 1 # % o # de pods que pueden estar no disponibles durante la actualización
    ports:
       - protocol: TCP
         port: 1433
         targetPort: 1433
    type:  ClusterIP                 
    template:  
        metadata: 
            labels: 
                app: myapp 
                zone: prod 
                version: v1 
        spec: 
            containers: 
                - name: app-web 
                  image: apomic80/myapp:frontend-v1 
                  ports: 
                      - containerPort: 80
                  env:
                      - name: "Environment"
                      - value: "Production"
                      - name: "PASSWORD"
                        valueFrom:
                            secretKeyRef:
                                name: secreto
                                key: Password   
                  volumeMounts: # volúmenes a montar
                      - name: mountVolume # volumen donde será montado
                        mountPath: ruta # ruta que será montada
                      - name: secret-volume
                        mountPath: /etc/secretVolume 
            volumes: # volúmenes reclamados a mapear en el host
            - name: mountVolume # volumen lógico a ser usado por los contenedores
              persistentVolumeClaim:
                  claimName: volume-claim # este volumen se tiene que haber creado previamente
            - name: secret-volume # volumen lógico que tb es secreto
              secret:
                  secretName: mssql # el nombre del secreto para poder acceder al volumen

Un deployment por defecto creará un ReplicaSet para poder indicar expresiones más complejas en las etiquetas, como si está contenida en un conjunto.

Hay dos estrategias de actualización:

  • Recreate: Quita la versión previa y carga una nueva, útil para escenarios de desarrollo o prueba
  • RollingUpdate: El valor por defecto, se mueve a una nueva versión gradualmente basado en los parámetros configurados, útil para entornos productivos

PersistentVolume

Un PersistentVolume es un recurso creado por un administrador de cluster con características específicas y un ciclo de vida independiente de tus aplicaciones

apiVersion: v1 
kind: PersistentVolume 
metadata: 
    name: local-volume 
    labels: 
        type: local 
spec: 
    storageClassName: hostpath 
    capacity: 
        storage: 10Gi # tamaño del almacenamiento
    accessModes: 
        - ReadWriteOnce # modo de acceso lectura/escritura
    hostPath: 
        path: /mnt/data # ruta donde se montará el volumen

Normalmente una ruta local para el almacenamiento solo se usa por razones de prueba o desarrollo.

PersistentVolumeClaim

PersistentVolumeClaim es un almacenamiento solicitado por el usuario basado en lo que necesita, como modos de acceso específico o tamaños.

El almacenamiento se crea con un fichero PersistentVolume con ciertas características y con un fichero PersistentVolumeClaim se solicita uno que tenga las características que quiere el usuario.

apiVersion: v1 
kind: PersistentVolumeClaim 
metadata: 
    name: local-volume-claim 
    spec: 
        storageClassName: hostpath 
        accessModes: 
            - ReadWriteOnce # tipo de modo de acceso solicitado
        resources: 
            requests: 
                storage: 3Gi # tamaño solicitado

Secret

Es posible crear un fichero que solo contenga un secreto que se usará para almacenar contraseñas por ejemplo.

apiVersion: v1 
kind: Secret 
metadata: 
    name: secreto
type: Opaque 
data: 
    PASSWORD: UGFzc3dvcmRfMTIz # tiene que estar en base 64

En Linux se puede pasar un literal a Base64 como:
echo -n Password_123 | base64
Y para decodificarlo:
echo -n UGFzc3dvcmRfMTIz | base64 –decode

ResourceQuota

Establecer cuotas de recursos

apiVersion: v1
kind: ResourceQuota
metadata:
    name: myapp-quota
spec:
    hard:
        limits.cpu: 1 # Cantidad de CPUs que pueden usar
        limits.memory: 2Gi # Cantidad de memoria que pueden usar

Kubernetes