Cómo actualizar a Terraform 0.12

Para comenzar con Terraform, utilicé la versión 0.11 de Terraform. Como han señalado algunos lectores, esta versión carece de algunas funciones importantes, por lo que en este artículo explicaré cómo actualizar Terraform a la versión 0.12 con más funciones.

Es posible que se sorprenda al saber que muchas personas todavía usan Terraform 0.11, incluidas las grandes organizaciones y los usuarios obstinados a quienes les gusta quedarse con la tecnología comprobada. La conversión de Terraform 0.11 a 0.12 puede ser muy compleja. Si desea aprovechar las funciones más recientes pero cree que no está listo para actualizar, este artículo debería ayudarlo a facilitar la conversión.

En este artículo, usaré el código de mi artículo "Primeros pasos" y el tfenv herramienta, que le permite utilizar diferentes versiones de Terraform en la misma máquina. También asumo que está familiarizado con dos versiones de Terraform (la que está usando y la que está migrando) y cómo usar el terraform mando en general.

Índice

    Se requieren cambios de código para la versión 12

    Algunas cosas funcionan en la versión 0.11 de Terraform que no funcionan en la versión 0.12. Aquí hay un ejemplo de código que usé en mi artículo anterior:

    resource "kubernetes_namespace" "1-minikube-namespace" {
      metadata {
            name = "my-first-terraform-namespace"
      }
    }

    Como señaló un lector, este bloque de código no funciona en la versión 0.12 debido a cambios en la forma en que funciona la última versión de Terraform. Este es un ejemplo simple y se vuelve más complicado. Estos son algunos ejemplos de cuántas cosas pueden necesitar cambiar en un entorno de producción.

    El nuevo Terraform necesita una sintaxis y una estructura ligeramente diferentes. Para comenzar, agregue un vars.tf Archivo:

    variable "namespace" {
      type = "string"
      default = "helloworld"
    }

    variable "cluster" {
      type = "string"
      default = "minikube"
    }

    Luego, intercambie partes del main.tf archivo para incrustar el nuevo vars.tf Archivo. El proveedor de Kubernetes ahora se ve así:

    provider "kubernetes" {
      config_context_cluster   = "${var.cluster}"
    }

    Aquí está el recurso de espacio de nombres revisado:

    resource "kubernetes_namespace" "1-minikube-namespace" {
      metadata {
            name = "${var.namespace}"
      }
    }

    Finalmente, el proveedor de Helm modificado:

    provider "helm" {
      kubernetes {
            config_context_cluster   = "${var.cluster}"
      }
    }

    ¡Atención! Estos pequeños cambios serán importantes al cambiar de versión.

    Distribuir antes de la conversión

    Antes de continuar, configure tfenv para usar la versión correcta de Terraform:

    [email protected]:~/terraform_doc$ tfenv list
      0.12.29
      0.11.15-oci
    [email protected]:~/terraform_doc$ tfenv use 0.11.15-oci
    Switching default version to v0.11.15-oci
    Switching completed
    [email protected]:~/terraform_doc$ terraform --version
    Terraform v0.11.15-oci
    + provider.helm v1.2.2
    + provider.kubernetes v1.11.2

    Your version of Terraform is out of date! The latest version
    is 0.xx.y. You can update by downloading from www.terraform.io/downloads.html

    Si (como yo) ha realizado otro trabajo con Terraform después de usar el código en mi artículo anterior de Terraform, debe volver a implementar todo. Configure el clúster de Minikube para esta implementación de Terraform iniciando un nuevo clúster limpio:

    $ minikube delete
    ?  Deleting "minikube" in kvm2 ...
    ?  Removed all traces of the "minikube" cluster.
    [email protected]:~/terraform_doc$ minikube start
    ?  minikube v1.14.0 on Ubuntu 18.04

    Después de configurar el clúster, puede implementar el código de Terraform modificado. Comience con el init mando:

    $ terraform init

    Initializing provider plugins...

    The following providers do not have any version constraints in configuration,
    so the latest version was installed.

    To prevent automatic upgrades to new major versions that may contain breaking
    changes, it is recommended to add version = "..." constraints to the
    corresponding provider blocks in configuration, with the constraint strings
    suggested below.

    * provider.helm
    : version = "~> 1.2"
    * provider.kubernetes
    : version = "~> 1.11"

    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 Infraestructura. All Terraform commands
    should now work. [...]

    Entonces, ejecuta tu plan:

    $ terraform plan
    Refreshing Terraform state in-memory prior to plan...
    helm_release.local
    : Refreshing state... (ID: buildachart)
    kubernetes_namespace.1-minikube-namespace
    : Refreshing state... (ID: my-first-terraform-namespace) [...]

    Terraform will perform the following actions
    :

      + helm_release.local
            id
    :                            <computed>
            atomic
    :                        "false"
            chart
    :                         "./buildachart"
            cleanup_on_fail
    :               "false"
            create_namespace
    :              "false"
            dependency_update
    :             "false"
            disable_crd_hooks
    :             "false"
            disable_openapi_validation
    : "false"
            [...]
      + kubernetes_namespace.1-minikube-namespace
            id
    :                            <computed>
            metadata.#:                     "1"
            [...]

    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.

    Por último, aplica el Terraform:

    $ terraform apply --auto-approve
    helm_release.local
    : Refreshing state... (ID: buildachart)
    kubernetes_namespace.1-minikube-namespace
    : Refreshing state... (ID: my-first-terraform-namespace)
    kubernetes_namespace.1-minikube-namespace
    : Creating...
      metadata.#:                   "" => "1"
      metadata.0.generation
    :       "" => "<computed>"
      [...]
    helm_release.local
    : Creating...
      atomic
    :                      "" => "false"
      chart
    :                       "" => "./buildachart"
      cleanup_on_fail
    :             "" => "false"
      create_namespace
    :            "" => "false"
     [...]
      version
    :                     "" => "0.1.0"
      wait
    :                        "" => "true"
    kubernetes_namespace.1-minikube-namespace
    : Creation complete after 1s (ID: helloworld)
    helm_release.local
    : Still creating... (10s elapsed)
    helm_release.local
    : Creation complete after 13s (ID: buildachart)

    Apply complete! Resources
    : 2 added, 0 changed, 0 destroyed.

    Ahora tiene una copia de seguridad local del estado de Terraform:

    $ ls -lrt

    drwxr-xr-x 6 jess jess 4096 May 16 14:15 buildachart
    -rw-r--r-- 1 jess jess  363 Oct 24 13:06 main.tf
    -rw-rw-r-- 1 jess jess  132 Oct 24 13:17 vars.tf
    -rw-rw-r-- 1 jess jess 3897 Oct 24 13:20 terraform.tfstate.backup
    -rw-rw-r-- 1 jess jess 3821 Oct 24 13:21 terraform.tfstate

    Convertir de Terraform 0.11 a 0.12

    Una vez que todo se haya implementado con Terraform 0.11, debe completar el proceso de conversión sin dañar lo que tiene en su nuevo clúster de producción. Primero, cambie su versión de Terraform a 0.12 usando tfenv:

    $ tfenv list
      0.12.29
    * 0.11.15-oci (set by /home/jess/.tfenv/version)
    [email protected]:~/terraform_doc$ tfenv use 0.12.29
    Switching default version to v0.12.29
    Switching completed
    [email protected]:~/terraform_doc$ terraform --version
    Terraform v0.12.29
    + provider.helm v1.2.2
    + provider.kubernetes v1.11.2

    Ahora que está en Terraform 0.12, está listo para convertir. Afortunadamente, Terraform tiene un comando incorporado para esto, como se muestra en este fragmento de la lista de comandos de Terraform:

    All other commands:
            0.12upgrade     Rewrites pre-0.12 module source code for v0.12

    Prueba el upgrade comando para ver lo que se reescribirá, luego ingrese yes actualizar:

    $ terraform 0.12upgrade

    This command will rewrite the configuration files in the given directory so
    that they use the new syntax features from Terraform v0.12, and will identify
    any constructs that may need to be adjusted for correct operation with
    Terraform v0.12.
    [...]
    Would you like to upgrade the module in the current directory?
      Only 'yes' will be accepted to confirm.

      Enter a value
    : yes

    -----------------------------------------------------------------------------

    Upgrade complete!

    The configuration files were upgraded successfully. Use your version control
    system to review the proposed changes, make any necessary adjustments, and
    then commit.

    Parece que ha ido bien. Es posible que haya reescrito algunas cosas, pero eso no tendrá en cuenta todo lo que debe editarse con los archivos de Terraform. Sin embargo, hace un gran trabajo al tomar notas dentro de los archivos. Estos son los cambios realizados en el vars.tf Archivo:

    variable "namespace" {
      type  = string
      default = "helloworld"
    }

    variable "cluster" {
      type  = string
      default = "minikube"
    }

    El type modificado para eliminar las comillas alrededor de la palabra string (el precio en los archivos de Terraform ha cambiado con el tiempo). Entonces, mira el main.tf Archivo:

    provider "kubernetes" {
      config_context_cluster = var.cluster
    }

    # TF-UPGRADE-TODO: In Terraform v0.11 and earlier, it was possible to begin a
    # resource name with a number, but it is no longer possible in Terraform v0.12.
    #
    # Rename the resource and run `terraform state mv` to apply the rename in the
    # state. Detailed information on the `state move` command can be found in the
    # documentation online: https://www.terraform.io/docs/commands/state/mv.html
    resource "kubernetes_namespace" "1-minikube-namespace" {
      metadata {
            name = var.namespace
      }
    }

    provider "helm" {
      kubernetes {
            config_context_cluster = var.cluster
      }
    }

    resource "helm_release" "local" {
      name  = "buildachart"
      chart = "./buildachart"
    }

    Aquí también las comillas han cambiado y las variables ya no están encerradas. ${} caracteres. La sección más grande es una gran nota TODO que el comando de conversión colocó en el código para mostrar lo que debe cambiar en el nombre del recurso para que sea aceptable en la versión 0.12. Aún mejor, explica cómo solucionar esto y el comando que necesita ejecutar. Los otros grandes cambios son los nuevos versions.tf archivo y un nuevo archivo de copia de seguridad:

    $ ls -lrt
    drwxr-xr-x 6 jess jess 4096 May 16 14:15 buildachart
    -rw-rw-r-- 1 jess jess 3897 Oct 24 13:20 terraform.tfstate.backup
    -rw-r--r-- 1 jess jess   46 Oct 24 13:28 versions.tf
    -rw-rw-r-- 1 jess jess  140 Oct 24 13:55 vars.tf
    -rw-r--r-- 1 jess jess  369 Oct 24 13:56 main.tf
    -rw-rw-r-- 1 jess jess 3821 Oct 24 13:56 terraform.tfstate.1603562212.backup
    -rw-rw-r-- 1 jess jess 3827 Oct 24 13:56 terraform.tfstate

    Para actualizar su clúster de producción, comience con un nombre diferente que sea más adecuado para esta versión:

    resource "kubernetes_namespace" "upgrade-minikube-namespace" {
      metadata {
            name = var.namespace
      }
    }

    Lijado de cantos ásperos

    Después de ese cambio, debe ejecutar el terraform state mv comando (como se indica en la gran nota TODO). Pero primero corre state list para ver con qué estás trabajando:

    $ terraform state list
    helm_release.local
    Kubernetes_namespace.1-minikube-namespace

    El espacio de nombres todavía está establecido en el estado as 1-minikube-namespace, y este es el estado al que debe mudarse. Esto se puede hacer asegurándose de tener los nombres de recursos nuevos y antiguos, luego ejecutando el archivo terraform state mv mando. Pero primero, debe volver a 0.11, usando tfenv para realizar estos cambios, porque esto se implementó usando Terraform 0.11 y 0.12 no reconoce los números al comienzo del nombre del recurso (como dice TODO). Deberá revertir todos los cambios de código realizados desde la actualización de Terraform, excepto el cambio de nombre del activo:

    principal.tf

    provider "kubernetes" {
      config_context_cluster   = "${var.cluster}"
    }

    resource "kubernetes_namespace" "upgrade-minikube-namespace" {
      metadata {
            name = "${var.namespace}"
      }
    }

    provider "helm" {
      kubernetes {
            config_context_cluster   = "${var.cluster}"
      }
    }
    resource "helm_release" "local" {
      name          = "buildachart"
      chart         = "./buildachart"
    }

    Vars.tf

    variable "namespace" {
      type  = "string"
      default = "helloworld"
    }

    variable "cluster" {
      type  = "string"
      default = "minikube"
    }

    Una vez que se reviertan los cambios, revierta tfenv a la versión 0.11 y ejecute el archivo state mv mando:

    $ tfenv use 0.11.15-oci
    Switching default version to v0.11.15-oci
    Switching completed
    [email protected]:~/terraform_doc$ terraform state mv 'kubernetes_namespace.1-minikube-namespace' 'kubernetes_namespace.upgrade-minikube-namespace'
    Moved kubernetes_namespace.1-minikube-namespace to kubernetes_namespace.upgrade-minikube-namespace

    Pasos finales

    Cuando termine, restablezca tfenv a la versión 0.12, luego elimine el suyo versions.tf archivo para asegurarse de que la conversión se haya completado. Si no elimina este archivo, recibirá un mensaje de error:

    $ terraform 0.12upgrade
    Error
    : Module already upgraded

      on versions.tf line 3, in terraform
    :
       3
    :  required_version = ">= 0.12"

    The module in directory . has a version constraint that suggests it has
    already been upgraded for v0.12. If this is incorrect, either remove this
    constraint or override this heuristic with the -force argument. Upgrading a
    module that was already upgraded may change the meaning of that module.

    Elimina el archivo y ejecuta el comando:

    $ terraform 0.12upgrade

    This command will rewrite the configuration files in the given directory so
    that they use the new syntax features from Terraform v0.12, and will identify
    any constructs that may need to be adjusted for correct operation with
    Terraform v0.12. [...]

    Would you like to upgrade the module in the current directory?
      Enter a value
    : yes

    -----------------------------------------------------------------------------

    Upgrade complete!

    Probar la conversión con otra distribución

    Pruebe su nueva conversión volviendo a ejecutar la suya init, plan, Y apply comandos (he omitido partes de la salida en estos fragmentos):

    $ terraform init

    Initializing the backend...
    Initializing provider plugins...
    [...]
    Terraform has been successfully initialized!

    $ 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 Almacenamiento.

    helm_release.local
    : Refreshing state... [id=buildachart]
    kubernetes_namespace.upgrade-minikube-namespace
    : Refreshing state... [id=helloworld]

    ------------------------------------------------------------------------

    No changes. Infraestructura is up-to-date

    $ terraform apply
    helm_release.local
    : Refreshing state... [id=buildachart]
    kubernetes_namespace.upgrade-minikube-namespace
    : Refreshing state... [id=helloworld]

    Apply complete! Resources
    : 0 added, 0 changed, 0 destroyed.

    Como muestra esto, una vez que todo estuvo preconfigurado y el estado se movió y se volvió a aplicar durante la conversión, no se realizaron otros cambios porque la infraestructura está en su lugar.

    Pensamientos finales

    Las actualizaciones de código y aplicaciones son difíciles de realizar, especialmente en un entorno de producción en vivo. Esto es muy cierto cuando se convierte de Terraform 0.11 a 0.12. Lo hice a gran escala e implicó una planificación extensa durante dos semanas.

    Si planea hacer esto en su entorno de producción, asegúrese de:

    • Comience eliminando cualquier recurso o formulario con números antepuestos.
    • Mover el estado antes de actualizar.
    • Mantenga sus archivos de Terraform actualizados en un repositorio bifurcado por seguridad.

    Espero que este artículo te ayude a avanzar más rápido y más fácilmente que yo.

    Artículos de interés

    Subir