Comment déployer une application sur GKE(GCP) en utilisant Terraform?

Contexte et Objectif

Infrastructure As Code , à l’ère du cloud consiste à utiliser du code source pour créer, mettre à jour et contrôler votre infrastructure. Parmi la multitude d’outils qui existe aujourd’hui, Terraform est sans doute la plus populaire et la plus intuitive. Il est permet de créer des ressources cloud AWS, AZURE, GCP.

Terraform, grâce à l’API WEB(Resful) est non seulement capable de créer des ressources, mais aussi de créer votre infrastructure et également déployer des applications sur des plates-formes d’orchestration comme Kubernetes.

Dans cet article, je vous présenterai comment créer un cluster Kubernetes sur Gloogle Cloud Platform(GCP) à l’aide de GKE, puis de déployer une application (nginx pour notre cas) grâce à Terraform.

Lien github du projet: https://github.com/franck-art/TERRAFORM-GKE-GCP-KUBERNETES_project

Prérequis
https://cloud.google.com/iam/docs/creating-managing-service-accounts?hl=fr

NB : Apres la création d’un compte de service, vous allez télécharger un fichier .json nécessaire à toute application de ce connecté sur votre compte afin de déployer les ressources. Il est en quelque sorte le « Acces key » et « secret key » sur AWS.

Infrastructure
Organisation en module

Nous allons mettre sur pieds deux modules : l’un pour la mise en place du cluster (gke_cluster) et l’autre pour le déploiement des ressources kubernetes sur le cluster crée (k8s_ressources).

C:UsersFujitsuDesktopmodule.PNG
Module gke_cluster
Ce module permet à Terraform de déployer le cluster sur GKE. Il contient 03 fichiers : cluster.tf pour la ressource de déploiement du cluster, output.tf pour exposer les attributs (informations nécessaires à l’authentification sur le cluster) et variables.tf, la déclaration des variables. La ressource « google_container_cluster » a été utilisée afin de créer un cluster avec 03 nœuds.
Cluster.tf
resource "google_container_cluster" "primary" {
  name               = "${var.name}"
  location           = "${var.location}"
  initial_node_count = "${var.initial_node_count}"

  master_auth {
    username = "${var.username}"
    password = "${var.password}"

    client_certificate_config {
      issue_client_certificate = false
    }
  }

  node_config {
    oauth_scopes = [
      "https://www.googleapis.com/auth/logging.write",
      "https://www.googleapis.com/auth/monitoring",
    ]

    metadata = {
      disable-legacy-endpoints = "true"
    }

    labels = {
      foo = "bar"
    }

    tags = ["foo", "bar"]
  }

  timeouts {
    create = "30m"
    update = "40m"
  }
}
Output.tf

Une fois le cluster crée, les attributs « client_certificate », « client_key », « cluster_ca_certificate » et « host » seront exposés afin que Terraform puisse les utiliser pour se connecter au cluster et déployer les ressources.

output "client_certificate" {
  value     = "${google_container_cluster.primary.master_auth.0.client_certificate}"
  sensitive = true
}

output "client_key" {
  value     = "${google_container_cluster.primary.master_auth.0.client_key}"
  sensitive = true
}

output "cluster_ca_certificate" {
  value     = "${google_container_cluster.primary.master_auth.0.cluster_ca_certificate}"
  sensitive = true
}

output "host" {
  value     = "${google_container_cluster.primary.endpoint}"
  sensitive = true
}

Afin de rendre le code source customisable et nous avons les variables à déclarer dans le fichier variables.tf

Variables.tf

variable "name" {
  description = "The name of the cluster, unique within the project and zone"
  //default     = "gke-franck"
}

variable "username"{
type = "string"
description = "username to connect in the cluster"
//default = "username"
}
variable "password"{
type = "string"
description = "password to connect in the cluster" // au moins 16 caracteres pour le password
//default = "password0123456789"
}

variable "initial_node_count"{
type = number
description = "number of node "
//default = 3
}

variable "location"{
type = "string"
description = "zone location where the cluster is deploy"
//default = "us-central1-a"
}
Module k8s_ressources

Ce module permet grâce au provider « kubernetes » de provisionner les ressources kubernetes dans le cluster GKE crée. Pour cela, la ressource « kubernetes_deployment » pour le déploiement d’un objet de type Deployment et « kubernetes_service » pour le deploiement d’un objet de type Service.

K8s_provider.tf

/* ------ variables  declaration --------------*/

variable "username" {
  default = "username"
  description = "username for user"
}
variable "password" {description = "password for user"}
variable "host" {description = "host connection to cluster"}
variable client_certificate {description = "client certificate"}
variable client_key {description = "private client key"}
variable cluster_ca_certificate {description = "certification authority"}


