Aller au contenu principal

Terraform Multi-Cloud


1 - Structure de projet

1.1 Organisation recommandée

terraform-multicloud/
├── modules/
│ ├── aws/
│ │ ├── vpc/
│ │ ├── eks/
│ │ └── rds/
│ ├── azure/
│ │ ├── vnet/
│ │ ├── aks/
│ │ └── database/
│ ├── gcp/
│ │ ├── vpc/
│ │ ├── gke/
│ │ └── cloudsql/
│ └── common/
│ └── kubernetes-app/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ └── production/
├── backend.tf
└── versions.tf

1.2 Providers multiples

# versions.tf
terraform {
required_version = ">= 1.5.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.0"
}
}
}

# Provider AWS
provider "aws" {
region = var.aws_region

default_tags {
tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "Terraform"
}
}
}

# Provider Azure
provider "azurerm" {
features {}

subscription_id = var.azure_subscription_id
}

# Provider GCP
provider "google" {
project = var.gcp_project_id
region = var.gcp_region
}

2 - State Management

2.1 Remote Backend par cloud

# AWS S3 Backend
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "multicloud/terraform.tfstate"
region = "eu-west-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}

2.2 State séparé par environnement

# Structure recommandée
terraform-state/
├── dev/
│ ├── aws.tfstate
│ ├── azure.tfstate
│ └── gcp.tfstate
├── staging/
│ └── ...
└── production/
└── ...

2.3 Workspaces

# Créer des workspaces
terraform workspace new dev
terraform workspace new staging
terraform workspace new production

# Utiliser dans le code
locals {
environment = terraform.workspace

instance_count = {
dev = 1
staging = 2
production = 5
}
}

resource "aws_instance" "app" {
count = local.instance_count[local.environment]
# ...
}

3 - Modules Multi-Cloud

3.1 Module VPC AWS

# modules/aws/vpc/main.tf
variable "cidr_block" {
type = string
}

variable "environment" {
type = string
}

resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true

tags = {
Name = "${var.environment}-vpc"
}
}

resource "aws_subnet" "private" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.cidr_block, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]

tags = {
Name = "${var.environment}-private-${count.index}"
}
}

output "vpc_id" {
value = aws_vpc.main.id
}

output "private_subnet_ids" {
value = aws_subnet.private[*].id
}

3.2 Module VNet Azure

# modules/azure/vnet/main.tf
variable "address_space" {
type = list(string)
}

variable "environment" {
type = string
}

variable "resource_group_name" {
type = string
}

variable "location" {
type = string
}

resource "azurerm_virtual_network" "main" {
name = "${var.environment}-vnet"
location = var.location
resource_group_name = var.resource_group_name
address_space = var.address_space
}

resource "azurerm_subnet" "private" {
count = 3
name = "private-${count.index}"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = [cidrsubnet(var.address_space[0], 8, count.index)]
}

output "vnet_id" {
value = azurerm_virtual_network.main.id
}

3.3 Module abstrait Kubernetes

# modules/common/kubernetes-app/main.tf
variable "name" {
type = string
}

variable "image" {
type = string
}

variable "replicas" {
type = number
default = 3
}

variable "port" {
type = number
default = 8080
}

resource "kubernetes_deployment" "app" {
metadata {
name = var.name
}

spec {
replicas = var.replicas

selector {
match_labels = {
app = var.name
}
}

template {
metadata {
labels = {
app = var.name
}
}

spec {
container {
name = var.name
image = var.image

port {
container_port = var.port
}

resources {
requests = {
cpu = "100m"
memory = "128Mi"
}
limits = {
cpu = "500m"
memory = "512Mi"
}
}
}
}
}
}
}

resource "kubernetes_service" "app" {
metadata {
name = var.name
}

spec {
selector = {
app = var.name
}

port {
port = 80
target_port = var.port
}

type = "ClusterIP"
}
}

4 - Configuration Multi-Cloud

4.1 Main.tf Production

# environments/production/main.tf

# AWS Infrastructure
module "aws_vpc" {
source = "../../modules/aws/vpc"

cidr_block = "10.0.0.0/16"
environment = "production"
}

module "aws_eks" {
source = "../../modules/aws/eks"

vpc_id = module.aws_vpc.vpc_id
subnet_ids = module.aws_vpc.private_subnet_ids

cluster_name = "production-cluster"
cluster_version = "1.28"
node_count = 5
}

# Azure Infrastructure (DR)
module "azure_rg" {
source = "../../modules/azure/resource-group"

name = "production-dr"
location = "westeurope"
}

module "azure_vnet" {
source = "../../modules/azure/vnet"

resource_group_name = module.azure_rg.name
location = module.azure_rg.location
address_space = ["10.1.0.0/16"]
environment = "production-dr"
}

module "azure_aks" {
source = "../../modules/azure/aks"

resource_group_name = module.azure_rg.name
location = module.azure_rg.location
vnet_id = module.azure_vnet.vnet_id

cluster_name = "production-dr-cluster"
node_count = 2 # Scaled down for DR
}

# GCP Infrastructure (Analytics)
module "gcp_vpc" {
source = "../../modules/gcp/vpc"

network_name = "production-analytics"
region = "europe-west1"
}

module "gcp_gke" {
source = "../../modules/gcp/gke"

network = module.gcp_vpc.network_name
subnetwork = module.gcp_vpc.subnetwork_name

cluster_name = "analytics-cluster"
node_count = 3
}

5 - Variables et tfvars

5.1 Variables communes

# variables.tf
variable "environment" {
type = string
description = "Environment name"
}

variable "project_name" {
type = string
description = "Project name"
}

# AWS
variable "aws_region" {
type = string
default = "eu-west-1"
}

# Azure
variable "azure_subscription_id" {
type = string
sensitive = true
}

variable "azure_location" {
type = string
default = "westeurope"
}

# GCP
variable "gcp_project_id" {
type = string
}

variable "gcp_region" {
type = string
default = "europe-west1"
}

5.2 tfvars par environnement

# environments/production/terraform.tfvars
environment = "production"
project_name = "myapp"

# AWS
aws_region = "eu-west-1"

# Azure
azure_subscription_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
azure_location = "westeurope"

# GCP
gcp_project_id = "myapp-production"
gcp_region = "europe-west1"

6 - Outputs et Data Sources

# outputs.tf
output "aws_eks_endpoint" {
value = module.aws_eks.cluster_endpoint
description = "AWS EKS cluster endpoint"
}

output "azure_aks_endpoint" {
value = module.azure_aks.cluster_endpoint
description = "Azure AKS cluster endpoint"
}

output "gcp_gke_endpoint" {
value = module.gcp_gke.cluster_endpoint
description = "GCP GKE cluster endpoint"
}

output "kubeconfig_commands" {
value = {
aws = "aws eks update-kubeconfig --name ${module.aws_eks.cluster_name} --region ${var.aws_region}"
azure = "az aks get-credentials --resource-group ${module.azure_rg.name} --name ${module.azure_aks.cluster_name}"
gcp = "gcloud container clusters get-credentials ${module.gcp_gke.cluster_name} --region ${var.gcp_region}"
}
}

Résumé

Dans ce chapitre, nous avons appris :

  • La structure de projet Multi-Cloud
  • La gestion des providers multiples
  • Le state management
  • La création de modules réutilisables
  • La configuration par environnement

Prochaine étape

Dans le prochain chapitre, nous verrons Kubernetes Multi-Cloud.

→ Chapitre suivant : Kubernetes Multi-Cloud


← Retour à la table des matières