Ansible کا استعمال کرتے ہوئے ایک ریل ایپلیکیشن کو تعینات کرنے کے لیے سرور ترتیب دینا

کچھ عرصہ پہلے مجھے ریل ایپلیکیشن کی تعیناتی کے لیے سرور تیار کرنے کے لیے کئی جوابی پلے بکس لکھنے کی ضرورت تھی۔ اور حیرت کی بات یہ ہے کہ مجھے ایک آسان مرحلہ وار دستی نہیں ملا۔ میں یہ سمجھے بغیر کسی اور کی پلے بک کاپی نہیں کرنا چاہتا تھا کہ کیا ہو رہا ہے، اور آخر میں مجھے سب کچھ خود جمع کرتے ہوئے دستاویزات کو پڑھنا پڑا۔ شاید میں اس مضمون کی مدد سے اس عمل کو تیز کرنے میں کسی کی مدد کر سکتا ہوں۔

سمجھنے کی پہلی چیز یہ ہے کہ جوابی آپ کو ایک آسان انٹرفیس فراہم کرتا ہے تاکہ ایس ایس ایچ کے ذریعے ریموٹ سرور پر کارروائیوں کی پہلے سے طے شدہ فہرست کو انجام دے سکے۔ یہاں کوئی جادو نہیں ہے، آپ پلگ ان انسٹال نہیں کر سکتے اور ڈاکر، مانیٹرنگ اور دیگر سامان کے ساتھ اپنی ایپلیکیشن کی صفر ڈاؤن ٹائم تعیناتی حاصل نہیں کر سکتے۔ پلے بک لکھنے کے لیے، آپ کو معلوم ہونا چاہیے کہ آپ بالکل کیا کرنا چاہتے ہیں اور اسے کیسے کرنا ہے۔ یہی وجہ ہے کہ میں GitHub کی ریڈی میڈ پلے بکس، یا اس طرح کے مضامین سے مطمئن نہیں ہوں: "کاپی کریں اور چلائیں، یہ کام کرے گا۔"

ہمیں کیا ضرورت ہے؟

جیسا کہ میں نے پہلے ہی کہا ہے، ایک پلے بک لکھنے کے لیے آپ کو یہ جاننے کی ضرورت ہے کہ آپ کیا کرنا چاہتے ہیں اور اسے کیسے کرنا ہے۔ آئیے فیصلہ کریں کہ ہمیں کیا ضرورت ہے۔ ریل ایپلی کیشن کے لیے ہمیں کئی سسٹم پیکجز کی ضرورت ہوگی: nginx، postgresql (redis، وغیرہ)۔ اس کے علاوہ، ہمیں روبی کے ایک مخصوص ورژن کی ضرورت ہے۔ اسے rbenv (rvm, asdf...) کے ذریعے انسٹال کرنا بہتر ہے۔ روٹ یوزر کے طور پر یہ سب چلانا ہمیشہ برا خیال ہوتا ہے، اس لیے آپ کو ایک الگ صارف بنانے اور اس کے حقوق کو ترتیب دینے کی ضرورت ہے۔ اس کے بعد، آپ کو ہمارے کوڈ کو سرور پر اپ لوڈ کرنے، nginx، postgres وغیرہ کے لیے کنفیگرز کو کاپی کرنے اور ان تمام سروسز کو شروع کرنے کی ضرورت ہے۔

نتیجے کے طور پر، اعمال کی ترتیب مندرجہ ذیل ہے:

  1. جڑ کے طور پر لاگ ان کریں۔
  2. سسٹم پیکجز انسٹال کریں۔
  3. ایک نیا صارف بنائیں، حقوق ترتیب دیں، ssh کلید
  4. سسٹم پیکجز (nginx وغیرہ) کو ترتیب دیں اور انہیں چلائیں۔
  5. ہم ڈیٹا بیس میں صارف بناتے ہیں (آپ فوری طور پر ڈیٹا بیس بنا سکتے ہیں)
  6. ایک نئے صارف کے طور پر لاگ ان کریں۔
  7. rbenv اور ruby ​​انسٹال کریں۔
  8. بنڈلر انسٹال کرنا
  9. درخواست کوڈ اپ لوڈ کرنا
  10. پوما سرور لانچ کرنا

