البنية التحتية كرمز مع Terraform: من الإدارة اليدوية إلى الإدارة السحابية الآلية

إدارة البنية التحتية السحابية باستخدام Terraform. يغطي بناء جملة HCL والوحدات النمطية وإدارة الحالة وتكامل CI/CD واستراتيجيات النشر في بيئات متعددة.

E
ECOSIRE Research and Development Team
|16 مارس 20267 دقائق قراءة1.4k كلمات|

البنية التحتية كرمز مع Terraform: من الإدارة اليدوية إلى الإدارة السحابية الآلية

المؤسسات التي تستخدم بيئات توفير البنية التحتية كرمز (IaC) أسرع بنسبة 90% وتواجه حالات انقطاع مرتبطة بالتكوين أقل بنسبة 60% من تلك التي تدير البنية التحتية يدويًا. برزت Terraform كأداة IaC المهيمنة، مع أكثر من 3000 مزود يدعمون كل منصة سحابية رئيسية وخدمة SaaS.

يغطي هذا الدليل الاستخدام العملي لـ Terraform لتطبيقات الويب وأنظمة تخطيط موارد المؤسسات (ERP) ومنصات التجارة الإلكترونية --- بدءًا من تعريف المورد الأول وحتى عمليات النشر في بيئات متعددة على مستوى الإنتاج.

الوجبات الرئيسية

  • يجعل Terraform تغييرات البنية التحتية قابلة للمراجعة والاختبار والعكس من خلال التحكم في الإصدار
  • تمنع إدارة الحالة عن بعد حدوث تعارضات عندما يقوم العديد من المهندسين بتعديل البنية التحتية
  • تحتوي الوحدات على أنماط قابلة لإعادة الاستخدام، مما يقلل التكوين من مئات الخطوط إلى عدد قليل من المعلمات
  • يفرض تكامل Terraform Cloud أو CI/CD انضباط التخطيط قبل التطبيق لإجراء تغييرات آمنة

لماذا Terraform للشركات الصغيرة والمتوسطة؟

مشكلة البنية التحتية اليدوية

بدون IaC، تتواجد معرفتك بالبنية التحتية في:

  • انقر فوق وحدة تحكم AWS على المسارات التي لم يوثقها أحد
  • أوامر SSH تعمل منذ أشهر ولا يتذكرها أحد
  • تحرير ملفات التكوين مباشرة على الخوادم
  • النموذج العقلي لأحد المهندسين حول "كيفية عمل الشبكة"

مع Terraform، تعيش البنية التحتية الخاصة بك في Git. كل تغيير هو طلب سحب. كل عملية نشر قابلة للتكرار. يمكن لكل مهندس فهم الصورة كاملة.

المفاهيم الأساسية

المفهومالوصف
مقدممكون إضافي يتفاعل مع النظام الأساسي السحابي (AWS وGCP وAzure وCloudflare)
المواردمكون بنية أساسية واحد (مثيل EC2، قاعدة بيانات RDS، مجموعة S3)
مصدر البياناتمرجع للقراءة فقط إلى البنية التحتية الموجودة
متغيرمعلمة الإدخال للتكوين القابل لإعادة الاستخدام
الإخراجالقيمة المصدرة من تكوين Terraform
الدولةسجل لما يديره Terraform وسماته الحالية
الوحدةمجموعة موارد قابلة لإعادة الاستخدام بواجهة محددة

تكوين Terraform الأول

AWS VPC وEC2 لتطبيق ويب

# providers.tf
terraform {
  required_version = ">= 1.7"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  backend "s3" {
    bucket = "ecosire-terraform-state"
    key    = "production/terraform.tfstate"
    region = "us-east-1"
    encrypt = true
    dynamodb_table = "terraform-locks"
  }
}

provider "aws" {
  region = var.aws_region
}

# variables.tf
variable "aws_region" {
  type    = string
  default = "us-east-1"
}

variable "environment" {
  type    = string
  default = "production"
}

variable "instance_type" {
  type    = string
  default = "t3.large"
}

# main.tf
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

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

resource "aws_subnet" "public" {
  count             = 2
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.${count.index + 1}.0/24"
  availability_zone = data.aws_availability_zones.available.names[count.index]

  map_public_ip_on_launch = true

  tags = {
    Name = "${var.environment}-public-${count.index + 1}"
  }
}

