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