اوبنتوداکر

استفاده از Ansible برای نصب Docker روی اوبونتو

مقدمه

اتوماسیون سرورها اکنون به دلیل ماهیت یک‌بارمصرفِ محیط‌های اپلیکیشن مدرن، نقشی ضروری در مدیریت سیستم‌ها ایفا می‌کند. ابزارهای مدیریت پیکربندی مانند Ansible معمولاً برای ساده‌سازی فرایند خودکارسازی راه‌اندازی سرورها استفاده می‌شوند؛ با استقرار رویه‌های استاندارد برای سرورهای جدید و هم‌زمان کاهش خطای انسانی مرتبط با راه‌اندازی‌های دستی.

Ansible معماری ساده‌ای ارائه می‌دهد که نیازمند نصب نرم‌افزار خاصی روی نودها نیست. همچنین مجموعه‌ای قوی از قابلیت‌ها و ماژول‌های داخلی را فراهم می‌کند که نوشتن اسکریپت‌های اتوماسیون را آسان می‌سازند.

این راهنما توضیح می‌دهد که چطور از Ansible برای خودکارسازی مراحل موجود در راهنمای «آموزش نصب و استفاده از Docker روی اوبونتو» استفاده کنید. Docker اپلیکیشنی است که فرایند مدیریت کانتینرها را ساده می‌کند؛ پروسه‌هایی ایزوله از نظر منابع که رفتاری شبیه ماشین‌های مجازی دارند، اما قابل‌حمل‌تر، بهینه‌تر از نظر منابع و وابسته‌تر به سیستم‌عامل میزبان هستند.

توجه: این راهنما روی اوبونتو 24.04 LTS تست شده است. اگرچه ممکن است روی سایر نسخه‌های جدید اوبونتو هم کار کند، اما برخی مراحل — مانند پیکربندی مخزن — ممکن است نیاز به تنظیمات جزئی داشته باشند.

نکات کلیدی

  • تکرارپذیری (Idempotency) به شما اجازه می‌دهد Playbook را چند بار به‌صورت ایمن دوباره اجرا کنید بدون ایجاد تغییرات ناخواسته؛ چون هر وظیفه قبل از اعمال تغییرات، وضعیت سیستم را بررسی می‌کند.
  • مدیریت مدرن کلید GPG، کلیدهای مخزن را در /etc/apt/keyrings همراه پارامترهای signed-by ذخیره می‌کند و جایگزین فرمان منسوخ‌شده apt-key و رویکرد قدیمی ماژول apt_key در Ansible شده است.
  • Docker Compose v2 به‌صورت پلاگین یکپارچه می‌شود (docker-compose-plugin) و زیردستور docker compose را به‌جای باینری قدیمی docker-compose فراهم می‌کند.
  • متغیر {{ ansible_distribution_release }} نام‌های رمز اوبونتو (‏focal، jammy، noble) را به‌طور خودکار تشخیص می‌دهد و سازگاری بین‌نسخه‌ای را بدون هاردکد‌کردن مقادیر خاصِ هر نسخه تضمین می‌کند.
  • باید Collection مربوط به community.docker را قبل از مدیریت کانتینرها، جداگانه روی نود کنترل خود با دستور ansible-galaxy collection install community.docker نصب کنید.
  • یک راه‌اندازی کامل Docker Engine به پنج پکیج اصلی نیاز دارد: docker-ce، docker-ce-cli، containerd.io، docker-buildx-plugin و docker-compose-plugin.
  • تغییرات عضویت در گروه ناشی از usermod -aG docker برای اعمال شدن، نیازمند خروج و ورود مجدد هستند؛ چون دسترسی‌ها هنگام ورود تنظیم می‌شوند.
  • ترتیب درست وظایف ضروری است؛ چون Ansible وظایف را به‌صورت ترتیبی (Synchronous) اجرا می‌کند؛ یعنی وابستگی‌هایی مثل gnupg باید قبل از عملیات GPG نصب شوند.
  • حالت Verbose (‏-vvv) دستورات واقعیِ اجراشده و پاسخ‌های کامل ماژول‌ها را نشان می‌دهد و اطلاعات دیباگ حیاتی برای مشکلات شبکه و دسترسی فراهم می‌کند.
  • Playbookهای Ansible از طریق Idempotency داخلی، ساختار خودمستند (Self-Documenting) و یکپارچگی کنترل نسخه، تکرارپذیری برتری نسبت به اسکریپت‌های شل ارائه می‌دهند.

پیش‌نیازها

برای اجرای راه‌اندازی خودکارِ فراهم‌شده توسط Playbook در این راهنما، به موارد زیر نیاز دارید:

  • یک نود کنترل Ansible: یک ماشین اوبونتو 24.04 با Ansible نصب‌شده که برای اتصال به هاست‌های Ansible شما با کلیدهای SSH پیکربندی شده باشد. مطمئن شوید نود کنترل دارای یک کاربر معمولی با دسترسی sudo و فایروال فعال است؛ همان‌طور که در راهنمای «راه‌اندازی اولیه سرور با اوبونتو» توضیح داده شده. برای راه‌اندازی Ansible، راهنمای «آموزش نصب و پیکربندی Ansible روی اوبونتو» را دنبال کنید.
  • یک یا چند هاست Ansible: یک یا چند سرور راه‌دور اوبونتو 24.04 که قبلاً طبق راهنمای «استفاده از Ansible برای خودکارسازی راه‌اندازی اولیه سرور روی اوبونتو» آماده شده باشند.

