Mostrando entradas con la etiqueta configmap. Mostrar todas las entradas
Mostrando entradas con la etiqueta configmap. Mostrar todas las entradas

jueves, 1 de mayo de 2025

Kubernetes & Quarkus: Configuration

En otros posts hemos visto como crear nuestro primer cluster de Kubernetes y en otro cómo desplegar varios contenedores y que se comuniquen entre sí. También hemos podido conocer un poco más sobre los objetos que componen Kubernetes.

Partiendo del anterior ejemplo, aquí mas info, aunque teníamos configurados los secrets y configmaps para generar el deployment correctamente. No lo estábamos haciendo del todo bien en cuanto a la configuración de Quarkus, donde teníamos los valores a mano. En este ejemplo obtendremos los valores del secret de Kubernetes. Para ello, lo primero es añadir la dependencia que nos permitirá hacer uso de ellos. 

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-kubernetes-config</artifactId>
</dependency>

El siguiente paso es añadir la configuración en el fichero application.properties que nos permita leer los valores almacenados en Kubernetes. 

%prod.quarkus.kubernetes.namespace=default
%prod.quarkus.kubernetes-config.enabled=true
%test,dev.quarkus.kubernetes-config.enabled=false

%prod.quarkus.kubernetes-config.secrets.enabled=true
%test,dev.quarkus.kubernetes-config.secrets.enabled=false

%prod.quarkus.kubernetes-config.config-maps=ms-k8s-config-configmap
%prod.quarkus.kubernetes-config.secrets=ms-k8s-config-secret

Hay que tener en cuenta, que debemos diferenciar entre el perfil de producción, que será cuando estemos desplegando la aplicación en un entorno clusterizado. Y el entorno de local o pruebas, donde ejecutaremos la aplicación en un entorno no clusterizado. Si no hacemos esta diferenciación, en local o en test, la aplicación intentará ponerse en contacto con Kubernetes y fallará al arrancar. 

A continuación vamos a crear una propiedad, pero solo para los entornos de test y local. Para el entorno de producción cogerá el valor directamente de Kubernetes. Así lo configuramos en nuestro properties. 

#Propery
%test,dev.log.message=log message from properties

Y así lo configuramos en nuestro objeto de Kubernetes

apiVersion: v1
kind: ConfigMap
metadata:
  name: ms-k8s-config-configmap
data:
  log.message: log message from configmap

Nuestra configuración de base de datos, que tendrá valores obtenidos del secret de Kubernetes, será igual que antes. Solo que en las credenciales pondremos el identificador de la misma configurado en el secret. Así es en el fichero properties:

%prod.quarkus.datasource.db-kind=mariadb
%prod.quarkus.datasource.username=username-default
%prod.quarkus.datasource.password=${user.pass}
%prod.quarkus.datasource.jdbc.url=jdbc:mariadb://mariadb:3306/library
%prod.quarkus.datasource.jdbc.max-size=5

Así está en el fichero de descripción del secret:

apiVersion: v1
kind: Secret
metadata:
  name: ms-k8s-config-secret
data:
  user.pass: bXlfY29vbF9zZWNyZXQ=

En principio ya tendríamos configurado nuestra aplicación para su correcto despliegue y ejecución en el cluster de Kubernetes. Pero si creamos la imagen y realizamos el despliegue con la configuración actual de Kubernetes que tenemos, nos daría el siguiente error. 

io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: 
GET at: https://10.96.0.1:443/api/v1/namespaces/default/configmaps/ms-k8s-config-configmap. 
Message: Forbidden!Configured service account doesn't have access. 
Service account may have been revoked. configmaps "ms-k8s-config-configmap" is forbidden: 
User "system:serviceaccount:default:default" cannot get resource "configmaps" in API group "" in the namespace "default".

Esto es debido a que uno de los elementos principales del Control Plane es su API. La cual pone a disposición de elementos externos un método para la gestión de los objetos de Kubernetes. Permitiendo un acceso a los objetos del propio cluster pero desde fuera del mismo. 

Para gestionar el permiso y uso de sus herramientas, Kubernetes tiene el control de acceso basado en roles (RBAC), el cual nos permite regular el acceso a los recursos informáticos o de red basado en los roles de los usuarios individuales dentro de su organización.

La autorización RBAC utiliza el grupo de API rbac.authorization.k8s.io para impulsar las decisiones de autorización, lo que le permite configurar dinámicamente las políticas a través de la API de Kubernetes.

Por tanto deberemos crear los objetos de tipo Role, Rolebinding y ServiceAccount que nos permitan manejar desde la aplicación de Quarkus los configmap y secrets. Esto lo podemos hacer de la siguiente forma:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: ms-k8s-config-service-account
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ms-k8s-config-role
rules:
- apiGroups:
  - ""
  resourceNames:
  - ms-k8s-config-configmap
  resources:
  - configmaps
  verbs:
  - get
- apiGroups:
  - ""
  resourceNames:
  - ms-k8s-config-secret
  resources:
  - secrets
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ms-k8s-config-role-binding
subjects:
- kind: ServiceAccount
  name: ms-k8s-config-service-account
roleRef:
  kind: Role
  name: ms-k8s-config-role
  apiGroup: rbac.authorization.k8s.io

Ahora si, podremos crear la imagen y desplegarla con Kubernetes. Tras ello, al realizar una invocación a nuestra API podremos comprobar como está cogiendo los valores correctamente del configmap y del secret. 

INFO  [com.hom.exa.res.BookResource] (executor-thread-1) Message from application.properties: log message from configmap

