Ansible-ի միջոցով Rails հավելվածը տեղակայելու համար սերվերի կարգավորում

Ոչ վաղ անցյալում ես պետք է գրեի մի քանի Ansible գրքույկ՝ սերվերը Rails հավելվածը տեղակայելու համար պատրաստելու համար: Եվ, զարմանալիորեն, ես չգտա պարզ քայլ առ քայլ ձեռնարկ: Ես չէի ուզում պատճենել ուրիշի խաղագիրքը՝ չհասկանալով, թե ինչ է կատարվում, և վերջում ստիպված էի կարդալ փաստաթղթերը՝ ինքս հավաքելով ամեն ինչ: Միգուցե ես կարող եմ օգնել ինչ-որ մեկին արագացնել այս գործընթացը այս հոդվածի օգնությամբ:

Առաջին բանը, որ պետք է հասկանալ, այն է, որ ansible-ն ապահովում է ձեզ հարմար ինտերֆեյս՝ SSH-ի միջոցով հեռավոր սերվերի (սերվերների) վրա գործողությունների նախապես սահմանված ցուցակը կատարելու համար: Այստեղ ոչ մի կախարդանք չկա, դուք չեք կարող տեղադրել պլագին և ստանալ ձեր հավելվածի զրոյական պարապուրդի տեղակայումը դոկերի, մոնիտորինգի և այլ բարիքների միջոցով: Խաղագիրք գրելու համար դուք պետք է իմանաք, թե կոնկրետ ինչ եք ուզում անել և ինչպես դա անել: Ահա թե ինչու ես չեմ բավարարվում GitHub-ի պատրաստի գրքույկներով կամ այնպիսի հոդվածներով, ինչպիսիք են՝ «Պատճենիր և գործարկիր, այն կաշխատի»:

Ի՞նչ է մեզ պետք։

Ինչպես արդեն ասացի, խաղագիրք գրելու համար պետք է իմանալ, թե ինչ ես ուզում անել և ինչպես դա անել: Եկեք որոշենք, թե ինչ է մեզ անհրաժեշտ: Rails հավելվածի համար մեզ անհրաժեշտ կլինեն մի քանի համակարգային փաթեթներ՝ nginx, postgresql (redis և այլն): Բացի այդ, մեզ անհրաժեշտ է ռուբինի կոնկրետ տարբերակ: Ավելի լավ է այն տեղադրել rbenv-ի միջոցով (rvm, asdf...): Այս ամենը որպես root օգտագործող գործարկելը միշտ էլ վատ գաղափար է, այնպես որ դուք պետք է ստեղծեք առանձին օգտվող և կարգավորեք նրա իրավունքները: Դրանից հետո դուք պետք է վերբեռնեք մեր կոդը սերվերում, պատճենեք nginx-ի, postgres-ի և այլնի կոնֆիգուրացիաները և գործարկեք այս բոլոր ծառայությունները:

Արդյունքում, գործողությունների հաջորդականությունը հետևյալն է.

  1. Մուտք գործեք որպես արմատ
  2. տեղադրել համակարգի փաթեթներ
  3. ստեղծել նոր օգտվող, կարգավորել իրավունքները, ssh ստեղնը
  4. կարգավորել համակարգի փաթեթները (nginx և այլն) և գործարկել դրանք
  5. Մենք օգտատեր ենք ստեղծում տվյալների բազայում (դուք կարող եք անմիջապես ստեղծել տվյալների բազա)
  6. Մուտք գործեք որպես նոր օգտվող
  7. Տեղադրեք rbenv և ruby
  8. Փաթեթի տեղադրում
  9. Դիմումի կոդը բեռնվում է
  10. Puma սերվերի գործարկում

Ավելին, վերջին փուլերը կարող են իրականացվել capistrano-ի միջոցով, համենայն դեպս, այն կարող է պատճենել կոդը թողարկման գրացուցակներում, հաջող տեղակայման դեպքում փոխել թողարկումը symlink-ով, պատճենել կոնֆիգուրացիաները ընդհանուր գրացուցակից, վերագործարկել puma և այլն: Այս ամենը կարելի է անել Ansible-ի միջոցով, բայց ինչո՞ւ:

Ֆայլի կառուցվածքը

