Բոլոր դասերը
DevOps և ամպՄիջին12 րոպե ընթերցումԱրժե իմանալ

Ansible

Կարգավորիր բազմաթիվ սերվերներ նույն կերպ՝ ընթեռնելի YAML playbook-ներով, պարզ SSH-ի միջոցով։

  • Playbooks
  • Inventory
  • Roles
  • Idempotency
Քայլ 1/6
Infrastructure as code՝ ուզածդ սերվերներն ու database-ը նկարագրում ես main.tf ֆայլում ու պահում Git-ում։

30 վայրկյանում

Ansible-ը ավտոմատացման գործիք է, որը SSH-ով միանում է քո սերվերներին և դրանք բերում նկարագրված վիճակի՝ փաթեթները տեղադրված, ֆայլերը տեղում, ծառայությունները աշխատող, օգտատերերը ստեղծված։ Ցանկալի վիճակը գրում ես YAML playbook-ներում, իսկ սերվերները թվարկում inventory-ում։ Սերվերների վրա agent պետք չէ, և լավ գրված playbook-ը idempotent է․ երկու անգամ աշխատեցնելիս երկրորդ անգամ ոչինչ չի փոխվում։

Իմ ամենօրյա stack-ում չէ․ գիտեմ հիմնական գաղափարները և մանրամասները կսովորեմ, երբ նախագիծը դա պահանջի։

Ինչու է սա կարևոր

  • Այն ձեռքով մուտքագրված սերվերի կարգավորումը փոխարինում է կոդով, որը կարող ես review անել, կրկնել և տարբերակավորել, ուստի տասներորդ սերվերը կարգավորվում է ճիշտ առաջինի պես։
  • Այն agentless է․ թիրախում պետք են միայն SSH և Python, ինչը հեշտացնում է ներդրումը գոյություն ունեցող սերվերներում՝ առանց որևէ բան տեղադրելու։
  • YAML playbook-ները ընթեռնելի են նաև նրանց համար, ովքեր լրիվ դրույքով ծրագրավորողներ չեն, ուստի operations և development թիմերը կարող են դրանք կիսել։
  • Այն լավ լրացնում է Terraform-ին․ Terraform-ը ստեղծում է մեքենաները, Ansible-ը կարգավորում է այն, ինչ աշխատում է դրանց վրա։

Ինչպես է աշխատում

01Գաղափարը՝ ցանկալի վիճակ SSH-ով

Պատկերացրու, որ ստուգաթերթ ես գրում սերվերի կարգավորման համար․ տեղադրել nginx, պատճենել կոնֆիգը, բացել 443 պորտը, գործարկել ծառայությունը։ Ansible-ը այդ ստուգաթերթը վերածում է կոդի։ Control node-ը՝ քո laptop-ը կամ CI runner-ը, որի վրա Ansible տեղադրված է, SSH-ով միանում է managed node-երին, պատճենում է փոքր Python մոդուլներ, աշխատեցնում դրանք և հեռացնում։ Յուրաքանչյուր task կանչում է մոդուլ, օրինակ՝ apt, copy, template, user կամ service, և նկարագրում է վերջնական վիճակը (state: present, state: started), ոչ թե այնտեղ հասնելու հրամանները։ Մոդուլը նախ ստուգում է ընթացիկ վիճակը և փոխում միայն այն, ինչը տարբերվում է՝ հաղորդելով ok կամ changed։ Այդ հատկությունը՝ idempotency-ն, նշանակում է, որ կարող ես նույն playbook-ը աշխատեցնել ամեն օր որպես drift-ի ստուգում։ Ansible-ը տարածվում է որպես ansible-core (շարժիչը և ներկառուցված մոդուլները) գումարած collection-ներ՝ ամպերի, տվյալների բազաների և ցանցային սարքերի մոդուլների փաթեթներ, որոնք միասին հավաքված են ansible community փաթեթում։

  • Control node՝ որտեղ աշխատում է Ansible-ը։ Managed node-եր՝ սերվերները։
  • Մոդուլ՝ աշխատանքի միավոր (apt, template, service)։
  • Idempotent՝ երկրորդ run-ը հաղորդում է ok, ոչ թե changed։

02Տեղադրում, inventory և ad-hoc հրամաններ

