Primeros pasos con ksonnet
Introducción
Este tutorial te mostrará cómo crear una aplicación simple y también cómo desplegarla en Kubernetes usando ksonnet. En los ejemplos, usaré minikube o puedes consultar este repositorio que tiene una buena visión general de minikube. Una vez instalado y arrancado (minikube start
), ese comando descargará y configurará el entorno local. Si has estado siguiendo las publicaciones anteriores, ya tienes minikube instalado y funcionando. Antes de sumergirnos en un ejemplo, revisemos alguna terminología de ksonnet (extraída de la documentación oficial):
Aplicación
Una aplicación ksonnet representa un directorio bien estructurado de manifiestos de Kubernetes (esto se genera usando ks init
).
Entorno
Un entorno consiste en cuatro elementos, algunos de los cuales pueden obtenerse de tu contexto kubeconfig actual: Nombre, Servidor, Espacio de nombres, Versión de API. El entorno determina a qué clúster vas a desplegar la aplicación.
Componente
Un componente puede ser tan simple como un recurso de Kubernetes (un Pod, Deployment, etc.), o una pila completamente funcional, por ejemplo EFK/ELK. Puedes generar componentes usando ks generate
.
Prototipo
Prototipo + Parámetros = Componente. Piensa en un prototipo como una plantilla base antes de aplicar los parámetros, para establecer un nombre, réplicas, etc., para el recurso. Puedes explorar algunos prototipos del sistema con ks prototype
.
Parámetro
Da vida a un componente con valores dinámicos. Puedes usar ks param
para ver o modificar parámetros. Hay parámetros de Aplicación (globales), parámetros de Componente y parámetros de Entorno (anulan los parámetros de la aplicación).
Módulo
Los módulos proporcionan una forma de compartir componentes entre entornos. Más concisamente, un módulo se refiere a un subdirectorio en components/ que contiene su propio params.libsonnet. Para crear un módulo: ks module create <nombre_del_módulo>
.
Parte
Proporciona una forma de organizar y reutilizar código.
Paquete
Un paquete es un conjunto de prototipos relacionados y bibliotecas auxiliares asociadas. Te permite crear y compartir paquetes entre aplicaciones.
Registro
Es esencialmente un repositorio para paquetes; soporta el registro de incubadora, GitHub, sistema de archivos y Helm.
Manifiesto
El mismo antiguo manifiesto YAML o JSON pero esta vez escrito en Jsonnet; básicamente, Jsonnet es una extensión simple de JSON.
Uf, son muchos nombres y terminología a la vez. Comencemos ya con el terminal.
Empecemos
Este comando generará la siguiente estructura de carpetas ks init wordpress
:
INFO Using context "minikube" from kubeconfig file "~/.kube/config"
INFO Creating environment "default" with namespace "default", pointing to "version:v1.12.4" cluster at address "https://192.168.99.100:8443"
INFO Generating ksonnet-lib data at path '~/k8s-examples/wordpress/lib/ksonnet-lib/v1.12.4'
$ ls -l | awk '{ print $9 }'
app.yaml <--- Define versiones, espacio de nombres, dirección del clúster, nombre de la aplicación, registro.
components <--- Componentes; por defecto está vacío y tiene un archivo de parámetros.
environments <--- Por defecto solo hay un entorno llamado default.
lib <--- Aquí podemos encontrar los ayudantes de ksonnet que coinciden con la API de Kubernetes con los recursos comunes (Pods, Deployments, etc.).
vendor <--- Aquí es donde se instalan los paquetes/aplicaciones; puede verse como una carpeta de dependencias.
Generemos un deployed-service e inspeccionemos su contexto:
$ ks generate deployed-service wordpress \
--image bitnami/wordpress:5.0.2 \
--type ClusterIP
INFO Writing component at '~/k8s-examples/wordpress/components/wordpress.jsonnet'
Al momento de escribir esto, la última versión de WordPress es 5.0.2. Siempre se recomienda usar números de versión estáticos en lugar de etiquetas como ‘latest’ (porque ‘latest’ puede no ser el más reciente).
Veamos cómo se ve nuestro componente:
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.wordpress;
[
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": params.name
},
"spec": {
"ports": [
{
"port": params.servicePort,
"targetPort": params.containerPort
}
],
"selector": {
"app": params.name
},
"type": params.type
}
},
{
"apiVersion": "apps/v1beta2",
"kind": "Deployment",
"metadata": {
"name": params.name
},
"spec": {
"replicas": params.replicas,
"selector": {
"matchLabels": {
"app": params.name
},
},
"template": {
"metadata": {
"labels": {
"app": params.name
}
},
"spec": {
"containers": [
{
"image": params.image,
"name": params.name,
"ports": [
{
"containerPort": params.containerPort
}
]
}
]
}
}
}
}
]
Es solo otra plantilla para algunos recursos conocidos, un Service y un Deployment; de ahí proviene el nombre: deployed-service. Pero, ¿de dónde vienen esos parámetros?
Si ejecutamos ks show default
:
---
apiVersion: v1
kind: Service
metadata:
labels:
ksonnet.io/component: wordpress
name: wordpress
spec:
ports:
- port: 80
targetPort: 80
selector:
app: wordpress
type: ClusterIP
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
labels:
ksonnet.io/component: wordpress
name: wordpress
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- image: bitnami/wordpress:5.0.2
name: wordpress
ports:
- containerPort: 80
Veremos lo que nuestro paquete generará en YAML con algunos buenos valores predeterminados. Y por defecto, si recuerdas de las definiciones, un componente necesita un archivo de parámetros para llenar los espacios en blanco; en este caso es components/params.libsonnet
:
{
global: {
// Parámetros globales definidos por el usuario; accesibles para todos los componentes y entornos, Ej:
// replicas: 4,
},
components: {
// Parámetros a nivel de componente, definidos inicialmente desde 'ks prototype use ...'
// Cada objeto a continuación debería corresponder a un componente en el directorio components/
wordpress: {
containerPort: 80,
image: "bitnami/wordpress:5.0.2",
name: "wordpress",
replicas: 1,
servicePort: 80,
type: "ClusterIP",
},
},
}
Pero eso no es suficiente para ejecutar WordPress, ¿verdad? No, no lo es. Necesitamos una base de datos con almacenamiento persistente para que funcione correctamente, así que necesitaremos generar y extender otro deployed-service.
El siguiente paso sería crear otro componente:
$ ks generate deployed-service mariadb \
--image bitnami/mariadb:10.1.37 \
--type ClusterIP
INFO Writing component at '/home/kainlite/Webs/k8s-examples/wordpress/components/mariadb.jsonnet'
La última versión estable de MariaDB 10.1 GA al momento de escribir esto es 10.1.37.
Luego necesitaremos agregar un volumen persistente y también decirle a WordPress que use esta instancia de MariaDB. ¿Cómo hacemos eso? Necesitaremos modificar algunos archivos, de esta manera (para reutilizar cosas, coloqué las variables de MySQL en la sección global; para este ejemplo eso simplificará las cosas, pero podría no ser el mejor enfoque para un entorno de producción):
El components/params.json
resultante será:
{
global: {
// Parámetros globales definidos por el usuario; accesibles para todos los componentes y entornos, Ej:
// replicas: 4,
mariadbEmptyPassword: "no",
mariadbUser: "mywordpressuser",
mariadbPassword: "mywordpresspassword",
mariadbDatabase: "bitnami_wordpress",
},
components: {
// Parámetros a nivel de componente, definidos inicialmente desde 'ks prototype use ...'
// Cada objeto a continuación debería corresponder a un componente en el directorio components/
wordpress: {
containerPort: 80,
image: "bitnami/wordpress:5.0.2",
name: "wordpress",
replicas: 1,
servicePort: 80,
type: "ClusterIP",
},
mariadb: {
containerPort: 3306,
image: "bitnami/mariadb:10.1.37",
name: "mariadb",
replicas: 1,
servicePort: 3306,
type: "ClusterIP",
},
},
}
El components/wordpress.jsonnet
resultante será:
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.wordpress;
[
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": params.name
},
"spec": {
"ports": [
{
"port": params.servicePort,
"targetPort": params.containerPort
}
],
"selector": {
"app": params.name
},
"type": params.type
}
},
{
"apiVersion": "apps/v1beta2",
"kind": "Deployment",
"metadata": {
"name": params.name
},
"spec": {
"replicas": params.replicas,
"selector": {
"matchLabels": {
"app": params.name
},
},
"template": {
"metadata": {
"labels": {
"app": params.name
}
},
"spec": {
"containers": [
{
"image": params.image,
"name": params.name,
"ports": [
{
"containerPort": params.containerPort
}
],
"env": [
{
"name": "WORDPRESS_DATABASE_USER",
"value": params.mariadbUser,
},
{
"name": "WORDPRESS_DATABASE_PASSWORD",
"value": params.mariadbPassword,
},
{
"name": "WORDPRESS_DATABASE_NAME",
"value": params.mariadbDatabase,
},
{
"name": "WORDPRESS_HOST",
"value": "mariadb",
}
]
}
]
}
}
}
}
]
Lo único que cambió aquí es spec.containers.env
, que no estaba presente antes.
El components/mariadb.jsonnet
resultante será:
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.mariadb;
[
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": params.name
},
"spec": {
"ports": [
{
"port": params.servicePort,
"targetPort": params.containerPort
}
],
"selector": {
"app": params.name
},
"type": params.type
}
},
{
"apiVersion": "apps/v1beta2",
"kind": "Deployment",
"metadata": {
"name": params.name
},
"spec": {
"replicas": params.replicas,
"selector": {
"matchLabels": {
"app": params.name
},
},
"template": {
"metadata": {
"labels": {
"app": params.name
}
},
"spec": {
"containers": [
{
"image": params.image,
"name": params.name,
"ports": [
{
"containerPort": params.containerPort
},
],
"env": [
{
"name": "ALLOW_EMPTY_PASSWORD",
"value": params.mariadbEmptyPassword,
},
{
"name": "MARIADB_USER",
"value": params.mariadbUser,
},
{
"name": "MARIADB_PASSWORD",
"value": params.mariadbPassword,
},
{
"name": "MARIADB_ROOT_PASSWORD",
"value": params.mariadbPassword,
},
{
"name": "MARIADB_DATABASE",
"value": params.mariadbDatabase,
},
],
"volumeMounts": [
{
"mountPath": "/var/lib/mysql",
"name": "mariadb"
}
]
}
],
"volumes": [
{
"name": "mariadb",
"hostPath": {
"path": "/home/docker/mariadb-data"
}
}
]
}
}
}
}
]
Lo sé, lo sé, eso es mucho JSON. Confío en que tienes un buen scroll :).
Las únicas cosas que cambiaron aquí son spec.containers.env
, spec.containers.volumeMount
y spec.volumes
, que no estaban presentes antes. Eso es todo lo que necesitas para hacer que WordPress funcione con MariaDB.
Esta publicación solo rasca la superficie de lo que Ksonnet y Jsonnet pueden hacer. En otra publicación describiré características más avanzadas con menos JSON / YAML. Hay muchas cosas que se pueden mejorar y cubriremos esas cosas en la siguiente publicación. Si deseas ver todo el código fuente de esta publicación, ve aquí.
Limpiemos con ks delete default
:
INFO Deleting services mariadb
INFO Deleting deployments mariadb
INFO Deleting services wordpress
INFO Deleting deployments wordpress
Notas
Si deseas verificar la instalación de WordPress a través del navegador, puedes hacer minikube proxy
y luego acceder a la siguiente URL: WordPress (estoy usando el espacio de nombres por defecto aquí y el nombre del servicio es wordpress; si usas ingress no necesitas hacer este paso).
No estoy al tanto de si Ksonnet soporta lanzamientos y rollbacks como Helm, pero parece que podría emularse usando etiquetas de git y algunos hooks de git.
Si todo va bien, deberías ver algo como esto en los logs:
$ kubectl logs -f wordpress-5b4d6bd47c-bdtmw
Welcome to the Bitnami wordpress container
Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-wordpress
Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-wordpress/issues
nami INFO Initializing apache
apache INFO ==> Patching httpoxy...
apache INFO ==> Configuring dummy certificates...
nami INFO apache successfully initialized
nami INFO Initializing php
nami INFO php successfully initialized
nami INFO Initializing mysql-client
nami INFO mysql-client successfully initialized
nami INFO Initializing libphp
nami INFO libphp successfully initialized
nami INFO Initializing wordpress
mysql-c INFO Trying to connect to MySQL server
mysql-c INFO Found MySQL server listening at mariadb:3306
mysql-c INFO MySQL server listening and working at mariadb:3306
wordpre INFO
wordpre INFO ########################################################################
wordpre INFO Installation parameters for wordpress:
wordpre INFO First Name: FirstName
wordpre INFO Last Name: LastName
wordpre INFO Username: user
wordpre INFO Password: **********
wordpre INFO Email: user@example.com
wordpre INFO Blog Name: User's Blog!
wordpre INFO Table Prefix: wp_
wordpre INFO (Passwords are not shown for security reasons)
wordpre INFO ########################################################################
wordpre INFO
nami INFO wordpress successfully initialized
INFO ==> Starting wordpress...
[Thu Dec 27 04:30:59.684053 2018] [ssl:warn] [pid 116] AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name
[Thu Dec 27 04:30:59.684690 2018] [ssl:warn] [pid 116] AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name
[Thu Dec 27 04:30:59.738783 2018] [ssl:warn] [pid 116] AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name
[Thu Dec 27 04:30:59.739701 2018] [ssl:warn] [pid 116] AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name
[Thu Dec 27 04:30:59.765798 2018] [mpm_prefork:notice] [pid 116] AH00163: Apache/2.4.37 (Unix) OpenSSL/1.1.0j PHP/7.2.13 configured -- resuming normal operations
[Thu Dec 27 04:30:59.765874 2018] [core:notice] [pid 116] AH00094: Command line: 'httpd -f /bitnami/apache/conf/httpd.conf -D FOREGROUND'
172.17.0.1 - - [27/Dec/2018:04:31:00 +0000] "GET / HTTP/1.1" 200 3718
172.17.0.1 - - [27/Dec/2018:04:31:01 +0000] "GET /wp-includes/js/wp-embed.min.js?ver=5.0.2 HTTP/1.1" 200 753
172.17.0.1 - - [27/Dec/2018:04:31:01 +0000] "GET /wp-includes/css/dist/block-library/theme.min.css?ver=5.0.2 HTTP/1.1" 200 452
172.17.0.1 - - [27/Dec/2018:04:31:01 +0000] "GET /wp-includes/css/dist/block-library/style.min.css?ver=5.0.2 HTTP/1.1" 200 4281
172.17.0.1 - - [27/Dec/2018:04:31:01 +0000] "GET /wp-content/themes/twentynineteen/style.css?ver=1.1 HTTP/1.1" 200 19371
172.17.0.1 - - [27/Dec/2018:04:31:01 +0000] "GET /wp-content/themes/twentynineteen/print.css?ver=1.1 HTTP/1.1" 200 1230
Y eso es todo por ahora. Asegúrate de revisar la documentación oficial de Ksonnet y ks help
para saber más sobre lo que Ksonnet puede hacer para ayudarte a desplegar tus aplicaciones en cualquier clúster de Kubernetes.
Errata
Si encuentras algún error o tienes alguna sugerencia, por favor envíame un mensaje para que pueda corregirlo.
No tienes cuenta? Regístrate aqui
Ya registrado? Iniciar sesión a tu cuenta ahora.
-
Comentarios
Online: 0
Por favor inicie sesión para poder escribir comentarios.