Como siempre, espero que haya sido de ayuda. Y si quieres, puedes ver el código aquí. En el README.md podrás ver los comandos para permitir la ejecución de esta prueba, los cuales son:

#Start Kubernetes
kind create cluster --config kind-config.yaml --name kind-basic
#Start Deployment
kubectl apply -f ms-k8s-config.yaml
#Test application
curl --location 'http://localhost:30000/book'
#See logs
kubectl logs deployment/ms-k8s-config --all-containers=true

lunes, 22 de abril de 2024

Kubernetes: Despliegue conjunto de Quarkus y BBDD

Hemos hecho hace poco un post donde explicábamos como montar un cluster de Kubernetes en local, aquí. Donde también vimos conceptos básicos de Kubernetes, que nos ayudaron a comprender mejor el despliegue. 

Hoy veremos cómo desplegar dos contenedores distintos y entablar una conexión entre ambos. Para ello seguiremos con un ejemplo de un microservicio Quarkus y su conexión con una base de datos MariaDB. Pero además también veremos nuevos conceptos de Kubernetes que ampliarán nuestro conocimiento del mismo. 

Empezaremos montando el servicio de MariaDB donde además necesitaremos de la ayuda de un configMap y un configSecret. 

  • ConfigMap: Es otro tipo de objeto disponible en Kubernetes. Utilizado para almacenar datos no confidenciales en el formato clave-valor. Pueden ser utilizados como variables de entorno, argumentos de la linea de comandos o como ficheros de configuración en un Volumen.
  • Secrets:  Otro objeto que permite almacenar y administrar información confidencial. Permitiendo flexibilidad para añadir palabras claves sin necesidad de configurarlas en los pods. 

Por un lado crearemos un ConfigMap que nos permita añadir un script.sql inicial y que se ejecute al inicializar la base de datos. Muy util para entornos de pruebas. 

apiVersion: v1
kind: ConfigMap
metadata:
name: mariadb-initdb-config
data:
initdb.sql: |
CREATE DATABASE library;
GRANT ALL PRIVILEGES ON library.* TO 'username-default'@'%' IDENTIFIED BY 'my_cool_secret';
USE `library`;
CREATE TABLE `BOOK` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`NAME` varchar(45) DEFAULT NULL,
`AUTHOR` varchar(45) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
INSERT INTO BOOK (NAME, AUTHOR) VALUES('Ender Game', 'Orson S. Card');
INSERT INTO BOOK (NAME, AUTHOR) VALUES('The stars my destination', 'Alfred Bester');
INSERT INTO BOOK (NAME, AUTHOR) VALUES('Dune', 'Frank Herbert');

Por otro, crearemos el Secret para poder almacenar de forma segura las contraseñas de usuario y administrador de la base de datos. Las claves que se incluyan en los secrets deben de estar codificados en base 64. 

apiVersion: v1
kind: Secret
metadata:
name: mariadb-secret
data:
user.pass: bXlfY29vbF9zZWNyZXQ=
root.pass: bXktc2VjcmV0LXB3

Lo siguiente es la configuración de la base de datos. Lo crearemos como un objeto deployment donde tendremos toda la configuración. A través de variables de entorno, que hacen referencia a los secrets almacenados, configuraremos los valores de las contraseñas del administrador y usuario. Y a través la configuración de los volúmenes podremos indicar el script que debe ejecutar al inicio. 

apiVersion: apps/v1
kind: Deployment # what to create?
metadata:
name: mariadb
spec: # specification for deployment resource
replicas: 1 # how many replicas of pods we want to create
selector:
matchLabels:
app: mariadb
strategy:
type: Recreate
template: # blueprint for pods
metadata:
labels:
app: mariadb # service will look for this label
spec: # specification for pods
containers: # we can have one or more containers
- name: mariadb
image: mariadb
ports:
- containerPort: 3306 #port exposed in cluster
env: # allows to define environment variables
- name: MARIADB_ROOT_PASSWORD
valueFrom:
secretKeyRef: # allows to refer to a secret configured
name: mariadb-secret #name of the secret
key: root.pass #key of the secret that you want to use
- name: MARIADB_USER
value: username-default
- name: MARIADB_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-secret
key: user.pass
volumeMounts:
- name: mariadb-initdb #configuration of the volumes
mountPath: /docker-entrypoint-initdb.d
volumes:
- name: mariadb-initdb #volumen to configure
configMap:
name: mariadb-initdb-config #refer key of the config map

El siguiente paso será configurar el microservicio Quarkus. En otro post entraremos más en las configuración de Quarkus con Kubernetes o Docker. Pero en esté solo indicaremos cómo configurar la base de datos para ver también cómo podemos realizar la conexión entre ambos contenedores. 

## bbdd testing conf
quarkus.datasource.devservices.image-name=mariadb:10.3.6
quarkus.datasource.jdbc.driver=org.mariadb.jdbc.Driver

%prod.quarkus.datasource.db-kind=mariadb
%prod.quarkus.datasource.username=username-default
%prod.quarkus.datasource.password=my_cool_secret
%prod.quarkus.datasource.jdbc.url=jdbc:mariadb://mariadb:3306/library
%prod.quarkus.datasource.jdbc.max-size=5

Como se puede apreciar, simplemente vale con indicar la etiqueta indicada en el deployment. Y los datos del usuario de BBDD que hemos indicado en la creación del pod. 

Y esto ha sido todo. Espero que os haya servido para aprender un poco más sobre Kubernetes, los ConfigMap, Secrets y Quarkus.