مزید برآں، آخری مراحل کیپسٹرانو کا استعمال کرتے ہوئے کیے جا سکتے ہیں، کم از کم باکس سے باہر یہ کوڈ کو ریلیز ڈائریکٹریز میں کاپی کر سکتا ہے، کامیاب تعیناتی پر ریلیز کو سملنک کے ساتھ تبدیل کر سکتا ہے، مشترکہ ڈائرکٹری سے کنفیگرز کاپی کر سکتا ہے، پوما کو دوبارہ شروع کر سکتا ہے، وغیرہ۔ یہ سب Ansible کا استعمال کرتے ہوئے کیا جا سکتا ہے، لیکن کیوں؟

فائل کا ڈھانچہ

جوابدہ سخت ہے فائل کی ساخت آپ کی تمام فائلوں کے لیے، لہذا یہ سب کو الگ ڈائرکٹری میں رکھنا بہتر ہے۔ اس کے علاوہ، یہ اتنا اہم نہیں ہے کہ آیا یہ ریلوں کی درخواست میں ہی ہوگا، یا الگ سے۔ آپ فائلوں کو الگ گٹ ریپوزٹری میں اسٹور کرسکتے ہیں۔ ذاتی طور پر، میں نے ریل ایپلی کیشن کی /config ڈائریکٹری میں ایک جوابدہ ڈائرکٹری بنانا اور ہر چیز کو ایک ذخیرہ میں محفوظ کرنا سب سے آسان پایا۔

سادہ پلے بک

پلے بک ایک yml فائل ہے جو خاص نحو کا استعمال کرتے ہوئے بیان کرتی ہے کہ Ansible کو کیا اور کیسے کرنا چاہیے۔ آئیے پہلی پلے بک بنائیں جو کچھ نہیں کرتی:

---
- name: Simple playbook
  hosts: all

یہاں ہم صرف یہ کہتے ہیں کہ ہماری پلے بک کہلاتی ہے۔ Simple Playbook اور یہ کہ اس کے مواد کو تمام میزبانوں کے لیے لاگو کیا جانا چاہیے۔ ہم اسے نام کے ساتھ /ansible ڈائریکٹری میں محفوظ کر سکتے ہیں۔ playbook.yml اور چلانے کی کوشش کریں:

ansible-playbook ./playbook.yml

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

جوابدہ کا کہنا ہے کہ وہ کسی ایسے میزبان کو نہیں جانتا جو تمام فہرست سے مماثل ہو۔ وہ ایک خاص میں درج ہونا ضروری ہے انوینٹری فائل.

آئیے اسے اسی جوابدہ ڈائریکٹری میں بنائیں:

123.123.123.123

اس طرح ہم صرف میزبان کی وضاحت کرتے ہیں (مثالی طور پر جانچ کے لیے ہمارے VPS کا میزبان، یا آپ لوکل ہوسٹ کو رجسٹر کر سکتے ہیں) اور اسے نام کے نیچے محفوظ کرتے ہیں۔ inventory.
آپ انویٹری فائل کے ساتھ جوابدہ چلانے کی کوشش کر سکتے ہیں:

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

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

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

اگر آپ کے پاس مخصوص میزبان تک ssh رسائی ہے، تو جوابی ریموٹ سسٹم کے بارے میں معلومات کو مربوط اور اکٹھا کرے گا۔ (پہلے سے طے شدہ ٹاسک [حقائق جمع کرنا]) جس کے بعد یہ عمل درآمد پر ایک مختصر رپورٹ دے گا (پلے ریکیپ)۔

پہلے سے طے شدہ طور پر، کنکشن صارف کا نام استعمال کرتا ہے جس کے تحت آپ سسٹم میں لاگ ان ہوتے ہیں۔ یہ زیادہ تر امکان ہے کہ میزبان پر نہیں ہوگا۔ پلے بک فائل میں، آپ remote_user ڈائرکٹیو کا استعمال کرتے ہوئے کنیکٹ کرنے کے لیے استعمال کرنے والے صارف کی وضاحت کر سکتے ہیں۔ نیز، ریموٹ سسٹم کے بارے میں معلومات اکثر آپ کے لیے غیر ضروری ہو سکتی ہیں اور آپ کو اسے جمع کرنے میں وقت ضائع نہیں کرنا چاہیے۔ اس کام کو بھی غیر فعال کیا جا سکتا ہے:

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

