Ansible का उपयोग करके रेल एप्लिकेशन को तैनात करने के लिए एक सर्वर सेट करना

कुछ समय पहले मुझे रेल एप्लिकेशन को तैनात करने के लिए सर्वर तैयार करने के लिए कई अन्सिबल प्लेबुक लिखने की आवश्यकता थी। और, आश्चर्य की बात है, मुझे कोई सरल चरण-दर-चरण मैनुअल नहीं मिला। मैं यह समझे बिना कि क्या हो रहा है, किसी और की प्लेबुक की नकल नहीं करना चाहता था और अंत में मुझे खुद ही सब कुछ इकट्ठा करके दस्तावेज पढ़ना पड़ा। शायद मैं इस लेख की मदद से इस प्रक्रिया को तेज़ करने में किसी की मदद कर सकूं।

समझने वाली पहली बात यह है कि ansible आपको SSH के माध्यम से दूरस्थ सर्वर पर क्रियाओं की पूर्वनिर्धारित सूची निष्पादित करने के लिए एक सुविधाजनक इंटरफ़ेस प्रदान करता है। यहां कोई जादू नहीं है, आप एक प्लगइन स्थापित नहीं कर सकते हैं और बॉक्स से बाहर डॉकर, मॉनिटरिंग और अन्य उपहारों के साथ अपने एप्लिकेशन की शून्य डाउनटाइम तैनाती प्राप्त कर सकते हैं। प्लेबुक लिखने के लिए, आपको पता होना चाहिए कि आप वास्तव में क्या करना चाहते हैं और इसे कैसे करना है। इसीलिए मैं GitHub की तैयार प्लेबुक या "कॉपी करो और चलाओ, यह काम करेगा" जैसे लेखों से संतुष्ट नहीं हूँ।

हमारी जरूरतें क्या हैं?

जैसा कि मैंने पहले ही कहा, एक प्लेबुक लिखने के लिए आपको यह जानना होगा कि आप क्या करना चाहते हैं और इसे कैसे करना है। आइए तय करें कि हमें क्या चाहिए. रेल एप्लिकेशन के लिए हमें कई सिस्टम पैकेजों की आवश्यकता होगी: nginx, postgresql (redis, आदि)। इसके अलावा, हमें रूबी के एक विशिष्ट संस्करण की आवश्यकता है। इसे rbenv (rvm, asdf...) के माध्यम से स्थापित करना सबसे अच्छा है। रूट उपयोगकर्ता के रूप में यह सब चलाना हमेशा एक बुरा विचार है, इसलिए आपको एक अलग उपयोगकर्ता बनाने और उसके अधिकारों को कॉन्फ़िगर करने की आवश्यकता है। इसके बाद, आपको हमारा कोड सर्वर पर अपलोड करना होगा, nginx, postgres आदि के लिए कॉन्फिगरेशन को कॉपी करना होगा और इन सभी सेवाओं को शुरू करना होगा।

परिणामस्वरूप, क्रियाओं का क्रम इस प्रकार है:

  1. रूट के रूप में लॉगिन करें
  2. सिस्टम पैकेज स्थापित करें
  3. एक नया उपयोगकर्ता बनाएं, अधिकार कॉन्फ़िगर करें, ssh कुंजी
  4. सिस्टम पैकेज (nginx आदि) कॉन्फ़िगर करें और उन्हें चलाएँ
  5. हम डेटाबेस में एक उपयोगकर्ता बनाते हैं (आप तुरंत एक डेटाबेस बना सकते हैं)
  6. नए उपयोगकर्ता के रूप में लॉगिन करें
  7. आरबेनव और रूबी स्थापित करें
  8. बंडलर स्थापित करना
  9. एप्लिकेशन कोड अपलोड हो रहा है
  10. प्यूमा सर्वर लॉन्च करना

इसके अलावा, अंतिम चरण कैपिस्ट्रानो का उपयोग करके किया जा सकता है, कम से कम बॉक्स से बाहर यह कोड को रिलीज निर्देशिकाओं में कॉपी कर सकता है, सफल तैनाती पर एक सिम्लिंक के साथ रिलीज को स्विच कर सकता है, एक साझा निर्देशिका से कॉन्फ़िगरेशन कॉपी कर सकता है, प्यूमा को पुनरारंभ कर सकता है, आदि। यह सब Ansible का उपयोग करके किया जा सकता है, लेकिन क्यों?

