תשתית בלתי ניתנת לשינוי: החלפת שרתים במקום עדכון

כל שרת צובר עם הזמן התאמות ידניות ותיקונים זמניים, והופך למערכת שבירה וייחודית שקשה לעדכן ולשחזר. אנחנו מיישמים את מודל התשתית הבלתי ניתנת לשינוי (Immutable Infrastructure), מחליפים שרתים במקום לעדכן אותם, ומספקים את הפרויקט במפתח מלא—מביקורת ועד הגדרת אוטומציה. הצוות שלנו מבטיח פעילות יציבה ותמיכה שוטפת, כך שהסביבות שלכם נשארות זהות ואמינות.

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

שרת חי שלוש שנים. עם הזמן, חבילות מתעדכנות ידנית, קבצי תצורה משתנים, ותיקונים זמניים מיושמים "לחמש דקות." אף מהנדס אחד לא יודע את המצב המדויק הנוכחי של המכונה הזו. ansible-playbook נכשל על ערכים לא סטנדרטיים שמישהו שינה ישירות. שרת כזה נקרא שרת פתית שלג — ייחודי ושביר. מצב טיפוסי: אחרי puppet apply נוסף, חצי מהייצור נופל כי למופע אחד היה את קובץ nginx.conf שלו משוכתב ידנית. אין למה לחזור — כל שרת הוא אינדיבידואלי. צריך לנפות באגים בכל אחד בנפרד, ולאבד שעות של זמן השבתה. צוות מהנדסי ה-DevOps שלנו עם ניסיון של 10+ שנים מתמודד עם בעיות אלה מדי יום ועוזר לחברות לעבור למודל תשתית בלתי ניתנת לשינוי אמין.

תשתית בלתי ניתנת לשינוי היא דחייה עקרונית של עדכון שרתים. במקום apt-get upgrade או ansible — צור תמונה חדשה, הפעל מופעים חדשים, מחק את הישנים. שרת אף פעם לא משתנה לאחר הפריסה. גישה זו מבטיחה זהות סביבה ומפשטת חזרות לאחור.

מדוע תשתית בלתי ניתנת לשינוי משתלמת יותר?

השווה את הגישה הישנה לחדשה בטבלה:

קריטריון פתית שלג (עדכון ידני) בלתי ניתן לשינוי (החלפת שרת)
זמן התאוששות לאחר תקלה שעות — צריך להבין מה שונה 5-7 דקות — פריסת AMI קודם
סחיפת תצורה בלתי נמנעת, כל שרת הוא ייחודי לא קיימת, כל השרתים מאותה תמונה
אבטחה סיכון של שינויים לא מתועדים ביקורת מלאה דרך תמונות ו-Git
עלויות תחזוקה גבוהות — תיקונים ידניים ו-runbooks נמוכות — אוטומציה וריפוי עצמי

דפוס שרת עוף החול

הרעיון פשוט: כל שרת הוא זמני. כמו ציפור עוף החול, הוא נשרף וחדש מופיע. תצורת היישום והקוד נאפים לתוך התמונה. נתונים מאוחסנים מחוץ לשרת — ב-S3, RDS, EFS.

עבור תשתית VM, זה מיושם דרך Packer + Terraform:

# packer/api-server.pkr.hcl
source "amazon-ebs" "api" {
  ami_name = "api-server-${var.version}-${formatdate("YYYYMMDD", timestamp())}"
  instance_type = "t3.medium"
  region = "eu-west-1"
  source_ami_filter {
    filters = {
      name = "ubuntu/images/hvm-ssd/ubuntu-22.04-amd64-server-*"
      root-device-type = "ebs"
      virtualization-type = "hvm"
    }
    most_recent = true
    owners = ["099720109477"]
  }
}

build {
  sources = ["source.amazon-ebs.api"]
  provisioner "ansible" {
    playbook_file = "ansible/api-server.yml"
    extra_arguments = ["--extra-vars", "app_version=${var.version}"]
  }
  post-processor "manifest" {
    output = "packer-manifest.json"
  }
}