Ansible-ը control node-ի վրա տեղադրիր pipx-ով կամ pip-ով առանձին միջավայրում, ինչը խուսափում է համակարգային Python-ի հետ կոնֆլիկտներից։ Inventory-ն թվարկում է managed host-երը և խմբավորում դրանք՝ INI կամ YAML ձևաչափով։ Խմբերը թույլ են տալիս առանձին թիրախավորել վեբ սերվերները կամ տվյալների բազաները, իսկ group_vars/ և host_vars/ թղթապանակները պահում են փոփոխականներ ըստ խմբի կամ host-ի։ Playbook-ներ գրելուց առաջ ստուգիր կապը ad-hoc հրամաններով՝ մեկանգամյա մոդուլի կանչեր հրամանի տողից։ ansible all -m ping-ը ICMP չի օգտագործում․ այն մուտք է գործում SSH-ով և ստուգում Python-ը։ Օգտագործիր SSH բանալիներ և ոչ root օգտատեր sudo-ով․ Ansible-ի become: true-ն բարձրացնում է իրավունքները այն task-երի համար, որոնց դա պետք է։ ansible.cfg-ն պահիր նախագծում՝ inventory-ի ուղին և խելամիտ լռելյայն արժեքները սահմանելու համար։

yaml
# install on the control node
pipx install --include-deps ansible
 
# inventory.yml
all:
  children:
    web:
      hosts:
        web1: { ansible_host: 203.0.113.10 }
        web2: { ansible_host: 203.0.113.11 }
  vars:
    ansible_user: your_user
 
# test connectivity and gather facts
ansible -i inventory.yml all -m ping
ansible -i inventory.yml web -m ansible.builtin.setup -a "filter=ansible_distribution*"

03Քո առաջին playbook-ը

Playbook-ը play-երի ցուցակ է․ յուրաքանչյուր play թիրախավորում է host-եր և հերթով աշխատեցնում task-եր։ Օրինակը web խմբի վրա տեղադրում է nginx, Jinja2 template-ից deploy անում կայքի կոնֆիգուրացիան և համոզվում, որ ծառայությունը աշխատում է։ notify տողը handler է գործարկում միայն այն դեպքում, երբ template-ն իսկապես փոխվել է, ուստի nginx-ը reload է լինում մեկ անգամ՝ play-ի վերջում, ոչ թե ամեն run-ի ժամանակ։ Միշտ օգտագործիր մոդուլների լիարժեք անուններ, օրինակ՝ ansible.builtin.apt, որոնք պարզ են դարձնում, թե որ collection-ից է մոդուլը։ Նախ աշխատեցրու --check --diff-ով՝ տեսնելու, թե ինչ կփոխվի առանց որևէ բան փոխելու, հետո՝ իրականում։ Երկրորդ իրական run-ը պետք է ցույց տա changed=0․ եթե ոչ, ինչ-որ task idempotent չէ և պետք է ուղղվի։

yaml
- name: Configure web servers
  hosts: web
  become: true
  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true
    - name: Deploy site config
      ansible.builtin.template:
        src: templates/site.conf.j2
        dest: /etc/nginx/sites-available/default
        mode: "0644"
      notify: Reload nginx
    - name: Ensure nginx is running
      ansible.builtin.service: { name: nginx, state: started, enabled: true }
  handlers:
    - name: Reload nginx
      ansible.builtin.service: { name: nginx, state: reloaded }

04Փոփոխականներ, template-ներ և secret-ներ

Փոփոխականները թույլ են տալիս մեկ playbook-ին աշխատել բազմաթիվ միջավայրերի համար․ նույն role-ը կարգավորում է staging-ը և production-ը տարբեր արժեքներով՝ group_vars/staging.yml-ից և group_vars/production.yml-ից։ Template-ները օգտագործում են Jinja2 syntax՝ {{ variable }} և պարզ ցիկլեր կամ պայմաններ, այդ փոփոխականներից կոնֆիգուրացիոն ֆայլեր render անելու համար։ Facts-ը փոփոխականներ են, որոնք Ansible-ը ավտոմատ հավաքում է յուրաքանչյուր host-ից, օրինակ՝ OS-ի տարբերակը, հիշողությունը և IP հասցեները, օգտակար when: ansible_distribution == 'Ubuntu'-ի նման պայմանների համար։ Փոփոխականների precedence-ը շատ մակարդակներ ունի․ պահիր այն պարզ՝ օգտագործելով role default-ներ խելամիտ արժեքների համար և group_vars՝ միջավայրի override-ների համար։ Secret-ների համար Ansible Vault-ը գաղտնաբառով գաղտնագրում է ֆայլեր կամ առանձին արժեքներ, ուստի դրանք կարող են ապահով ապրել Git-ում։ CI-ում vault գաղտնաբառը տուր CI-ի secret store-ից կամ secret-ները վերցրու աշխատանքի պահին manager-ից, օրինակ՝ HashiCorp Vault-ից, lookup plugin-ով։

