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