Packer בונה את ה-AMI. Ansible provisioner אופה את היישום ישירות לתוך התמונה. לאחר הבנייה — # packer/api-server.pkr.hcl source "amazon-ebs" "api" { ami_name = "api-server-${var.version}-${formatdate("YYYYMMDD", timestamp())}" instance_type = "t3.medium" region = "eu-west-1" source_ami_filter { filters = { name = "ubuntu/images/hvm-ssd/ubuntu-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } most_recent = true owners = ["099720109477"] } } build { sources = ["source.amazon-ebs.api"] provisioner "ansible" { playbook_file = "ansible/api-server.yml" extra_arguments = ["--extra-vars", "app_version=${var.version}"] } post-processor "manifest" { output = "packer-manifest.json" } } מכיל את מזהה ה-AMI החדש.

Terraform: החלפת מופעים דרך Launch Template

resource "aws_launch_template" "api" {
  name_prefix = "api-server-"
  image_id = var.ami_id # ID из packer-manifest.json
  instance_type = "t3.medium"

  tag_specifications {
    resource_type = "instance"
    tags = {
      Name = "api-server"
      Version = var.app_version
    }
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "api" {
  name = "api-${var.app_version}"
  desired_capacity = 3
  min_size = 2
  max_size = 6
  vpc_zone_identifier = var.private_subnet_ids

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

  instance_refresh {
    strategy = "Rolling"
    preferences {
      min_healthy_percentage = 50
      instance_warmup = 120
    }
  }

  lifecycle {
    create_before_destroy = true
  }
}

packer-manifest.json — מנגנון AWS מובנה להחלפת מופעים ללא זמן השבתה. כאשר resource "aws_launch_template" "api" { name_prefix = "api-server-" image_id = var.ami_id # ID из packer-manifest.json instance_type = "t3.medium" tag_specifications { resource_type = "instance" tags = { Name = "api-server" Version = var.app_version } } lifecycle { create_before_destroy = true } } resource "aws_autoscaling_group" "api" { name = "api-${var.app_version}" desired_capacity = 3 min_size = 2 max_size = 6 vpc_zone_identifier = var.private_subnet_ids launch_template { id = aws_launch_template.api.id version = "$Latest" } instance_refresh { strategy = "Rolling" preferences { min_healthy_percentage = 50 instance_warmup = 120 } } lifecycle { create_before_destroy = true } } ב-Launch Template משתנה, ה-ASG מחליף בהדרגה מופעים ישנים בחדשים, תוך שמירה על מינימום של 50% תקינים.

צינור CI/CD: מהתחייבות לתמונה חדשה

# .github/workflows/deploy.yml
jobs:
  build-ami:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build AMI with Packer
        run: |
          packer init packer/
          packer build \
            -var "version=${{ github.sha }}" \
            packer/api-server.pkr.hcl
      - name: Extract AMI ID
        id: ami
        run: |
          AMI_ID=$(jq -r '.builds[-1].artifact_id' packer-manifest.json | cut -d: -f2)
          echo "ami_id=$AMI_ID" >> $GITHUB_OUTPUT
  deploy:
    needs: build-ami
    steps:
      - name: Update Terraform
        run: |
          terraform apply \
            -var "ami_id=${{ needs.build-ami.outputs.ami_id }}" \
            -var "app_version=${{ github.sha }}" \
            -auto-approve

כל התחייבות ל-main → AMI חדש → עדכון ASG. אין instance_refresh לשרתי ייצור. אין image_id נגד מופעים חיים.

איך ליישם תשתית בלתי ניתנת לשינוי: תוכנית שלב אחר שלב

  • ביקורת תשתית נוכחית: זהה את כל הרכיבים האוגרים מצב על דיסק ותכנן את ההגירה שלהם.
  • חילוץ נתונים: העבר מסדי נתונים ל-RDS, קבצים ל-S3, סשנים ל-Redis. הגדר אקסטרנליזציה של לוגים.
  • צור תבניות Packer: עבור כל סוג שרת — תבנית נפרדת עם Ansible provisioner, האופה את היישום והתלויות.
  • הגדר מודולי Terraform: Launch Template עם image_id מ-Packer, Auto Scaling Group עם instance refresh.
  • בנה צינור CI/CD: GitHub Actions או GitLab CI: התחייבות → בניית AMI → עדכון Terraform → פריסה לייצור.
  • בדוק וחזור לאחור: אמת החלפת מופעים, בצע חזרה ל-AMI הקודם.
  • הכשר את הצוות: מסור תיעוד ו-runbook.

קריטי: מה אסור שיהיה על השרת

תשתית בלתי ניתנת לשינוי עובדת רק אם מקפידים על כמה כללים:

כל הנתונים מחוץ לשרת. מסד נתונים — ב-RDS. קבצים שהועלו — ב-S3. סשנים — ב-Redis. לוגים — ל-CloudWatch Logs או Loki. אם נתונים מאוחסנים על דיסק המופע, הם יאבדו בעת החלפה.

תצורה דרך משתני סביבה. אין קבצי תצורה שנוצרים במהלך פריסה. רק משתני סביבה מ-Secrets Manager או Parameter Store:

# user-data script для инстанса
export DB_URL=$(aws ssm get-parameter --name /api/db-url --with-decryption --query Value --output text)
export SECRET_KEY=$(aws secretsmanager get-secret-value --secret-id api/secret-key --query SecretString --output text)
systemctl start api

אין SSH לייצור. אם מהנדס יכול להתחבר ולשנות משהו ידנית — הבלתי ניתנות לשינוי נשברת. השתמש ב-SSM Session Manager במקום SSH ישיר, ורק לאבחון חירום עם לוג ביקורת מלא.

חזרה לאחור היא פריסת AMI קודם

# Откатываем на предыдущий AMI
terraform apply \
  -var "ami_id=ami-0abcdef1234567890" \
  -var "app_version=previous-sha" \
  -auto-approve

5-7 דקות להחלפת מופעים. צפוי. אין הפתעות כמו "החזרה עברה אבל התצורה שונה." תשתית בלתי ניתנת לשינוי מהירה פי 10 בזמן התאוששות בהשוואה לגישה המסורתית — נתונים אמפיריים מהפרויקטים שלנו.

מה לעשות עם רכיבי Legacy שאוגרים מצב על דיסק?

החלק הקשה ביותר במהלך הגירה הוא רכיבי legacy שאוגרים מצב על דיסק: יישומים עם סשנים מבוססי קבצים, משימות cron הכותבות ל-/tmp, יישומים עם נתיבי תצורה מקודדים. יש לבצע refactoring לפני המעבר לבלתי ניתן לשינוי. אנו עוזרים לבצע ביקורת, לזהות מקומות כאלה ולתכנן הגירה. זה לוקח יותר זמן מאשר הגדרת Packer + Terraform עצמה, אבל בלעדיו הבלתי ניתן לשינוי לא יעבוד.

מה כלול בפתרון סוהר

אנו מטפלים בכל המחזור: מביקורת ועד מסירת תיעוד. כתוצאה מכך, אתה מקבל:

  • תבניות Packer לבניית תמונות של כל הרכיבים
  • מודולי Terraform עם Auto Scaling ו-instance refresh
  • צינור CI/CD (GitHub Actions / GitLab CI) עם פריסה אוטומטית וחזרה לאחור
  • Runbook לתפעול והתאוששות
  • הכשרת הצוות שלך על התשתית החדשה
  • אחריות לפעולה יציבה למשך 30 יום לאחר היישום
דוגמה לתוכנית עבודה טיפוסית
שלב משך
ביקורת: מה מאוחסן על השרת, מה צריך לחלץ יום אחד
תבנית Packer + Ansible provisioner 1.5 ימים
Terraform ASG עם instance_refresh יום אחד
צינור CI/CD (בניית AMI + פריסה) 0.5 יום
בדיקת חזרה לאחור + runbook 0.5 יום

העלות מחושבת באופן אישי לאחר ביקורת תשתית. אנו נעריך את הפרויקט שלך — צור קשר כדי לקבל ייעוץ ותוכנית ראשונית.

צור קשר לביקורת של התשתית שלך והזמן יישום של הגישה הבלתי ניתנת לשינוי.