yaml
# group_vars/production/vars.yml
app_domain: example.com
app_workers: 4
db_password: "{{ vault_db_password }}"
 
# group_vars/production/vault.yml (encrypted)
# ansible-vault create group_vars/production/vault.yml
# vault_db_password: change-me
 
# run with the vault password
ansible-playbook -i inventory.yml site.yml --ask-vault-pass

05Role-եր և collection-ներ․ կառուցվածք, որը scale է լինում

Երբ playbook-ները մեծանում են, բաժանիր դրանք role-երի՝ ստանդարտ թղթապանակային կառուցվածք tasks-ով, handlers-ով, templates-ով, files-ով, defaults-ով և meta-ով։ Role-ը լավ է անում մեկ բան, օրինակ՝ nginx, postgres կամ base hardening baseline, իսկ site playbook-ը role-երը համադրում է ըստ host խմբերի։ ansible-galaxy role init-ը ստեղծում է կմախքը։ Collection-ները role-երը, մոդուլները և plugin-ները փաթեթավորում են միասին namespace-ի տակ, և դու դրանք տեղադրում ես Ansible Galaxy-ից կամ private hub-ից requirements.yml-ով՝ ամրացված տարբերակներով, ինչպես կամրացնեիր npm փաթեթները։ Role-երը թեստավորիր Molecule-ով, որը գործարկում է container կամ VM, կիրառում role-ը, նորից աշխատեցնում այն idempotency-ն ստուգելու համար և ստուգում արդյունքը։ CI-ում lint արա ansible-lint-ով՝ հնացած syntax-ը, բացակայող անունները և ռիսկային pattern-ները բռնելու համար։

yaml
# requirements.yml
collections:
  - name: community.general
    version: ">=10.0.0,<11.0.0"
  - name: ansible.posix
    version: ">=2.0.0"
 
# site.yml
- hosts: web
  become: true
  roles:
    - base_hardening
    - nginx
 
# ansible-galaxy collection install -r requirements.yml

Օգտագործեք, երբ

  • Linux սերվերների կամ VM-ների պարկի հետևողական կարգավորում՝ փաթեթներ, օգտատերեր, կոնֆիգներ, ծառայություններ, hardening։
  • Terraform-ով կամ ամպային կոնսոլով ստեղծված սերվերների կրկնվող provisioning։
  • Կազմակերպված գործողություններ՝ rolling restart-եր, խմբաքանակներով patching, սերտիֆիկատների rotation host-երի վրա։
  • Ցանցային սարքեր և appliance-ներ, որոնց համար վաճառողները ունեն ուժեղ Ansible collection-ներ։

Մի՛ օգտագործեք, երբ

  • Ամպային ենթակառուցվածքի ստեղծում և հետևում՝ կախվածություններով և state-ով․ Terraform-ը կամ OpenTofu-ն ավելի հարմար են։
  • Ամբողջությամբ Kubernetes-ում container-ացված workload-ներ, որտեղ կոնֆիգուրացիան կառավարում են manifest-ները, Helm-ը և operator-ները։
  • Շատ մեծ պարկեր, որոնց պետք է անընդհատ պարտադրում ամեն մի քանի րոպեն մեկ, որտեղ agent-ի վրա հիմնված գործիքները կամ immutable image-ները կարող են ավելի հարմար լինել։

Այլընտրանքներ

  • Terraform / OpenTofu

    Declarative ենթակառուցվածքի provisioning՝ state-ով․ հաճախ օգտագործվում է Ansible-ի հետ միասին։

  • Chef / Puppet

    Agent-ի վրա հիմնված configuration management՝ անընդհատ պարտադրմամբ։

  • Salt

    Արագ, event-driven կոնֆիգուրացիա և remote execution՝ agent-ով կամ SSH ռեժիմով։

  • Immutable image-ներ (Packer, cloud-init)

    Կոնֆիգուրացիան «թխիր» image-ների մեջ և փոխարինիր սերվերները՝ դրանք փոխելու փոխարեն։