Ansible-ն ունի խիստ ֆայլի կառուցվածքը ձեր բոլոր ֆայլերի համար, ուստի ավելի լավ է այն պահել առանձին գրացուցակում: Ընդ որում, այնքան էլ կարևոր չէ՝ այն կլինի բուն ռելսերի հավելվածում, թե առանձին։ Դուք կարող եք ֆայլեր պահել առանձին git պահոցում: Անձամբ ես ամենահարմար համարեցի ստեղծել ansible գրացուցակ rails հավելվածի /config գրացուցակում և ամեն ինչ պահել մեկ պահեստում:

Պարզ խաղագիրք

Playbook-ը yml ֆայլ է, որը, օգտագործելով հատուկ շարահյուսություն, նկարագրում է, թե ինչ և ինչպես պետք է անի Ansible-ը: Եկեք ստեղծենք առաջին խաղագիրքը, որը ոչինչ չի անում.

---
- name: Simple playbook
  hosts: all

Այստեղ մենք պարզապես ասում ենք, որ մեր խաղագիրքը կոչվում է Simple Playbook և որ դրա բովանդակությունը պետք է կատարվի բոլոր հոսթերի համար: Մենք կարող ենք այն պահել անունով /ansible գրացուցակում playbook.yml և փորձիր վազել.

ansible-playbook ./playbook.yml

PLAY [Simple Playbook] ************************************************************************************************************************************
skipping: no hosts matched

Ansible-ն ասում է, որ չգիտի որևէ հաղորդավար, որը համապատասխանում է բոլոր ցանկին: Նրանք պետք է նշված լինեն հատուկ գույքագրման ֆայլ.

Եկեք ստեղծենք այն նույն ansible գրացուցակում.

123.123.123.123

Ահա թե ինչպես մենք պարզապես նշում ենք հյուրընկալողը (իդեալականում մեր VPS-ի հյուրընկալողը թեստավորման համար, կամ դուք կարող եք գրանցել localhost) և պահպանել այն անվան տակ: inventory.
Դուք կարող եք փորձել գործարկել ansible-ը գույքագրման ֆայլով.

ansible-playbook ./playbook.yml -i inventory
PLAY [Simple Playbook] ************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************

PLAY RECAP ************************************************************************************************************************************

Եթե ​​դուք ունեք ssh մուտք դեպի նշված հոսթ, ապա ansible-ը կմիանա և կհավաքի տեղեկատվություն հեռավոր համակարգի մասին: (լռելյայն ԱՌԱՋԱԴՐԱՆՔ [Փաստերի հավաքում]), որից հետո այն կարճ հաշվետվություն կտա կատարման մասին (PLAY RECAP):

Լռելյայնորեն, կապն օգտագործում է օգտվողի անունը, որով դուք մուտք եք գործել համակարգ: Այն, ամենայն հավանականությամբ, չի լինի հաղորդավարի վրա: Playbook ֆայլում կարող եք նշել, թե որ օգտվողին միանալու համար օգտագործելով remote_user հրահանգը: Բացի այդ, հեռավոր համակարգի մասին տեղեկատվությունը հաճախ կարող է ձեզ համար անհարկի լինել, և դուք չպետք է ժամանակ վատնեք դրանք հավաքելու համար: Այս առաջադրանքը կարող է նաև անջատվել.

---
- name: Simple playbook
  hosts: all
  remote_user: root
  become: true
  gather_facts: no

Փորձեք նորից գործարկել խաղագիրքը և համոզվեք, որ կապն աշխատում է: (Եթե դուք նշել եք արմատային օգտվողին, ապա դուք նույնպես պետք է նշեք դառնալ: ճշմարիտ հրահանգը բարձրացված իրավունքներ ձեռք բերելու համար: Ինչպես գրված է փաստաթղթերում. become set to ‘true’/’yes’ to activate privilege escalation. թեև լիովին պարզ չէ, թե ինչու):

Միգուցե դուք ստանաք սխալ, որը պայմանավորված է նրանով, որ ansible-ը չի կարող որոշել Python թարգմանիչը, ապա կարող եք ձեռքով նշել այն.

ansible_python_interpreter: /usr/bin/python3 

Դուք կարող եք պարզել, թե որտեղ ունեք python հրամանով whereis python.

Համակարգային փաթեթների տեղադրում

