שרת חי שלוש שנים. עם הזמן, חבילות מתעדכנות ידנית, קבצי תצורה משתנים, ותיקונים זמניים מיושמים "לחמש דקות." אף מהנדס אחד לא יודע את המצב המדויק הנוכחי של המכונה הזו. 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-approve5-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 יום |
העלות מחושבת באופן אישי לאחר ביקורת תשתית. אנו נעריך את הפרויקט שלך — צור קשר כדי לקבל ייעוץ ותוכנית ראשונית.
צור קשר לביקורת של התשתית שלך והזמן יישום של הגישה הבלתי ניתנת לשינוי.