Լավագույն պրակտիկաներ

  1. Գրիր idempotent task-եր մոդուլներով․ shell կամ command օգտագործիր միայն երբ մոդուլ չկա՝ creates:-ով կամ changed_when-ով։
  2. Օգտագործիր collection-ների լիարժեք անուններ (ansible.builtin.copy) և ամրացրու collection-ների տարբերակները requirements.yml-ում։
  3. Կոդը կազմակերպիր փոքր role-երում default-ներով, իսկ միջավայրերի տարբերությունները պահիր group_vars-ում։
  4. Secret-ները գաղտնագրիր Ansible Vault-ով կամ վերցրու secret manager-ից․ երբեք մի՛ commit արա բաց գաղտնաբառեր։
  5. Ռիսկային փոփոխություններից առաջ աշխատեցրու --check --diff և rolling թարմացումների համար օգտագործիր serial:։
  6. Lint արա ansible-lint-ով և CI-ում role-երը թեստավորիր Molecule-ով։
  7. Օգտագործիր SSH բանալիներ, առանձին ավտոմատացման օգտատեր և become միայն այնտեղ, որտեղ պետք է։

Տարածված սխալներ

  • shell:-ը օգտագործել ամեն ինչի համար, ուստի ամեն run հաղորդում է changed, և ոչինչ ապահով կրկնելի չէ։
  • Tab-եր խառնել, սխալ indentation կամ առանց չակերտների արժեքներ, որոնք YAML-ը կարդում է որպես boolean կամ թիվ, օրինակ՝ yes կամ 0644։
  • Հույս դնել փոփոխականների բարդ precedence-ի վրա, մինչև որ ոչ ոք չիմանա, թե արժեքը որտեղից է գալիս։
  • Փոփոխությունը միանգամից բոլոր host-երի վրա աշխատեցնել առանց serial-ի՝ ամբողջ ծառայությունը միասին անջատելով։
  • Vault գաղտնաբառերը պահել գաղտնագրված ֆայլերի կողքին ռեպոզիտորիայում։

Խորը վերլուծություն

06Ինչպես է task-ը իրականում կատարվում

Յուրաքանչյուր task-ի համար Ansible-ը control node-ի վրա Jinja2-ով render է անում մոդուլի արգումենտները, փաթեթավորում մոդուլի կոդը (AnsiballZ) և ուղարկում SSH-ով, հետո աշխատեցնում այն հեռավոր Python-ով և հետ կարդում JSON։ Լռելյայն այն դա անում է միաժամանակ forks host-ի համար (լռելյայն 5) linear strategy-ով, որտեղ ամեն host ավարտում է task-ը, մինչև որևէ host սկսի հաջորդը։ Մեծ մասշտաբում կատարողականի կարգավորումը կարևոր է․ մեծացրու forks-ը, ansible.cfg-ում միացրու pipelining (այն հեռացնում է SSH-ի լրացուցիչ round-trip-ները, բայց պահանջում է, որ sudo-ն TTY չպահանջի), պահիր SSH ControlPersist multiplexing-ը միացված և անջատիր կամ cache արա fact-երի հավաքումը, երբ fact-եր պետք չեն։ Free strategy-ն թույլ է տալիս արագ host-երին առաջ անցնել։ Երկար task-երը կարող են աշխատել ասինխրոն async-ով և poll-ով, որպեսզի կապերը բաց չպահվեն։

ini
# ansible.cfg
[defaults]
inventory = inventory.yml
forks = 25
gathering = smart
fact_caching = jsonfile
fact_caching_connection = .ansible_facts
fact_caching_timeout = 3600
 
[ssh_connection]
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=60s

07Rolling update-ներ serial-ով և health check-երով

Production-ի փոփոխությունները երբեք չպետք է միանգամից հասնեն բոլոր host-երին։ serial-ը ընդունում է թիվ, տոկոս կամ ցուցակ, օրինակ՝ [1, 5, "25%"], ինչը տալիս է canary host, հետո փոքր խմբաքանակ, հետո ավելի մեծերը։ delegate_to-ն task-ը աշխատեցնում է այլ մեքենայի վրա, սովորաբար ընթացիկ host-ը load balancer-ից հանելու համար։ until-ի և retries-ի հետ համատեղ health check-ը սպասում է, մինչև ծառայությունը առողջ դառնա, նախքան առաջ շարժվելը։ max_fail_percentage-ը դադարեցնում է play-ը, երբ խմբաքանակում չափազանց շատ host-եր են ձախողվում, ինչը կանգնեցնում է վատ release-ի տարածումը։ any_errors_fatal-ը կանգնեցնում է ամեն ինչ առաջին ձախողման ժամանակ, ինչը օգտակար է տվյալների բազաների կլաստերների համար, որտեղ մասնակի փոփոխությունները վտանգավոր են։

yaml
- hosts: web
  become: true
  serial: [1, 5, "25%"]
  max_fail_percentage: 0
  tasks:
    - name: Deploy new release
      ansible.builtin.include_role: { name: app_release }
    - name: Wait until healthy
      ansible.builtin.uri:
        url: "http://{{ ansible_host }}:8080/healthz"
        status_code: 200
      register: health
      until: health.status == 200
      retries: 20
      delay: 3
      delegate_to: localhost