Ansible-ի ստանդարտ բաշխումը ներառում է բազմաթիվ մոդուլներ համակարգային տարբեր փաթեթների հետ աշխատելու համար, այնպես որ մենք ստիպված չենք լինի որևէ պատճառով գրել bash սցենարներ: Այժմ մեզ անհրաժեշտ է այս մոդուլներից մեկը՝ համակարգը թարմացնելու և համակարգի փաթեթները տեղադրելու համար: Ես ունեմ Ubuntu Linux իմ VPS-ում, ուստի փաթեթներ տեղադրելու համար ես օգտագործում եմ apt-get и մոդուլ դրա համար. Եթե ​​դուք օգտագործում եք այլ օպերացիոն համակարգ, ապա ձեզ կարող է անհրաժեշտ լինել այլ մոդուլ (հիշեք, ես սկզբում ասացի, որ մենք պետք է նախապես իմանանք, թե ինչ և ինչպես ենք անելու): Այնուամենայնիվ, շարահյուսությունը, ամենայն հավանականությամբ, նման կլինի:

Եկեք լրացնենք մեր խաղագիրքը առաջին առաջադրանքներով.

---
- name: Simple playbook
  hosts: all
  remote_user: root
  become: true
  gather_facts: no

  tasks:
    - name: Update system
      apt: update_cache=yes
    - name: Install system dependencies
      apt:
        name: git,nginx,redis,postgresql,postgresql-contrib
        state: present

Առաջադրանքը հենց այն խնդիրն է, որը Ansible-ը կկատարի հեռավոր սերվերների վրա: Մենք առաջադրանքին տալիս ենք անուն, որպեսզի կարողանանք հետևել դրա կատարմանը գրանցամատյանում: Եվ մենք նկարագրում ենք, օգտագործելով կոնկրետ մոդուլի շարահյուսությունը, թե ինչ պետք է անի: Այս դեպքում apt: update_cache=yes - ասում է թարմացնել համակարգի փաթեթները՝ օգտագործելով apt մոդուլը: Երկրորդ հրամանը մի փոքր ավելի բարդ է: Մենք փաթեթների ցուցակ ենք փոխանցում apt մոդուլին և ասում, որ դրանք այդպես են state պետք է դառնա present, այսինքն՝ ասում ենք տեղադրել այս փաթեթները։ Նմանապես, մենք կարող ենք նրանց ասել, որ ջնջեն դրանք կամ թարմացնեն դրանք՝ պարզապես փոխելով state. Խնդրում ենք նկատի ունենալ, որ ռելսերը postgresql-ի հետ աշխատելու համար մեզ անհրաժեշտ է postgresql-contrib փաթեթը, որը մենք հիմա տեղադրում ենք: Կրկին, դուք պետք է իմանաք և անեք դա, խելամիտը ինքնուրույն չի անի դա:

Փորձեք նորից գործարկել խաղագիրքը և ստուգեք, որ փաթեթները տեղադրված են:

Նոր օգտվողների ստեղծում:

Օգտատերերի հետ աշխատելու համար Ansible-ն ունի նաև մոդուլ՝ օգտատեր։ Ավելացնենք ևս մեկ առաջադրանք (ես մեկնաբանությունների հետևում թաքցրել եմ գրքույկի արդեն հայտնի հատվածները, որպեսզի ամեն անգամ ամբողջությամբ չպատճենեմ այն).

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Add a new user
      user:
        name: my_user
        shell: /bin/bash
        password: "{{ 123qweasd | password_hash('sha512') }}"

Մենք ստեղծում ենք նոր օգտատեր, դրա համար սահմանում ենք շելլ և գաղտնաբառ։ Եվ հետո մենք բախվում ենք մի քանի խնդիրների. Ինչ անել, եթե օգտվողի անունները պետք է տարբեր լինեն տարբեր հոստերի համար: Իսկ գաղտնաբառը գրքում մաքուր տեքստով պահելը շատ վատ գաղափար է: Սկսենք, եկեք օգտագործողի անունը և գաղտնաբառը դնենք փոփոխականների մեջ, և մինչև հոդվածի վերջում ես ցույց կտամ, թե ինչպես կարելի է ծածկագրել գաղտնաբառը:

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"

Փոփոխականները տեղադրվում են խաղային գրքերում, օգտագործելով կրկնակի գանգուր փակագծեր:

Մենք նշում ենք փոփոխականների արժեքները գույքագրման ֆայլում.

123.123.123.123

