SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-07

VPS-এ Ansible-এর প্রথম playbook: Ubuntu 24.04 গাইড

Ubuntu 24.04-এ pipx দিয়ে Ansible ইনস্টল করে inventory ও প্রথম playbook লিখুন। নতুন VPS harden করুন, আর Permission denied ও sudo error ঠিক করার উপায় জানুন।

যা তৈরি করবেন

একটি control machine-এ Ansible ইনস্টল থাকবে। পাশাপাশি এক বা একাধিক নতুন Ubuntu 24.04 VPS থাকবে, যেখানে stock image ছাড়া আর কিছু থাকবে না। শেষে আপনার কাছে এমন একটি inventory file থাকবে যাতে server-গুলোর নাম থাকবে, একটি ad-hoc ping থাকবে যা শুরু থেকে শেষ পর্যন্ত authentication কাজ করছে প্রমাণ করবে, এবং একটি playbook থাকবে যা নতুন VPS প্রস্তুতের পুরো checklist-কে code হিসেবে চালাবে: আপনার SSH key-সহ একটি deploy user, নিরাপদভাবে কনফিগার করা sshd, fail2ban, unattended upgrades এবং এমন একটি firewall, যা অন্য সবকিছু deny করার আগে OpenSSH অনুমোদন করবে। এটি একটি server বা বিশটি server-এ চালাতে পারবেন। এটি দুবার চালালে দ্বিতীয়বার কোনো পরিবর্তন হবে না। এটাই মূল উদ্দেশ্য।

VPS প্রস্তুত করার 15 বছরের অভিজ্ঞতায় আমি একটি বাস্তব ধরণ দেখেছি: সবাই প্রথম পাঁচটি server হাতে সেট আপ করে। তারপর ষষ্ঠ server-এ একটি weekend নষ্ট হয়, কারণ প্রথম পাঁচটিতে কী করা হয়েছিল তা কেউ মনে রাখতে পারে না। একাধিক Linux server পরিচালনা বিষয়ক survey-টি এই guide-এ আরও বিস্তৃত করা হয়েছে। একই apt install তিনটি terminal-এ লিখতে গিয়ে নিজেকে ধরার দিন এটি শুরু করুন।

Ansible আসলে কী, এক অনুচ্ছেদে

Ansible agentless। এটি পরিচালিত সার্ভারগুলোতে কোনো daemon ইনস্টল করে না। control machine সাধারণ SSH-এর মাধ্যমে সংযোগ করে, target-এ একটি ছোট Python module কপি করে, সেটি চালায়, module-এর প্রকাশ করা JSON পড়ে, তারপর module-টি মুছে দেয়। target-এর একমাত্র প্রয়োজন হলো python3, যা প্রতিটি stock Ubuntu image-এ আগে থেকেই থাকে। এখানে গুরুত্বপূর্ণ শব্দটি হলো idempotent। এর অর্থ সরল: একটি task কোনো action নয়, একটি state বর্ণনা করে। কোনো package-এর জন্য state: present-এর অর্থ হলো “এটি ইনস্টল করা আছে তা নিশ্চিত করুন”, “installer চালান” নয়। state আগে থেকেই সঠিক থাকলে Ansible কোনো পরিবর্তন করে না এবং সেটিকে ok হিসেবে রিপোর্ট করে, changed হিসেবে নয়। এই বৈশিষ্ট্যই পুরো product-এর ভিত্তি। এর কারণেই playbook পুনরায় চালানো নিরাপদ হয়, আর নিরাপদ পুনরায় চালানোই একটি shell script-কে infrastructure-এ পরিণত করে।