08Dynamic inventory, AWX և Execution Environment-ներ

Ստատիկ inventory ֆայլերը ամպում արագ հնանում են։ Inventory plugin-ները, օրինակ՝ amazon.aws.aws_ec2, azure.azcollection.azure_rm կամ google.cloud.gcp_compute, հարցում են անում պրովայդերին և խմբեր կառուցում tag-երից, ուստի role=web tag-ով սերվերը ավտոմատ հայտնվում է web խմբում։ Ansible-ը laptop-ներից աշխատեցնելու փոխարեն որպես ընդհանուր ծառայություն աշխատեցնելու համար AWX-ը (Red Hat Ansible Automation Platform-ի open-source upstream-ը) տրամադրում է վեբ UI, role-based մուտք, credentials-ի պահեստ, ժամանակացույցեր, API և աուդիտի լոգեր։ Execution Environment-ները container image-ներ են, որոնք փաթեթավորում են ansible-core-ը, collection-ները և Python dependency-ները, build են արվում ansible-builder-ով և աշխատեցվում ansible-navigator-ով կամ AWX-ով։ Դրանք լուծում են դասական «իմ control node-ի վրա աշխատում է» խնդիրը՝ ավտոմատացման runtime-ը դարձնելով նույնքան վերարտադրելի, որքան իր deploy արած հավելվածների image-ները։

Իրական իրավիճակներ

01

Քսան գոյություն ունեցող սերվերների հետևողական hardening

Խնդիր

Քսան Ubuntu սերվեր տարիների ընթացքում կարգավորվել են ձեռքով։ SSH կարգավորումները, firewall-ի կանոնները և օգտատերերը տարբերվում են, և աուդիտ է սպասվում։

Ինչպես լուծել

Ստեղծիր base_hardening role․ անջատիր SSH գաղտնաբառով և root մուտքը sshd_config-ի template-ով validate: sshd -t ստուգումով, տեղադրիր և կարգավորիր ufw-ը default deny incoming-ով, միացրու unattended անվտանգության թարմացումները, կառավարիր admin օգտատերերին և նրանց բանալիները փոփոխականների ցուցակից և տեղադրիր fail2ban։ Աշխատեցրու այն --check --diff-ով բոլոր host-երի դեմ՝ drift-ը տեսնելու համար, review արա, հետո կիրառիր մեկ host-ի վրա, հետո մնացածին serial-ով։ CI-ից պլանավորիր շաբաթական check-mode run և ազդանշան տուր ցանկացած changed արդյունքի դեպքում, որպեսզի drift-ը հայտնաբերվի հաջորդ աուդիտից առաջ։

02

Playbook-ը միշտ հաղորդում է changed

Խնդիր

Թիմի deploy playbook-ը ամեն run-ում ամեն task-ի վրա ցույց է տալիս changed, ուստի ոչ ոք չի կարող ասել, թե երբ է ինչ-որ բան իսկապես փոխվել, և handler-ները անտեղի վերագործարկում են ծառայությունները։

Ինչպես լուծել

Shell հրամանները փոխարինիր մոդուլներով․ apt՝ apt-get install-ի փոխարեն, copy կամ template՝ ֆայլերի մեջ echo անելու փոխարեն, systemd՝ systemctl restart-ի փոխարեն։ Որտեղ հրամանն անխուսափելի է, ավելացրու creates: մեկանգամյա կարգավորման համար, կամ register արա output-ը և դրա հիման վրա սահմանիր changed_when։ Restart-ները տեղափոխիր notify-ով գործարկվող handler-ների մեջ, որպեսզի դրանք աշխատեն միայն իրական փոփոխություններից հետո։ Playbook-ը երկու անգամ աշխատեցրու Molecule-ում idempotence թեստով և CI-ին ավելացրու ansible-lint, որը նշում է no-changed-when pattern-ները։ Երկրորդ run-ը պետք է հաղորդի changed=0։

03

Տվյալների բազայի կլաստերի ապահով patching

Խնդիր

Տվյալների բազայի երեք replica-ին և primary-ին պետք են kernel-ի թարմացումներ և reboot-ներ։ Միաժամանակ մեկից ավելիի reboot-ը կամ primary-ն առաջինը reboot անելը կառաջացնի outage։

Ինչպես լուծել

