Publicando contenedores en Kubernetes con Terraform
Terraform es una herramienta ideal para definir infraestructura de forma programática (Infraestructura como código). Dado que las aplicaciones de Kubernetes están contenerizadas (Dockers), su despliegue se puede realizar fácilmente con un pequeño fichero de configuración de Terraform que define los recursos a crear en Kubernetes.
En este breve tutorial, mostramos cómo publicar una aplicación y crear un NodePort en Kubernetes usando Terraform. Su ejecución solo lleva 10 segundos.
La aplicación será obtenida desde el registro público de Docker y Terraform instruirá a Kubernetes para crear 3 réplicas y publicar sus servicios en un NodePort.
Pulse para ver la ejecución:
Atención: Esto no es una buena práctica
Las buenas prácticas para infraestructura de IT Wonder Lab incluyen modularizar la configuración de Terraform.
Sin embargo, en este ejemplo se define todo en un único fichero. Puede ver otros de nuestros tutoriales que sí aplican buenas prácticas para el despliegue con Kubernetes.
Prerrequisitos
- Disponer de acceso a un clúster de Kubernetes.En el ejemplo usaremos el creado siguiendo el tutorial Creación de un Clúster de Kubernetes con Vagrant y Ansible.
- Disponer de un fichero de configuración de acceso a Kubernetes local y conocer el contexto.
- Descargar el código fuente desde el repositorio de Git Hub de IT Wonder Lab o crear el fichero con el código mostrado.
Comprobación del contexto de conexión al clúster de Kubernetes
Para el ejemplo usaremos la configuración de conexión a un clúster de Kubernetes existente en la ubicación por defecto ~/.kube/config
El fichero ~/.kube/config
puede tener diferentes contextos, un contexto define un clúster, un usuario y el nombre asociado al contexto.
Comprueben los contextos usando el comando kubectl config view
:
$ kubectl config view apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://192.168.50.11:6443 name: kubernetes contexts: - context: cluster: kubernetes user: kubernetes-admin name: [email protected] current-context: [email protected] kind: Config preferences: {} users: - name: kubernetes-admin user: client-certificate-data: REDACTED client-key-data: REDACTED
En el siguiente ejemplo se muestra el contenido del fichero ~/.kube/config
que contiene el contexto con nombre [email protected]
:
apiVersion: v1 clusters: - cluster: certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lH....Q0VSVElGSUNBVEUtLS0tLQo= server: https://192.168.50.11:6443 name: kubernetes contexts: - context: cluster: kubernetes user: kubernetes-admin name: [email protected] current-context: [email protected] kind: Config preferences: {} users: - name: kubernetes-admin user: client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJWTJsaU5WWjVrZ1V3....U4rbW9qL1l6V0NJdURnSXZBRU1NZDVIMnBOaHMvcz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= client-key-data: LS0tLS1XRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpWSUlFcFFJQkFBS0NBUUVBK295RXBYVTZu.....BLRVktLS0tLQo=
Utilizaremos el contexto kubern[email protected] en la definición de nuestro proveedor de Terraform para Kubernetes.
Si el contexto es diferente, puede actualizar el nombre en el fichero de Terraform o renombrar el contexto utilizando los comandos kubectl config get-contexts
y kubectl config rename-context
En el siguiente ejemplo, se renombra un contexto existente llamado [email protected] a [email protected]
$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * [email protected] kubernetes kubernetes-admin $ kubectl config rename-context [email protected] [email protected] Context "[email protected]" renamed to "[email protected]". $ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * [email protected] kubernetes kubernetes-admin
Comprobar la conectividad del Clúster de Kubernetes
Por favor compruebe que su fichero de configuración de conexión a Kubernetes tiene las credenciales correctas, la comprobación se realiza conectando al clúster con el comando kubectl
:
[email protected]:~/git/github/terraform-kubernetes-deploy-app$ kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-m-1 Ready master 3h33m v1.18.6 k8s-n-1 Ready <none> 3h30m v1.18.6 k8s-n-2 Ready <none> 3h27m v1.18.6
Fichero de Terraform para despliegue de aplicación en Kubernetes
Cree o descargue el fichero terraform.tf desde GitHub:
# Copyright (C) 2018 - 2020 IT Wonder Lab (https://www.itwonderlab.com) # # This software may be modified and distributed under the terms # of the MIT license. See the LICENSE file for details. # -------------------------------- WARNING -------------------------------- # IT Wonder Lab's best practices for infrastructure include modularizing # Terraform configuration. # In this example, we define everything in a single file. # See other tutorials for Terraform best practices for Kubernetes deployments. # -------------------------------- WARNING -------------------------------- terraform { required_version = "~> 0.12" #cannot contain interpolations. Means requiered version >= 0.12 and < 0.13 } #----------------------------------------- # Default provider: Kubernetes #----------------------------------------- provider "kubernetes" { #Context to choose from the config file. config_context = "[email protected]" version = "~> 1.12" } #----------------------------------------- # KUBERNETES DEPLOYMENT COLOR APP #----------------------------------------- resource "kubernetes_deployment" "color" { metadata { name = "color-blue-dep" labels = { app = "color" color = "blue" } //labels } //metadata spec { selector { match_labels = { app = "color" color = "blue" } //match_labels } //selector #Number of replicas replicas = 3 #Template for the creation of the pod template { metadata { labels = { app = "color" color = "blue" } //labels } //metadata spec { container { image = "itwonderlab/color" #Docker image name name = "color-blue" #Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). #Block of string name and value pairs to set in the container's environment env { name = "COLOR" value = "blue" } //env #List of ports to expose from the container. port { container_port = 8080 }//port resources { limits { cpu = "0.5" memory = "512Mi" } //limits requests { cpu = "250m" memory = "50Mi" } //requests } //resources } //container } //spec } //template } //spec } //resource #------------------------------------------------- # KUBERNETES DEPLOYMENT COLOR SERVICE NODE PORT #------------------------------------------------- resource "kubernetes_service" "color-service-np" { metadata { name = "color-service-np" } //metadata spec { selector = { app = "color" } //selector session_affinity = "ClientIP" port { port = 8080 node_port = 30085 } //port type = "NodePort" } //spec } //resource
Las líneas 13 a 15 definen la versión requerida de Terraform. Usaremos Terraform 0.12.
Las líneas 21 a 25 definen el config_context (contexto de configuración) del fichero file ~/.kube/config
que será utilizado, usaremos [email protected], también se define la versión requerida del proveedor de Kubernetes para Terraform.
Las líneas 32 a 91 definen un recurso de despliegue en Kubernetes por parte de Terraform con el nombre «color» y las siguientes propiedades:
- Nombre = «color-blue-dep»
- Etiquetas
- app=»color»
- color=»blue»
- Réplicas: 3
- Todas las réplicas usarán la plantilla de contenedor para crear los PODS que:
- Obtiene la imagen Docker «itwonderlab/color» desde el repositorio público de Docker (https://hub.docker.com/u/itwonderlab)
- Fija una variable de entorno en el contenedor de Docker con nombre COLOR y valor «blue»
- Publica el puerto 8080 del contenedor (El puerto HTTP usado por la aplicación)
- Fija límites en memoria y CPU.
Dado que estamos usando el clúster local del tutorial Kubernetes usando Vagrant y Ansible, se debe crear un puerto NodePort para exponer el puerto de la aplicación color fuera de la red de VirtualBox
Las líneas 97 a 112 crean un NodePort que publica el puerto 8080 de la aplicación «color» como Node Port 30085 en todos las IPs públicas de los nodos de Kubernetes. Vea Using a NodePort in a Kubernetes Cluster on top of VirtualBox para más información.
Inicializar los proveedores de Terraform
Si es la primera vez que se ejecuta el plan, se deben inicializar los proveedores de Terraform (Proveedor Terraform para Kubernetes) con el comando terraform init
que descargará los plugins necesarios.
~/git/github/terraform-kubernetes-deploy-app$ terraform init Initializing the backend... Initializing provider plugins... - Checking for available provider plugins... - Downloading plugin for provider "kubernetes" (hashicorp/kubernetes) 1.12.0... Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, othercommands will detect it and remind you to do so if necessary
Publicar la aplicación en Kubernetes junto con el NodePort usando Terraform
Ya estamos listos para publicar la aplicación definida en la configuración del fichero de Terrafom.
Ejecute terraform plan
para ver los cambios a realizar sobre el clúster:
[email protected]:~/git/github/terraform-kubernetes-deploy-app$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. ------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # kubernetes_deployment.color will be created + resource "kubernetes_deployment" "color" { + id = (known after apply) + wait_for_rollout = true + metadata { + generation = (known after apply) + labels = { + "app" = "color" + "color" = "blue" } + name = "color-blue-dep" + namespace = "default" + resource_version = (known after apply) + self_link = (known after apply) + uid = (known after apply) } + spec { + min_ready_seconds = 0 + paused = false + progress_deadline_seconds = 600 + replicas = 3 ... + spec { + cluster_ip = (known after apply) + external_traffic_policy = (known after apply) + publish_not_ready_addresses = false + selector = { + "app" = "color" } + session_affinity = "ClientIP" + type = "NodePort" + port { + node_port = 30085 + port = 8080 + protocol = "TCP" + target_port = (known after apply) } } } Plan: 2 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.
Ejecute terraform apply
para ejecutar los cambios en Kubernetes:
[email protected]:~/git/github/terraform-kubernetes-deploy-app$ terraform plan [email protected]:~/git/github/terraform-kubernetes-deploy-app$ terraform apply An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # kubernetes_deployment.color will be created + resource "kubernetes_deployment" "color" { + id = (known after apply) + wait_for_rollout = true + metadata { + generation = (known after apply) + labels = { + "app" = "color" + "color" = "blue" } + name = "color-blue-dep" + namespace = "default" + resource_version = (known after apply) + self_link = (known after apply) + uid = (known after apply) } + spec { + min_ready_seconds = 0 + paused = false + progress_deadline_seconds = 600 + replicas = 3 ... + template { + metadata { + generation = (known after apply) + labels = { + "app" = "color" + "color" = "blue" } + name = (known after apply) + resource_version = (known after apply) + self_link = (known after apply) + uid = (known after apply) } + spec { ... + container { + image = "itwonderlab/color" + image_pull_policy = (known after apply) + name = "color-blue" + stdin = false + stdin_once = false + termination_message_path = "/dev/termination-log" + tty = false + env { + name = "COLOR" + value = "blue" } + port { + container_port = 8080 + protocol = "TCP" } ... } # kubernetes_service.color-service-np will be created + resource "kubernetes_service" "color-service-np" { + id = (known after apply) ... + spec { + cluster_ip = (known after apply) + external_traffic_policy = (known after apply) + publish_not_ready_addresses = false + selector = { + "app" = "color" } + session_affinity = "ClientIP" + type = "NodePort" + port { + node_port = 30085 + port = 8080 + protocol = "TCP" + target_port = (known after apply) } } } Plan: 2 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes kubernetes_service.color-service-np: Creating... kubernetes_service.color-service-np: Creation complete after 0s [id=default/color-service-np] kubernetes_deployment.color: Creating... kubernetes_deployment.color: Creation complete after 8s [id=default/color-blue-dep] Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Acceda a la aplicación usando el NodePort
Abra la URL http://192.168.50.11:30085/ para acceder a la aplicación Color (Todos los nodos de Kubernetes exponen el mismo NodePort, puede usar cualquier IP del clúster para acceder tal como se explica en Using a NodePort in a Kubernetes Cluster on top of VirtualBox.

Ha finalizado la publicación y ha accedido correctamente a una de las réplicas.
A continuación se muestran otras opciones para comprobar el desligue y modificar la configuración.
Uso del Kubernetes Dashboard para comprobar el despliegue
Acceda al Dashboard de Kubernetes, si ha utilizado el tutorial de Kubernetes local será la URL https://192.168.50.11:30002/

En el Dashboard de Kubernetes se observan las tres réplicas o PODS de la aplicación color, un set de réplica y el servicio de NodePort.
Modifique el número de replicas a 1
Es muy sencillo modificar el número de replicas de la aplicación desplegadas en Kubernetes usando Terraform sin afectar las conexiones existentes usando una estrategia de rolling update.
Edite el fichero terraform.tf para indicar un número diferente de réplicas:
replicas = 1
Ejecute terraform plan
[email protected]:~/git/github/terraform-kubernetes-deploy-app$ terraform plan Refreshing Terraform state in-memory prior to plan... ... ~ update in-place Terraform will perform the following actions: # kubernetes_deployment.color will be updated in-place ~ resource "kubernetes_deployment" "color" { id = "default/color-blue-dep" wait_for_rollout = true metadata { annotations = {} generation = 1 labels = { "app" = "color" "color" = "blue" } ... ~ spec { min_ready_seconds = 0 paused = false progress_deadline_seconds = 600 ~ replicas = 3 -> 1 revision_history_limit = 10 ... strategy { type = "RollingUpdate" rolling_update { max_surge = "25%" max_unavailable = "25%" } } ... } Plan: 0 to add, 1 to change, 0 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.
Ejecute terraform apply
para ver los cambios:
[email protected]:~/git/github/terraform-kubernetes-deploy-app$ terraform apply ... Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: # kubernetes_deployment.color will be updated in-place ~ resource "kubernetes_deployment" "color" { id = "default/color-blue-dep" wait_for_rollout = true ... ~ spec { min_ready_seconds = 0 paused = false progress_deadline_seconds = 600 ~ replicas = 3 -> 1 revision_history_limit = 10 ... } Plan: 0 to add, 1 to change, 0 to destroy. ... kubernetes_deployment.color: Modifying... [id=default/color-blue-dep] kubernetes_deployment.color: Modifications complete after 1s [id=default/color-blue-dep] Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
2 comentarios
Fantástico tutorial, expones los conceptos de forma muy clara, pero con la suficiente profundidad como para que pueda ser útil en la realidad.
Muchas gracias Alfonso, nos alegra mucho que te sea útil. Kubernetes facilita mucho los despliegues de aplicaciones y su infraestructura asociada.