provider "kubernetes" {
  host     = "${var.host}"
  username = "${var.username}"
  password = "${var.password}"

  client_certificate     = "${base64decode(var.client_certificate)}"
  client_key             = "${base64decode(var.client_key)}"
  cluster_ca_certificate = "${base64decode(var.cluster_ca_certificate)}"
}

Ce fichier permet de déclarer le provider « kubernetes » nécessaire afin de se connecter sur le cluster. Il contient plusieurs ressources notamment les ressources permettant de déployer les objets kubernetes.

Les outputs exposés dans la ressource de création du cluster seront utilisés ici afin de se connecter au cluster.

La suite des fichiers (variables.tf, services.tf et deployment.tf) se trouve sur mon repository :

https://github.com/franck-art/TERRAFORM-GKE-GCP-KUBERNETES_project/tree/master/modules/k8s_ressources

Dans le repertoire du projet principal, il faut appeler les modules créer afin que terraform puisse les deployer. Nous avon ainsi crees les fichiers « main.tf » et « provider.tf » afin respectivement de lancer les modules et declarer le provider Google qui telechargera les plugins.

Main.tf

# Variables

#####################################################################

variable "username" { default = "username" }

variable "password" { default = "password0123456789" }

#####################################################################

# Modules

#####################################################################

module "gke_cluster" {

source = "./modules/gke_cluster"

//project = "${var.project}"

//region = "${var.region}"

/* --------- variables surchargées -------*/

name = "gke-franck"

username = "username"

password = "password0123456789"

module "k8s" {

source = "./modules/k8s_ressources"

//depends_on = ["${module.gke_cluster}"]

/* ---------- variables peuvent etre egalement surchargées -------*/

host = "${module.gke_cluster.host}"

username = "${var.username}"

password = "${var.password}"

initial_node_count = 3

location = "us-central1-a"

}

module "k8s" {

source = "./modules/k8s_ressources"

//depends_on = ["${module.gke_cluster}"]

/* ---------- variables peuvent etre egalement surchargées -------*/

host = "${module.gke_cluster.host}"

username = "${var.username}"

password = "${var.password}"

initial_node_count = 3

location = "us-central1-a"

}

module "k8s" {

source = "./modules/k8s_ressources"

//depends_on = ["${module.gke_cluster}"]

/* ---------- variables peuvent etre egalement surchargées -------*/

host = "${module.gke_cluster.host}"

username = "${var.username}"

password = "${var.password}"

client_certificate = "${module.gke_cluster.client_certificate}"

client_key = "${module.gke_cluster.client_key}"

cluster_ca_certificate = "${module.gke_cluster.cluster_ca_certificate}"

}

Provider.tf

/* ------ variables declaration --------------*/

variable "path" {

type = string

default = "/home/franck/Bureau/TP/gke_project"

}

/* ------ provider declaration --------------*/

provider "google" {

credentials = "${file("${var.path}/account.json")}" // put the path to your service account file

project = "phonic-command-291302"

region = "europe-west2-a"

}

Une fois le code bien structuré, il faut l’initialiser afin de permettre à terraform de télécharger les plugins nécessaires. Exécutons la commande  terraform init puis terraform plan afin de vérifier les modifications de notre infrastructure qui seront appliquées avec la commande terraform apply.

A la fin du déploiement, nous pouvons nous connecter sur notre compte Google cloud pour vérifier nos ressources.

C:UsersFujitsuDesktopcluster_gke.PNG

On peut également vérifier que 03 nœuds ont été déployé sur le cluster, ce qui correspond à 03 instances « compute engine ».

C:UsersFujitsuDesktopinstance.PNG
Disponibilité de l’application

GKE nous propose un point de terminaison contenant le port 8080 permettant de consommer l’application.

C:UsersFujitsuDesktopservice.PNG

Et cette adresse IP dans un navigateur nous conduit à la page web de nginx

C:UsersFujitsuDesktopnginx_app.PNG
Conclusion

Terraform apparait aujourd’hui comme un outil incontournable dans le provisioning des ressources dans le cloud. Il a surtout l’avantage d’avoir un langage simple, intuitif et unique pour créer un cluster et déployer une application à travers un seul code source. Son statut « stateful » lui permet de garder l’état de l’infrastructure, ce qui peut être important pour les mises à jour et les déploiements faciles. Dans le cadre de ce projet, l’état (tfstate) de notre infrastructure est stocké en local mais il pouvait être stocké sur la Bucket de GCP. Ici, nous avons voulu nous concentrer sur le déploiement du cluster et l’application.

Référence:

Projet sur github : https://github.com/franck-art/TERRAFORM-GKE-GCP-KUBERNETES_project
Auteur:  Franck Junior TCHOUNZOU, Software Engineer Devops

Linkedinhttps://www.linkedin.com/in/franck-junior-tchounzou-696512184/