फ़ाइल संरचना

अन्सिबल ने सख्त किया है फ़ाइल संरचना आपकी सभी फ़ाइलों के लिए, इसलिए इन सभी को एक अलग निर्देशिका में रखना सबसे अच्छा है। इसके अलावा, यह इतना महत्वपूर्ण नहीं है कि यह रेल एप्लिकेशन में ही होगा या अलग से। आप फ़ाइलों को एक अलग git रिपॉजिटरी में संग्रहीत कर सकते हैं। व्यक्तिगत रूप से, मुझे रेल एप्लिकेशन की /कॉन्फिग डायरेक्टरी में एक एन्सिबल डायरेक्टरी बनाना और सब कुछ एक रिपॉजिटरी में स्टोर करना सबसे सुविधाजनक लगा।

सरल प्लेबुक

प्लेबुक एक yml फ़ाइल है, जो विशेष सिंटैक्स का उपयोग करके बताती है कि Ansible को क्या और कैसे करना चाहिए। आइए पहली प्लेबुक बनाएं जो कुछ नहीं करती:

---
- name: Simple playbook
  hosts: all

यहां हम बस यह कहते हैं कि हमारी प्लेबुक कहलाती है Simple Playbook और इसकी सामग्री सभी होस्टों के लिए निष्पादित की जानी चाहिए। हम इसे /ansible डायरेक्टरी में नाम से सेव कर सकते हैं playbook.yml और चलाने का प्रयास करें:

ansible-playbook ./playbook.yml

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

एन्सिबल का कहना है कि वह सभी सूची से मेल खाने वाले किसी भी होस्ट को नहीं जानता है। उन्हें एक विशेष में सूचीबद्ध किया जाना चाहिए इन्वेंट्री फ़ाइल.

आइए इसे उसी ansible निर्देशिका में बनाएं:

123.123.123.123

इस प्रकार हम बस होस्ट निर्दिष्ट करते हैं (आदर्श रूप से परीक्षण के लिए हमारे वीपीएस का होस्ट, या आप लोकलहोस्ट पंजीकृत कर सकते हैं) और इसे नाम के तहत सहेज सकते हैं inventory.
आप इन्वेट्री फ़ाइल के साथ ansible चलाने का प्रयास कर सकते हैं:

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

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

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

यदि आपके पास निर्दिष्ट होस्ट तक एसएसएच पहुंच है, तो एन्सिबल कनेक्ट होगा और रिमोट सिस्टम के बारे में जानकारी एकत्र करेगा। (डिफ़ॉल्ट कार्य [तथ्य एकत्र करना]) जिसके बाद यह निष्पादन पर एक संक्षिप्त रिपोर्ट देगा (प्ले रीकैप)।

डिफ़ॉल्ट रूप से, कनेक्शन उस उपयोगकर्ता नाम का उपयोग करता है जिसके तहत आप सिस्टम में लॉग इन हैं। यह संभवतः मेज़बान पर नहीं होगा. प्लेबुक फ़ाइल में, आप निर्दिष्ट कर सकते हैं कि रिमोट_यूज़र निर्देश का उपयोग करके कनेक्ट करने के लिए किस उपयोगकर्ता का उपयोग करना है। साथ ही, रिमोट सिस्टम के बारे में जानकारी अक्सर आपके लिए अनावश्यक हो सकती है और आपको इसे इकट्ठा करने में समय बर्बाद नहीं करना चाहिए। यह कार्य अक्षम भी किया जा सकता है:

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

प्लेबुक को दोबारा चलाने का प्रयास करें और सुनिश्चित करें कि कनेक्शन काम कर रहा है। (यदि आपने रूट उपयोगकर्ता को निर्दिष्ट किया है, तो आपको उन्नत अधिकार प्राप्त करने के लिए बन: सत्य निर्देश को भी निर्दिष्ट करने की आवश्यकता है। जैसा कि दस्तावेज़ में लिखा गया है: become set to ‘true’/’yes’ to activate privilege escalation. हालाँकि यह पूरी तरह से स्पष्ट नहीं है कि क्यों)।