توجه: قبل از ادامه، ابتدا باید مطمئن شوید نود کنترل Ansible شما قادر است به هاست‌های Ansible شما متصل شده و دستورات را روی آن‌ها اجرا کند. برای تست اتصال، مرحله ۳ مقاله «آموزش نصب و پیکربندی Ansible روی اوبونتو» را ببینید.

این Playbook چه کاری انجام می‌دهد؟

این Playbook انصیبل، جایگزینی برای اجرای دستیِ رویه توضیح‌داده‌شده در راهنمای «آموزش نصب و استفاده از Docker روی اوبونتو» است. Playbook خود را یک بار راه‌اندازی کنید و از آن برای هر نصب بعدی استفاده کنید.

اجرای این Playbook، این اقدامات را روی هاست‌های Ansible شما انجام خواهد داد:

  • نصب aptitude که توسط Ansible به‌عنوان جایگزینی برای مدیر پکیج apt ترجیح داده می‌شود.
  • نصب پکیج‌های سیستمی موردنیاز.
  • دانلود و پیکربندی کلید GPG داکر با روش‌های مدرن Keyring.
  • افزودن مخزن رسمی Docker به منابع apt.
  • نصب Docker.
  • نصب Docker Compose (پلاگین v2).
  • نصب ماژول Python مربوط به Docker از طریق pip.
  • دریافت (Pull) ایمیج پیش‌فرضِ تعیین‌شده توسط default_container_image از Docker Hub.
  • ساخت تعداد کانتینرهای تعریف‌شده توسط متغیر container_count که هر کدام از ایمیج تعریف‌شده در default_container_image استفاده کرده و دستور تعریف‌شده در default_container_command را در هر کانتینر جدید اجرا می‌کنند.

وقتی اجرای Playbook تمام شود، تعدادی کانتینر بر اساس گزینه‌هایی که در متغیرهای پیکربندی خود تعریف کرده‌اید، ساخته خواهید داشت.

برای شروع، با کاربری دارای دسترسی sudo روی سرور نود کنترل Ansible خود وارد شوید.

مرحله ۱ — آماده‌سازی Playbook

فایل playbook.yml جایی است که همه وظایف شما در آن تعریف می‌شوند. یک وظیفه (Task)، کوچک‌ترین واحد اقدامی است که می‌توانید با یک Playbook انصیبل خودکارسازی کنید. اما ابتدا، فایل Playbook خود را با ویرایشگر متن دلخواهتان بسازید:

nano playbook.yml

این کار یک فایل YAML خالی باز می‌کند. قبل از پرداختن به افزودن وظایف به Playbook، با افزودن موارد زیر شروع کنید:

playbook.yml

---
- hosts: all
  become: true
  vars:
    container_count: 4
    default_container_name: docker
    default_container_image: hub.cr.parmincloud.ir/library/ubuntu
    default_container_command: sleep 1d

تقریباً هر Playbookی که با آن روبرو می‌شوید با تعریف‌هایی مشابه این شروع می‌شود. مقدار hosts مشخص می‌کند نود کنترل Ansible با این Playbook کدام سرورها را هدف می‌گیرد. مقدار become مشخص می‌کند آیا همه دستورات با دسترسی‌های ارتقایافته root انجام شوند یا نه.

بخش vars به شما اجازه می‌دهد داده‌ها را در متغیرها ذخیره کنید. اگر در آینده تصمیم به تغییر آن‌ها گرفتید، فقط باید این خطوط منفرد را در فایل خود ویرایش کنید. توضیح مختصری از هر متغیر:

  • container_count: تعداد کانتینرهایی که باید ساخته شوند.
  • default_container_name: نام پیش‌فرض کانتینر.
  • default_container_image: ایمیج پیش‌فرض Docker که هنگام ساخت کانتینرها استفاده می‌شود.
  • default_container_command: دستور پیش‌فرضی که روی کانتینرهای جدید اجرا می‌شود.

توجه: اگر می‌خواهید فایل Playbook را در حالت نهایی و کاملش ببینید، به مرحله ۵ بروید. فایل‌های YAML در ساختار تورفتگی‌شان حساس هستند؛ پس ممکن است بعد از افزودن همه وظایف، بخواهید Playbook خود را دوباره بررسی کنید.

مرحله ۲ — افزودن وظایف نصب پکیج‌ها به Playbook

به‌صورت پیش‌فرض، وظایف توسط Ansible به‌صورت ترتیبی و از بالا به پایین در Playbook اجرا می‌شوند. این یعنی ترتیب وظایف مهم است و می‌توانید با اطمینان فرض کنید هر وظیفه قبل از شروع وظیفه بعدی، اجرایش تمام می‌شود.

همه وظایف این Playbook می‌توانند مستقل باشند و در سایر Playbookهای شما استفاده مجدد شوند.