پلے بک کو دوبارہ چلانے کی کوشش کریں اور یقینی بنائیں کہ کنکشن کام کر رہا ہے۔ (اگر آپ نے روٹ صارف کی وضاحت کی ہے، تو پھر آپ کو بننا: حقیقی ہدایت نامہ بھی بتانا ہوگا تاکہ اعلیٰ حقوق حاصل ہوں۔ جیسا کہ دستاویزات میں لکھا گیا ہے: become set to ‘true’/’yes’ to activate privilege escalation. اگرچہ یہ مکمل طور پر واضح نہیں ہے کہ کیوں)۔

شاید آپ کو اس حقیقت کی وجہ سے ایک غلطی موصول ہوگی کہ جواب دینے والا Python ترجمان کا تعین نہیں کرسکتا، پھر آپ اسے دستی طور پر بتا سکتے ہیں:

ansible_python_interpreter: /usr/bin/python3 

آپ کمانڈ کے ساتھ یہ جان سکتے ہیں کہ آپ کے پاس python کہاں ہے۔ whereis python.

سسٹم پیکجز کی تنصیب

Ansible کی معیاری تقسیم میں مختلف سسٹم پیکجز کے ساتھ کام کرنے کے لیے بہت سے ماڈیولز شامل ہیں، اس لیے ہمیں کسی بھی وجہ سے bash اسکرپٹ لکھنے کی ضرورت نہیں ہے۔ اب ہمیں سسٹم کو اپ ڈیٹ کرنے اور سسٹم پیکجز کو انسٹال کرنے کے لیے ان میں سے ایک ماڈیول کی ضرورت ہے۔ میرے پاس اپنے VPS پر Ubuntu Linux ہے، لہذا میں جو پیکیج استعمال کرتا ہوں ان کو انسٹال کرنے کے لیے 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') }}". بات یہ ہے کہ جوابی صارف کے ذریعے انسٹال نہیں کرتا ہے۔ 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 (main وہ اہم فائل ہے جو اس وقت لوڈ اور عمل میں لائی جائے گی جب کوئی رول پلے بک سے منسلک ہوتا ہے؛ دیگر رول فائلوں کو اس سے منسلک کیا جا سکتا ہے)۔ اب آپ صارف سے متعلق تمام کام اس فائل میں منتقل کر سکتے ہیں۔

# 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

اب ہمیں فائلوں اور ٹیمپلیٹس کی ضرورت ہے۔ ان کے درمیان فرق یہ ہے کہ جوابدہ فائلوں کو براہ راست کاپی کرتا ہے، جیسا کہ ہے۔ اور ٹیمپلیٹس میں j2 ایکسٹینشن ہونا ضروری ہے اور وہ ایک ہی ڈبل گھوبگھرالی منحنی خطوط وحدانی کا استعمال کرتے ہوئے متغیر اقدار کا استعمال کر سکتے ہیں۔

آئیے nginx کو فعال کرتے ہیں۔ main.yml فائل اس کے لیے ہمارے پاس ایک systemd ماڈیول ہے:

# 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-playbook -i inventory ./playbook.yml -l "staging"

دوسرا آپشن یہ ہے کہ مختلف گروپس کے لیے الگ الگ انوینٹری فائلیں رکھیں۔ یا اگر آپ کے پاس بہت سے مختلف میزبان ہیں تو آپ دونوں طریقوں کو یکجا کر سکتے ہیں۔

