منذ وقت ليس ببعيد ، كنت بحاجة إلى كتابة العديد من كتب اللعب غير المرئية لإعداد الخادم لنشر تطبيق القضبان. وبشكل مدهش ، لم أجد دليلًا بسيطًا خطوة بخطوة. لم أكن أرغب في نسخ كتاب اللعب الخاص بشخص آخر دون فهم ما كان يحدث وكنتيجة لذلك اضطررت إلى قراءة الوثائق وجمع كل شيء بنفسي. ربما شخص يمكنني المساعدة في تسريع هذه العملية مع هذه المادة.
أول شيء يجب فهمه هو أن ansible يوفر لك واجهة ملائمة لأداء قائمة محددة مسبقًا من الإجراءات على الخادم (الخوادم) عن بُعد عبر SSH. لا يوجد سحر هنا ، لا يمكنك تثبيت المكون الإضافي والخروج من مربع تعطل الصفر من نشر التطبيق الخاص بك مع عامل ميناء ، ومراقبة وغيرها من الأشياء الجيدة. من أجل كتابة كتاب اللعب ، يجب أن تعرف بالضبط ما تريد القيام به وكيفية القيام بذلك. لذلك ، أنا لا أحب كتب اللعب الجاهزة من جيثب ، أو مقالات مثل: "النسخ والتشغيل ، ستنجح".
ماذا نحتاج؟
كما قلت ، من أجل كتابة كتاب اللعب ، فأنت بحاجة إلى معرفة ما تريد القيام به وكيفية القيام بذلك. دعنا نقرر ما نحتاجه. لتطبيق Rails ، سنحتاج إلى عدة حزم نظام: nginx ، postgresql (redis ، إلخ). بالإضافة إلى ذلك ، نحن بحاجة إلى روبي إصدار معين. من الأفضل تثبيته من خلال rbenv (rvm ، asdf ...). يعد تشغيل كل هذا من جذر المستخدم دائمًا فكرة سيئة ، لذلك تحتاج إلى إنشاء مستخدم منفصل وتكوين الحقوق له. بعد ذلك ، تحتاج إلى تحميل الكود الخاص بنا إلى الخادم ، ونسخ التهيئة لـ nginx ، و postgres ، وغيرها وبدء جميع هذه الخدمات.
نتيجة لذلك ، تسلسل الإجراءات كما يلي:
- تسجيل الدخول كجذر
- تثبيت حزم النظام
- إنشاء مستخدم جديد ، تكوين الحقوق ، مفتاح سه
- تكوين حزم النظام (nginx وما إلى ذلك) وتشغيلها
- إنشاء مستخدم في قاعدة البيانات (يمكنك إنشاء قاعدة بيانات على الفور)
- تسجيل الدخول كمستخدم جديد
- تثبيت rbenv وروبي
- تثبيت المجمع
- ملء رمز التطبيق
- نبدأ خادم بوما
علاوة على ذلك ، يمكن القيام بالخطوات الأخيرة باستخدام capistrano ، على الأقل يمكنها نسخ الكود إلى دلائل الإصدار من المربع ، وتبديل الإصدار برمز ارتباط عند نشر ناجح ، ونسخ التكوينات من الدليل المشترك ، وإعادة تشغيل puma ، إلخ. كل هذا يمكن القيام به مع Ansible ، لكن لماذا؟
هيكل الملف
يحتوي Ansible على بنية ملف صارمة لجميع ملفاته ، لذلك من الأفضل الاحتفاظ بها جميعًا في دليل منفصل. وليس من المهم للغاية ما إذا كان سيكون في تطبيق القضبان نفسه ، أو بشكل منفصل. يمكنك تخزين الملفات في مستودع بوابة منفصل. شخصيا ، كان الأمر الأكثر ملاءمة بالنسبة لي لإنشاء دليل غير مرئي في / 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 الخاص بك للاختبارات ، أو يمكنك تسجيل مضيف محلي) وحفظه تحت اسم inventory
.
يمكنك تجربة تشغيل ansible باستخدام ملف invetory:
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
حاول تشغيل playbook مرة أخرى وتأكد من أن الاتصال يعمل. (إذا حددت جذر المستخدم ، فيجب عليك أيضًا تحديد الأمر يصبح: التوجيه الحقيقي للحصول على حقوق مرتفعة. كما تقول الوثائق: become set to 'true'/'yes' to activate privilege escalation.
رغم أنه ليس من الواضح سبب ذلك) .
ربما تحصل على خطأ بسبب الخطأ الذي لا يمكن لمترجم بايثون تحديده ، ثم يمكنك تحديده يدويًا:
ansible_python_interpreter: /usr/bin/python3
حيث يمكنك العثور على whereis 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 ، ونقول أن حالتها يجب أن تكون present
، أي نقول لتثبيت هذه الحزم. وبالمثل ، يمكننا أن نقول لهم أن يتم حذفها أو تحديثها ، ببساطة عن طريق تغيير state
. يرجى ملاحظة أنه لكي تعمل القضبان مع postgresql ، نحتاج إلى حزمة postgresql التي نقوم بتثبيتها حاليًا. يحتاج هذا مرة أخرى إلى أن يكون معروفًا وفعلًا ، ولن يقوم بذلك ansible بحد ذاته.
حاول تشغيل playbook مرة أخرى وتحقق من تثبيت الحزم.
إنشاء مستخدمين جدد.
للعمل مع المستخدمين ، يحتوي Ansible أيضًا على وحدة - مستخدم. أضف مهمة أخرى (أخفيت الأجزاء المعروفة بالفعل في playbook وراء التعليقات ، حتى لا تنسخها بالكامل في كل مرة):
--- - name: Simple playbook # ... tasks: # ... - name: Add a new user user: name: my_user shell: /bin/bash password: "{{ 123qweasd | password_hash('sha512') }}"
نخلق مستخدمًا جديدًا ونضع له كلمة مرور وكلمة مرور. ثم نواجه العديد من المشاكل. ماذا لو كان يجب أن تكون أسماء المستخدمين مختلفة للمضيفين المختلفين؟ نعم ، وإبقاء كلمة المرور مفتوحة في playbook هي فكرة سيئة للغاية. بادئ ذي بدء ، سنضع اسم المستخدم وكلمة المرور في متغيرات ، وفي نهاية المقال سوف أعرض كيفية تشفير كلمة المرور.
--- - 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
في playbook الرئيسي ، يجب عليك تحديد استخدام دور المستخدم:
--- - 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_path }}
{{ app_name }}
و {{ app_path }}
و {{ server_name }}
و {{ inventory_hostname }}
- فهذه كلها متغيرات ستستبدل قيمها في النص القالب قبل النسخ. هذا مفيد إذا كنت تستخدم قواعد اللعبة التي تمارسها لمجموعات مضيفة مختلفة. على سبيل المثال ، يمكننا استكمال ملف المخزون لدينا:
[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 حاليًا به مخزّن هناك.
إذا كنت تريد أن يكون لديك ملف مخزون للعديد من المضيفين ، ويتم تشغيله لمجموعة واحدة فقط ، يمكن القيام بذلك باستخدام الأمر التالي:
ansible-playbook -i inventory ./playbook.yml -l "staging"
خيار آخر هو أن يكون لديك ملفات جرد منفصلة لمجموعات مختلفة. أو يمكنك دمج طريقتين إذا كان لديك العديد من المضيفين المختلفين.
دعنا نعود إلى تكوين nginx. بعد نسخ ملفات التكوين ، نحتاج إلى إنشاء رابط في sitest_enabled على my_app.conf من sites_available. وإعادة تشغيل إنجن إكس.
... # 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
كل شيء بسيط هنا - مرة أخرى ، وحدات ansible مع بناء جملة قياسي إلى حد ما. ولكن هناك نقطة واحدة. إعادة تشغيل 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
وسيتم تسجيل متغير restart_nginx
. وفقط إذا تم تسجيل هذا المتغير ، سيتم إعادة تشغيل الخدمة.
حسنًا ، بالطبع ، تحتاج إلى إضافة دور nginx إلى playbook الرئيسي.
إعداد Postgresql
نحتاج إلى تمكين postgresql مع systemd ، تمامًا كما فعلنا مع nginx ، وكذلك إنشاء مستخدم سنستخدمه للوصول إلى قاعدة البيانات وقاعدة البيانات نفسها.
قم /ansible/roles/postgresql/tasks/main.yml
الدور /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
الأكثر إثارة للاهتمام become_user: postgres
. والحقيقة هي أن المستخدم postgres بشكل افتراضي فقط لديه حق الوصول إلى قاعدة بيانات postgresql وفقط محليا. يسمح لنا هذا التوجيه بتنفيذ الأوامر نيابة عن هذا المستخدم (ما لم يكن لدينا بالطبع إمكانية الوصول).
أيضًا ، قد تضطر إلى إضافة سطر إلى pg_hba.conf لفتح الوصول إلى قاعدة البيانات لمستخدم جديد. يمكن القيام بذلك بنفس الطريقة التي قمنا بها بتغيير التكوين nginx.
وبالطبع تحتاج إلى إضافة دور postgresql إلى playbook الرئيسي.
تثبيت روبي من خلال 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
نحن نستخدم مرة أخرى توجيه أصبح Bec_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
وأخيرا تثبيت روبي. يتم ذلك عبر 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 لا يوجد لديه حالة من حيث ansible. وهذا يعني أن التحقق التلقائي ما إذا كان هذا الإصدار من روبي مثبت أم لا. يمكننا أن نفعل ذلك بأنفسنا:
- 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 إلى playbook الرئيسي.
الملفات المشتركة.
بشكل عام ، يمكن إكمال هذا الإعداد. ثم يبقى لتشغيل 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
لقد تعثرت بالفعل حقيقة أن البيانات السرية مثل كلمة مرور المستخدم قد تظهر في المتغيرات. إذا قمت بإنشاء ملف .env
للتطبيق ، و database.yml
، فيجب أن يكون هناك المزيد من هذه البيانات الهامة. سيكون من الجميل أن نخفيهم عن أعين المتطفلين. يستخدم قبو Ansible لهذا الغرض.
لنقم بإنشاء ملف للمتغيرات /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
يمكن فك تشفير الملف وتعديله ثم تشفيره مرة أخرى.
للعمل ، فك تشفير الملف ليست ضرورية. يمكنك تخزينه في شكل مشفر وتشغيل playbook مع الوسيطة --ask-vault-pass
. سيطلب Ansible كلمة مرور والحصول على المتغيرات وإكمال المهام. ستبقى جميع البيانات مشفرة.
يبدو الأمر الكامل للعديد من مجموعات المضيف والقبو غير المرغوب فيه مثل هذا:
ansible-playbook -i inventory ./playbook.yml -l "staging" --ask-vault-pass
ولن أعطيك النص الكامل للكتب والأدوار ، اكتب لنفسك. لأن الشيء غير الواضح هو - إذا لم تفهم ما يجب القيام به ، فلن يفعل ذلك.