یک مفهوم مهم در Ansible، تکرارپذیری (Idempotency) است؛ یعنی اجرای مکرر یک Playbook همیشه به یک وضعیت سیستمی یکسان منجر می‌شود، بدون ایجاد تغییرات ناخواسته.

در این Playbook، هر وظیفه به‌صورت Idempotent نوشته شده است. مثلاً، وظایف نصب پکیج از state: latest یا state: present استفاده می‌کنند تا مطمئن شوند پکیج‌ها فقط در صورت لزوم نصب یا به‌روزرسانی شوند. به‌طور مشابه، وظایف پیکربندی مخزن و کلید فقط در صورتی تغییر ایجاد می‌کنند که از قبل در جای خود نباشند.

این موضوع Playbook را برای اجرای مجدد در هر زمان ایمن می‌کند؛ که به‌خصوص هنگام آماده‌سازی سرورهای جدید یا اعمال به‌روزرسانی روی محیط‌های موجود کاربردی است.

اولین وظایف خود را اضافه کنید: نصب aptitude (ابزاری برای تعامل با مدیر پکیج لینوکس) و نصب پکیج‌های سیستمی موردنیاز. Ansible مطمئن می‌شود این پکیج‌ها همیشه روی سرور شما نصب باشند:

playbook.yml

  tasks:
    - name: Install aptitude
      apt:
        name: aptitude
        state: latest
        update_cache: true

    - name: Install required system packages
      apt:
        pkg:
          - ca-certificates
          - curl
          - gnupg
          - software-properties-common
          - python3-pip
          - python3-venv
          - python3-setuptools
        state: latest
        update_cache: true

اینجا از ماژول داخلی apt انصیبل استفاده می‌کنید تا به Ansible دستور دهید پکیج‌هایتان را نصب کند. ماژول‌ها در Ansible میان‌برهایی برای اجرای عملیاتی هستند که در غیر این صورت باید آن‌ها را به‌صورت دستورات خام bash اجرا می‌کردید. Ansible در صورت در دسترس نبودن aptitude، به‌طور ایمن به apt برای نصب پکیج‌ها برمی‌گردد؛ اما به‌طور تاریخی aptitude را ترجیح داده است.

می‌توانید پکیج‌ها را به سلیقه خود اضافه یا حذف کنید. این کار تضمین می‌کند همه پکیج‌ها نه‌تنها موجود، بلکه در آخرین نسخه باشند و پس از فراخوانی به‌روزرسانی با apt انجام شوند.

مرحله ۳ — افزودن وظایف نصب Docker به Playbook

وظیفه شما، آخرین نسخه Docker را از مخزن رسمی نصب خواهد کرد. کلید GPG داکر برای تأیید دانلود اضافه می‌شود، مخزن رسمی به‌عنوان منبع پکیج جدید اضافه شده و Docker نصب خواهد شد. علاوه بر این، پلاگین Docker Compose و ماژول Docker برای Python هم نصب خواهند شد:

playbook.yml

    - name: Create keyrings directory
      file:
        path: /etc/apt/keyrings
        state: directory
        mode: '0755'

    - name: Download Docker GPG key
      get_url:
        url: https://docker-ce.parmincloud.ir/gpg
        dest: /etc/apt/keyrings/docker.asc
        mode: '0644'
        force: true

    - name: De-armor Docker GPG key for APT
      command: gpg --dearmor --yes --output /etc/apt/keyrings/docker.gpg /etc/apt/keyrings/docker.asc
      args:
        creates: /etc/apt/keyrings/docker.gpg

    - name: Add Docker repository
      apt_repository:
        repo: "deb [signed-by=/etc/apt/keyrings/docker.gpg] https://docker-ce.parmincloud.ir/ {{ ansible_distribution_release }} stable"
        state: present
        filename: docker

    - name: Update apt and install Docker Engine
      apt:
        pkg:
          - docker-ce
          - docker-ce-cli
          - containerd.io
          - docker-buildx-plugin
          - docker-compose-plugin
        state: latest
        update_cache: true

    - name: Install Docker Module for Python
      pip:
        name: docker
        extra_args: "--index-url https://pypi.parmincloud.ir/simple/"

این رویکرد از یک Keyring مربوط به APT به‌همراه مشخصه signed-by مخزن استفاده می‌کند که روش توصیه‌شده فعلی در نسخه‌های مدرن اوبونتو است و از ماژول منسوک apt_key اجتناب می‌کند.

Docker Compose از طریق پکیج docker-compose-plugin نصب می‌شود که سینتکس مدرن CLI یعنی docker compose را فراهم می‌کند. این جایگزین باینری مستقلِ قدیمی docker-compose در راه‌اندازی‌های قدیمی‌تر است.

توجه: با Docker Compose v2، دستورات از سینتکس یکپارچه docker compose (با فاصله) استفاده می‌کنند؛ به‌جای docker-compose قدیمی.

مرحله ۴ — افزودن وظایف ایمیج و کانتینر Docker به Playbook

ساخت واقعی کانتینرهای Docker از اینجا با دریافت (Pull) ایمیج مورد نظر Docker شروع می‌شود. به‌صورت پیش‌فرض، این ایمیج‌ها از Docker Hub رسمی می‌آیند. با استفاده از این ایمیج، کانتینرها طبق مشخصاتی که متغیرهای تعریف‌شده در بالای Playbook شما تعیین کرده‌اند ساخته می‌شوند.