resource "aws_instance" "app" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = var.instance_type
  subnet_id     = aws_subnet.public[0].id

  vpc_security_group_ids = [aws_security_group.app.id]
  key_name               = aws_key_pair.deploy.key_name

  root_block_device {
    volume_size = 50
    volume_type = "gp3"
    encrypted   = true
  }

  tags = {
    Name        = "${var.environment}-app"
    Environment = var.environment
  }
}

resource "aws_db_instance" "postgres" {
  identifier     = "${var.environment}-db"
  engine         = "postgres"
  engine_version = "17"
  instance_class = "db.t3.medium"

  allocated_storage     = 50
  max_allocated_storage = 200
  storage_encrypted     = true

  db_name  = "ecosire"
  username = "app"
  password = var.db_password

  vpc_security_group_ids = [aws_security_group.db.id]
  db_subnet_group_name   = aws_db_subnet_group.main.name

  backup_retention_period = 7
  backup_window           = "03:00-04:00"
  maintenance_window      = "sun:04:00-sun:05:00"

  skip_final_snapshot = false
  final_snapshot_identifier = "${var.environment}-db-final"

  tags = {
    Environment = var.environment
  }
}

وحدات البنية التحتية القابلة لإعادة الاستخدام

إنشاء وحدة تطبيق ويب

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

variable "environment" {
  type = string
}

variable "instance_type" {
  type    = string
  default = "t3.medium"
}

variable "vpc_id" {
  type = string
}

variable "subnet_ids" {
  type = list(string)
}

resource "aws_lb" "app" {
  name               = "${var.name}-${var.environment}-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = var.subnet_ids
}

resource "aws_lb_target_group" "app" {
  name     = "${var.name}-${var.environment}-tg"
  port     = 3000
  protocol = "HTTP"
  vpc_id   = var.vpc_id

  health_check {
    path                = "/health"
    healthy_threshold   = 2
    unhealthy_threshold = 3
    interval            = 30
  }
}

resource "aws_autoscaling_group" "app" {
  name                = "${var.name}-${var.environment}-asg"
  min_size            = 2
  max_size            = 10
  desired_capacity    = 2
  vpc_zone_identifier = var.subnet_ids
  target_group_arns   = [aws_lb_target_group.app.arn]

  launch_template {
    id      = aws_launch_template.app.id
    version = "$Latest"
  }

  tag {
    key                 = "Name"
    value               = "${var.name}-${var.environment}"
    propagate_at_launch = true
  }
}

output "alb_dns_name" {
  value = aws_lb.app.dns_name
}

استخدام الوحدة

# environments/production/main.tf
module "web" {
  source = "../../modules/web-app"

  name          = "ecosire-web"
  environment   = "production"
  instance_type = "t3.large"
  vpc_id        = module.network.vpc_id
  subnet_ids    = module.network.public_subnet_ids
}

module "api" {
  source = "../../modules/web-app"

  name          = "ecosire-api"
  environment   = "production"
  instance_type = "t3.large"
  vpc_id        = module.network.vpc_id
  subnet_ids    = module.network.public_subnet_ids
}

إدارة الدولة

الحالة البعيدة مع S3

# Bootstrap: create the state bucket and DynamoDB table manually or with a separate config
resource "aws_s3_bucket" "terraform_state" {
  bucket = "ecosire-terraform-state"

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_s3_bucket_versioning" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

يمنع قفل الحالة عبر DynamoDB مهندسين من تشغيل terraform apply في وقت واحد، مما قد يؤدي إلى إتلاف الحالة.

أمن ملفات الدولة

يحتوي ملف حالة Terraform على معلومات حساسة بما في ذلك كلمات مرور قاعدة البيانات ومفاتيح API ومعرفات الموارد. حمايته:

  • التشفير في حالة عدم النشاط: إصدار مجموعة S3 + التشفير من جانب الخادم
  • التشفير أثناء النقل: HTTPS فقط للوصول إلى الحالة
  • تقييد الوصول: سياسات IAM تحدد من يمكنه قراءة/كتابة الحالة
  • عدم الالتزام مطلقًا بـ Git: يجب ألا تكون ملفات الحالة أبدًا تحت التحكم في الإصدار
  • تمكين الإصدار: يسمح الإصدار S3 بالاسترداد من الحالة التالفة

تكامل CI/CD

خط أنابيب Terraform لإجراءات GitHub

name: Terraform
on:
  pull_request:
    paths: ['infrastructure/**']
  push:
    branches: [main]
    paths: ['infrastructure/**']

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3

      - name: Terraform Init
        run: terraform init
        working-directory: infrastructure/environments/production

      - name: Terraform Plan
        run: terraform plan -out=tfplan
        working-directory: infrastructure/environments/production

      - name: Comment PR with plan
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const plan = require('fs').readFileSync('infrastructure/environments/production/tfplan.txt', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## Terraform Plan\n\`\`\`\n${plan}\n\`\`\``
            });

  apply:
    needs: plan
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3

      - name: Terraform Apply
        run: terraform apply -auto-approve
        working-directory: infrastructure/environments/production

استراتيجية البيئات المتعددة

| البيئة | الغرض | أحجام المثيلات | هدف التكلفة | |-------------|-----------------|-------------|----------|--| | التنمية | اختبار الميزة | t3.micro / t3.small | <$100/شهر | | التدريج | التحقق من صحة ما قبل الإنتاج | انتاج المرايا (اصغر) | ~30% من الإنتاج | | الإنتاج | حركة المرور الحية | الحجم المناسب للتحميل | الأمثل |

استخدم مساحات عمل Terraform أو أدلة منفصلة لكل بيئة:

infrastructure/
  modules/
    web-app/
    database/
    network/
  environments/
    development/
      main.tf
      terraform.tfvars
    staging/
      main.tf
      terraform.tfvars
    production/
      main.tf
      terraform.tfvars

الأسئلة المتداولة

Terraform أم Pulumi --- أيهما يجب أن نختار؟

Terraform إذا كان فريقك يضم مهندسي عمليات يفضلون التكوين التعريفي. Pulumi إذا كان فريقك مثقلًا بالمطورين ويفضل البنية التحتية للكتابة في TypeScript أو Python. لدى Terraform نظام بيئي أكبر والمزيد من وحدات المجتمع. يتمتع Pulumi بمنحنى تعليمي أولي أكثر حدة ولكنه أكثر مرونة في التعامل مع المنطق المعقد.

كيف يمكننا استيراد البنية التحتية الحالية إلى Terraform؟

استخدم terraform import لإخضاع الموارد الموجودة لإدارة Terraform. على سبيل المثال: terraform import aws_instance.app i-1234567890abcdef0. بعد الاستيراد، اكتب التكوين المطابق. يدعم Terraform 1.5+ كتل الاستيراد في ملفات التكوين لعمليات الاستيراد المجمعة.

كيف نتعامل مع الأسرار في Terraform؟

لا ترتكب أسرارًا أبدًا مع ملفات Terraform. استخدم terraform.tfvars (مستثنى من Git)، أو متغيرات البيئة (TF_VAR_db_password)، أو مدير الأسرار (AWS Secrets Manager، HashiCorp Vault). قم بتمييز المتغيرات الحساسة بـ sensitive = true لمنع ظهورها في مخرجات الخطة.

ما هي تكلفة إدارة Terraform؟

Terraform نفسها مجانية ومفتوحة المصدر. تحتوي Terraform Cloud على طبقة مجانية لما يصل إلى 5 مستخدمين مع حالة التحكم عن بعد والتخطيط/التطبيق. التكلفة الرئيسية هي منحنى التعلم (20-40 ساعة للمهندس ذي الخبرة) والصيانة المستمرة (2-4 ساعات شهريًا). ويقابل ذلك الوقت الموفر في الإدارة اليدوية للبنية التحتية.


ما يأتي بعد ذلك

يوفر Terraform الأساس للبنية التحتية الآلية. يمكنك دمجها مع خطوط CI/CD للنشر التلقائي، والمراقبة للرؤية التشغيلية، والتعافي من الكوارث للمرونة.

اتصل بـ ECOSIRE للحصول على استشارات بشأن أتمتة البنية التحتية، أو استكشف دليل DevOps للشركات الصغيرة للحصول على خريطة الطريق الكاملة.


تم النشر بواسطة ECOSIRE - مساعدة الشركات على أتمتة البنية التحتية السحابية.

E

بقلم

ECOSIRE Research and Development Team

بناء منتجات رقمية بمستوى المؤسسات في ECOSIRE. مشاركة رؤى حول تكاملات Odoo وأتمتة التجارة الإلكترونية وحلول الأعمال المدعومة بالذكاء الاصطناعي.

الدردشة على الواتساب