প্রয়োজনীয়তা এবং শুরুতেই জানা গুরুত্বপূর্ণ বিষয়

  • একটি নিয়ন্ত্রণ মেশিন: আপনার ল্যাপটপ বা একটি ছোট VPS। এখানে Ubuntu 24.04 ধরা হয়েছে; Homebrew থেকে pipx ইনস্টল করার পর macOS-এও একইভাবে কাজ করবে।
  • KVM-এ Ubuntu 24.04 চালানো এক বা একাধিক target VPS, যেগুলোতে root হিসেবে সংযোগ করা যায়। এগুলোতে কিছুই ইনস্টল করা হবে না।
  • প্রতিটি target-এ SSH key authentication। আপনার ssh command যতটা authenticated, Ansible-ও ঠিক ততটাই authenticated। ssh root@host password-এর জন্য prompt করলে Ansible ব্যর্থ হবে।
  • Ubuntu 24.04-এ pip install ansible, error: externally-managed-environment-এর কারণে বন্ধ হয়ে যায়। এটি ইচ্ছাকৃত distro policy, কোনো ত্রুটি নয়। pipx ব্যবহার করুন।
  • YAML-এ whitespace syntax-এর অংশ। ভুল indentation হলে mapping values are not allowed in this context তৈরি হয়, এবং যেকোনো জায়গায় tab character থাকলে কাজ ব্যর্থ হবে।
  • Playbook sshd-এর security configuration শক্ত করার সময় প্রতিটি target-এ একটি কার্যকর SSH session খোলা রাখুন। গ্রাহকের জন্য যে প্রতিটি lockout থেকে আমাকে পুনরুদ্ধার করতে হয়েছে, তার ক্ষেত্রে শেষ session-টি "clean থেকে পরীক্ষা করার জন্য" বন্ধ করা হয়েছিল।

ধাপ 1: pip নয়, pipx ব্যবহার করে control machine-এ Ansible ইনস্টল করুন

সাধারণভাবে প্রথমে pip3 install ansible চালানোর কথা মনে হয়। কিন্তু সত্যিকারের নতুন 24.04 image-এ সেটি এক ধাপ আগেই ব্যর্থ হয়: 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 system Python-কে externally managed হিসেবে চিহ্নিত করে (PEP 668)। তাই একই ফাইল নিয়ে pip এবং apt পরস্পরের সঙ্গে বিরোধ করতে পারে না। --break-system-packages ব্যবহার করবেন না; flag-টির নামই এর কাজ স্পষ্ট করে। সঠিক সমাধান হলো pipx। এটি Ansible-এর জন্য আলাদা isolated virtualenv তৈরি করে এবং binary-গুলো আপনার PATH-এ রাখে:

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

pipx ensurepath চালানোর পরে একটি নতুন shell খুলুন, যাতে PATH পরিবর্তন কার্যকর হয়। --include-deps কোনো আনুষ্ঠানিকতা নয়: ansible package নিজে কোনো console script সরবরাহ করে না, ansible, ansible-playbook এবং বাকি script-গুলো তার ansible-core dependency-এর entry point। তাই flag ছাড়া pipx ইনস্টলেশন প্রত্যাখ্যান করে এবং No apps associated with package ansible or its dependencies দেখায়। এছাড়া bare ansible-core নয়, ansible package ইনস্টল করুন। পূর্ণ package-এ community collection-গুলো অন্তর্ভুক্ত থাকে, আর এই playbook-এ দুটি collection-এর module ব্যবহার করা হয়েছে (ansible.posix এবং community.general)।

ansible --version

সঠিক ফলাফলের শুরুতে ansible [core 2.19.x]-এর মতো একটি লাইন থাকবে এবং এটি কোন Python-এর অধীনে চলছে তা উল্লেখ করবে। এখানে যেকোনো বর্তমান core release যথেষ্ট। কিন্তু ansible: command not found-এর অর্থ হলো ~/.local/bin এখনও আপনার PATH-এ নেই। নতুন shell খুলুন, অথবা source ~/.bashrc চালান।

এটাই সম্পূর্ণ ইনস্টলেশন। target-গুলোতে কিছুই ইনস্টল করা হবে না।

ধাপ 2: প্রতিটি target-এ SSH key access

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

এই এক লাইনে দুটি কাজ হয়: এটি password ছাড়াই key authentication কাজ করছে কি না নিশ্চিত করে এবং host key-টি known_hosts-এ সংরক্ষণ করে। এখনই এটি করুন। কারণ Ansible সংরক্ষিত নয় এমন host key-কে run-এর মাঝখানে থাকা একটি interactive prompt হিসেবে দেখায়, যা দেখতে সম্পূর্ণভাবে hang-এর মতো লাগে।

ধাপ 3: inventory, শুরুতে INI, বড় হলে YAML

inventory হলো এমন একটি text file, যেখানে Ansible যে machine-গুলোতে কাজ করতে পারে সেগুলোর তালিকা থাকে। নতুন project directory-তে inventory.ini তৈরি করুন:

[vps]
web1 ansible_host=10.0.0.10
web2 ansible_host=10.0.0.20

[vps:vars]
ansible_user=root

web1 হলো আপনার বেছে নেওয়া একটি alias। এটি output-এ দেখা যায় এবং --limit web1 দিয়ে যেটিকে target করেন। ansible_host হলো প্রকৃত address। [vps] হলো একটি group, আর [vps:vars] ওই group-এর প্রতিটি host-এর জন্য variable নির্ধারণ করে; ansible_user হলো যে user হিসেবে Ansible login করে। এর পাশে একটি ansible.cfg যোগ করুন, যাতে আর কখনও -i টাইপ করতে না হয়:

[defaults]
inventory = inventory.ini

Ansible বর্তমান directory থেকে ansible.cfg পড়ে। একই inventory YAML-এ লিখে inventory.yml নামে save করুন এবং তার বদলে ansible.cfg-কে ওই নামের দিকে নির্দেশ করুন। প্রতিটি host-এর সঙ্গে একাধিক variable থাকলে তখন এই পদ্ধতিই বেশি সুবিধাজনক:

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

দুটির কাজ একই। দুইটি server থাকলে INI দ্রুত দেখে বোঝা সহজ; বিশটি server হলে YAML ভালোভাবে scale করে। একটি বেছে নিন এবং এ নিয়ে আর ভাববেন না।

ধাপ 4: ad-hoc command, সবকিছু ঠিক আছে তা নিশ্চিত করা সবুজ pong

ansible all -m ping

এটি ICMP নয়। ping module একটি পূর্ণাঙ্গ পরীক্ষা চালায়: SSH login, module copy, target-এ Python execution এবং cleanup। সঠিক ফলাফল হলো সবুজ status; প্রতিটি host-এর জন্য একটি block:

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

সবুজ SUCCESS বোঝায় যে authentication, Python interpreter এবং transport—সবই কাজ করছে। Playbook-ও কাজ করবে। লাল UNREACHABLE! বোঝায় যে কোনো module চালানোর আগেই transport ব্যর্থ হয়েছে; সঠিক error string এবং সমাধান নিচের failure modes section-এ দেওয়া আছে। আরও দুটি গুরুত্বপূর্ণ ad-hoc command:

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

ad-hoc command একবারের কাজ ও যাচাইয়ের জন্য ব্যবহার করুন। কোনো কাজ দ্বিতীয়বার চালাতে হলে সেটি playbook-এ রাখা উচিত।

ধাপ 5: প্রথম playbook, কোড হিসেবে নতুন VPS-এর checklist

নতুন সার্ভারে প্রথম দশ মিনিটে হাতে করে আপনি যা করতেন, এটি তার সম্পূর্ণ রূপ। এটি 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 }}" দিয়ে reference করা হয়। কোনো value brace দিয়ে শুরু হলে পুরো expression quote করুন, নইলে YAML parser সেটিকে ভুলভাবে পড়তে পারে। lookup('file', ...) runtime-এ control machine থেকে আপনার public key পড়ে, তাই playbook-এ কোনো key material থাকে না।

The loop। loop: "{{ baseline_services }}" প্রতিটি item-এর জন্য service task একবার করে চালায় এবং output-এ প্রতিটি item আলাদা লাইনে দেখায়। মনে রাখুন, apt task পুরো package list একবারে গ্রহণ করে। একটি apt transaction দ্রুততর এবং package-এর জন্য এটিই preferred pattern। Loop এমন module-এর জন্য ব্যবহার করুন, যেগুলো সত্যিই একবারে একটি item নিয়ে কাজ করে।

The handler হলো যে ধারণাটি ভালোভাবে বোঝা দরকার। notify: Restart ssh-এর অর্থ “এখনই ssh restart করুন” নয়। এটি handler-কে queue করে। Handler play-এর শেষে একবার চলে, এবং notifying task সত্যিই changed report করলেই চলে। আগামীকাল playbook আবার চালালে drop-in file ইতিমধ্যে সঠিক থাকবে, copy task ok report করবে এবং sshd কখনো restart হবে না। validate: line-টি trigger-এর নিরাপত্তা নিশ্চিত করে। sshd পুরোনো file প্রতিস্থাপনের আগে file পরীক্ষা করে, তাই ভুল syntax থাকলে daemon নষ্ট না হয়ে task ব্যর্থ হবে।