قبل از افزودن این وظایف، مطمئن شوید Collection انصیبلِ community.docker روی نود کنترل شما نصب است. آن را با این دستور نصب کنید:

ansible-galaxy collection install community.docker

حالا وظایف زیر را به Playbook خود اضافه کنید:

playbook.yml

    - name: Pull default Docker image
      community.docker.docker_image:
        name: "{{ default_container_image }}"
        source: pull

    - name: Create default containers
      community.docker.docker_container:
        name: "{{ default_container_name }}{{ item }}"
        image: "{{ default_container_image }}"
        command: "{{ default_container_command }}"
        state: present
      with_sequence: count={{ container_count }}

ماژول community.docker.docker_image برای دریافت ایمیج Dockerی استفاده می‌شود که می‌خواهید به‌عنوان پایه کانتینرهایتان استفاده شود. ماژول community.docker.docker_container به شما اجازه می‌دهد مشخصات کانتینرهایی که می‌سازید را به‌همراه دستوری که می‌خواهید به آن‌ها پاس بدهید، تعیین کنید.

with_sequence روش Ansible برای ساخت حلقه است و در این مورد، ساخت کانتینرهای شما را بر اساس تعدادی که مشخص کرده‌اید حلقه می‌زند. این یک حلقه شمارشی پایه است؛ پس متغیر item اینجا عددی را فراهم می‌کند که نشان‌دهنده تکرار فعلی حلقه است. این عدد برای نام‌گذاری کانتینرهای شما استفاده می‌شود.

مرحله ۵ — بررسی Playbook کامل

Playbook شما باید تقریباً به شکل زیر باشد؛ با تفاوت‌های جزئی بسته به سفارشی‌سازی‌هایتان:

playbook.yml

---
- hosts: all
  become: true
  vars:
    container_count: 4
    default_container_name: docker
    default_container_image: hub.cr.parmincloud.ir/library/ubuntu
    default_container_command: sleep 1d

  tasks:
    - name: Install aptitude
      apt:
        name: aptitude
        state: latest
        update_cache: true

    - name: Install required system packages
      apt:
        pkg:
          - ca-certificates
          - curl
          - gnupg
          - software-properties-common
          - python3-pip
          - python3-venv
          - python3-setuptools
        state: latest
        update_cache: true

    - name: Create keyrings directory
      file:
        path: /etc/apt/keyrings
        state: directory
        mode: '0755'

    - name: Download Docker GPG key
      get_url:
        url: https://docker-ce.parmincloud.ir/gpg
        dest: /etc/apt/keyrings/docker.asc
        mode: '0644'
        force: true

    - name: De-armor Docker GPG key for APT
      command: gpg --dearmor --yes --output /etc/apt/keyrings/docker.gpg /etc/apt/keyrings/docker.asc
      args:
        creates: /etc/apt/keyrings/docker.gpg

    - name: Add Docker repository
      apt_repository:
        repo: "deb [signed-by=/etc/apt/keyrings/docker.gpg] https://docker-ce.parmincloud.ir/ {{ ansible_distribution_release }} stable"
        state: present
        filename: docker

    - name: Update apt and install Docker Engine
      apt:
        pkg:
          - docker-ce
          - docker-ce-cli
          - containerd.io
          - docker-buildx-plugin
          - docker-compose-plugin
        state: latest
        update_cache: true

    - name: Install Docker Module for Python
      pip:
        name: docker
        extra_args: "--index-url https://pypi.parmincloud.ir/simple/"

    - name: Pull default Docker image
      community.docker.docker_image:
        name: "{{ default_container_image }}"
        source: pull

    - name: Create default containers
      community.docker.docker_container:
        name: "{{ default_container_name }}{{ item }}"
        image: "{{ default_container_image }}"
        command: "{{ default_container_command }}"
        state: present
      with_sequence: count={{ container_count }}

این Playbook را آزادانه تغییر دهید تا بهترین تناسب را با نیازهای فردی شما در گردش کار خودتان داشته باشد. مثلاً، می‌توانید از ماژول docker_image برای ارسال (Push) ایمیج‌ها به Docker Hub یا از ماژول docker_container برای راه‌اندازی شبکه‌های کانتینری استفاده کنید.

توجه: این یک یادآوری ملایم است که به تورفتگی‌های خود توجه کنید. اگر به خطا خوردید، به‌احتمال خیلی زیاد مقصر همین است. YAML استفاده از ۲ فاصله به‌عنوان تورفتگی را پیشنهاد می‌کند؛ همان‌طور که در این مثال انجام شد.

وقتی از Playbook خود راضی شدید، می‌توانید از ویرایشگر متن خارج شده و فایل را ذخیره کنید.

مرحله ۶ — اجرای Playbook

اکنون آماده اجرای این Playbook روی یک یا چند سرور هستید. بیشتر Playbookها به‌صورت پیش‌فرض طوری پیکربندی می‌شوند که روی همه سرورهای Inventory اجرا شوند؛ اما این بار سرورتان را مشخص می‌کنید.

برای اجرای Playbook فقط روی server1 و اتصال به‌عنوان sammy، می‌توانید از دستور زیر استفاده کنید:

ansible-playbook playbook.yml -l server1 -u sammy

فلگ l- سرور شما و فلگ u- مشخص می‌کند با کدام کاربر به سرور راه‌دور وارد شوید. خروجی مشابه این دریافت می‌کنید:

خروجی:

. . .
changed: [server1]

TASK [Create default containers] *****************************************************************************************************************
changed: [server1] => (item=1)
changed: [server1] => (item=2)
changed: [server1] => (item=3)
changed: [server1] => (item=4)

PLAY RECAP ***************************************************************************************************************************************
server1                  : ok=10    changed=8    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

توجه: برای اطلاعات بیشتر درباره نحوه اجرای Playbookهای Ansible، راهنمای Cheat Sheet انصیبل را ببینید.

این یعنی راه‌اندازی سرور شما کامل است! خروجی شما لازم نیست دقیقاً یکسان باشد، اما مهم این است که صفر خطا داشته باشید.

وقتی اجرای Playbook تمام شد، از طریق SSH وارد سروری شوید که توسط Ansible آماده شده تا بررسی کنید کانتینرها با موفقیت ساخته شده‌اند یا نه.

با این دستور وارد سرور راه‌دور شوید:

ssh sammy@your_remote_server_ip

و کانتینرهای Docker خود را روی سرور راه‌دور فهرست کنید:

sudo docker ps -a

باید خروجی مشابه این را ببینید:

خروجی:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a3fe9bfb89cf        ubuntu              "sleep 1d"          5 minutes ago       Created                                 docker4
8799c16cde1e        ubuntu              "sleep 1d"          5 minutes ago       Created                                 docker3
ad0c2123b183        ubuntu              "sleep 1d"          5 minutes ago       Created                                 docker2
b9350916ffd8        ubuntu              "sleep 1d"          5 minutes ago       Created                                 docker1

این یعنی کانتینرهای تعریف‌شده در Playbook با موفقیت ساخته شدند. از آنجا که این آخرین وظیفه در Playbook بود، همین موضوع تأیید می‌کند که Playbook به‌طور کامل روی این سرور اجرا شده است.

عیب‌یابی خطاهای رایج

درحالی‌که این Playbook طوری طراحی شده که روی یک سیستمِ درست پیکربندی‌شده روان اجرا شود، ممکن است بسته به پیکربندی شبکه سرور، وضعیت پکیج‌های موجود یا دسترسی‌ها، گاهی با مشکلاتی روبرو شوید. این بخش رایج‌ترین مشکلاتی که ممکن است با آن‌ها روبرو شوید را پوشش داده و راهنمای گام‌به‌گام برای رفع آن‌ها فراهم می‌کند.

خطاهای کلید GPG داکر

خطاهای مربوط به کلید GPG داکر معمولاً زمانی رخ می‌دهند که Playbook نتواند کلید امضای مخزن را دانلود یا پردازش کند. این ممکن است به دلیل مشکلات اتصال شبکه، مشکلات DNS یا محدودیت‌های دسترسی فایل روی دایرکتوری /etc/apt/keyrings باشد.

اگر خطاهای کلید GPG را در خروجی Ansible دیدید، ابتدا تأیید کنید که URL کلید GPG داکر از نود مدیریت‌شده شما در دسترس است. می‌توانید این را با تلاش برای دانلود کلید با curl به‌صورت دستی تست کنید:

curl -fsSL https://docker-ce.parmincloud.ir/gpg

اگر دانلود موفق بود، برای دیدن اینکه آیا مشکل پیکربندی مخزنی باقی مانده است، سعی کنید کش apt را به‌صورت دستی به‌روز کنید:

sudo apt update

اگر مشکلات ادامه داشتند، بررسی کنید که سیستم شما دسترسی شبکه و تفکیک DNS درست دارد. می‌توانید تفکیک DNS را با nslookup docker-ce.parmincloud.ir تست کنید یا اتصال کلی را با ping 8.8.8.8 بررسی کنید.

مشکلات مخزن Docker

خطاهای پیکربندی مخزن معمولاً به شکل پیام‌های «package not found» در مرحله نصب Docker ظاهر می‌شوند. رایج‌ترین علت، عدم تطابق بین URL مخزن و نام رمز نسخه اوبونتوی شماست؛ هرچند این Playbook از ansible_distribution_release استفاده می‌کند تا نام رمز درست را به‌طور خودکار تشخیص دهد.

برای تشخیص مشکلات مخزن، منابع APT پیکربندی‌شده خود را بررسی کنید تا مطمئن شوید مخزن Docker به‌درستی اضافه شده است:

grep -r docker /etc/apt/sources.list*

باید ورودی‌ای را ببینید که شامل [signed-by=/etc/apt/keyrings/docker.gpg] و نام رمز درست برای نسخه اوبونتوی شماست (مثلاً focal برای 20.04، jammy برای 22.04 یا noble برای 24.04). اگر پیکربندی مخزن درست به نظر می‌رسد اما پکیج‌ها همچنان پیدا نمی‌شوند، sudo apt update را برای رفرش ایندکس پکیج‌ها اجرا کرده و سپس Playbook را دوباره اجرا کنید.

شکست نصب پکیج‌ها