Գրիր play serial: 1-ով և any_errors_fatal: true-ով, որը նախ թիրախավորում է replica-ները իրենց խմբում, հետո primary-ն հաջորդ play-ում։ Յուրաքանչյուր host-ի համար․ check task-ով հաստատիր, որ replication-ը առողջ է, apt upgrade, reboot ansible.builtin.reboot մոդուլով (որը սպասում է host-ի վերադարձին), հետո until-ով և retries-ով սպասիր, մինչև replication lag-ը վերադառնա շեմից ցածր։ Primary-ից առաջ տվյալների բազայի գործիքներով գործարկիր վերահսկվող failover դեպի replica, հետո patch արա հին primary-ն որպես replica։ Նախ աշխատեցրու staging-ում։

Արագ ուղեցույց

Ստուգել կապը
ansible -i inventory.yml all -m ping
Dry run diff-ով
ansible-playbook site.yml --check --diff
Սահմանափակել մեկ host-ով
ansible-playbook site.yml --limit web1
Աշխատեցնել միայն tag-ավորված task-երը
ansible-playbook site.yml --tags nginx
Ստեղծել գաղտնագրված ֆայլ
ansible-vault create group_vars/production/vault.yml
Գաղտնագրել մեկ արժեք
ansible-vault encrypt_string 'change-me' --name 'vault_db_password'
Նոր role-ի կմախք
ansible-galaxy role init nginx
Տեղադրել ամրացված collection-ներ
ansible-galaxy collection install -r requirements.yml
Playbook-ների lint
ansible-lint
Ցույց տալ մոդուլի փաստաթղթերը
ansible-doc ansible.builtin.template

Հարցեր և պատասխաններ

Q1Ի՞նչ է նշանակում idempotent Ansible-ում։

Idempotent task-ը տալիս է նույն վերջնական վիճակը՝ անկախ նրանից, թե քանի անգամ ես այն աշխատեցնում, և ոչինչ չի փոխում, երբ համակարգն արդեն ճիշտ է։ Օրինակ՝ ansible.builtin.apt-ը state: present-ով տեղադրում է nginx միայն եթե այն բացակայում է․ հաջորդ run-ում այն հաղորդում է ok։ Դա թույլ է տալիս playbook-ները կրկին ու կրկին աշխատեցնել որպես անվտանգության ցանց և drift-ի ստուգում։ Մոդուլները նախագծված են idempotent լինելու համար, իսկ raw shell հրամանները՝ ոչ, որովհետև Ansible-ը չի կարող իմանալ, թե ինչ են դրանք արել։ Երբ պետք է օգտագործել command կամ shell, ավելացրու creates: կամ removes: կամ changed_when պայման, որպեսզի task-ը ազնիվ հաղորդի։ Լավ թեստ է playbook-ը երկու անգամ աշխատեցնելը․ երկրորդ run-ը պետք է ցույց տա changed=0։

Q2Ansible, թե՞ Terraform։

Դրանք լուծում են տարբեր շերտեր և լավ են աշխատում միասին։ Terraform-ը declarative provisioning է state-ով․ այն ստեղծում է ամպային ռեսուրսներ, ինչպես ցանցեր, VM-ներ, տվյալների բազաներ և DNS գրառումներ, հետևում դրանց state ֆայլում, պլանավորում փոփոխությունները և կարող է ոչնչացնել դրանք։ Ansible-ը procedural կոնֆիգուրացիա է SSH-ով․ այն կարգավորում է մեքենաների ներսը՝ փաթեթներ, ֆայլեր, օգտատերեր և ծառայություններ, և կազմակերպում գործողություններ, օրինակ՝ rolling restart-եր։ Ansible-ն ունի ամպային մոդուլներ, բայց առանց state ֆայլի այն ավելի թույլ է ռեսուրսներին հետևելու և ջնջելու հարցում։ Տարածված pattern է, երբ Terraform-ը ստեղծում է սերվերներ և output անում դրանց հասցեները, իսկ Ansible-ը dynamic inventory-ով կարգավորում է դրանք։

Q3Ինչո՞ւ է Ansible-ը կոչվում agentless, և որո՞նք են փոխզիջումները։