PermitRootLogin prohibit-password, no নয়, ইচ্ছাকৃতভাবে। এই playbook key ব্যবহার করে root হিসেবে login করে। prohibit-password password দিয়ে root login বন্ধ করে, তবে আপনার বর্তমান login চালু রাখে। Deploy user কাজ করছে নিশ্চিত হওয়ার পরে (ssh deploy@10.0.0.10 sudo true, অর্থাৎ সরাসরি address, কারণ web1 শুধু Ansible-এর জানা একটি alias), inventory-তে ansible_user=deploy পরিবর্তন করুন এবং পরের run-এ সেটিকে no-এ আরও কঠোর করুন। এমন ক্রমে hardening করুন, যাতে আপনি সার্ভার থেকে বিচ্ছিন্ন হয়ে না পড়েন।

00- prefix গুরুত্বপূর্ণ। অধিকাংশ keyword-এর ক্ষেত্রে sshd যে occurrence প্রথমে parse করে, সেটিই গ্রহণ করে। Ubuntu-এর sshd_config নিজস্ব body-এর আগে lexical order-এ sshd_config.d/*.conf include করে। Ubuntu 24.04 cloud image-গুলোতে ওই directory-তে ইতিমধ্যে 60-cloudimg-settings.conf থাকে। Cloud-init-এর মাধ্যমে password login সক্রিয় করা provider-গুলো 50-cloud-init.conf-এর সঙ্গে PasswordAuthentication yes যোগ করে। আমাদেরটির নাম 00-hardening.conf রাখলে এটি সবার আগে sort হয় এবং উভয়টির উপর কার্যকর হয়।

Task order-ই firewall-এর নিরাপত্তা। Allow OpenSSH deny policy-সহ Enable ufw-এর আগে চলে। Ansible তালিকাভুক্ত ক্রমেই task চালায়, তাই দেয়াল ওঠার আগে প্রয়োজনীয় access পথ খোলা থাকে। এখানে কার্যকর হওয়ার জন্য fail2ban-এর কোনো configuration দরকার নেই। এর Ubuntu default configuration স্বয়ংক্রিয়ভাবে sshd monitor করে। Jail-গুলো বাস্তবে কী করে এবং কীভাবে tune করতে হয়, তা Ubuntu 24.04-এ fail2ban guide-এ আলোচনা করা হয়েছে।

ধাপ 6: --check দিয়ে dry run করুন, তারপর বাস্তবে চালান

ansible-playbook site.yml --check

Check mode সংযোগ স্থাপন করে, এটি কী করবে তা হিসাব করে, কিন্তু কোনো পরিবর্তন করে না। নিচের PLAY RECAP-এর মধ্যে changed=-এর সংখ্যা দেখুন। এটি প্রতিটি host-এ কতটি task পরিবর্তন করবে, তার সংখ্যা। একটি গুরুত্বপূর্ণ সীমাবদ্ধতা আছে: পরবর্তী কোনো task আগের task-এর পরিবর্তনের ওপর নির্ভর করলে check mode কাঠামোগতভাবে সীমিত থাকে। Ubuntu-এর standard server image-এ ufw আগে থেকেই থাকে। তাই এই playbook-এর dry run কোনো সমস্যা ছাড়াই চলে। কিন্তু ufw ছাড়া minimal image-এ check mode-এ ufw-সংক্রান্ত task ব্যর্থ হয়। কারণ check mode প্যাকেজটি বাস্তবে install করে না, ফলে module-এর call করার মতো কিছু থাকে না। এটি dry run-এর সীমাবদ্ধতা, আপনার playbook-এর bug নয়। পরিকল্পনাটি সঠিক মনে হলে:

ansible-playbook site.yml

প্রতিটি task প্রতিটি host-এর জন্য একটি line দেখায়। হলুদ হলো changed, সবুজ হলো ok, এবং recap-এর ফলাফল এমন হওয়া উচিত:

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 হলো fact-gathering, আটটি task এবং handler মিলিয়ে। আপনার changed আমার ফলাফল থেকে এক বা দুইটি ভিন্ন হতে পারে। Ubuntu-এর standard image-এ ufw এবং unattended-upgrades আগে থেকেই থাকে, আর apt এটি install করার সঙ্গে সঙ্গে fail2ban নিজে start হয়। তাই প্রথম run-এই কোনো task বৈধভাবে ok দেখাতে পারে, কারণ task যে state ঘোষণা করে, সেটি ইতিমধ্যেই বিদ্যমান। যে সংখ্যাগুলো অবশ্যই শূন্য হতে হবে, সেগুলো হলো unreachable এবং failedbecome: true সম্পর্কে একটি কথা: আপনি root হিসেবে সংযোগ করার সময় এটি শুধু আনুষ্ঠানিকতা। কিন্তু ansible_user-কে deploy-এ পরিবর্তন করার সঙ্গে সঙ্গে sudo কার্যকর হয়ে যায়। এই playbook যে NOPASSWD sudoers file install করে, সেটিই -K-কে command line থেকে দূরে রাখে। এটি না থাকলে Missing sudo password পাবেন, যা নিচে ব্যাখ্যা করা হয়েছে।

ধাপ 7: একই কমান্ড দুবার চালান, idempotence কেমন হয়

অবিলম্বে একই কমান্ড আবার চালান:

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

changed=0 এবং ok এক করে কমেছে, কারণ notification না-পাওয়া handler কখনও চলেনি। কোনো কিছু পুনরায় install করা হয়নি, sshd restart হয়নি, ufw-তেও কোনো পরিবর্তন করা হয়নি। এই কারণেই playbook একটি provisioner-এর পাশাপাশি audit হিসেবেও কাজ করে: আগামী মাসে inventory-তে web3 যোগ করে আবার চালান, নতুন box তৈরি হবে এবং পুরোনো box-গুলো যাচাই হবে। আপনি পরিবর্তন করেননি এমন কোনো box-এ changed শূন্য না হলে সেটি drift। এর অর্থ, playbook-এ যে পরিবর্তন করা উচিত ছিল, কেউ তা হাতে সম্পাদনা করেছে।

এখান থেকে একই pattern আরও বিস্তৃত হয়। পরবর্তী উপযোগী playbook-এ একই VPS-এ একটি WireGuard VPN স্থাপন করুন এবং ufw rule আরও কঠোর করুন, যাতে SSH শুধু tunnel-এর মাধ্যমে সাড়া দেয়। এরপর প্রতিটি app server-এ Docker ও Compose install করার জন্য আরেকটি playbook লিখুন। site.yml তিনটি screen ছাড়িয়ে গেলে সেটিকে roles-এ ভাগ করুন, তবে তার আগে নয়।

যে failure mode-গুলোর সঙ্গে আপনি নির্দিষ্ট error string দেখবেন

Permission denied-সহ UNREACHABLE।

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

কোনো module চলার আগেই SSH transport ব্যর্থ হয়েছে: ansible_user ভুল, ওই host-এ key কপি করা হয়নি, অথবা ভুল key offer করা হচ্ছে। সাধারণ ssh root@10.0.0.10 দিয়ে পুনরায় চেষ্টা করুন। এরপর ssh -v চালিয়ে দেখুন কোন key offer করা হয়েছিল। Password দিয়ে SSH কাজ করলেও Ansible কাজ না করলে আপনি ssh-copy-id বাদ দিয়েছেন।

sudo password অনুপস্থিত।

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

আপনি become: true সেট করেছেন, non-root user হিসেবে সংযোগ করেছেন, এবং ওই user-এর sudo ব্যবহারের জন্য password প্রয়োজন। হয় command line-এ -K (--ask-become-pass) যোগ করুন, অথবা user-এর জন্য NOPASSWD sudoers entry দিন। এই কারণেই playbook-এ deploy-এর জন্য entry ইনস্টল করা হয়, তাকে ব্যবহার করার আগেই।

error: externally-managed-environment। Ubuntu 24.04-এর system Python-এর বিরুদ্ধে pip চালিয়েছেন। এটি step 1-এ ব্যাখ্যা করা হয়েছে: pip নয়, pipx ব্যবহার করুন, এবং --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 ভুল depth-এ আছে, অথবা colon-এর পরে space নেই। Report করা line number সাধারণত ভুলটির কাছাকাছি অবস্থান নির্দেশ করে, ভুলটির সঠিক অবস্থান নয়। তাই তার আগের line-টিও পরীক্ষা করুন। এর অনুরূপ found character '\t' that cannot start any token error-এর অর্থ হলো কোথাও tab ঢুকে গেছে; YAML-এ tab নিষিদ্ধ। প্রতিবার run করার আগে ansible-playbook site.yml --syntax-check চালানো অভ্যাস করুন। YAML-এর জন্য editor-এ two-space indentation সেট করুন।

/usr/bin/python3: not found। Standard Ubuntu 24.04 image-এ এটি বিরল, তবে minimal বা netboot image-এ সাধারণ। Target-এ Python না থাকায় module execution ব্যর্থ হয়। raw module ব্যবহার করে Python bootstrap করুন। দূরের host-এ কোনো কিছু না থাকলেও কাজ করতে পারে এমন এটিই একমাত্র module: ansible all -m raw -a "apt-get update && apt-get install -y python3" --become। এরপর playbook পুনরায় চালান।

FAQ

Ansible যে সার্ভারগুলো পরিচালনা করে, সেগুলোতে কি Ansible ইনস্টল করতে হবে?

না। Ansible agent ছাড়াই কাজ করে। এটি control machine থেকে SSH-এর মাধ্যমে ছোট Python module পাঠায়, সেগুলো চালায় এবং পরে সরিয়ে দেয়। Target-এ শুধু python3 এবং SSH access থাকা দরকার। Stock Ubuntu image-এ দুটিই আগে থেকে থাকে। এই সম্পূর্ণ guide-এ একমাত্র installation আপনার control machine-এ করতে হবে।

Ansible কেন "Permission denied (publickey)" দেখায়?

Permission denied (publickey)-সহ UNREACHABLE! block-এর অর্থ হলো Ansible কিছু চালানোর আগেই SSH authentication ব্যর্থ হয়েছে। Inventory-তে ansible_user যে account-এর সঙ্গে মেলে, আপনি বাস্তবে সেই account-ই সেট আপ করেছেন কি না যাচাই করুন। সেই host-এ ssh-copy-id চালিয়েছেন কি না দেখুন। সাধারণ ssh user@host command password ছাড়াই login করতে পারে কি না পরীক্ষা করুন। সাধারণ ssh command ঠিক হলে Ansible-ও ঠিক হবে, কারণ দুটিই একই transport ব্যবহার করে।

Ansible-এ idempotent বলতে কী বোঝায়?

একটি task কোনো action নয়, বরং পছন্দসই state ঘোষণা করে। যেমন, “এই package-টি উপস্থিত থাকবে” বা “এই file-এ এই line থাকবে”। State আগে থেকেই ঠিক থাকলে Ansible কোনো পরিবর্তন করে না এবং changed-এর বদলে ok report করে। তাই playbook দ্বিতীয়বার চালালে changed=0 দেখা যায়। পুনরায় চালানো তখন ঝুঁকিপূর্ণ re-install নয়, নিরাপদ audit হিসেবে কাজ করে।

Ubuntu 24.04-এ Ansible ইনস্টল করতে pip নাকি pipx ব্যবহার করা উচিত?

pipx ব্যবহার করুন। Ubuntu 24.04 system Python-কে externally managed হিসেবে চিহ্নিত করে। তাই pip install ansible ইচ্ছাকৃতভাবেই error: externally-managed-environment error দিয়ে ব্যর্থ হয়। pipx install --include-deps ansible Ansible-কে একটি বিচ্ছিন্ন virtualenv-এ রাখে এবং ansible, ansible-playbook ও অন্যান্য command পরিষ্কারভাবে আপনার PATH-এ উপলভ্য করে।

ansible এবং ansible-core package-এর মধ্যে পার্থক্য কী?

ansible-core হলো engine এবং শুধু ansible.builtin module-এর সমন্বয়। ansible package-এ core-এর সঙ্গে বাছাই করা community collection-ও থাকে। এর মধ্যে ansible.posix (authorized_key module) এবং community.general (ufw module) অন্তর্ভুক্ত, যেগুলো এই guide-এ ব্যবহার করা হয়েছে। শুরুতে পূর্ণ package ব্যবহার করুন। নির্দিষ্ট কারণ থাকলেই core এবং হাতে বাছাই করা collection-এ সীমিত করুন।