CI/CD والبنية التحتية كرمز
البنية التحتية كرمز مع Terraform
4 دقيقة للقراءة
Terraform هو المعيار الصناعي لـ IaC. كل مقابلة DevOps/SRE ستختبر معرفتك.
مفاهيم Terraform الأساسية
إدارة الحالة
حالة Terraform تتتبع البنية التحتية:
# عمليات الحالة
terraform state list # قائمة الموارد
terraform state show <resource> # عرض التفاصيل
terraform state mv <src> <dst> # نقل/إعادة تسمية
terraform state rm <resource> # إزالة من الحالة
terraform state pull # تنزيل الحالة
terraform state push # رفع الحالة (خطير!)
Backend الحالة البعيدة
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/infrastructure.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks" # قفل الحالة
}
}
سؤال مقابلة: "لماذا تستخدم الحالة البعيدة مع القفل؟"
الجواب: الحالة البعيدة تُمكّن تعاون الفريق—الجميع يرى نفس الحالة. القفل (عبر DynamoDB) يمنع التعديلات المتزامنة التي قد تُفسد الحالة أو تسبب تغييرات متعارضة.
تصميم وحدات Terraform
بنية الوحدة
modules/
├── vpc/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ └── README.md
├── eks/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── rds/
├── main.tf
├── variables.tf
└── outputs.tf
مثال وحدة قابلة لإعادة الاستخدام
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(var.tags, {
Name = "${var.name}-vpc"
})
}
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnets[count.index]
availability_zone = var.azs[count.index]
tags = merge(var.tags, {
Name = "${var.name}-private-${count.index + 1}"
Type = "private"
})
}
# modules/vpc/variables.tf
variable "name" {
type = string
description = "بادئة اسم الموارد"
}
variable "cidr_block" {
type = string
description = "كتلة CIDR لـ VPC"
}
variable "private_subnets" {
type = list(string)
description = "كتل CIDR للشبكات الفرعية الخاصة"
}
# modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
description = "معرف VPC"
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
description = "معرفات الشبكات الفرعية الخاصة"
}
استخدام الوحدات
# environments/prod/main.tf
module "vpc" {
source = "../../modules/vpc"
name = "prod"
cidr_block = "10.0.0.0/16"
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
module "eks" {
source = "../../modules/eks"
cluster_name = "prod-cluster"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
}
مساحات عمل Terraform
# قائمة مساحات العمل
terraform workspace list
# إنشاء مساحة عمل
terraform workspace new staging
# التبديل لمساحة عمل
terraform workspace select prod
# مساحة العمل الحالية في الكود
resource "aws_instance" "web" {
instance_type = terraform.workspace == "prod" ? "m5.large" : "t3.small"
}
بديل أفضل: استخدم مجلدات منفصلة لكل بيئة بدلاً من مساحات العمل لأنظمة الإنتاج. أسهل للفهم وأقل عرضة للأخطاء.
أنماط Terraform المتقدمة
مصادر البيانات
# جلب الموارد الموجودة
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.small"
}
الكتل الديناميكية
resource "aws_security_group" "web" {
name = "web-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = "tcp"
cidr_blocks = ingress.value.cidrs
}
}
}
استيراد الموارد الموجودة
# استيراد البنية التحتية الموجودة
terraform import aws_instance.web i-1234567890abcdef0
# توليد التكوين (Terraform 1.5+)
terraform plan -generate-config-out=generated.tf
أسئلة المقابلة
س: "كيف تتعامل مع الأسرار في Terraform؟"
# 1. متغيرات البيئة
# export TF_VAR_db_password="secret"
variable "db_password" {
type = string
sensitive = true # يُخفي في المخرجات
}
# 2. AWS Secrets Manager
data "aws_secretsmanager_secret_version" "db" {
secret_id = "prod/database/password"
}
resource "aws_db_instance" "main" {
password = data.aws_secretsmanager_secret_version.db.secret_string
}
# 3. مزود Vault
data "vault_generic_secret" "db" {
path = "secret/database"
}
س: "فشل terraform apply في المنتصف. كيف تسترد؟"
- تحقق من الحالة:
terraform state list- انظر ما تم إنشاؤه - راجع الخطأ: افهم لماذا فشل
- أصلح وأعد:
terraform applyمتساوي القوة - إذا الحالة تالفة: استرجع من نسخة احتياطية أو أصلح يدوياً
- Taint إذا لزم:
terraform taint <resource>لإجبار إعادة الإنشاء
س: "كيف تمنع التدمير العرضي للموارد الحرجة؟"
resource "aws_db_instance" "production" {
# منع التدمير
lifecycle {
prevent_destroy = true
}
# أو تجاهل التغييرات لسمات محددة
lifecycle {
ignore_changes = [tags]
}
}
التالي، سنغطي استراتيجيات النشر—blue-green، canary، والنشر المتدرج. :::