Ansible-ին managed սերվերների վրա daemon պետք չէ։ Այն միանում է SSH-ով, պատճենում փոքր Python մոդուլներ, աշխատեցնում դրանք և մաքրում։ Թիրախի պահանջները միայն SSH-ն ու Python-ն են, որոնք ունի գրեթե ամեն Linux սերվեր։ Դա պարզեցնում է ներդրումը և փոքրացնում հարձակման մակերեսը։ Փոխզիջումները․ այն push-based է, ուստի կոնֆիգուրացիան պարտադրվում է միայն այն ժամանակ, երբ ինչ-որ մեկը կամ ինչ-որ բան աշխատեցնում է playbook-ը, ոչ թե անընդհատ։ SSH կապերը շատ մեծ պարկերում ժամանակ են արժենում, թեև forks-ը, pipelining-ը և SSH multiplexing-ը շատ են օգնում։ Agent-ի վրա հիմնված գործիքները, ինչպես Puppet-ը, ինքնուրույն պարտադրում են վիճակը ամեն կես ժամը մեկ։ Ansible-ով նման վարքագիծ ստանում ես՝ playbook-ները ժամանակացույցով աշխատեցնելով CI-ից կամ AWX-ից։

Q4Ինչպե՞ս ես աշխատում secret-ների հետ Ansible-ում։

Ներկառուցված պատասխանը Ansible Vault-ն է․ այն AES-256-ով գաղտնագրում է ամբողջ ֆայլեր կամ առանձին փոփոխականներ, ուստի secret-ները կարող են commit արվել playbook-ների կողքին։ Տարածված կառուցվածքում գաղտնագրված vault.yml-ը պահվում է բաց vars.yml-ի կողքին, որը հղում է vault_ նախածանցով փոփոխականներին, ուստի դեռ կարող ես փնտրել փոփոխականների անունները։ Vault գաղտնաբառն ինքը գալիս է prompt-ից, ռեպոզիտորիայից դուրս գաղտնաբառի ֆայլից կամ script-ից, որը կարդում է այն secret store-ից․ CI-ում այն պաշտպանված secret է։ Ավելի մեծ համակարգերի համար lookup plugin-ները secret-ները վերցնում են աշխատանքի պահին HashiCorp Vault-ից կամ ամպային secret manager-ներից, ուստի դրանք ընդհանրապես երբեք Git-ում չեն լինում։ Օգտագործիր no_log: true այն task-երում, որոնք կտպեին secret-ներ։

Q5Ինչպե՞ս փոփոխություն ներդնել 50 վեբ սերվերի վրա՝ առանց downtime-ի։

Օգտագործիր rolling update մեկ play-ում։ serial:-ը դիր խմբաքանակի չափին, օրինակ՝ 5 կամ 10%, որպեսզի Ansible-ը մեկ խմբաքանակի վրա ավարտի բոլոր task-երը, մինչև հաջորդը։ pre_tasks-ում host-ը հանիր load balancer-ից, tasks-ում deploy և restart արա, հետո ansible.builtin.uri-ով health check աշխատեցրու, մինչև հավելվածը պատասխանի, և post_tasks-ում նորից ավելացրու այն։ Սահմանիր max_fail_percentage, որպեսզի rollout-ը կանգնի, եթե խմբաքանակը ձախողվի, ոչ թե կոտրի ամբողջ պարկը։ Նախ թեստավորիր --check --diff-ով staging-ում և canary-ի համար սահմանափակիր մեկ host-ով --limit-ով։ Սա ռիսկային փոփոխությունը վերածում է վերահսկվող, դիտարկելի գործընթացի։

Սենիոր մակարդակի հարցեր

S1Mutable կոնֆիգուրացիա Ansible-ով, թե՞ immutable image-ներ․ որն ես նախընտրում։

Immutable նշանակում է սերվերի image build անել՝ ամբողջ կոնֆիգուրացիան ներսում «թխած», օրինակ՝ Packer-ով, և սերվերները փոխարինել՝ դրանք փոխելու փոխարեն։ Դա տալիս է նույնական մեքենաներ, արագ scaling և հեշտ rollback նախորդ image-ին, և վերացնում է drift-ը։ Mutable կոնֆիգուրացիան Ansible-ով աշխատող սերվերները փոխում է տեղում․ ավելի էժան է սկսելու համար, աշխատում է գոյություն ունեցող երկարակյաց սերվերների և stateful համակարգերի, ինչպես տվյալների բազաների հետ, և ավելի արագ է փոքր փոփոխությունների համար։ Շատ հասուն համակարգեր համատեղում են դրանք․ Ansible-ը աշխատում է Packer build-ի ներսում՝ image ստանալու համար, ուստի նույն role-երը ծառայում են երկու դեպքում էլ։ Autoscaling խմբում stateless հավելվածային սերվերների համար ես նախընտրում եմ immutable-ը, իսկ տվյալների բազաների, bastion-ների և մի քանի երկարակյաց VM-ի համար Ansible-ը տեղում պրագմատիկ է։ Իրական թշնամին չկառավարվող ձեռքով փոփոխությունն է, ինչ մոդել էլ ընտրես։

S2Ինչպե՞ս կկառուցես Ansible-ը մի քանի թիմի և միջավայրի համար։

Առանձնացրու վերօգտագործվող կոդը միջավայրի տվյալներից։ Role-երը և մոդուլները ապրում են տարբերակավորված collection-ներում՝ իրենց ռեպոզիտորիաներում, թեստավորված Molecule-ով և թողարկված semantic version-ներով։ Յուրաքանչյուր միջավայր ունի inventory ռեպոզիտորիա կամ թղթապանակ group_vars-ով, host_vars-ով և requirements.yml-ով, որը ամրացնում է collection-ների տարբերակները, ուստի staging-ը կարող է փորձել role-ի նոր տարբերակը production-ից առաջ։ Execution Environment-ները սառեցնում են ansible-core-ը և Python dependency-ները։ Run-երը տեղի են ունենում CI-ից կամ AWX-ից, ոչ թե laptop-ներից, credentials-ը պահվում են այնտեղ, իսկ role-based մուտքը վերահսկում է, թե ով կարող է որ job template-ը աշխատեցնել որ inventory-ի դեմ։ Փոփոխականների precedence-ը պահիր հարթ․ default-ներ role-երում, override-ներ group_vars-ում, և խուսափիր extra-vars-ից, բացի մեկանգամյա պարամետրերից։ Փոխզիջումը ծիսակարգն է․ երկու հոգանոց թիմի համար՝ հինգ սերվերով, մեկ ռեպոզիտորիան միանգամայն բավարար է։

S3Ի՞նչն է սահմանափակում Ansible-ի կատարողականը, և ինչպե՞ս scale անել այն հազարավոր host-երի համար։

Խցանները SSH կապի հաստատումն են, ամեն task-ի round-trip-ները, fact-երի հավաքումը և control node-ի CPU-ն, քանի որ ամեն fork պրոցես է։ Scaling-ի քայլեր․ մեծացրու forks-ը control node-ի core-երին և հիշողությանը համապատասխան, միացրու pipelining և ControlPersist՝ կապերը վերօգտագործելու համար, cache արա fact-երը կամ դիր gather_facts: false, որտեղ պետք չեն, կրճատիր task-երը՝ օգտագործելով ցուցակներ ընդունող մոդուլներ, օրինակ՝ շատ փաթեթներ տեղադրելով մեկ apt կանչով, և երկար գործողությունների համար օգտագործիր async։ Շատ մեծ run-երը բաժանիր ըստ խմբի կամ տարածաշրջանի և աշխատեցրու զուգահեռ մի քանի control node-ից կամ host-երին մոտ AWX execution node-երից։ Mitogen ոճի արագացուցիչներ կան, բայց անհավասար են հետևում ansible-core-ի տարբերակներին, ուստի զգուշորեն թեստավորիր։ Շատ մեծ մասշտաբում դիտարկիր pull ռեժիմը ansible-pull-ով կամ immutable image-ներ՝ ամեն host-ի push անելու փոխարեն։

Բառարան

Control node
Մեքենան, որտեղ տեղադրված է Ansible-ը, և որտեղից աշխատում են playbook-ները։
Managed node
Սերվեր, որը Ansible-ը կարգավորում է՝ հասանելի SSH-ով (կամ WinRM-ով Windows-ի համար)։
Inventory
Managed host-երի ցուցակը՝ իրենց խմբերով և փոփոխականներով, ստատիկ կամ դինամիկ։
Playbook
Play-երի YAML ֆայլ, որը host խմբերը կապում է հերթականությամբ task-երին։
Module
Աշխատանքի միավոր, որը Ansible-ը աշխատեցնում է host-ի վրա, օրինակ՝ apt, template կամ service։
Handler
Task, որը աշխատում է միայն փոխված task-ի notify-ով, սովորաբար restart կամ reload։
Role
Task-երի, template-ների, handler-ների և default-ների վերօգտագործվող թղթապանակային կառուցվածք մեկ նպատակի համար։
Collection
Մոդուլների, role-երի և plugin-ների տարբերակավորված փաթեթ namespace-ի տակ՝ Galaxy-ից կամ hub-ից։
Ansible Vault
Ներկառուցված գաղտնագրում secret ֆայլերի և արժեքների համար, որոնք պահվում են playbook-ների կողքին։
Facts
Տեղեկություններ, որոնք Ansible-ը հավաքում է յուրաքանչյուր host-ի մասին, օրինակ՝ OS, հիշողություն և ցանցային հասցեներ։

Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։

Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։