Tarkibga o'tish

Infrastructure as Code asoslari

Linux bulutda (cloud) maqolasida bitta instansiya o'zini cloud-init user-data faylidan sozlashi ko'rsatilgan edi. Infrastructure as Code (IaC) o'sha g'oyani — infratuzilmani qo'lda bosib yig'ish o'rniga faylda tasvirlashni — olib, uni butun parkka umumlashtiradi. Tashkilot ishlatadigan har bir server, tarmoq qoidasi va DNS yozuvi versiyalar nazorati ostidagi matnda tasvirlanadi va runbook’ga amal qilayotgan inson emas, vosita tomonidan qo'llaniladi. Bu maqola ikkita asosiy vosita toifasini, yaxshi IaC’ni mo'rt skriptlar uyumidan ajratib turadigan xususiyatlarni va amalda ikkalasini ham tanib olish uchun yetarli amaliy Ansible va Terraform’ni ko'rib chiqadi.

Nimalarni o'rganasiz

Bu maqola oxirida siz quyidagilarni qila olasiz:

  • infratuzilmani deklarativ va imperativ boshqarish o'rtasidagi farqni tushuntirish;
  • idempotentlikni va u nega IaC’ni qayta ishga tushirish uchun xavfsiz qiladigan xususiyat ekanini tushuntirish;
  • haqiqiy hostga qarshi SSH orqali minimal Ansible playbook yozish va ishga tushirish;
  • minimal Terraform konfiguratsiyasini yozish, qo'llash va uning plan chiqishini talqin qilish;
  • konfiguratsiya siljishi (configuration drift) va IaC uni nega avtomatik ravishda yo'q qilmasligi haqida mulohaza yuritish.

Deklarativ va imperativ: o'zgarishni tasvirlashning ikki usuli

Imperativ yondashuv maqsadga erishish qadamlarini tasvirlaydi: "nginx’ni o'rnat, keyin uni ishga tushir, keyin 80-portni och". Serverni tayyorlash uchun yozilgan shell skripti — hatto yaxshi yozilgani ham — o'z tabiatiga ko'ra imperativ, chunki u tizimning joriy holatidan qat’i nazar buyruqlarning qat’iy ketma-ketligini bajaradi.

Deklarativ yondashuv esa kerakli yakuniy holatni tasvirlaydi va unga erishish uchun qanday qadamlar kerakligini (agar umuman kerak bo'lsa) aniqlashni vositaga qoldiradi: "nginx o'rnatilgan va ishlab turgan bo'lishi kerak; 80-port ochiq bo'lishi kerak". Ansible ham, Terraform ham deklarativ vositalar. Amaliy farq ularni ikkinchi marta ishga tushirganingizda ko'rinadi: deklarativ vosita avval joriy holatni tekshiradi va farqni yopish uchun faqat haqiqatan kerak bo'lgan o'zgarishlarni kiritadi. Sodda imperativ skript esa biror narsa o'zgarganmi yoki yo'qmi, qat’i nazar, har safar har bir buyruqni qayta ishga tushiradi.

Imperative:  "run apt install nginx; run systemctl start nginx"
             — runs the same steps every time, whether or not needed

Declarative: "nginx: present, running"
             — checks current state; only acts if the state doesn't already match

Idempotentlik: qayta ishga tushirishni xavfsiz qiladigan xususiyat

Idempotentlik amalni bir marta qo'llash uni ko'p marta qo'llash bilan bir xil natija berishini anglatadi. Bu ishonchli IaC’ni mo'rt shell skriptidan ajratib turadigan eng muhim xususiyat. Chunki real operatsiyalarda tayyorlash (provisioning) jarayoni har doim qayta ishga tushiriladi — qisman muvaffaqiyatsizlikdan keyin, mavjud parkka bitta yangi server qo'shish uchun yoki shunchaki rejalashtirilgan siljishni tuzatish o'tishi sifatida. Idempotent bo'lmagan skript esa ikkinchi ishga tushirishda boshqacha, ko'pincha buzuvchi tarzda ishlaydi.

# Not idempotent: appends a duplicate line every single run
echo "127.0.0.1 myapp.local" >> /etc/hosts
# Idempotent: only adds the line if it is not already present
grep -qxF "127.0.0.1 myapp.local" /etc/hosts || \
  echo "127.0.0.1 myapp.local" >> /etc/hosts

Ikkinchi versiyani ming marta ishga tushirish mumkin va natija uni bir marta ishga tushirish bilan bir xil bo'ladi. Ansible modullari (xom shell buyruqlari emas) ham, Terraform’ning holatni solishtirish modeli ham aynan shu intizomni avtomatik ravishda o'z ichiga oladi. Vazifa bir martadan ko'p bajarilishi kerak bo'lgan zahoti qo'lda yozilgan tayyorlash skripti o'rniga ulardan biriga murojaat qilishning asosiy sababi shu.

Intervyuda: "nega buning uchun shunchaki Bash skript yozmaslik kerak?"

IaC vositalariga qarshi asosli ko'rinadigan e’tiroz — Bash ham xuddi shu ishni qila oladi. Halol javob shuki, Bash xuddi shu qadamlarni ifodalay oladi, lekin idempotentlik, holatni kuzatish va siljishni aniqlash har bir alohida skriptda qo'lda qurilishi va qo'lda qo'llab-quvvatlanishi kerak. Amalda esa bu kamdan-kam qilinadi, chunki ularni to'g'ri qilish (yuqoridagi /etc/hosts misoli hatto bitta oddiy holat uchun ham ko'rsatganidek) haqiqiy, osongina o'tkazib yuboriladigan intizomni talab qiladi. Ansible va Terraform mavjud, chunki kimdir "harakat qilishdan oldin joriy holatni tekshirish" va "aynan shuni o'zgartirish yoki olib tashlash uchun nima yaratganimni kuzatib borish" vazifalarini bir marta, umumiy tarzda hal qilib bo'lgan. Shunda alohida skriptlarning har biri buni qaytadan, nomuvofiq tarzda hal qilishi shart emas.

Ansible: agentsiz, push’ga asoslangan konfiguratsiya

Ansible masofaviy hostlarni oddiy SSH orqali boshqaradi — boshqariladigan mashinaga oldindan hech qanday agent o'rnatish kerak emas. Bu aynan SSH asoslari va SSH kalit autentifikatsiyasi maqolalarida allaqachon ko'rib chiqilgan SSH kirishi.

# inventory.ini
[web]
web-01 ansible_host=203.0.113.10
web-02 ansible_host=203.0.113.11

[web:vars]
ansible_user=deploy
# site.yml
- name: Configure web servers
  hosts: web
  become: true
  tasks:
    - name: Ensure nginx is installed
      apt:
        name: nginx
        state: present
        update_cache: true

    - name: Ensure nginx is running and enabled
      service:
        name: nginx
        state: started
        enabled: true

    - name: Deploy the site's index page
      copy:
        src: files/index.html
        dest: /var/www/html/index.html
        owner: www-data
        group: www-data
        mode: "0644"
ansible-playbook -i inventory.ini site.yml
PLAY [Configure web servers] **************************************

TASK [Ensure nginx is installed] ***********************************
changed: [web-01]
changed: [web-02]

TASK [Ensure nginx is running and enabled] *************************
ok: [web-01]
ok: [web-02]

PLAY RECAP ***********************************************************
web-01     : ok=3   changed=2   unreachable=0  failed=0
web-02     : ok=3   changed=2   unreachable=0  failed=0

Chiqishdagi changed/ok farqi — ko'zga ko'rinadigan idempotentlik. changed Ansible tizim e’lon qilingan holatga hali mos kelmaganini aniqlagani va o'zgarish kiritganini anglatadi. ok esa u allaqachon mos kelganini va hech narsa sodir bo'lmaganini anglatadi. ansible-playbook ni xuddi shu hostlarga qarshi ikkinchi marta ishga tushirish har bir vazifa uchun ok ni ko'rsatadi va qiladigan hech narsa qolmaganini isbotlaydi. Bu yuqorida tasvirlangan xususiyatning har bir vazifa bo'yicha jonli namoyishi va har qanday playbook ishga tushirilgandan keyin birinchi tekshirishga arziydigan narsa. Qayta ishga tushirishdagi kutilmagan changed natijalari odatda vazifa to'g'ri idempotent Ansible moduli o'rniga imperativ tarzda (tasodifiy command: yoki shell: moduli chaqiruvi bilan) yozilganini anglatadi.

become: true — Ansible’da har bir vazifa oldiga sudo qo'yishning ekvivalenti. Bu Root va sudo maqolasida ko'rib chiqilgan o'sha imtiyozni oshirish modeli, faqat har bir hostda qo'lda yozilish o'rniga barcha boshqariladigan hostlarga avtomatik qo'llaniladi.

Ansible’ning o'z dry run’i bor va u shu maqolada keyinroq ko'rsatiladigan terraform plan ning bevosita o'xshashi. Intervyuerlar bu savolni aynan nomzod Ansible’ga "ishga tushir-u, unut" skripti sifatida qaraydimi yoki ko'rib chiqiladigan o'zgarish sifatida qaraydimi, tekshirish uchun beradi:

ansible-playbook -i inventory.ini site.yml --check --diff

--check har bir vazifani check mode'da ishga tushiradi: Ansible aslida hech narsani o'zgartirmasdan, nima o'zgarishini xabar qiladi va haqiqiy ishga tushirish beradigan o'sha changed/ok taqsimotini chiqaradi. --diff vazifa o'zgartiradigan har bir faylning qatorma-qator farqini qo'shadi, shunda copy yoki template vazifasi hostga tegishdan oldin aynan qaysi qatorlarni qayta yozmoqchi ekanini ko'rsatadi. Playbook’ni production’ga qo'llashdan oldin --check --diff ni ishga tushirish terraform apply dan oldin terraform plan ni o'qish bilan bir xil intizom. Aytib o'tishga arziydigan yagona ogohlantirish: command:/shell: modulidan foydalanadigan vazifani simulyatsiya qilib bo'lmaydi (Ansible ixtiyoriy buyruq nima qilishini bilishning hech qanday usuliga ega emas), shuning uchun bunday vazifalar check mode’da o'tkazib yuboriladi. Bu xom shell o'rniga to'g'ri modullarni afzal ko'rish uchun yana bir aniq sabab.

Terraform: bulut resurslarini deklarativ tayyorlash

Ansible odatda allaqachon mavjud mashinalardagi dasturiy ta’minotni sozlasa, Terraform odatda mashinalarning o'zini (shuningdek, tarmoqlar, DNS yozuvlari va xotirani) bulut provayderining API’siga qarshi yaratadi.

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

provider "aws" {
  region = "us-east-1"
}

resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.micro"

  tags = {
    Name = "web-01"
  }
}
terraform init
terraform plan
Terraform will perform the following actions:

  # aws_instance.web will be created
  + resource "aws_instance" "web" {
      + ami           = "ami-0abcdef1234567890"
      + instance_type = "t3.micro"
      + id            = (known after apply)
      ...
    }

Plan: 1 to add, 0 to change, 0 to destroy.

terraform plan — dry run. U konfiguratsiyani Terraform’ning yozib olingan state'i (Terraform oldin aynan qaysi real resurslarni yaratganini kuzatib boradigan fayl) bilan solishtiradi va hali hech narsani o'zgartirmasdan, aynan nima o'zgarishini xabar qiladi. Uni apply dan oldin har doim ishga tushiring va o'qing — bu shu kursning boshqa joylarida har qanday buzuvchi buyruqdan oldin --dry-run chiqishini ko'rib chiqish bilan bir xil intizom.

terraform apply
aws_instance.web: Creating...
aws_instance.web: Creation complete after 34s [id=i-0a1b2c3d4e5f6g7h8]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Shundan keyin darhol, konfiguratsiyani o'zgartirmasdan terraform plan ni qayta ishga tushirish No changes. Your infrastructure matches the configuration. deb xabar beradi. Bu Ansible ko'rsatgan o'sha idempotentlik xususiyati, endi ularning ustiga o'rnatilgan dasturiy ta’minotga emas, resurslarning o'ziga qo'llanilgan.

Warning

Terraform’ning state fayli u aynan qaysi real resurslarni boshqarishini va ular konfiguratsiyangizga qanday mos kelishini yozib boradi. State faylini o'chirish yoki buzish asosiy bulut resurslarini o'chirmaydi — u Terraform’ning ularni kuzatishini yo'qotadi va ular ishlab turgan, boshqarilmaydigan, to'lov olinadigan holda, hech qanday konfiguratsiya ularga ishora qilmagan holda qolib ketadi. Bir kishidan ortiq har qanday jamoa uchun state’ni yo'qolishi yoki ikki kishi tomonidan bir vaqtda tahrirlanishi mumkin bo'lgan mahalliy fayl o'rniga masofaviy, versiyalangan, qulflanadigan backend’da saqlang (Terraform Cloud, DynamoDB qulflashli S3 bucket yoki ekvivalenti).

Konfiguratsiya siljishi: IaC o'zi hal qilmaydigan narsa

Siljish (drift) — resursning real holati IaC konfiguratsiyasi aytgan holatdan uzoqlashganda paydo bo'ladigan bo'shliq. Masalan, kimdir hodisa paytida bulut konsolida firewall qoidasini qo'lda o'zgartirgan va Terraform faylini yangilashni unutgan, yoki SSH orqali serverga kirib, Ansible boshqarishi kerak bo'lgan konfiguratsiya faylini qo'lda tahrirlagan. IaC vositalari siljish sodir bo'lishining oldini olmaydi — ular uni keyingi safar ishga tushganda aniqlaydi. Jamoalarni kutilmaganda qo'lga tushiradigan qism shuki, siljishni aniqlagan vosita standart holatda uni fayl aytgan holatga qaytarib tuzatishga urinadi. Agar fayl hech qachon unga mos ravishda yangilanmagan bo'lsa, bu qonuniy favqulodda tuzatishni bekor qilib yuborishi mumkin.

terraform plan
  # aws_instance.web has been changed
  ~ resource "aws_instance" "web" {
      ~ instance_type = "t3.small" -> "t3.micro"
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Bu chiqish kimdir (yoki nimadir) instansiya hajmini Terraform’dan tashqarida t3.small ga o'zgartirganini anglatadi. Bu plan’ni qo'llash uni jimgina yana t3.micro ga kichraytiradi. Aynan shu holatda apply dan oldin plan chiqishini diqqat bilan o'qish yaxshi sabab bilan kiritilgan bo'lishi mumkin bo'lgan o'zgarishni bekor qilishning oldini oladi.

Keng tarqalgan xatolar

  • To'g'ri idempotent modul mavjud bo'lganda Ansible vazifalarini shell:/command: moduli bilan yozish. shell: apt-get install -y nginx vazifasi har bir ishga tushirishda changed deb xabar beradi va siljishni ko'rinadigan qilishning butun maqsadini yo'qqa chiqaradi. Yuqorida ishlatilgan apt: moduli esa faqat haqiqatan biror narsa sodir bo'lishi kerak bo'lgandagina changed deb xabar beradi.
  • Terraform state’ini yo'qotish yoki uning zaxira nusxasini olmaslik. Yuqorida ko'rib chiqilganidek, bu resurslarni o'chirmaydi — ularni egasiz qoldiradi, ko'pincha ko'rinmas tarzda, toki kutilmaganda katta bulut hisobi muammoni oshkor qilmaguncha.
  • terraform plan chiqishini avval o'qimasdan terraform apply ni ishga tushirish. Plan — dry run. Uni umumiy, production’ni boshqaradigan konfiguratsiyada o'tkazib yuborish buzuvchi buyruqni oldindan hech qanday faqat o'qish tekshiruvisiz ishga tushirishning bevosita ekvivalenti.
  • Hodisani bulut konsolida qo'lda tuzatib, IaC konfiguratsiyasini unga mos ravishda hech qachon yangilamaslik. Bu siljishning eng keng tarqalgan real manbai va u keyingi avtomatlashtirilgan ishga tushirish yo tuzatishni bekor qilishini, yo kutilmagan holatga duch kelib, chalkash tarzda muvaffaqiyatsiz bo'lishini kafolatlaydi.

Mashqlar

  1. Lab VM’da o'zingiz tanlagan paket o'rnatilganini va tegishli servis ishlab turganini ta’minlaydigan Ansible playbook yozing, uni ikki marta ishga tushiring va ikkinchi ishga tushirish har bir vazifa uchun ok (changed emas) deb xabar berishini tasdiqlang.
  2. Paketni o'rnatish uchun apt:/dnf: moduli o'rniga shell: dan foydalanadigan bitta Ansible vazifasini ataylab yozing, playbook’ni ikki marta ishga tushiring va u ikkala safar ham changed deb xabar berishini kuzating. Nega ekanini tushuntiring.
  3. Sinab ko'rish imkoningiz bor resurs turi uchun minimal Terraform konfiguratsiyasini yozing (bulut instansiyasi yoki bulut akkaunti bo'lmasa, hatto mahalliy null_resource), terraform plan va terraform apply ni ishga tushiring, keyin resursni Terraform’dan tashqarida qo'lda o'zgartiring va u xabar qiladigan siljishni kuzatish uchun terraform plan ni qayta ishga tushiring.
  4. Har bir vosita aslida nimani kuzatib borishiga tayanib, yo'qolgan Terraform state fayli nega yo'qolgan Ansible playbook faylidan xavfliroq hodisa ekanini qisqa paragrafda tushuntiring.

Xulosa

Infrastructure as Code qo'lda bajariladigan, imperativ tayyorlash qadamlarini kerakli holatning deklarativ tavsiflari bilan almashtiradi. Ularni vositalar qo'llaydi — mavjud hostlarni sozlash uchun SSH orqali Ansible, resurslarning o'zini yaratish uchun provayder API’lariga qarshi Terraform. Bu vositalar harakat qilishdan oldin joriy holatni tekshiradi va shuning uchun ularni qayta ishga tushirish xavfsiz — bu xususiyat idempotentlik deb ataladi. Konfiguratsiya siljishi — resurs IaC vositasining o'z ish jarayonidan tashqarida o'zgartirilganda e’lon qilingan holat va haqiqat o'rtasida paydo bo'ladigan bo'shliq. IaC bu bo'shliqni faqat aniqlaydi va xabar qiladi — uni bartaraf etish, ayniqsa ataylab qilingan qo'lda tuzatishdan keyin, hali ham inson mulohazasini talab qiladi. Monitoring, logging va automation shu yerdan davom etadi va shu tarzda tayyorlangan park qanday kuzatilishi va doimiy ravishda sog'lom saqlanishini ko'rib chiqadi.

Manbalar