مدیریت زیرساخت VPS و سرور اختصاصی با Terraform: آموزش Infrastructure as Code
مدیریت دستی چند سرور مجازی شاید در ابتدای یک پروژه ساده به نظر برسد: یک VPS میسازید، از طریق SSH وارد میشوید، بستهها را نصب میکنید و تنظیمات شبکه را تغییر میدهید. اما با افزایش تعداد سرورها، همین فرایند به مجموعهای از عملیات تکراری، خطاپذیر و دشوار برای مستندسازی تبدیل میشود.
اگر یک سرور حذف شود، آیا میتوانید آن را دقیقاً با همان مشخصات قبلی بازسازی کنید؟ آیا اعضای تیم میدانند چه کسی آخرین تغییر را روی فایروال، شبکه یا اندازه منابع اعمال کرده است؟ آیا محیط آزمایش واقعاً مشابه محیط تولید است؟
Infrastructure as Code یا «زیرساخت بهعنوان کد» برای پاسخ به همین مسائل شکل گرفته است. در این رویکرد، منابعی مانند سرور مجازی، شبکه، دیسک، آدرس IP و قواعد امنیتی در فایلهای متنی تعریف میشوند. Terraform نیز یکی از شناختهشدهترین ابزارها برای پیادهسازی این مدل است.
در این آموزش، اصول مدیریت سرور مجازی با Terraform را بررسی میکنیم، یک ساختار عملی برای پروژه میسازیم و نشان میدهیم چگونه Terraform را در کنار Ansible به کار ببریم.
Terraform چیست و چه مسئلهای را حل میکند؟
Terraform ابزاری متنباز برای تعریف و مدیریت زیرساخت با زبان پیکربندی HCL است. شما وضعیت مطلوب زیرساخت را در فایلهایی با پسوند tf مینویسید و Terraform تغییرات لازم برای رسیدن به آن وضعیت را محاسبه میکند.
برای مثال، بهجای ساخت دستی سه سرور در پنل، میتوانید در کد مشخص کنید:
- سه VPS با اندازه منابع یکسان ایجاد شوند.
- همه سرورها در یک شبکه خصوصی قرار بگیرند.
- یک کلید SSH مشخص روی آنها نصب شود.
- دیسک داده به هر سرور متصل شود.
- خروجی شامل IP عمومی و خصوصی ماشینها باشد.
مزیت مهم این روش فقط خودکارسازی نیست. تعریف زیرساخت در قالب کد را میتوان در Git نگهداری، بازبینی، نسخهبندی و در فرایند CI/CD اجرا کرد. در نتیجه تغییر زیرساخت نیز مانند تغییر نرمافزار قابل ردگیری میشود.
Terraform از طریق Provider با سرویس مقصد ارتباط برقرار میکند. Provider واسطی است که منابع و عملیات قابل پشتیبانی هر پلتفرم را در اختیار Terraform میگذارد. بسته به زیرساخت مورد استفاده، این ارتباط ممکن است از طریق Provider رسمی، Provider سازگار با OpenStack یا API اختصاصی انجام شود.
چرا مدیریت دستی سرورها در مقیاس بالا مشکلساز میشود؟
در مدیریت سنتی، بخش مهمی از دانش زیرساخت در ذهن مدیر سیستم، تاریخچه دستورات Shell یا فایلهای پراکنده باقی میماند. این وضعیت معمولاً به تفاوت ناخواسته میان سرورها منجر میشود؛ مشکلی که به آن Configuration Drift میگویند.
برای نمونه، ممکن است دو VPS در ابتدا یکسان باشند، اما پس از چند ماه یکی از آنها نسخه متفاوتی از Nginx، قانون فایروال اضافی یا تنظیم شبکه اصلاحشدهای داشته باشد. وقتی حادثهای رخ دهد، یافتن این تفاوتها زمانبر خواهد بود.
Terraform با نگهداری تعریف مطلوب منابع، تغییرات زیرساختی را قابل پیشبینی میکند. پیش از اعمال هر تغییر، دستور terraform plan دقیقاً نشان میدهد چه منابعی ساخته، ویرایش یا حذف خواهند شد.
مقایسه رویکرد دستی و زیرساخت بهعنوان کد تصویر روشنتری ارائه میکند:
| معیار | مدیریت دستی | مدیریت با Terraform |
|---|---|---|
| تکرارپذیری | وابسته به فرد و مستندات | قابل بازسازی از روی کد |
| ثبت تغییرات | معمولاً ناقص | قابل نگهداری در Git |
| بررسی پیش از اجرا | محدود | امکان مشاهده Plan |
| توسعه به چند سرور | زمانبر و خطاپذیر | مبتنی بر متغیر و حلقه |
| بازیابی پس از خرابی | نیازمند عملیات دستی | بازسازی سریعتر منابع |
| هماهنگی تیمی | دشوار | مناسب Code Review |
| جلوگیری از تفاوت محیطها | دشوار | تعریف مشترک و ماژولار |
اجزای اصلی یک پروژه Terraform
یک پروژه Terraform معمولاً از چند بخش اصلی تشکیل میشود. شناخت این اجزا پیش از نوشتن مثال عملی ضروری است.
Provider
Provider نحوه ارتباط Terraform با پلتفرم زیرساخت را مشخص میکند. اطلاعاتی مانند آدرس API، نام پروژه، منطقه و اعتبارنامهها معمولاً در تنظیمات Provider یا متغیرهای محیطی قرار میگیرند. اطلاعات حساس را مستقیماً داخل فایلهای Terraform یا مخزن Git قرار ندهید. استفاده از متغیرهای محیطی، Secret Manager سامانه CI/CD یا فایل محلی خارج از Git انتخاب امنتری است.
Resource
Resource یک جزء واقعی زیرساخت است؛ مانند VPS، شبکه، دیسک یا IP. هر Resource شامل نوع، نام داخلی و مجموعهای از ویژگیهاست. نمونه زیر ساختار کلی تعریف یک ماشین را نشان میدهد. نام دقیق Resource و فیلدها به Provider زیرساخت شما بستگی دارد:
resource "example_compute_instance" "web" {
name = "web-01"
image = var.image_name
plan = var.server_plan
ssh_key_id = var.ssh_key_id
network_id = example_network.private.id
tags = {
environment = "production"
role = "web"
managed_by = "terraform"
}
}
Variable و Output
Variable باعث میشود مقادیر وابسته به محیط از منطق اصلی جدا شوند. برای مثال، تعداد سرورها، اندازه منابع و نام Image را میتوان بهصورت متغیر تعریف کرد.
variable "server_count" {
description = "تعداد سرورهای وب"
type = number
default = 2
validation {
condition = var.server_count > 0
error_message = "تعداد سرورها باید بیشتر از صفر باشد."
}
}
variable "server_plan" {
description = "پلن منابع سرور"
type = string
}
Output نیز اطلاعات موردنیاز پس از ایجاد زیرساخت را نمایش میدهد:
output "server_public_ips" {
value = example_compute_instance.web[*].public_ip
}
State
Terraform وضعیت منابع مدیریتشده را در State نگهداری میکند. این فایل ارتباط میان کد و منابع واقعی را ثبت میکند و ممکن است حاوی دادههای حساس باشد. بنابراین فایل terraform.tfstate را نباید در Git قرار دهید.
در کار تیمی بهتر است State در یک Backend راه دور با رمزنگاری، کنترل دسترسی، نسخهبندی و قفلگذاری ذخیره شود. قفلگذاری مانع اعمال همزمان دو تغییر ناسازگار خواهد شد.
ساخت یک پروژه نمونه برای چند VPS
فرض کنیم میخواهیم سه سرور وب بسازیم و بعداً تعداد آنها را بدون کپیکردن بلوکهای تکراری تغییر دهیم. ساختار پوشه پروژه میتواند چنین باشد:
terraform-vps/
├── main.tf
├── variables.tf
├── outputs.tf
├── versions.tf
├── terraform.tfvars.example
└── .gitignore
در versions.tf نسخه Terraform و Provider را محدود میکنیم تا اجرای پروژه در سیستمهای مختلف نتیجه قابل پیشبینیتری داشته باشد:
terraform {
required_version = ">= 1.8, < 2.0"
required_providers {
example = {
source = "vendor/example"
version = "~> 1.4"
}
}
}
سپس در main.tf از count برای ایجاد چند ماشین استفاده میکنیم:
provider "example" {
endpoint = var.api_endpoint
token = var.api_token
}
resource "example_network" "private" {
name = "production-private-network"
cidr = "10.20.0.0/24"
}
resource "example_compute_instance" "web" {
count = var.server_count
name = format("web-%02d", count.index + 1)
image = var.image_name
plan = var.server_plan
ssh_key_id = var.ssh_key_id
network_id = example_network.private.id
tags = {
environment = "production"
role = "web"
managed_by = "terraform"
}
}
این کد یک نمونه عمومی است و باید Resourceها و ویژگیهای آن را با Provider واقعی خود تطبیق دهید. نکته اصلی، تعریف نتیجه مطلوب است: یک شبکه خصوصی و تعداد مشخصی ماشین که به آن متصلاند.
اجرای چرخه استاندارد Terraform
پس از نصب Terraform و آمادهسازی اعتبارنامهها، ابتدا Providerها و Backend پروژه را مقداردهی اولیه کنید:
terraform init
قبل از هر اجرا، قالب و اعتبار پیکربندی را بررسی کنید:
terraform fmt -check
terraform validate
سپس برنامه تغییرات را بسازید:
terraform plan -out=tfplan
خروجی Plan را با دقت بخوانید. نماد + نشاندهنده ایجاد، ~ نشاندهنده ویرایش و - نشاندهنده حذف منبع است. اگر نتیجه مورد انتظار بود، همان Plan ذخیرهشده را اعمال کنید:
terraform apply tfplan
استفاده از Plan ذخیرهشده اهمیت دارد؛ زیرا اطمینان میدهد همان تغییری اعمال میشود که قبلاً بررسی شده است. اجرای مستقیم terraform apply در محیط تولید، بدون بازبینی خروجی، احتمال تغییر ناخواسته را افزایش میدهد.
برای مدیریت سرور اختصاصی نیز منطق کلی مشابه است، به شرط آنکه Provider یا API زیرساخت امکان ایجاد و کنترل منابع Bare Metal را ارائه کند. تفاوت اصلی معمولاً در زمان Provision، گزینههای شبکه و محدودیت تغییر منابع فیزیکی است.
Terraform و Ansible چه تفاوتی دارند؟
Terraform و Ansible رقیب مستقیم یکدیگر نیستند. Terraform بیشتر برای Provisioning زیرساخت مناسب است، در حالی که Ansible سیستمعامل و نرمافزارهای داخل ماشین را پیکربندی میکند. Terraform میتواند VPS، شبکه، دیسک و IP را بسازد. پس از آمادهشدن ماشین، Ansible میتواند کاربران لینوکس، فایروال، Docker، Nginx، مانیتورینگ و تنظیمات امنیتی را اعمال کند.
| وظیفه | Terraform | Ansible |
|---|---|---|
| ایجاد VPS و شبکه | مناسب | کاربرد اصلی نیست |
| اتصال دیسک و IP | مناسب | محدود |
| نصب بستههای لینوکس | ممکن، اما توصیه نمیشود | مناسب |
| مدیریت فایلهای پیکربندی | محدود | مناسب |
| تعریف وضعیت زیرساخت ابری | مناسب | محدود |
| اجرای Playbook داخل ماشین | کاربرد اصلی نیست | مناسب |
مرزبندی روشن میان این دو ابزار، نگهداری پروژه را سادهتر میکند: Terraform مسئول «ساخت منابع» و Ansible مسئول «آمادهسازی سیستمعامل» باشد.
اتصال خروجی Terraform به Ansible
یک روش ساده این است که Terraform فهرست IPها را در قالب JSON خروجی دهد:
terraform output -json server_public_ips
در پروژههای کوچک میتوان از این خروجی برای تولید Inventory انسیبل استفاده کرد. در محیطهای بزرگتر، Dynamic Inventory یا یک اسکریپت کنترلشده انتخاب مناسبتری است. نمونه Playbook زیر Nginx را نصب و فعال میکند:
---
- name: Configure web servers
hosts: web
become: true
tasks:
- name: Install Nginx
ansible.builtin.package:
name: nginx
state: present
- name: Enable and start Nginx
ansible.builtin.service:
name: nginx
enabled: true
state: started
ترتیب اجرای خط لوله میتواند شامل اعتبارسنجی Terraform، تولید Plan، تأیید تغییر، اجرای Apply و سپس اجرای Ansible باشد. برای محیط تولید بهتر است مرحله Apply به تأیید دستی، کنترل دسترسی و ثبت گزارش وابسته شود.
مدیریت محیطهای توسعه، آزمایش و تولید
یکی از خطاهای رایج، نگهداری همه محیطها در یک State و اعمال شرطهای فراوان در فایلهاست. این ساختار خطر اثرگذاری تغییر محیط آزمایش بر تولید را افزایش میدهد. برای جداسازی بهتر میتوان از پوشهها و Stateهای مستقل استفاده کرد:
infrastructure/
├── modules/
│ ├── network/
│ └── compute/
└── environments/
├── development/
├── staging/
└── production/
ماژولها منطق مشترک را نگهداری میکنند و هر محیط فقط مقادیر مخصوص خود را تعیین میکند. بهتر است دسترسی به State و اعتبارنامه تولید نیز از محیطهای دیگر جدا باشد. Workspaceهای Terraform در برخی سناریوهای ساده مفیدند، اما جایگزین کامل جداسازی امنیتی نیستند. اگر محیطها حساب کاربری، سطح دسترسی یا چرخه انتشار متفاوتی دارند، State و تنظیمات مستقل انتخاب مطمئنتری است.
نکات امنیتی و عملیاتی مهم
مدیریت سرور مجازی با Terraform بدون توجه به امنیت سرور و فرایند اجرا میتواند ریسکهای تازهای ایجاد کند. این موارد را در پروژه جدی بگیرید:
- فایلهای State، Plan و متغیرهای حساس را وارد Git نکنید.
- توکن API را با حداقل سطح دسترسی لازم ایجاد کنید.
- نسخه Providerها را در Lock File ثبت و تغییرات آن را بازبینی کنید.
- برای State راه دور، رمزنگاری و قفلگذاری فعال کنید.
- حذف منابع مهم را با قابلیتهایی مانند prevent_destroy محدود کنید.
- پیش از Apply در تولید، Plan را در فرایند Code Review بررسی کنید.
- از اجرای Provisionerهای محلی و remote-exec برای پیکربندی گسترده پرهیز کنید.
- برای سرویسهای Stateful، پیش از تغییر دیسک یا ماشین از دادهها نسخه پشتیبان بگیرید.
- اجرای Terraform را در CI/CD با هویت ماشینی و دسترسی محدود انجام دهید.
گزینه prevent_destroy میتواند برای منابعی که حذف اتفاقی آنها خسارتزاست مفید باشد:
lifecycle {
prevent_destroy = true
}
این قابلیت جایگزین پشتیبانگیری نیست، اما یک مانع اضافی در برابر حذف ناخواسته ایجاد میکند.
اشتباهات رایج در شروع کار با Terraform
اولین اشتباه، قرار دادن توکنها در terraform.tfvars و Commit کردن آنهاست. فایل نمونه بدون مقدار واقعی ایجاد کنید و فایل حاوی Secret را در .gitignore قرار دهید.
اشتباه دوم، ویرایش دستی منابعی است که Terraform مدیریت میکند. این کار باعث Drift میشود. اگر تغییر اضطراری از پنل انجام شد، باید کد و State نیز بهشکل کنترلشده با وضعیت جدید هماهنگ شوند.
اشتباه سوم، استفاده افراطی از remote-exec برای نصب و پیکربندی نرمافزارهاست. اجرای فرمان از Terraform بهسرعت به فرایندی شکننده تبدیل میشود. این مسئولیت را به Ansible یا ابزار مدیریت پیکربندی دیگری بسپارید.
اشتباه چهارم، اجرای terraform apply -auto-approve روی شاخه اصلی بدون کنترل است. خودکارسازی مفید است، اما حذف مرحله بازبینی در محیط تولید میتواند یک تغییر کوچک را به قطعی گسترده تبدیل کند.
در نهایت، پیش از ارتقای Terraform یا Provider، Release Noteها را بررسی و تغییر را ابتدا در محیط آزمایش اجرا کنید. ارتقای کنترلنشده ممکن است رفتار Resourceها یا ساختار State را تغییر دهد.
اجرای این الگو روی زیرساخت آریانت
برای پیادهسازی این معماری، ابتدا تعداد ماشینها، اندازه CPU و RAM، ظرفیت ذخیرهسازی، نیاز به IP عمومی و توپولوژی شبکه خصوصی را مشخص کنید. سپس بررسی کنید Provider یا API در دسترس چه Resourceهایی را پشتیبانی میکند و کد نمونه را بر همان اساس تطبیق دهید. اگر برای شروع به زیرساخت محاسباتی انعطافپذیر نیاز دارید، میتوانید پلنهای سرور مجازی ابری آریانت را بررسی کنید. برای بارهای کاری سنگین، پایگاهدادههای پرترافیک یا نیاز به منابع فیزیکی مستقل نیز سرور اختصاصی آریانت گزینه متناسبتری است. پیش از طراحی کامل Pipeline، یک محیط آزمایشی کوچک بسازید: یک شبکه، یک VPS و یک Playbook ساده. پس از اطمینان از رفتار Provider، Backend راه دور، مدیریت Secret و قواعد تأیید تغییر را اضافه کنید. اگر مقصد نهایی این زیرساخت اجرای کانتینرهاست، همین سرورهای ساختهشده با Terraform میتوانند پایه یک کلاستر Kubernetes نیز باشند.
جمعبندی
Terraform زیرساخت را از مجموعهای از عملیات دستی به کدی قابل نسخهبندی و تکرار تبدیل میکند. با این رویکرد میتوان ساخت VPS، شبکه، دیسک و سایر منابع را استاندارد کرد، تغییرات را پیش از اجرا دید و محیطهای مشابه را با خطای کمتر بازسازی کرد. برای رسیدن به یک فرایند کامل، Terraform را مسئول Provisioning و Ansible را مسئول پیکربندی داخل سیستمعامل قرار دهید. State را ایمن نگه دارید، تغییرات تولید را با Plan و Code Review کنترل کنید و منابع حساس را بدون نسخه پشتیبان تغییر ندهید. بهترین نقطه شروع برای مدیریت سرور مجازی با Terraform یک پروژه کوچک و قابل آزمایش است. پس از تثبیت ساختار، همان الگو را به چند VPS، محیطهای مستقل و در نهایت زیرساخت تولید گسترش دهید.