[all:vars]
user=my_user
user_password=123qweasd

Խնդրում ենք նկատի ունենալ հրահանգը [all:vars] - ասում է, որ տեքստի հաջորդ բլոկը փոփոխականներն են (vars) և դրանք կիրառելի են բոլոր հոսթների համար (բոլորը):

Դիզայնը նույնպես հետաքրքիր է "{{ user_password | password_hash('sha512') }}". Բանն այն է, որ ansible-ը չի տեղադրում օգտվողին միջոցով user_add ինչպես դուք դա կանեիք ձեռքով: Եվ այն ուղղակիորեն պահպանում է բոլոր տվյալները, այդ իսկ պատճառով մենք պետք է նաև նախապես գաղտնաբառը վերածենք հեշի, ինչն էլ անում է այս հրամանը:

Եկեք մեր օգտվողին ավելացնենք sudo խմբին: Այնուամենայնիվ, մինչ այս մենք պետք է համոզվենք, որ նման խումբ գոյություն ունի, քանի որ ոչ ոք դա չի անի մեզ համար.

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Ensure a 'sudo' group
      group:
        name: sudo
        state: present
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"
        groups: "sudo"

Ամեն ինչ բավականին պարզ է, մենք ունենք նաև խմբեր ստեղծելու խմբակային մոդուլ՝ շարահյուսությամբ, որը շատ նման է apt-ին։ Այնուհետև բավական է գրանցել այս խումբը օգտվողին (groups: "sudo").
Օգտակար է նաև այս օգտվողին ավելացնել ssh բանալի, որպեսզի մենք կարողանանք մուտք գործել՝ օգտագործելով այն առանց գաղտնաբառի.

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Ensure a 'sudo' group
      group:
      name: sudo
        state: present
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"
        groups: "sudo"
    - name: Deploy SSH Key
      authorized_key:
        user: "{{ user }}"
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
        state: present

Այս դեպքում դիզայնը հետաքրքիր է "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" — այն պատճենում է id_rsa.pub ֆայլի բովանդակությունը (ձեր անունը կարող է տարբեր լինել), այսինքն՝ ssh բանալիի հանրային մասը և այն վերբեռնում է սերվերի օգտատիրոջ համար լիազորված բանալիների ցանկում։

Դերը

Օգտագործման ստեղծման բոլոր երեք առաջադրանքները հեշտությամբ կարելի է դասակարգել մեկ աշխատանքային խմբի մեջ, և լավ գաղափար կլինի այս խումբը պահել հիմնական գրքույկից առանձին, որպեսզի այն շատ չմեծանա: Այդ նպատակով Ansible-ն ունի դերերը.
Ըստ սկզբում նշված ֆայլի կառուցվածքի՝ դերերը պետք է տեղադրվեն առանձին դերերի գրացուցակում, յուրաքանչյուր դերի համար կա նույն անունով առանձին գրացուցակ՝ առաջադրանքների, ֆայլերի, ձևանմուշների և այլն գրացուցակի ներսում։
Եկեք ստեղծենք ֆայլի կառուցվածք. ./ansible/roles/user/tasks/main.yml (հիմնականը հիմնական ֆայլն է, որը կբեռնվի և կկատարվի, երբ դերը միացված է խաղատախտակին, այլ դերային ֆայլեր կարող են միացվել դրան): Այժմ դուք կարող եք օգտատիրոջ հետ կապված բոլոր առաջադրանքները փոխանցել այս ֆայլին՝

# Create user and add him to groups
- name: Ensure a 'sudo' group
  group:
    name: sudo
    state: present

- name: Add a new user
  user:
    name: "{{ user }}"
    shell: /bin/bash
    password: "{{ user_password | password_hash('sha512') }}"
    groups: "sudo"

- name: Deploy SSH Key
  authorized_key:
    user: "{{ user }}"
    key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
    state: present

Հիմնական խաղագրքում դուք պետք է նշեք օգտվողի դերն օգտագործելու համար.

---
- name: Simple playbook
  hosts: all
  remote_user: root
  gather_facts: no

  tasks:
    - name: Update system
      apt: update_cache=yes
    - name: Install system dependencies
      apt:
        name: git,nginx,redis,postgresql,postgresql-contrib
        state: present

  roles:
    - user

Բացի այդ, կարող է իմաստ ունենալ թարմացնել համակարգը բոլոր մյուս առաջադրանքներից առաջ, դա անելու համար կարող եք վերանվանել բլոկը tasks որոնցում դրանք սահմանվում են pre_tasks.

Nginx-ի կարգավորում

Մենք պետք է արդեն տեղադրված ունենանք Nginx-ը, մենք պետք է կարգավորենք այն և գործարկենք այն: Եկեք դա անենք անմիջապես դերում: Եկեք ստեղծենք ֆայլի կառուցվածք.

- ansible
  - roles
    - nginx
      - files
      - tasks
        - main.yml
      - templates

Այժմ մեզ անհրաժեշտ են ֆայլեր և ձևանմուշներ: Նրանց միջև տարբերությունն այն է, որ ansible-ը ուղղակիորեն պատճենում է ֆայլերը, ինչպես կա: Եվ կաղապարները պետք է ունենան j2 ընդլայնում, և նրանք կարող են օգտագործել փոփոխական արժեքներ՝ օգտագործելով նույն կրկնակի գանգուր փակագծերը:

Եկեք միացնենք nginx-ը main.yml ֆայլ. Դրա համար մենք ունենք համակարգային մոդուլ.

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

Այստեղ մենք ոչ միայն ասում ենք, որ nginx-ը պետք է գործարկվի (այսինքն՝ մենք գործարկում ենք), այլ անմիջապես ասում ենք, որ այն պետք է միացված լինի։
Այժմ եկեք պատճենենք կազմաձևման ֆայլերը.

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

- name: Copy the nginx.conf
  copy:
    src: nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: yes

- name: Copy template my_app.conf
  template:
    src: my_app_conf.j2
    dest: /etc/nginx/sites-available/my_app.conf
    owner: root
    group: root
    mode: '0644'

Մենք ստեղծում ենք հիմնական nginx կազմաձևման ֆայլը (կարող եք այն վերցնել անմիջապես սերվերից կամ գրել ինքներդ): Եվ նաև մեր հավելվածի կազմաձևման ֆայլը sites_available գրացուցակում (սա անհրաժեշտ չէ, բայց օգտակար): Առաջին դեպքում մենք օգտագործում ենք պատճենման մոդուլը ֆայլերը պատճենելու համար (ֆայլը պետք է լինի /ansible/roles/nginx/files/nginx.conf) Երկրորդում մենք պատճենում ենք ձևանմուշը՝ փոխարինելով փոփոխականների արժեքները։ Կաղապարը պետք է լինի /ansible/roles/nginx/templates/my_app.j2) Եվ դա կարող է նման բան թվալ.

upstream {{ app_name }} {
  server unix:{{ app_path }}/shared/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name {{ server_name }} {{ inventory_hostname }};
  root {{ app_path }}/current/public;

  try_files $uri/index.html $uri.html $uri @{{ app_name }};
  ....
}

Ուշադրություն դարձրեք ներդիրներին {{ app_name }}, {{ app_path }}, {{ server_name }}, {{ inventory_hostname }} — սրանք բոլոր այն փոփոխականներն են, որոնց արժեքները Ansible-ը կփոխարինի ձևանմուշում նախքան պատճենելը: Սա օգտակար է, եթե դուք օգտագործում եք խաղագիրք հյուրընկալողների տարբեր խմբերի համար: Օրինակ, մենք կարող ենք ավելացնել մեր գույքագրման ֆայլը.

[production]
123.123.123.123

[staging]
231.231.231.231

[all:vars]
user=my_user
user_password=123qweasd

[production:vars]
server_name=production
app_path=/home/www/my_app
app_name=my_app

[staging:vars]
server_name=staging
app_path=/home/www/my_stage
app_name=my_stage_app

Եթե ​​մենք հիմա գործարկենք մեր խաղագիրքը, այն կկատարի նշված առաջադրանքները երկու հյուրընկալողների համար: Բայց միևնույն ժամանակ, բեմադրող հաղորդավարի համար փոփոխականները տարբեր կլինեն արտադրականներից և ոչ միայն դերերով և խաղային գրքույկներով, այլ նաև nginx կոնֆիգուրացիաներով։ {{ inventory_hostname }} կարիք չկա նշել գույքագրման ֆայլում, սա հատուկ ansible փոփոխական և հյուրընկալողը, որի համար ներկայումս աշխատում է խաղագիրքը, պահվում է այնտեղ:
Եթե ​​ցանկանում եք ունենալ գույքագրման ֆայլ մի քանի հոստերի համար, բայց գործարկել միայն մեկ խմբի համար, դա կարելի է անել հետևյալ հրամանով.

ansible-playbook -i inventory ./playbook.yml -l "staging"

Մեկ այլ տարբերակ տարբեր խմբերի համար առանձին գույքագրման ֆայլեր ունենալն է: Կամ կարող եք համատեղել երկու մոտեցումները, եթե ունեք շատ տարբեր հյուրընկալողներ:

Եկեք վերադառնանք nginx-ի տեղադրմանը: Կազմաձևման ֆայլերը պատճենելուց հետո մենք պետք է ստեղծենք symlink sites_enabled-ում my_app.conf-ին sites_available-ից: Եվ վերագործարկեք nginx-ը:

... # old code in mail.yml

- name: Create symlink to sites-enabled
  file:
    src: /etc/nginx/sites-available/my_app.conf
    dest: /etc/nginx/sites-enabled/my_app.conf
    state: link

- name: restart nginx
  service:
    name: nginx
    state: restarted

Այստեղ ամեն ինչ պարզ է. դարձյալ պարզ մոդուլներ՝ բավականին ստանդարտ շարահյուսությամբ: Բայց կա մի կետ. Ամեն անգամ nginx-ը վերագործարկելու իմաստ չկա: Նկատե՞լ եք, որ մենք չենք գրում այնպիսի հրամաններ, ինչպիսիք են. «արա սա այսպես», շարահյուսությունն ավելի շատ նման է «սա պետք է ունենա այս վիճակը»: Եվ ամենից հաճախ հենց այդպես է աշխատում ansible-ը: Եթե ​​խումբն արդեն գոյություն ունի, կամ համակարգի փաթեթն արդեն տեղադրված է, ապա ansible-ը կստուգի դա և բաց կթողնի առաջադրանքը: Բացի այդ, ֆայլերը չեն պատճենվի, եթե դրանք ամբողջությամբ համընկնեն այն, ինչ արդեն սերվերում է: Մենք կարող ենք օգտվել դրանից և վերագործարկել nginx-ը միայն այն դեպքում, եթե կազմաձևման ֆայլերը փոխված են: Դրա համար կա ռեգիստրի հրահանգ.

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

- name: Copy the nginx.conf
  copy:
    src: nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: yes
  register: restart_nginx

- name: Copy template my_app.conf
  template:
    src: my_app_conf.j2
    dest: /etc/nginx/sites-available/my_app.conf
    owner: root
    group: root
    mode: '0644'
  register: restart_nginx

- name: Create symlink to sites-enabled
  file:
    src: /etc/nginx/sites-available/my_app.conf
    dest: /etc/nginx/sites-enabled/my_app.conf
    state: link

- name: restart nginx
  service:
    name: nginx
    state: restarted
  when: restart_nginx.changed

Եթե ​​կազմաձևման ֆայլերից մեկը փոխվի, պատճենը կկատարվի և փոփոխականը կգրանցվի restart_nginx. Եվ միայն եթե այս փոփոխականը գրանցված է, ծառայությունը կվերագործարկվի:

Եվ, իհարկե, դուք պետք է ավելացնեք nginx դերը հիմնական գրքույկում:

Postgresql-ի կարգավորում

Մենք պետք է միացնենք postgresql-ն՝ օգտագործելով systemd-ը նույն կերպ, ինչպես արեցինք nginx-ի դեպքում, ինչպես նաև ստեղծենք օգտատեր, որը մենք կօգտագործենք տվյալների բազա և հենց տվյալների բազա մուտք գործելու համար:
Եկեք դեր ստեղծենք /ansible/roles/postgresql/tasks/main.yml:

# Create user in postgresql
- name: enable postgresql and start
  systemd:
    name: postgresql
    state: started
    enabled: yes

- name: Create database user
  become_user: postgres
  postgresql_user:
    name: "{{ db_user }}"
    password: "{{ db_password }}"
    role_attr_flags: SUPERUSER

- name: Create database
  become_user: postgres
  postgresql_db:
    name: "{{ db_name }}"
    encoding: UTF-8
    owner: "{{ db_user }}"