शायद आपको इस तथ्य के कारण एक त्रुटि प्राप्त होगी कि एन्सिबल पायथन दुभाषिया को निर्धारित नहीं कर सकता है, तो आप इसे मैन्युअल रूप से निर्दिष्ट कर सकते हैं:

ansible_python_interpreter: /usr/bin/python3 

आप कमांड से पता लगा सकते हैं कि आपके पास पाइथॉन कहां है whereis python.

सिस्टम पैकेज संस्थापित करना

Ansible के मानक वितरण में विभिन्न सिस्टम पैकेजों के साथ काम करने के लिए कई मॉड्यूल शामिल हैं, इसलिए हमें किसी भी कारण से बैश स्क्रिप्ट लिखने की ज़रूरत नहीं है। अब हमें सिस्टम को अद्यतन करने और सिस्टम पैकेज स्थापित करने के लिए इनमें से एक मॉड्यूल की आवश्यकता है। मेरे वीपीएस पर उबंटू लिनक्स है, इसलिए मैं पैकेज स्थापित करने के लिए इसका उपयोग करता हूं 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 - उपयुक्त मॉड्यूल का उपयोग करके सिस्टम पैकेज को अपडेट करने के लिए कहा गया है। दूसरा आदेश थोड़ा अधिक जटिल है. हम उपयुक्त मॉड्यूल में पैकेजों की एक सूची पास करते हैं और कहते हैं कि वे हैं state बन जाना चाहिए present, यानी हम कहते हैं कि इन पैकेजों को इंस्टॉल करें। इसी तरह, हम उन्हें उन्हें हटाने या बस बदलकर अपडेट करने के लिए कह सकते हैं state. कृपया ध्यान दें कि रेल के लिए पोस्टग्रेस्क्ल के साथ काम करने के लिए हमें पोस्टग्रेस्क्ल-कॉन्ट्रिब पैकेज की आवश्यकता है, जिसे हम अभी इंस्टॉल कर रहे हैं। फिर, आपको यह जानने और करने की आवश्यकता है; ansible अपने आप ऐसा नहीं करेगा।

प्लेबुक को दोबारा चलाने का प्रयास करें और जांचें कि पैकेज स्थापित हैं।

नए उपयोगकर्ता बनाना.

उपयोगकर्ताओं के साथ काम करने के लिए, 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"

सब कुछ काफी सरल है, हमारे पास समूह बनाने के लिए एक समूह मॉड्यूल भी है, जिसका सिंटैक्स एपीटी के समान है। फिर इस समूह को उपयोगकर्ता के लिए पंजीकृत करना पर्याप्त है (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 कॉन्फ़िगरेशन फ़ाइल बनाते हैं (आप इसे सीधे सर्वर से ले सकते हैं, या इसे स्वयं लिख सकते हैं)। और हमारे एप्लिकेशन के लिए साइट_उपलब्ध निर्देशिका में कॉन्फ़िगरेशन फ़ाइल भी (यह आवश्यक नहीं है लेकिन उपयोगी है)। पहले मामले में, हम फ़ाइलों की प्रतिलिपि बनाने के लिए कॉपी मॉड्यूल का उपयोग करते हैं (फ़ाइल अंदर होनी चाहिए)। /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-playbook -i inventory ./playbook.yml -l "staging"

एक अन्य विकल्प विभिन्न समूहों के लिए अलग-अलग इन्वेंट्री फ़ाइलें रखना है। या यदि आपके पास कई अलग-अलग होस्ट हैं तो आप दोनों दृष्टिकोणों को जोड़ सकते हैं।

आइए nginx की स्थापना पर वापस जाएं। कॉन्फ़िगरेशन फ़ाइलों की प्रतिलिपि बनाने के बाद, हमें साइट_उपलब्ध से my_app.conf में sitest_enabled में एक सिम्लिंक बनाने की आवश्यकता है। और 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 इसकी जाँच करेगा और कार्य को छोड़ देगा। साथ ही, यदि फ़ाइलें सर्वर पर पहले से मौजूद फ़ाइलों से पूरी तरह मेल खाती हैं तो उन्हें कॉपी नहीं किया जाएगा। हम इसका लाभ उठा सकते हैं और 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 भूमिका जोड़ने की आवश्यकता है।

पोस्टग्रेस्क्ल की स्थापना

हमें सिस्टमडी का उपयोग करके पोस्टग्रेस्क्ल को उसी तरह सक्षम करने की आवश्यकता है जैसे हमने 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. तथ्य यह है कि डिफ़ॉल्ट रूप से, केवल पोस्टग्रेज उपयोगकर्ता के पास ही पोस्टग्रैस्कल डेटाबेस तक पहुंच होती है और केवल स्थानीय रूप से। यह निर्देश हमें इस उपयोगकर्ता की ओर से कमांड निष्पादित करने की अनुमति देता है (यदि हमारे पास पहुंच है, तो निश्चित रूप से)।
साथ ही, नए उपयोगकर्ता को डेटाबेस तक पहुंच की अनुमति देने के लिए आपको pg_hba.conf में एक पंक्ति जोड़नी पड़ सकती है। यह उसी तरह किया जा सकता है जैसे हमने nginx कॉन्फिगरेशन को बदला था।

और निश्चित रूप से, आपको मुख्य प्लेबुक में पोस्टग्रेस्क्ल भूमिका जोड़ने की आवश्यकता है।

आरबीएनवी के माध्यम से रूबी स्थापित करना

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 अपने होम डायरेक्टरी में स्थापित है, वैश्विक स्तर पर नहीं। और हम रेपो और डेस्ट को निर्दिष्ट करते हुए रिपॉजिटरी को क्लोन करने के लिए गिट मॉड्यूल का भी उपयोग करते हैं।

इसके बाद, हमें bashrc में rbenv init को पंजीकृत करना होगा और वहां PATH में rbenv को जोड़ना होगा। इसके लिए हमारे पास लाइनइनफ़ाइल मॉड्यूल है:

- 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 -)"'