نصب پکیج‌ها می‌تواند به چند دلیل شکست بخورد؛ از جمله تداخل با پکیج‌های موجود، نصب‌های قبلیِ نیمه‌کاره یا پایگاه داده قفل‌شده پکیج‌ها. وقتی Ansible خطاهای نصب پکیج را گزارش می‌کند، مشکل زیربنایی معمولاً با وضعیت داخلی APT است، نه خود Playbook.

برای عیب‌یابی مشکلات نصب پکیج، ابتدا مطمئن شوید کش پکیج AFT به‌روز است. کش قدیمی می‌تواند باعث شود APT به‌دنبال نسخه‌هایی از پکیج‌ها بگردد که دیگر در مخزن وجود ندارند. سپس، وابستگی‌های خراب پکیجی که ممکن است مانع نصب‌های جدید شوند را بررسی کنید:

sudo apt --fix-broken install

این دستور سعی می‌کند هرگونه نصب ناقص یا خراب پکیج روی سیستم را تعمیر کند. علاوه بر این، تأیید کنید که هیچ پروسه مدیر پکیج دیگری در پس‌زمینه در حال اجرا نیست. اگر پروسه APT دیگری فعال باشد (مثل به‌روزرسانی‌های خودکار)، پایگاه داده پکیج‌ها را قفل کرده و از اعمال تغییرات توسط Playbook شما جلوگیری می‌کند. می‌توانید پروسه‌های در حال اجرای پکیج را با ps aux | grep apt بررسی کنید.

خطای Permission denied هنگام اجرای دستورات Docker

به‌صورت پیش‌فرض، Docker برای تعامل با دیمن Docker نیازمند دسترسی‌های root است. اگر سعی کنید دستورات Docker را به‌عنوان کاربر معمولی و بدون sudo اجرا کنید، با خطاهای «permission denied» روبرو می‌شوید. درحالی‌که Playbook، Docker را با موفقیت نصب می‌کند، حساب کاربری شما را به‌طور خودکار به گروه docker اضافه نمی‌کند.

برای اجرای دستورات Docker بدون sudo، کاربر خود را به گروه docker اضافه کنید:

sudo usermod -aG docker $USER

این دستور کاربر فعلی شما را به گروه docker اضافه می‌کند؛ که اجازه ارتباط با دیمن Docker را می‌دهد. با این حال، تغییرات عضویت در گروه در نشست شل فعلی شما اعمال نمی‌شوند. باید از سیستم خارج شده و دوباره وارد شوید تا عضویت جدید گروه توسط سیستم شناخته شود. همچنین می‌توانید با newgrp docker یک نشست شل جدید با گروه‌های به‌روز شده شروع کنید.

در نظر داشته باشید که کاربرانِ گروه docker عملاً دسترسی سطح root به سیستم دارند؛ چون می‌توانند کانتینرهایی با دسترسی کامل به فایل‌سیستم اجرا کنند. فقط کاربران مورد اعتماد را به این گروه اضافه کنید.

راه‌اندازی‌نشدن سرویس Docker

اگر سرویس Docker بعد از نصب به‌طور خودکار راه‌اندازی نشد، مشکل می‌تواند مربوط به پیکربندی systemd، سرویس‌های متناقض یا محدودیت‌های منابع باشد. Docker به‌عنوان یک سرویس systemd مدیریت می‌شود؛ پس می‌توانید از ابزارهای استاندارد عیب‌یابی systemd برای تشخیص مشکل استفاده کنید.

ابتدا، وضعیت فعلی سرویس Docker را بررسی کنید تا ببینید آیا پیام‌های خطای واضحی وجود دارد:

sudo systemctl status docker

خروجی نشان می‌دهد که سرویس فعال است، شکست خورده یا متوقف شده؛ به‌همراه ورودی‌های لاگ اخیر. برای اطلاعات تشخیصی دقیق‌تر، لاگ‌های کامل سرویس Docker را با journalctl بررسی کنید:

journalctl -u docker

اگر می‌خواهید در کل تاریخچه لاگ اسکرول کنید، فلگ ‎–no-pager را اضافه کنید؛ یا از ‎-n 50 برای دیدن فقط ۵۰ خط آخر استفاده کنید. مشکلات رایج شامل تداخل پورت‌ها (اگر سرویس دیگری از پورت‌های پیش‌فرض Docker استفاده می‌کند) یا مشکلات درایور ذخیره‌سازی است.

اگر لاگ‌ها مشکل پیکربندی‌ای را که رفع کرده‌اید نشان دادند، سرویس Docker را ری‌استارت کنید:

sudo systemctl restart docker

همچنین می‌توانید با sudo systemctl enable docker مطمئن شوید Docker هنگام بوت به‌طور خودکار راه‌اندازی می‌شود.

مشکلات ماژول Python یا وابستگی‌ها

ماژول Python مربوط به Docker (نصب‌شده از طریق پکیج docker) برای تعامل Collection انصیبلِ community.docker با API داکر لازم است. شکست نصب این ماژول معمولاً ناشی از مشکلات پیکربندی pip، ناسازگاری نسخه Python یا نبود وابستگی‌های Build است.