Ես չեմ նկարագրի, թե ինչպես ավելացնել փոփոխականներ գույքագրում, դա արդեն բազմիցս արվել է, ինչպես նաև postgresql_db և postgresql_user մոդուլների շարահյուսությունը: Լրացուցիչ տեղեկություններ կարելի է գտնել փաստաթղթերում: Այստեղ ամենահետաքրքիր հրահանգն է become_user: postgres. Փաստն այն է, որ լռելյայնորեն միայն postgres օգտագործողն ունի մուտք դեպի postgresql տվյալների բազա և միայն տեղական: Այս հրահանգը թույլ է տալիս մեզ հրամաններ կատարել այս օգտվողի անունից (եթե մենք, իհարկե, մուտք ունենք):
Բացի այդ, գուցե ստիպված լինեք տող ավելացնել pg_hba.conf-ին, որպեսզի թույլատրեք նոր օգտվողին մուտք գործել տվյալների բազա: Սա կարելի է անել այնպես, ինչպես մենք փոխեցինք nginx կոնֆիգուրը:

Եվ, իհարկե, դուք պետք է ավելացնեք postgresql դերը հիմնական խաղատախտակի մեջ:

Ruby-ի տեղադրում rbenv-ի միջոցով

Ansible-ը չունի rbenv-ի հետ աշխատելու մոդուլներ, սակայն այն տեղադրվում է git պահեստի կլոնավորմամբ։ Հետեւաբար, այս խնդիրը դառնում է ամենաոչ ստանդարտը։ Եկեք նրա համար դեր ստեղծենք /ansible/roles/ruby_rbenv/main.yml և եկեք սկսենք լրացնել այն.

# Install rbenv and ruby
- name: Install rbenv
  become_user: "{{ user }}"
  git: repo=https://github.com/rbenv/rbenv.git dest=~/.rbenv

Մենք կրկին օգտագործում ենք be_user հրահանգը՝ այս նպատակների համար մեր ստեղծած օգտատիրոջ ներքո աշխատելու համար: Քանի որ rbenv-ը տեղադրված է իր հիմնական գրացուցակում, և ոչ թե գլոբալ: Եվ մենք նաև օգտագործում ենք git մոդուլը պահեստը կլոնավորելու համար՝ նշելով repo-ն և dest-ը:

Հաջորդը, մենք պետք է գրանցենք rbenv init-ը bashrc-ում և այնտեղ ավելացնենք rbenv PATH-ին: Դրա համար մենք ունենք lineinfile մոդուլը.

- name: Add rbenv to PATH
  become_user: "{{ user }}"
  lineinfile:
    path: ~/.bashrc
    state: present
    line: 'export PATH="${HOME}/.rbenv/bin:${PATH}"'

- name: Add rbenv init to bashrc
  become_user: "{{ user }}"
  lineinfile:
    path: ~/.bashrc
    state: present
    line: 'eval "$(rbenv init -)"'

Ապա դուք պետք է տեղադրել ruby_build:

- name: Install ruby-build
  become_user: "{{ user }}"
  git: repo=https://github.com/rbenv/ruby-build.git dest=~/.rbenv/plugins/ruby-build

Եվ վերջապես տեղադրել ruby: Սա արվում է rbenv-ի միջոցով, այսինքն՝ պարզապես bash հրամանով.

- name: Install ruby
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    rbenv install {{ ruby_version }}
  args:
    executable: /bin/bash

Մենք ասում ենք, թե որ հրամանը կատարել և ինչով։ Այնուամենայնիվ, այստեղ մենք բախվում ենք այն փաստի, որ ansible-ը չի գործարկում bashrc-ում պարունակվող կոդը հրամանները գործարկելուց առաջ։ Սա նշանակում է, որ rbenv-ը պետք է ուղղակիորեն սահմանվի նույն սցենարով:

Հաջորդ խնդիրը պայմանավորված է նրանով, որ shell-ի հրամանը հասկանալի տեսանկյունից չունի վիճակ։ Այսինքն՝ ավտոմատ ստուգում չի լինի՝ արդյոք ruby-ի այս տարբերակը տեղադրված է, թե ոչ։ Մենք ինքներս կարող ենք դա անել.

- name: Install ruby
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    if ! rbenv versions | grep -q {{ ruby_version }}
      then rbenv install {{ ruby_version }} && rbenv global {{ ruby_version }}
    fi
  args:
    executable: /bin/bash

Մնում է միայն տեղադրել փաթեթը.

- name: Install bundler
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    gem install bundler

Եվ կրկին ավելացրեք մեր ruby_rbenv դերը հիմնական խաղագրքին:

Համօգտագործվող ֆայլեր:

Ընդհանուր առմամբ, կարգավորումը կարող է ավարտվել այստեղ: Հաջորդը, մնում է միայն գործարկել capistrano-ն, և այն ինքնին պատճենելու է կոդը, կստեղծի անհրաժեշտ դիրեկտորիաները և կգործարկի հավելվածը (եթե ամեն ինչ ճիշտ է կազմաձևված): Այնուամենայնիվ, capistrano-ն հաճախ պահանջում է լրացուցիչ կազմաձևման ֆայլեր, ինչպիսիք են database.yml կամ .env Նրանք կարող են պատճենվել այնպես, ինչպես nginx-ի ֆայլերն ու կաղապարները: Միայն մեկ նրբություն կա. Նախքան ֆայլերը պատճենելը, դուք պետք է ստեղծեք գրացուցակի կառուցվածք նրանց համար, նման բան.

# Copy shared files for deploy
- name: Ensure shared dir
  become_user: "{{ user }}"
  file:
    path: "{{ app_path }}/shared/config"
    state: directory

մենք նշում ենք միայն մեկ գրացուցակ և անհրաժեշտության դեպքում ansible-ն ավտոմատ կերպով կստեղծի մայր գրացուցակները:

Ansible Vault

Մենք արդեն հանդիպել ենք այն փաստի հետ, որ փոփոխականները կարող են պարունակել գաղտնի տվյալներ, ինչպիսիք են օգտագործողի գաղտնաբառը: Եթե ​​դուք ստեղծել եք .env ֆայլ դիմումի համար, և database.yml ապա պետք է ավելի շատ լինեն նման կրիտիկական տվյալներ։ Լավ կլինի դրանք թաքցնել հետաքրքրասեր աչքերից։ Այդ նպատակով այն օգտագործվում է անշարժ պահոց.

Եկեք ստեղծենք ֆայլ փոփոխականների համար /ansible/vars/all.yml (այստեղ կարող եք տարբեր ֆայլեր ստեղծել հոսթների տարբեր խմբերի համար, ինչպես գույքագրման ֆայլում՝ production.yml, staging.yml և այլն):
Բոլոր փոփոխականները, որոնք պետք է կոդավորված լինեն, պետք է փոխանցվեն այս ֆայլին՝ օգտագործելով ստանդարտ yml շարահյուսություն.

# System vars
user_password: 123qweasd
db_password: 123qweasd

# ENV vars
aws_access_key_id: xxxxx
aws_secret_access_key: xxxxxx
aws_bucket: bucket_name
rails_secret_key_base: very_secret_key_base

Դրանից հետո այս ֆայլը կարող է գաղտնագրվել հրամանով.

ansible-vault encrypt ./vars/all.yml

Բնականաբար, գաղտնագրման ժամանակ անհրաժեշտ կլինի գաղտնաբառ սահմանել ապակոդավորման համար։ Այս հրամանը կանչելուց հետո կարող եք տեսնել, թե ինչ կլինի ֆայլի ներսում:

Միջոցով ansible-vault decrypt ֆայլը կարող է վերծանվել, փոփոխվել և այնուհետև նորից գաղտնագրվել:

Աշխատելու համար ֆայլը վերծանելու կարիք չկա: Դուք պահում եք այն կոդավորված և գործարկում եք խաղագիրքը փաստարկով --ask-vault-pass. Ansible-ը կխնդրի գաղտնաբառը, առբերի փոփոխականները և կկատարի առաջադրանքները: Բոլոր տվյալները կմնան կոդավորված:

Ամբողջական հրամանը մի քանի խմբերի հոսթինգների և անսիրալ պահոցի համար այսպիսի տեսք կունենա.

ansible-playbook -i inventory ./playbook.yml -l "staging" --ask-vault-pass

Բայց ես ձեզ չեմ տա խաղային գրքերի և դերերի ամբողջական տեքստը, գրեք ինքներդ: Որովհետև ansible-ն այդպիսին է. եթե դուք չեք հասկանում, թե ինչ է պետք անել, ապա դա ձեզ չի անի:

Source: www.habr.com

Добавить комментарий