फिर आपको रूबी_बिल्ड इंस्टॉल करना होगा:

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

और अंत में रूबी स्थापित करें। यह rbenv के माध्यम से किया जाता है, अर्थात, केवल बैश कमांड के साथ:

- 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 को सीधे उसी स्क्रिप्ट में परिभाषित करना होगा।

अगली समस्या इस तथ्य के कारण है कि शेल कमांड की कोई स्थिति नहीं है। यानी कोई स्वचालित जांच नहीं होगी कि रूबी का यह संस्करण स्थापित है या नहीं। हम यह स्वयं कर सकते हैं:

- 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

और फिर, मुख्य प्लेबुक में हमारी भूमिका रूबी_आरबेनव जोड़ें।

फ़ाइलें साझा की गईं।

सामान्य तौर पर, सेटअप यहां पूरा किया जा सकता है। इसके बाद, जो कुछ बचा है वह कैपिस्ट्रानो को चलाना है और यह कोड को स्वयं कॉपी करेगा, आवश्यक निर्देशिकाएं बनाएगा और एप्लिकेशन लॉन्च करेगा (यदि सब कुछ सही ढंग से कॉन्फ़िगर किया गया है)। हालाँकि, कैपिस्ट्रानो को अक्सर अतिरिक्त कॉन्फ़िगरेशन फ़ाइलों की आवश्यकता होती है, जैसे 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 स्वचालित रूप से मूल निर्देशिका बनाएगा।

अन्सिबल वॉल्ट

हम पहले ही इस तथ्य से परिचित हो चुके हैं कि वेरिएबल्स में उपयोगकर्ता का पासवर्ड जैसा गुप्त डेटा हो सकता है। यदि आपने बनाया है .env आवेदन के लिए फ़ाइल, और database.yml तो फिर ऐसे और भी महत्वपूर्ण डेटा होने चाहिए। उन्हें चुभती नज़रों से छिपाना अच्छा होगा। इसी उद्देश्य से इसका प्रयोग किया जाता है उत्तरदायी तिजोरी.

आइए वेरिएबल्स के लिए एक फ़ाइल बनाएं /ansible/vars/all.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

लेकिन मैं आपको प्लेबुक और भूमिकाओं का पूरा पाठ नहीं दूंगा, इसे स्वयं लिखें। क्योंकि अन्सिबल ऐसा ही है - यदि आप नहीं समझते कि क्या करने की आवश्यकता है, तो यह आपके लिए यह नहीं करेगा।

स्रोत: www.habr.com

एक टिप्पणी जोड़ें