آئیے nginx کو ترتیب دینے پر واپس جائیں۔ کنفیگریشن فائلوں کو کاپی کرنے کے بعد، ہمیں sites_available سے 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 کو دوبارہ شروع کرنے کا کوئی فائدہ نہیں ہے۔ کیا آپ نے دیکھا ہے کہ ہم اس طرح کے کمانڈ نہیں لکھتے ہیں: "یہ اس طرح کرو"، نحو زیادہ ایسا لگتا ہے کہ "اس کی یہ حالت ہونی چاہیے"۔ اور اکثر ایسا ہوتا ہے کہ جوابدہ کیسے کام کرتا ہے۔ اگر گروپ پہلے سے موجود ہے، یا سسٹم پیکج پہلے سے انسٹال ہے، تو جواب دینے والا اس کی جانچ کرے گا اور کام کو چھوڑ دے گا۔ نیز، فائلوں کو کاپی نہیں کیا جائے گا اگر وہ سرور پر پہلے سے موجود چیزوں سے پوری طرح مماثل ہوں۔ ہم اس سے فائدہ اٹھا سکتے ہیں اور 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 ترتیب دینا

ہمیں systemd کا استعمال کرتے ہوئے postgresql کو اسی طرح فعال کرنے کی ضرورت ہے جیسا کہ ہم نے 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 config کو تبدیل کیا ہے۔

اور ظاہر ہے، آپ کو مرکزی پلے بک میں postgresql رول شامل کرنے کی ضرورت ہے۔

روبی کو rbenv کے ذریعے انسٹال کرنا

Ansible میں rbenv کے ساتھ کام کرنے کے لیے ماڈیولز نہیں ہیں، لیکن یہ گٹ ریپوزٹری کو کلون کرکے انسٹال کیا جاتا ہے۔ لہذا، یہ مسئلہ سب سے زیادہ غیر معیاری بن جاتا ہے. آئیے اس کے لیے ایک کردار بنائیں /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

ہم ان مقاصد کے لیے بنائے گئے صارف کے تحت کام کرنے کے لیے ایک بار پھر become_user ہدایت کا استعمال کرتے ہیں۔ چونکہ rbenv اس کی ہوم ڈائرکٹری میں انسٹال ہے، اور عالمی سطح پر نہیں۔ اور ہم ریپو اور ڈیسٹ کی وضاحت کرتے ہوئے ریپوزٹری کو کلون کرنے کے لیے گٹ ماڈیول کا بھی استعمال کرتے ہیں۔

اگلا، ہمیں rbenv init کو bashrc میں رجسٹر کرنا ہوگا اور وہاں PATH میں rbenv شامل کرنا ہوگا۔ اس کے لیے ہمارے پاس 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

اور آخر میں روبی انسٹال کریں۔ یہ 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 کو اسی اسکرپٹ میں براہ راست بیان کرنا ہوگا۔

اگلا مسئلہ اس حقیقت کی وجہ سے ہے کہ شیل کمانڈ کی جوابی نقطہ نظر سے کوئی حالت نہیں ہے۔ یعنی روبی کا یہ ورژن انسٹال ہے یا نہیں اس کی کوئی خودکار جانچ نہیں ہوگی۔ ہم یہ خود کر سکتے ہیں:

- 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 کو اکثر اضافی کنفیگریشن فائلوں کی ضرورت ہوتی ہے، جیسے database.yml یا .env انہیں nginx کے لیے فائلوں اور ٹیمپلیٹس کی طرح کاپی کیا جا سکتا ہے۔ صرف ایک باریکتا ہے۔ فائلوں کو کاپی کرنے سے پہلے، آپ کو ان کے لیے ڈائرکٹری کا ڈھانچہ بنانا ہوگا، کچھ اس طرح:

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

ہم صرف ایک ڈائرکٹری بتاتے ہیں اور اگر ضروری ہو تو جوابدہ خود بخود پیرنٹ ڈائرکٹری بنا لے گا۔

جوابدہ والٹ

ہم پہلے ہی اس حقیقت کو دیکھ چکے ہیں کہ متغیرات میں خفیہ ڈیٹا ہو سکتا ہے جیسے صارف کا پاس ورڈ۔ اگر آپ نے بنایا ہے۔ .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-playbook -i inventory ./playbook.yml -l "staging" --ask-vault-pass

لیکن میں آپ کو پلے بکس اور کرداروں کا مکمل متن نہیں دوں گا، خود لکھیں۔ کیونکہ جواب دینے والا ایسا ہی ہے - اگر آپ نہیں سمجھتے ہیں کہ کیا کرنے کی ضرورت ہے، تو یہ آپ کے لیے نہیں کرے گا۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں