SSD Nodes Learn
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-07-24

آموزش نصب و اولین Playbook در Ansible

نصب Ansible با pipx در Ubuntu 24.04، ساخت فایل inventory و نوشتن اولین playbook برای امنیت VPS. رفع خطاهای Permission denied و sudo در اجرا.

آنچه در حال ساخت آن هستید

یک ماشین کنترل که Ansible روی آن نصب شده است، و یک یا چند VPS تازه با سیستم‌عامل Ubuntu 24.04 که هیچ برنامه‌ای جز تصویر پیش‌فرض (stock image) روی آن‌ها نصب نشده است. در پایان، شما یک فایل inventory خواهید داشت که نام سرورهای شما را مشخص می‌کند، یک دستور ad-hoc ping که صحت احراز هویت را از ابتدا تا انتها تایید می‌کند، و یک playbook که تمام مراحل چک‌لیست یک VPS جدید را به صورت کد اجرا می‌کند: یک کاربر deploy با SSH key شما، sshd امن‌شده، fail2ban، unattended upgrades و یک فایروال که اجازه دسترسی به OpenSSH را می‌دهد و سپس سایر دسترسی‌ها را مسدود می‌کند. این فرآیند را برای یک سرور یا بیست سرور اجرا کنید. اگر آن را دو بار اجرا کنید، اجرای دوم تغییری ایجاد نمی‌کند — هدف اصلی همین است.

پس از 15 سال مدیریت و آماده‌سازی VPSها، می‌توانم الگوی واقعی را به شما بگویم: همه 5 سرور اول را به صورت دستی تنظیم می‌کنند، سپس سرور ششم باعث هدر رفتن یک آخر هفته می‌شود، زیرا هیچ‌کس به خاطر نمی‌آورد که در 5 سرور اول چه کارهایی انجام داده است. این راهنما، بررسی در زمینه مدیریت چندین سرور Linux را تکمیل می‌کند — زمانی که متوجه شدید در حال تایپ کردن یک دستور apt install یکسان در 3 ترمینال هستید، این راهنما را مطالعه کنید.

Ansible در واقع چیست، در یک پاراگراف

Ansible بدون نیاز به Agent عمل می‌کند. هیچ Daemon ای برای نصب روی سرورهای تحت مدیریت نیاز نیست: ماشین کنترل از طریق SSH معمولی متصل می‌شود، یک ماژول کوچک Python را به مقصد کپی می‌کند، آن را اجرا می‌کند، خروجی JSON آن را می‌خواند و سپس آن را حذف می‌کند. تنها چیزی که مقصد به آن نیاز دارد python3 است که در تمام نسخه‌های پیش‌فرض Ubuntu وجود دارد. کلمه کلیدی در اینجا idempotent است که معنای ساده‌ای دارد: یک Task، یک state (وضعیت) را توصیف می‌کند، نه یک Action (عمل). برای یک Package، دستور state: present به معنای «اطمینان حاصل کن که این بسته نصب شده است» می‌باشد، نه «نصب‌کننده را اجرا کن». اگر وضعیت از قبل برقرار باشد، Ansible هیچ تغییری ایجاد نمی‌کند و به جای changed، وضعیت را به صورت ok گزارش می‌دهد. این ویژگی، هسته اصلی این محصول است؛ ویژگی‌ای که اجرای مجدد یک Playbook را ایمن می‌کند و اجرای ایمن و مکرر است که یک Shell Script را به Infrastructure تبدیل می‌کند.

پیش‌نیازها و نکات مهم اولیه

  • یک ماشین کنترل: لپ‌تاپ شما یا یک VPS کوچک. فرض بر این است که از Ubuntu 24.04 استفاده می‌کنید؛ در macOS نیز پس از نصب pipx از طریق Homebrew، عملکرد کاملاً مشابه است.
  • یک یا چند VPS هدف که Ubuntu 24.04 را روی KVM اجرا می‌کنند و با دسترسی root در دسترس هستند. هیچ نرم‌افزاری روی آن‌ها نصب نمی‌شود.
  • احراز هویت با SSH key برای تمام هدف‌ها. سطح دسترسی Ansible دقیقاً مشابه دستور ssh شما است؛ اگر ssh root@host درخواست رمز عبور بدهد، Ansible با خطا مواجه می‌شود.
  • در Ubuntu 24.04، دستور pip install ansible با خطای error: externally-managed-environment متوقف می‌شود. این یک سیاست عمدی توزیع است و نشان‌دهنده خرابی نیست. از pipx استفاده کنید.
  • فاصله‌گذاری (whitespace) در YAML بخشی از سینتکس است. رعایت نکردن فاصله باعث ایجاد mapping values are not allowed in this context می‌شود و وجود کاراکتر tab در هر نقطه، باعث توقف عملیات می‌شود.
  • هنگام اجرای playbook برای ایمن‌سازی sshd، یک نشست SSH فعال روی هر هدف باز نگه دارید. تمام مواردی که در آن به مشتری برای بازیابی کمک کرده‌ام، به دلیل بستن آخرین نشست برای «تست از حالت پاک» رخ داده است.

Step 1: نصب Ansible روی ماشین کنترل با استفاده از pipx، نه pip

غریزه معمول استفاده از pip3 install ansible است. در یک Image کاملاً تازه از نسخه 24.04 که در یک مرحله زودتر با خطا مواجه می‌شود — Command 'pip3' not found, but can be installed with: sudo apt install python3-pip — و نصب pip فقط شما را با یک مانع واقعی روبرو می‌کند:

pip3 install ansible
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

در Ubuntu 24.04، پایتون سیستم به عنوان externally managed (PEP 668) علامت‌گذاری شده است، بنابراین pip نمی‌تواند با apt بر سر فایل‌های یکسان رقابت کند. از --break-system-packages استفاده نکنید؛ نام این flag کاملاً گویا است. راه حل تمیز استفاده از pipx است که برای Ansible یک virtualenv مجزا ایجاد می‌کند و فایل‌های باینری را در PATH شما قرار می‌دهد:

sudo apt update && sudo apt install -y pipx
pipx ensurepath
pipx install --include-deps ansible

پس از اجرای pipx ensurepath، یک shell جدید باز کنید تا تغییرات PATH اعمال شود. --include-deps صرفاً یک تزیین نیست: بسته ansible هیچ console script اختصاصی ندارد — ansible، ansible-playbook و بقیه موارد، entry pointهای وابستگی ansible-core هستند — بنابراین بدون این flag، pipx با خطای No apps associated with package ansible or its dependencies از نصب خودداری می‌کند. همچنین بسته ansible را نصب کنید، نه ansible-core خالی؛ بسته کامل شامل community collections است و این playbook از ماژول‌های دو مورد از آن‌ها (ansible.posix و community.general) استفاده می‌کند.

ansible --version

نتیجه صحیح با خطی شبیه به ansible [core 2.19.x] شروع می‌شود و نام پایتونی که تحت آن اجرا می‌شود را ذکر می‌کند؛ هر نسخه اصلی (core release) فعلی برای تمام موارد اینجا مناسب است. ansible: command not found به این معناست که ~/.local/bin هنوز در PATH شما نیست — یک shell جدید باز کنید یا از source ~/.bashrc استفاده کنید.

مراحل نصب به همین‌جا ختم می‌شود. هدف‌ها (targets) هیچ تغییری دریافت نمی‌کنند.

Step 2: SSH key access to every target

ssh-keygen -t ed25519 -C "ansible control"
ssh-copy-id root@10.0.0.10
ssh-copy-id root@10.0.0.20

سپس برای هر host، یک بار این کار را انجام دهید تا صحت آن تایید شود:

ssh root@10.0.0.10 true && echo ok

این دستور یک خطی دو وظیفه دارد: تایید می‌کند که احراز هویت با key بدون نیاز به password انجام می‌شود، و host key را در known_hosts ثبت می‌کند. این کار را همین حالا انجام دهید؛ زیرا Ansible در صورت عدم ثبت host key، یک prompt تعاملی در میان فرآیند اجرا نمایش می‌دهد که دقیقاً شبیه به هنگ کردن (hang) به نظر می‌رسد.

Step 3: inventory — ابتدا INI، سپس YAML در صورت افزایش حجم

inventory یک فایل متنی است که لیست ماشین‌هایی که Ansible می‌تواند با آن‌ها کار کند را شامل می‌شود. فایل inventory.ini را در یک دایرکتوری پروژه جدید ایجاد کنید:

[vps]
web1 ansible_host=10.0.0.10
web2 ansible_host=10.0.0.20

[vps:vars]
ansible_user=root

web1 یک نام مستعار (alias) است که خودتان انتخاب می‌کنید؛ این نام در خروجی نمایش داده می‌شود و هدف شما هنگام استفاده از --limit web1 خواهد بود. ansible_host آدرس واقعی است. [vps] یک گروه است و [vps:vars] متغیرهایی را برای تمام میزبان‌های (hosts) موجود در آن گروه تنظیم می‌کند؛ ansible_user کاربری است که Ansible با آن وارد سیستم می‌شود. در کنار آن، یک ansible.cfg قرار دهید تا دیگر نیازی به تایپ کردن -i نداشته باشید:

[defaults]
inventory = inventory.ini

Ansible فایل ansible.cfg را از دایرکتوری فعلی می‌خواند. همان inventory در قالب YAML — که آن را با نام inventory.yml ذخیره می‌کنید و ansible.cfg را به جای آن به آن نام ارجاع می‌دهید — زمانی که هر میزبان چندین متغیر داشته باشد، گزینه مورد علاقه شما خواهد بود:

vps:
  hosts:
    web1:
      ansible_host: 10.0.0.10
    web2:
      ansible_host: 10.0.0.20
  vars:
    ansible_user: root

این دو فرمت معادل یکدیگر هستند. فرمت INI برای بررسی دو سرور ساده‌تر است؛ فرمت YAML برای مدیریت 20 سرور مقیاس‌پذیری بهتری دارد. یکی را انتخاب کنید و دیگر به آن فکر نکنید.

Step 4: ad-hoc commands — the green pong that proves everything

ansible all -m ping

این پروتکل ICMP نیست. ماژول ping یک تمرین کامل است: ورود از طریق SSH، کپی ماژول، اجرای Python در مقصد و پاک‌سازی. نتیجه صحیح سبز است و برای هر host یک بلوک نمایش داده می‌شود:

web1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

رنگ سبز SUCCESS به این معناست که احراز هویت، مفسر Python و لایه انتقال (transport) همگی بدون مشکل کار می‌کنند؛ بنابراین playbook نیز بدون مشکل اجرا خواهد شد. رنگ قرمز UNREACHABLE! به این معناست که لایه انتقال قبل از اجرای هر ماژولی با خطا مواجه شده است؛ متن دقیق خطا و راه حل آن در بخش failure modes در ادامه آمده است. دو دستور ad-hoc دیگر که دانستن آن‌ها مهم است:

ansible all -a "uptime"
ansible all -m apt -a "update_cache=true upgrade=dist" --become

دستورات ad-hoc برای بررسی‌ها و کارهای موردی هستند. هر چیزی که قصد دارید 2 بار اجرا کنید، باید در یک playbook قرار بگیرد.

Step 5: اولین playbook — چک‌لیست new-VPS به صورت کد

این شامل تمام کارهایی است که در 10 دقیقه اول در یک سرور جدید به صورت دستی انجام می‌دهید. آن را با نام site.yml ذخیره کنید:

---
- name: Baseline a fresh Ubuntu VPS
  hosts: vps
  become: true

  vars:
    deploy_user: deploy
    deploy_pubkey: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
    baseline_packages:
      - fail2ban
      - unattended-upgrades
      - ufw
    baseline_services:
      - fail2ban
      - unattended-upgrades

  tasks:
    - name: Create the deploy user
      ansible.builtin.user:
        name: "{{ deploy_user }}"
        groups: sudo
        append: true
        shell: /bin/bash

    - name: Install the deploy user's SSH key
      ansible.posix.authorized_key:
        user: "{{ deploy_user }}"
        key: "{{ deploy_pubkey }}"

    - name: Passwordless sudo for the deploy user
      ansible.builtin.copy:
        dest: /etc/sudoers.d/deploy
        content: "{{ deploy_user }} ALL=(ALL) NOPASSWD:ALL\n"
        mode: "0440"
        validate: /usr/sbin/visudo -cf %s

    - name: Install baseline packages
      ansible.builtin.apt:
        name: "{{ baseline_packages }}"
        state: present
        update_cache: true

    - name: Enable and start baseline services
      ansible.builtin.service:
        name: "{{ item }}"
        state: started
        enabled: true
      loop: "{{ baseline_services }}"

    - name: Harden sshd with a drop-in
      ansible.builtin.copy:
        dest: /etc/ssh/sshd_config.d/00-hardening.conf
        content: |
          PasswordAuthentication no
          KbdInteractiveAuthentication no
          PermitRootLogin prohibit-password
          X11Forwarding no
        mode: "0644"
        validate: /usr/sbin/sshd -t -f %s
      notify: Restart ssh

    - name: Allow OpenSSH through ufw
      community.general.ufw:
        rule: allow
        name: OpenSSH

    - name: Enable ufw with default deny
      community.general.ufw:
        state: enabled
        policy: deny

  handlers:
    - name: Restart ssh
      ansible.builtin.service:
        name: ssh
        state: restarted

خطوطی که به جای کپی کردن، باید درک شوند:

Variables در زیرمجموعه vars: قرار دارند و با "{{ deploy_user }}" ارجاع داده می‌شوند — اگر یک مقدار با علامت brace شروع می‌شود، کل عبارت را داخل کوتیشن قرار دهید، در غیر این صورت YAML parser آن را اشتباه می‌خواند. lookup('file', ...) کلید عمومی شما را در زمان اجرا از ماشین control می‌خواند، بنابراین playbook هیچ کلید امنیتی‌ای با خود حمل نمی‌کند.

The loop. عبارت loop: "{{ baseline_services }}" وظیفه service را برای هر آیتم یک بار اجرا می‌کند و خروجی، هر آیتم را در یک خط مجزا نشان می‌دهد. توجه داشته باشید که وظیفه apt لیست کامل پکیج‌ها را یک‌باره دریافت می‌کند — یک تراکنش apt سریع‌تر است و الگوی ترجیحی برای پکیج‌ها محسوب می‌شود؛ حلقه‌ها برای ماژول‌هایی هستند که واقعاً روی یک مورد در هر زمان عمل می‌کنند.

The handler مفهومی است که باید در ذهن بسپارید. notify: Restart ssh به معنای "همین حالا ssh را ری‌استارت کن" نیست. این دستور handler را در صف قرار می‌دهد که در پایان play و فقط در صورتی که وظیفه notifying واقعاً گزارش changed را داده باشد، اجرا می‌شود. فردا playbook را دوباره اجرا کنید: فایل drop-in از قبل درست است، وظیفه copy گزارش ok می‌دهد و sshd هرگز ری‌استارت نمی‌شود. خط validate: مانند ضامن ایمنی است — sshd فایل را قبل از جایگزینی فایل قدیمی بررسی می‌کند، بنابراین یک غلط تایپی باعث شکست خوردن وظیفه می‌شود، نه از کار افتادن daemon.

PermitRootLogin prohibit-password، نه no — به عمد. این playbook با استفاده از یک کلید به عنوان root وارد می‌شود. prohibit-password ورود با رمز عبور برای root را غیرفعال می‌کند در حالی که دسترسی شما را حفظ می‌کند. پس از اینکه کاربر deploy تایید شد (ssh deploy@10.0.0.10 sudo true — آدرس مستقیم، چون web1 فقط یک alias است که فقط Ansible آن را می‌شناسد)، در inventory عبارت ansible_user=deploy را تغییر دهید و در اجرای بعدی آن را به no محدود کنید. فرآیند hardening را به ترتیبی انجام دهید که باعث قطع دسترسی شما نشود.

پیشوند 00- اهمیت دارد. برای اکثر کلمات کلیدی، sshd اولین موردی را که پارس می‌کند در نظر می‌گیرد و sshd_config در Ubuntu شامل sshd_config.d/*.conf به ترتیب لغوی قبل از بدنه خود است. ایمیج‌های cloud در Ubuntu 24.04 از قبل یک 60-cloudimg-settings.conf در آن دایرکتوری دارند و ارائه‌دهندگانی که ورود با رمز عبور را از طریق cloud-init فعال می‌کنند، یک 50-cloud-init.conf با PasswordAuthentication yes اضافه می‌کنند؛ نام‌گذاری ما به صورت 00-hardening.conf باعث می‌شود این مورد در اولویت قرار گرفته و بر هر دو پیروز شود.

ترتیب وظایف (Task order) مانند ایمنی دیوار آتش است. Allow OpenSSH قبل از Enable ufw با سیاست deny اجرا می‌شود — Ansible وظایف را دقیقاً به همان ترتیبی که لیست شده‌اند اجرا می‌کند، بنابراین حفره امنیتی قبل از بالا رفتن دیوار ایجاد می‌شود. fail2ban برای مفید بودن در اینجا نیازی به پیکربندی ندارد؛ تنظیمات پیش‌فرض Ubuntu در حالت پیش‌فرض از sshd محافظت می‌کنند و آنچه jails واقعاً انجام می‌دهند — و آنچه باید تنظیم شود — در راهنمای fail2ban در Ubuntu 24.04 پوشش داده شده است.

Step 6: اجرای آزمایشی با --check، سپس اجرای واقعی

ansible-playbook site.yml --check

حالت check متصل می‌شود، عملیات‌های مورد نظر را محاسبه می‌کند و هیچ تغییری ایجاد نمی‌کند. تعداد changed= را در بخش PLAY RECAP در پایین صفحه بررسی کنید؛ این عدد نشان‌دهنده تعداد وظایفی است که هر host را تغییر می‌دهند. یک نکته مهم: حالت check محدودیت ساختاری دارد؛ در صورتی که یک وظیفه (task) بعدی به تغییرات یک وظیفه قبلی وابسته باشد، حالت check با مشکل مواجه می‌شود. در image استاندارد سرور Ubuntu، بسته ufw از قبل نصب شده است، بنابراین این playbook در حالت آزمایشی بدون خطا اجرا می‌شود؛ اما در یک image مینیمال که فاقد آن باشد، وظایف ufw در حالت check شکست می‌خورند؛ زیرا حالت check هرگز بسته را نصب نکرده است و ماژول چیزی برای فراخوانی ندارد. این یک محدودیت در اجرای آزمایشی است، نه یک باگ در playbook شما. وقتی طرح اجرا درست به نظر رسید:

ansible-playbook site.yml

هر وظیفه یک خط برای هر host چاپ می‌کند — زرد changed، سبز ok — و خلاصه باید به این صورت باشد:

PLAY RECAP *********************************************************************
web1 : ok=10  changed=9  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
web2 : ok=10  changed=9  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0

ده مورد ok شامل جمع‌آوری اطلاعات، هشت وظیفه و handler است. مقدار changed شما ممکن است با مقدار من 1 یا 2 واحد تفاوت داشته باشد: image استاندارد Ubuntu شامل ufw و unattended-upgrades است، و fail2ban بلافاصله پس از نصب توسط apt خودکار اجرا می‌شود، بنابراین یک وظیفه می‌تواند در اولین اجرای خود، وضعیت ok را گزارش دهد — یعنی وضعیتی که از قبل برقرار است. اعدادی که باید 0 باشند، unreachable و failed هستند. یک نکته درباره become: true: این یک تشریفات است در حالی که با کاربر root متصل هستید، اما به محض اینکه ansible_user را به deploy تغییر دهید، sudo فعال می‌شود — و فایل sudoers با قابلیت NOPASSWD که این playbook نصب می‌کند، دقیقاً همان چیزی است که از نمایش -K در خط فرمان جلوگیری می‌کند. بدون آن، با Missing sudo password مواجه می‌شوید که در ادامه توضیح داده شده است.

Step 7: اجرای مجدد — مفهوم idempotence

دستور را بلافاصله دوباره اجرا کنید:

web1 : ok=9  changed=0  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0

مقدار changed=0 و ok به دلیل اجرا نشدن handler بدون اطلاع‌رسانی، یک واحد کاهش یافتند. هیچ چیزی مجدداً نصب نشد، sshd بازنشانی نشد و ufw تغییری نکرد. همین ویژگی باعث می‌شود playbook هم یک ابزار provisioner و هم یک ابزار audit باشد: ماه آینده web3 را به inventory اضافه کنید و دوباره اجرا کنید؛ سرور جدید ساخته می‌شود و سرورهای قدیمی بررسی می‌شوند. مقدار غیرصفر changed در سروری که به آن دست نکرده‌اید، نشان‌دهنده drift است؛ این یعنی کسی آنچه را که باید در playbook ویرایش می‌شد، به صورت دستی تغییر داده است.

از اینجا به بعد، این الگو گسترش می‌یابد. مرحله بعدی که ارزش نوشتن دارد، راه‌اندازی WireGuard VPN روی همان VPS و محدود کردن rule در ufw است تا SSH فقط از طریق tunnel پاسخ دهد؛ پس از آن، نوشتن playbook برای نصب Docker and Compose روی تمام app serverها. زمانی که site.yml از سه صفحه فراتر رفت، آن را به roles تقسیم کنید — اما پیش از آن این کار را انجام ندهید.

حالت‌های شکست، همراه با رشته‌هایی که مشاهده خواهید کرد

UNREACHABLE with Permission denied.

web1 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: root@10.0.0.10: Permission denied (publickey).",
    "unreachable": true
}

انتقال SSH قبل از اجرای هر ماژولی با شکست مواجه شده است: ansible_user اشتباه است، کلید هرگز به آن host کپی نشده است، یا کلید اشتباهی ارائه شده است. با دستور ساده‌ی ssh root@10.0.0.10 خطا را بازسازی کنید، سپس از ssh -v استفاده کنید تا ببینید چه کلیدهایی ارائه شده‌اند. اگر SSH با رمز عبور کار می‌کند اما Ansible کار نمی‌کند، مرحله‌ی ssh-copy-id را نادیده گرفته‌اید.

Missing sudo password.

web1 | FAILED! => {
    "msg": "Missing sudo password"
}

شما become: true را تنظیم کرده‌اید، با یک کاربر غیر-root متصل شده‌اید، و آن کاربر برای sudo به رمز عبور نیاز دارد. یا -K (--ask-become-pass) را به خط فرمان اضافه کنید، یا برای کاربر یک entry در sudoers با ویژگی NOPASSWD ایجاد کنید — دقیقاً به همین دلیل است که playbook قبل از اینکه شما به آن کاربر سوئیچ کنید، یکی برای deploy نصب می‌کند.

error: externally-managed-environment. شما pip را روی Python سیستم در Ubuntu 24.04 اجرا کرده‌اید. این مورد در مرحله 1 پوشش داده شده است: استفاده از pipx به جای pip، و نه --break-system-packages.

mapping values are not allowed in this context.

ERROR! Syntax Error while loading YAML.
  mapping values are not allowed in this context

تقریباً همیشه مربوط به indentation است: یک key در عمق اشتباه، یا نبود یک space بعد از colon. شماره خط گزارش شده نزدیک خطا است، نه دقیقاً روی آن — خط بالایی را نیز بررسی کنید. خطای مشابه found character '\t' that cannot start any token به معنای ورود یک tab است؛ YAML از آن‌ها ممنوع می‌کند. قبل از هر اجرا، ansible-playbook site.yml --syntax-check را به یک عادت تبدیل کنید و ویرایشگر خود را روی two-space indentation برای YAML تنظیم کنید.

/usr/bin/python3: not found. در ایمیج‌های استاندارد Ubuntu 24.04 نادر است، اما در نسخه‌های minimal یا netboot رایج است: اجرای ماژول شکست می‌خورد زیرا هدف فاقد Python است. آن را با ماژول raw بوت استرپ کنید؛ تنها ماژولی که در سمت مقصد به هیچ چیز نیاز ندارد: ansible all -m raw -a "apt-get update && apt-get install -y python3" --become، سپس playbook را دوباره اجرا کنید.

FAQ

آیا نیاز است Ansible را روی سرورهایی که مدیریت می‌کند نصب کنم؟

خیر. Ansible بدون نیاز به agent کار می‌کند: ماشین کنترل، ماژول‌های کوچک Python را از طریق SSH ارسال، اجرا و سپس حذف می‌کند. سرور هدف تنها به python3 و دسترسی SSH نیاز دارد که هر دو در نسخه‌های پیش‌فرض Ubuntu موجود هستند. تنها نصب در تمام این راهنما، روی ماشین کنترل شما انجام می‌شود.

چرا Ansible خطای "Permission denied (publickey)" می‌دهد؟

بلاک UNREACHABLE! با Permission denied (publickey) به این معناست که احراز هویت SSH قبل از اجرای هر عملیاتی توسط Ansible شکست خورده است. بررسی کنید که ansible_user در فایل inventory با حسابی که تنظیم کرده‌اید مطابقت داشته باشد، دستور ssh-copy-id را برای آن host اجرا کرده باشید و دستور ساده‌ی ssh user@host بدون رمز عبور وارد شود. هر چیزی که دستور ساده‌ی ssh را اصلاح کند، Ansible را نیز اصلاح می‌کند، زیرا هر دو از یک پروتکل انتقال استفاده می‌کنند.

مفهوم idempotent در Ansible چیست؟

یک task به جای انجام یک عمل، یک وضعیت مطلوب را اعلام می‌کند — مثلاً "این package باید نصب باشد" یا "این خط باید در این file باشد". اگر وضعیت از قبل برقرار باشد، Ansible هیچ کاری انجام نمی‌دهد و به جای changed، گزارش ok را ارائه می‌دهد. به همین دلیل است که اجرای یک playbook برای بار دوم، در بار دوم changed=0 را نشان می‌دهد و اجرای مجدد، یک audit ایمن است و نه یک نصب مجدد پرخطر.

برای نصب Ansible روی Ubuntu 24.04 باید از pip استفاده کنم یا pipx؟

از pipx. در Ubuntu 24.04، پایتونِ سیستم به عنوان externally managed شناخته می‌شود، بنابراین pip install ansible به صورت پیش‌فرض با خطای error: externally-managed-environment مواجه می‌شود. ابزار pipx install --include-deps ansible، Ansible را در یک virtualenv مجزا قرار می‌دهد و ansible، ansible-playbook و سایر موارد را به صورت تمیز در PATH شما قرار می‌دهد.

تفاوت بین بسته‌های ansible و ansible-core چیست؟

بسته ansible-core شامل موتور اصلی و فقط ماژول‌های ansible.builtin است. بسته ansible هسته اصلی را همراه با مجموعه‌های منتخب جامعه کاربری (community collections) ارائه می‌دهد — از جمله ansible.posix (ماژول authorized_key) و community.general (ماژول ufw) که هر دو در این راهنما استفاده شده‌اند. کار را با بسته کامل شروع کنید؛ تنها زمانی به نسخه core به همراه مجموعه‌های منتخب محدود شوید که دلیل مشخصی داشته باشید.