اگر Playbook در وظیفه «Install Docker Module for Python» شکست خورد، ابتدا با تأیید نصب و کارکرد pip شروع کنید. نصب Python 3 خود را بررسی کنید:

python3 --version

ماژول Python داکر به Python 3.6 یا بالاتر نیاز دارد. اگر نسخه Python شما به‌روز است اما نصب ماژول همچنان شکست می‌خورد، آن را به‌صورت دستی نصب کنید تا خروجی خطای دقیق‌تری ببینید:

pip3 install -i https://pypi.parmincloud.ir/simple/ docker

اگر هنگام نصب با خطاهای کامپایل روبرو شدید، ممکن است سیستم شما هدرهای توسعه یا ابزارهای Build نداشته باشد. نصب پکیج python3-dev معمولاً این مشکلات را رفع می‌کند. همچنین توجه کنید که اگر از یک محیط مجازی Python استفاده می‌کنید، مطمئن شوید ماژول را در محیط درست نصب می‌کنید.

شکست اتصال Ansible

شکست اتصال زمانی رخ می‌دهد که نود کنترل Ansible شما نتواند اتصال SSH به هاست‌های مدیریت‌شده برقرار کند. این یکی از بنیادی‌ترین نیازمندی‌های کار Ansible است؛ پس مشکلات اتصال باید قبل از اینکه Playbook بتواند هر وظیفه‌ای را اجرا کند، رفع شوند.

برای تشخیص مشکلات اتصال، ابتدا تأیید کنید که می‌توانید با همان اطلاعات احراز هویتی که Ansible استفاده می‌کند، به‌صورت دستی به هاست هدف SSH بزنید:

ssh user@host

اگر دسترسی دستی SSH کار می‌کند اما Ansible همچنان در اتصال شکست می‌خورد، مشکل احتمالاً به پیکربندی Inventory انصیبل شما یا احراز هویت با کلید SSH مربوط است. فایل Inventory خود را بررسی کنید تا مطمئن شوید نام‌های میزبان یا آدرس‌های IP درست هستند و هرگونه پورت SSH سفارشی یا پارامترهای اتصال به‌درستی مشخص شده‌اند.

تأیید کنید که کلید SSH شما در SSH Agentتان بارگذاری شده: ssh-add -l. اگر کلید شما فهرست نشده، آن را با ssh-add ~/.ssh/id_rsa اضافه کنید (یا هر مسیری که به کلید خصوصی شما اشاره می‌کند). همچنین تأیید کنید که کلید عمومی مربوطه در فایل ~/.ssh/authorized_keys روی هاست مدیریت‌شده موجود است.

شکست اجرای Playbook

وقتی یک وظیفه از Playbook شکست می‌خورد، Ansible اجرا را متوقف کرده و پیام خطایی فراهم می‌کند که نشان می‌دهد کدام وظیفه شکست خورده و چرا. این پیام‌های خطا ابزار اصلی شما برای تشخیص مشکلات هستند؛ پس آن‌ها را با دقت بخوانید. خروجی خطا معمولاً شامل نام وظیفه، ماژولِ شکست‌خورده و جزئیات خاص درباره مشکل است.

برای عیب‌یابی اولیه، پیام خطا در خروجی Ansible را برای شناسایی وظیفه شکست‌خورده بررسی کنید. پیام اغلب سرنخ‌هایی درباره علت ریشه‌ای دارد؛ مانند نبودن دسترسی‌ها، URLهای غیرقابل‌دسترس یا خطاهای سینتکس در Playbook.

اگر خروجی استاندارد جزئیات کافی فراهم نمی‌کند، Playbook را در حالت Verbose اجرا کنید تا دقیقاً ببینید Ansible در پس‌زمینه چه کاری انجام می‌دهد:

ansible-playbook playbook.yml -vvv

فلگ ‎-vvv حداکثر تفصیل را فراهم می‌کند و دستورات واقعیِ در حال اجرا، خروجی کامل هر وظیفه و اطلاعات دیباگ دقیق را نشان می‌دهد. این به‌خصوص برای تشخیص مشکلات شبکه، مشکلات دسترسی یا رفتار غیرمنتظره ماژول‌ها مفید است.

قبل از اجرای مجدد Playbook، تأیید کنید که همه منابعی که لازم دارد در دسترس‌اند — URL کلید GPG داکر باید قابل دسترس باشد، هاست‌های مدیریت‌شده شما باید برای دانلود پکیج‌ها اتصال اینترنت داشته باشند و باید فضای دیسک کافی برای نصب پکیج‌ها وجود داشته باشد.

به یاد داشته باشید که چون این Playbook تکرارپذیر (Idempotent) است، بعد از رفع هر مشکلی می‌توانید آن را به‌صورت ایمن دوباره اجرا کنید. وظایفی که قبلاً با موفقیت کامل شده‌اند به‌جای changed با عنوان ok نمایش داده می‌شوند و Ansible کار خود را روی وظایفی که قبلاً شکست خورده‌ بودند از سر می‌گیرد.

سوالات متداول

۱. چه نسخه‌ای از Ansible برای اجرای این Playbook لازم است؟

هر نسخه جدید Ansible باید کار کند؛ اما Ansible نسخه 2.10 به بالا، یک توصیه پایه خوب است. آن نسخه (و نسخه‌های جدیدتر) به‌صورت پیش‌فرض از چیدمان Collectionها استفاده می‌کنند که مهم است؛ چون این راهنما برای وظایف docker_image و docker_container از Collection مربوط به community.docker استفاده می‌کند. می‌توانید نسخه نصب‌شده خود را با ansible --version روی نود کنترل تأیید کنید.

۲. آیا Playbook، Docker Compose را نصب می‌کند و کدام نسخه را نصب می‌کند؟

بله. این Playbook پکیج docker-compose-plugin را نصب می‌کند که Docker Compose نسخه v2 را فراهم می‌کند. با Compose v2، شما Compose را به‌عنوان یک زیردستور Docker اجرا می‌کنید (docker compose با فاصله)؛ به‌جای باینری مستقل قدیمی (docker-compose).

۳. چرا از Ansible برای نصب Docker استفاده کنیم به‌جای اسکریپت شل یا cloud-init؟

Ansible حفظِ تکرارپذیری و ممیزی‌پذیری راه‌اندازی سرور را آسان می‌کند. چون وظایف Idempotent هستند، می‌توانید Playbook را دوباره اجرا کنید تا سیستم‌ها را به وضعیت موردنظر همگرا کنید (مثلاً اطمینان از پیکربندی‌بودن مخزن Docker و نصب‌بودن پکیج‌های درست)؛ بدون آنکه لازم باشد بررسی‌های «از قبل پیکربندی شده؟» خودتان را بنویسید. Playbookها همچنین برای بازبینی، کنترل نسخه و گسترش در کنار سایر مراحل آماده‌سازی، راحت‌تر هستند.

۴. تکرارپذیری (Idempotent) در زمینه این Playbook به چه معناست؟

یعنی می‌توانید همان Playbook را مکرراً اجرا کنید و نتایج قابل پیش‌بینی بگیرید. هر وظیفه وضعیت فعلی سیستم را بررسی کرده و فقط در صورت لزوم تغییر ایجاد می‌کند. مثلاً، اگر Docker از قبل نصب باشد، مخزن از قبل موجود باشد و پکیج‌ها به‌روز باشند، Ansible آن وظایف را به‌صورت ok گزارش می‌کند؛ به‌جای اینکه همه‌چیز را دوباره نصب کند.

۵. آیا می‌توانم از این Playbook برای آماده‌سازی چند سرور اوبونتو به‌طور هم‌زمان استفاده کنم؟

بله. همه هاست‌های هدف را به Inventory خود اضافه کنید (مثلاً زیر یک گروه مشترک) و سپس Playbook را در برابر آن گروه اجرا کنید. Ansible وظایف را روی چند هاست به‌صورت موازی اجرا می‌کند و می‌توانید سطح موازی‌کاری را با تنظیم forks در پیکربندی Ansible خود کنترل کنید.

۶. آیا از این Playbook سفارشی استفاده کنم یا Role انصیبل گالکسیِ geerlingguy.docker؟

به اهداف شما بستگی دارد. یک Playbook سفارشی همه‌چیز را در یک جا نگه می‌دارد و دیدنِ دقیقاً چه تغییراتی در حال اعمال‌شدن است را آسان می‌کند (که برای بازبینی داخلی یا الزامات انطباق مفید است). یک Role شناخته‌شده گالکسی مانند geerlingguy.docker می‌تواند وقت شما را ذخیره کند و استفاده گسترده‌ای دارد؛ اما یک وابستگی خارجی اضافه می‌کند که باید بازبینی و به‌روز نگه داشته شود.

۷. چطور بعد از اجرای Playbook تأیید کنم که Docker درست نصب شده است؟

با SSH وارد نود مدیریت‌شده شوید و تأیید کنید Docker پاسخ می‌دهد:

  • موتور را بررسی کنید: docker --version
  • تأیید کنید دیمن در حال اجراست: sudo systemctl status docker
  • یک کانتینر تست اجرا کنید: sudo docker run hub.cr.parmincloud.ir/library/hello-world

اگر کاربر خود را به گروه docker اضافه کرده باشید، بعد از خروج و ورود مجدد می‌توانید دستورات Docker را بدون sudo اجرا کنید. برای تأیید در دسترس بودن Compose v2، دستور docker compose version را اجرا کنید.

جمع‌بندی

اتوماسیون راه‌اندازی زیرساخت شما نه‌تنها می‌تواند وقتتان را ذخیره کند، بلکه کمک می‌کند مطمئن شوید سرورهایتان از یک پیکربندی استاندارد پیروی می‌کنند که می‌توانید مطابق نیازهایتان سفارشی‌اش کنید. با ماهیت توزیع‌شده اپلیکیشن‌های مدرن و نیاز به سازگاری بین محیط‌های مختلف استaging، اتوماسیونی مانند این به بخشی مرکزی در فرایندهای توسعه بسیاری از تیم‌ها تبدیل شده است.

در این راهنما، نحوه استفاده از Ansible برای خودکارسازی فرایند نصب و راه‌اندازی Docker روی یک سرور راه‌دور در حال اجرای اوبونتو 24.04 را نشان دادید؛ شامل پشتیبانی از پلاگین مدرن Docker Compose.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا