تمرین هفته ۴

در این تمرین، مفاهیم کلیدی هفته‌ی چهارم یعنی تکرارپذیری (Repeatability)، تک‌نتیجه‌بودن (Idempotency)، کار با APIها از طریق curl و jq، استانداردسازی وظایف با Makefile و مدیریت پیکربندی با Ansible را در قالب یک سناریوی واقعی DevOps پیاده‌سازی می‌کنید.

شما یک وب‌سرویس پایتونی تحت نام statusapi تحویل می‌گیرید که وضعیت سیستم و سلامت خود را از طریق REST API گزارش می‌دهد. هدف شما این است که بدون هیچ‌گونه دخالت دستی، کل فرآیند آماده‌سازی کاربر، محیط مجازی، فایل‌ها، راه‌اندازی سرویس در پس‌زمینه با systemd و فراخوانی داده‌ها با کلاینت را به‌صورت خودکار پیاده‌سازی کنید.

پیش از شروع، درس‌های این هفته به‌ویژه اصول Automation در DevOps، Automation با curl و jq، Makefile و Task Runner و آشنایی با Ansible را مرور کنید.

دیمن (Daemon) چیست؟

در سیستم‌عامل‌های شبه‌یونیکس (از جمله لینوکس)، دیمن (Daemon) به برنامه‌ای گفته می‌شود که در پس‌زمینه (Background) و بدون اتصال به یک ترمینال تعاملی (tty) اجرا می‌شود و بی‌صدا منتظر رخدادها یا درخواست‌های شبکه می‌ماند (مانند sshd، وب‌سرورها یا systemd).

اجرای دستی برنامه‌ها در پس‌زمینه با دستوراتی مانند python3 app.py & یا nohup برای محیط‌های عملیاتی نامناسب است؛ زیرا در صورت Crash یا ری‌استارت سیستم به‌طور خودکار راه‌اندازی نمی‌شوند و مدیریت چرخه‌ی حیات (Start/Stop/Restart) استانداردی ندارند. به همین دلیل مدیریت دیمن‌ها به ابزاری مانند systemd واگذار می‌شود تا اجرای پایدار، راه‌اندازی خودکار پس از خطا، ایزوله‌سازی کاربر و ثبت منظم لاگ‌ها را تضمین کند.

مشخصات فنی و استانداردهای استقرار

پیاده‌سازی شما باید دقیقاً مطابق با ساختار و مشخصات جدول زیر باشد:

پایبندی به مشخصات فنی (Technical Specifications)

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

مولفه / پارامترمقدار استاندارد الزامیتوضیحات
نام سرویس و اپلیکیشنstatusapiنام فایل سرویس: /etc/systemd/system/statusapi.service
کاربر و گروه سیستمیstatusapi:statusapiکاربر سیستمی بدون لاگین تعاملی (/usr/sbin/nologin) و بدون نیاز به Home
مسیر دایرکتوری برنامه/opt/statusapiفایل‌های پروژه باید به این مسیر کپی شده و مالکیت آن متعلق به statusapi:statusapi باشد
مسیر محیط مجازی پایتون/opt/statusapi/venvبسته‌های پایتون تنها داخل این venv نصب می‌شوند
آدرس و پورت اتصال127.0.0.1:8090سرویس فقط روی رابط Loopback محلی و پورت 8090 گوش می‌دهد
اندپوینت بررسی سلامتGET /healthبازگشت کد 200 OK با بدنه JSON به فرمت {"status": "ok"}
اندپوینت اطلاعات وضعیتGET /api/v1/statusبازگشت کد 200 OK شامل کلیدهای service, version, hostname, uptime_seconds, status
اسکریپت خودکارسازی نصبinstall.shاستقرار صفر تا صد، با ویژگی‌های Idempotency (تک‌نتیجه‌بودن) و Self-healing (خودترمیمی در صورت شکست اجرای قبلی)
اسکریپت کلاینت خط فرمانclient.shارسال درخواست با curl و تحلیل با jq با ساب‌کامندهای health و status
مدیریت وظایف پروژهMakefileتارگت‌های معتبر: install, start, stop, restart, status, client, health, ansible
اسکریپت اعتبارسنجی فایل‌هاverify.shابزار ارزیابی و تست خودکار فایل‌های پوشه‌ی assets/ پیش از ارسال PR

گام ۱ — دریافت بسته و بررسی اولیه

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

1mkdir -p ~/week-4-lab && cd ~/week-4-lab
2
3# دریافت فایل فشرده وب‌سرویس
4wget https://iut-cessa.github.io/techstack-1405-devops-docs/bin/week-4/statusapi.tar.gz
5
6# استخراج محتویات
7tar -xzvf statusapi.tar.gz

محتویات استخراج‌شده شامل دو فایل است:

  • app.py: کد وب‌سرویس نوشته‌شده با Flask
  • requirements.txt: نیازمندی‌های پایتون (Flask==3.0.3)

راه‌اندازی آزمایشی و محلی

محیط‌های مجازی پایتون (venv) و استفاده از هوش مصنوعی

محیط مجازی پایتون (Virtual Environment یا venv) ابزاری برای ایزوله‌سازی بسته‌ها و نیازمندی‌های پروژه‌های پایتونی از پکیج‌های عمومی سیستم‌عامل است تا نسخه‌های مختلف کتابخانه‌ها با سیستم یا سایر پروژه‌ها تداخل پیدا نکنند.

از آنجا که توسعه با پایتون و سازوکار داخلی venv در سرفصل‌های اصلی این دوره DevOps قرار ندارد و خارج از دامنه (Out of scope) محسوب می‌شود:

  1. برای مطالعه‌ی تکمیلی و آشنایی با چرایی و نحوه‌ی کارکرد محیط‌های مجازی، مقاله‌ی زیر را مطالعه کنید:
  1. استفاده آزاد از هوش مصنوعی: در نوشتن بخش‌های مرتبط با پایتون و venv (مانند دستورات ایجاد محیط مجازی و نصب requirements در اسکریپت Bash) مجازید از ابزارهای هوش مصنوعی استفاده کنید. تمرکز این تمرین روی اتوماسیون فرآیندها در لینوکس، مدیریت سرویس با systemd و اصول Idempotency و Self-healing است.

پیش از شروع اسکریپت‌نویسی سیستمی، یک محیط مجازی موقت در دایرکتوری کار بسازید و برنامه را به‌صورت دستی تست کنید:

 1# نصب پکیج venv در صورت عدم وجود روی سیستم
 2sudo apt update && sudo apt install -y python3-venv python3-pip curl jq
 3
 4# ساخت venv موقت و نصب بسته‌ها
 5python3 -m venv test-venv
 6source test-venv/bin/activate
 7pip install -r requirements.txt
 8
 9# اجرای برنامه
10python3 app.py

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

1curl -s http://127.0.0.1:8090/health
2curl -s http://127.0.0.1:8090/api/v1/status | jq .

پس از اطمینان از عملکرد، با فشردن Ctrl+C پروسه را خاتمه دهید و با دستور deactivate از محیط مجازی آزمایشی خارج شوید. محیط موقت test-venv را حذف کنید:

1rm -rf test-venv

نتایج پاسخ‌های دریافتی از دو اندپوینت و نسخه پایتون ماشین خود را در گزارش 01-manual-test.md یادداشت کنید.


گام ۲ — خودکارسازی استقرار با install.sh (اصول Idempotency و Self-healing)

اکنون باید اسکریپت install.sh را بنویسید. این اسکریپت قلب تمرین است و باید تمام مراحل نصب را از ابتدا تا انتهای بالا آمدن سرویس انجام دهد. در نوشتن این اسکریپت باید دو اصل مهندسی را مدنظر داشته باشید:

  • تک‌نتیجه‌بودن (Idempotency): اجرای دوباره‌ی اسکریپت روی سامانه‌ای که قبلاً با موفقیت نصب شده، نباید هیچ خطایی ایجاد کند یا وضعیت مطلوب را به هم بزند.
  • خودترمیمی (Self-healing): اگر اجرای قبلی به دلیلی در میانه‌ی راه متوقف شده باشد (مثلاً به دلیل نبود پکیج، قطع اتصال، یا وجود فایل‌های نیمه‌کاره و خراب)، اجرای مجدد اسکریپت باید وضعیت خراب را تشخیص داده، آن را ترمیم یا پاک‌سازی کند و سیستم را به وضعیت سالم نهایی برساند.

الزامات اسکریپت install.sh:

  1. با #!/usr/bin/env bash آغاز شود و دستور set -euo pipefail در ابتدای آن قرار گیرد.
  2. دسترسی root را بررسی کند؛ اگر بدون sudo اجرا شد، پیامی در stderr چاپ کرده و با کد خروج غیرصفر خارج شود.
  3. پکیج‌های پیش‌نیاز سیستم‌عامل (python3, python3-venv, curl) را بررسی کند یا در صورت عدم وجود، به‌صورت خودکار با apt-get نصب نماید.
  4. کاربر و گروه سیستمی statusapi:
    • اگر این کاربر وجود ندارد، آن را با شل غیرتعاملی (/usr/sbin/nologin) بسازد.
    • نکته تک‌نتیجه‌بودن: اگر کاربر از قبل ساخته شده بود، اسکریپت نباید با خطا متوقف شود.
  5. دایرکتوری برنامه و انتقال فایل‌ها:
    • دایرکتوری /opt/statusapi را بسازد.
    • فایل‌های app.py و requirements.txt را از محل اجرای اسکریپت به /opt/statusapi/ منتقل یا کپی کند.
  6. محیط مجازی پایتون و پیاده‌سازی Self-healing:
    • محیط مجازی را در مسیر مشخص /opt/statusapi/venv بسازد (برای نوشتن دستورهای کار با venv در Bash می‌توانید از هوش مصنوعی کمک بگیرید).
    • الزام خودترمیمی: وجود دایرکتوری را به‌تنهایی نشانه‌ی سلامت venv ندانید (زیرا اگر اجرای قبلی پایتون نیمه‌کاره متوقف شده باشد، پوشه ایجاد می‌شود اما باینری pip ساخته نمی‌شود). اسکریپت باید سلامت venv را علاوه بر بررسی وجود فایل /opt/statusapi/venv/bin/pip، با بررسی امکان ایمپورت شدن فریم‌ورک اصلی وب‌سرویس (/opt/statusapi/venv/bin/python -c "import flask") نیز ارزیابی کند؛ اگر ساختار venv ناقص بود یا پکیج قابل ایمپورت نبود، محیط را ترمیم یا بازسازی کند.
    • پکیج‌های موجود در /opt/statusapi/requirements.txt را با استفاده از باینری pip محیط مجازی (/opt/statusapi/venv/bin/pip) نصب کند.
    • تمام دایرکتوری /opt/statusapi و محتویات آن را در مالکیت کاربر statusapi:statusapi قرار دهد.
  7. پیکربندی و راه‌اندازی systemd unit:
    • فایل /etc/systemd/system/statusapi.service را ایجاد کرده یا کپی کند.
    • سرویس باید دارای ساختار استاندارد زیر باشد:
 1[Unit]
 2Description=Status API Daemon
 3After=network.target
 4
 5[Service]
 6Type=simple
 7User=statusapi
 8Group=statusapi
 9WorkingDirectory=/opt/statusapi
10ExecStart=/opt/statusapi/venv/bin/python /opt/statusapi/app.py
11Restart=always
12RestartSec=3
13Environment=PYTHONUNBUFFERED=1
14
15[Install]
16WantedBy=multi-user.target
  1. دستور systemctl daemon-reload را اجرا کند.
  2. سرویس را فعال و بلافاصله اجرا کند (systemctl enable --now statusapi).
  3. با استفاده از curl یا بررسی وضعیت سیستم، سلامت سرویس را بررسی کرده و پیام موفقیت‌آمیز چاپ کند.
آزمون Idempotency و Self-healing

اسکریپت خود را در دو سناریو بیازمایید:

  1. تک‌نتیجه‌بودن: دو بار متوالی sudo ./install.sh را اجرا کنید. بار دوم باید سریع، بدون خطا و با کد خروج 0 تمام شود.
  2. خودترمیمی: عمداً پوشه‌ی venv را به‌صورت ناقص درآورید (مثلاً باینری pip یا پکیج flask را حذف کنید) و دوباره sudo ./install.sh را اجرا کنید. اسکریپت باید بتواند سلامت venv و قابلیت import فریم‌ورک را ارزیابی کرده و به‌صورت خودکار محیط را ترمیم و راه‌اندازی کند.

پس از پیاده‌سازی و اجرای اسکریپت، وضعیت سرویس را با systemctl status statusapi بررسی کرده و خروجی را در 02-installation.md مستند کنید.


گام ۳ — پیاده‌سازی کلاینت خط فرمان (client.sh)

یک کلاینت Bash به نام client.sh بسازید که کارشناس عملیات بتواند با استفاده از آن به‌سرعت وضعیت سرویس را بدون تایپ دستورهای طولانی بررسی کند. این اسکریپت از curl و jq استفاده می‌کند.

الزامات اسکریپت client.sh:

  1. دارای #!/usr/bin/env bash و set -euo pipefail.
  2. بررسی وجود ابزارهای curl و jq.
  3. پشتیبانی از دو ساب‌کامند:
    • ./client.sh health:
      • درخواست به http://127.0.0.1:8090/health
      • بررسی کد وضعیت HTTP: اگر سرویس فعال بود و پاسخ 200 داد، دقیقاً عبارت OK: Service is healthy را در خروجی استاندارد چاپ کند و با کد خروج 0 تمام شود (جریان stderr باید خالی بماند).
      • در صورت بروز خطا (عدم دسترسی به سرویس، Timeout یا کد خطای غیر 200)، پیام خطا به stderr فرستاده شده و با کد خروج 1 خاتمه یابد.
    • ./client.sh status:
      • درخواست به http://127.0.0.1:8090/api/v1/status
      • چاپ یک گزارش خوانا برای انسان از فیلدهای خروجی که حتماً شامل خطی با شروع Service: باشد (مانند Service: statusapi).
      • در خط پایانی، چاپ یک شیء JSON فشرده با دستور jq -c شامل دقیقاً کلیدهای: service, status, uptime_seconds
      • خروج با کد 0 در صورت موفقیت و کد 1 در صورت عدم اتصال (با چاپ پیام خطا در stderr).
  4. اگر آرگومان نامعتبر یا خالی داده شد، متنی حاوی راهنمای Usage را فقط در stderr چاپ کرده و با کد خروج 2 تمام شود (خروجی stdout باید خالی بماند).

خروجی اجرای هر دو حالت و یک حالت خطادار (مثلاً هنگام متوقف بودن سرویس) را در 03-client.md قرار دهید.


گام ۴ — استانداردسازی با Makefile

همان‌طور که در درس Makefile دیدید، یک تسک‌رانر به اعضای تیم اجازه می‌دهد بدون حفظ کردن دستورات پیچیده، کارهای روتین را با یک رابط یکنواخت پیش ببرند.

در ریشه‌ی پروژه یک فایل Makefile بسازید که شامل تارگت‌های زیر باشد:

 1.PHONY: install start stop restart status client health ansible
 2
 3install:
 4	sudo ./install.sh
 5
 6start:
 7	sudo systemctl start statusapi
 8
 9stop:
10	sudo systemctl stop statusapi
11
12restart:
13	sudo systemctl restart statusapi
14
15status:
16	systemctl status statusapi
17
18client:
19	./client.sh status
20
21health:
22	./client.sh health
23
24ansible:
25	ansible-playbook -i ansible/inventory.ini ansible/playbook.yml

مطمئن شوید دستورات Makefile تورفتگی با کاراکتر واقعی Tab دارند. اجرای make install و make client را آزمایش کرده و گزارش کارکرد آن را در 04-makefile.md ثبت کنید.


گام ۵ — استقرار به روش Declarative با Ansible (اختیاری)

اگر مایلید مهارت Configuration Management خود را محک بزنید و درس آشنایی با Ansible را عمیق‌تر تمرین کنید، تمام فرآیند نصب گام ۲ را به یک Playbook انسیبل تبدیل کنید.

ساختار پوشه Ansible

یک پوشه به نام ansible/ در مسیر تمرین بسازید:

  • ansible/inventory.ini: تعریف هاست محلی:
    1[local]
    2localhost ansible_connection=local
  • ansible/playbook.yml: یک Playbook با become: yes که تسک‌های زیر را با ماژول‌های استاندارد Ansible اجرا می‌کند:
    • نصب پیش‌نیازها با ماژول apt (python3-venv)
    • ساخت کاربر و گروه سیستمی با ماژول user و group
    • ساخت دایرکتوری /opt/statusapi با ماژول file
    • انتقال فایل‌های app.py و requirements.txt با ماژول copy
    • ایجاد محیط مجازی و نصب وابستگی‌ها با ماژول pip
    • قرار دادن فایل واحد با ماژول copy در /etc/systemd/system/statusapi.service
    • فعال‌سازی و استارت سرویس با ماژول systemd (daemon_reload: yes, state: started, enabled: yes)

اجرای این پلی‌بوک:

1ansible-playbook -i inventory.ini playbook.yml

اگر پلی‌بوک را برای بار دوم اجرا کنید، تمام مراحل باید وضعیت ok داشته باشند و خروجی گزارش دهد: changed=0. خروجی اجرای اول و اجرای دوم پلی‌بوک را در 05-ansible.md قرار دهید.


گام ۶ — خودآزمایی و ارزیابی فایل‌ها با verify.sh

برای اطمینان از صحت کامل عملکرد اسکریپت‌ها، رعایت ساختارها و پاس‌شدن سناریوهای تکرارپذیری، یک اسکریپت اعتبارسنجی جامع به نام verify.sh در اختیارتان قرار داده شده است. این اسکریپت فایل‌های داخل پوشه‌ی assets/ شما را به همان صورتی که اسکریپت‌های داوری ارزیابی می‌کنند، تست خواهد کرد.

هشدار مهم درباره‌ی اجرای verify.sh

اسکریپت verify.sh در فرآیند راه‌اندازی و پاک‌سازی خود، تمام ردپای سرویس statusapi (پروسه‌ی در حال اجرا، لینک‌ها و فایل unit در systemd، پوشه‌ی /opt/statusapi و کاربر و گروه سیستمی statusapi) را حذف می‌کند تا استقرار را از نقطه صفر و بدون وابستگی به داده‌های قبلی آزمایش کند.

این اسکریپت را ترجیحا داخل ماشین مجازی آزمایشی دوره (VM) اجرا کنید، نه روی سیستم اصلی.

دریافت و اجرای اسکریپت:

1# دریافت اسکریپت تستر
2wget https://iut-cessa.github.io/techstack-1405-devops-docs/bin/week-4/verify.sh
3
4# دادن مجوز اجرایی
5chmod +x verify.sh
6
7# اجرای تست روی پوشه‌ی assets
8./verify.sh assets

یا اگر فایل‌ها در مسیر دیگری قرار دارند:

1./verify.sh /path/to/<your-github-username>/4/assets

مواردی که verify.sh بررسی می‌کند:

  1. تحلیل ایستا (Static Analysis): وجود کلیه‌ی فایل‌های مورد نیاز، صحت سینتکس Bash (bash -n)، رعایت shebang، فعال بودن set -euo pipefail، وجود گارد روت، تورفتگی‌های Tab در Makefile، صحت ساختار statusapi.service و بررسی کیفیت کد با shellcheck.
  2. آزمون گارد روت: ممانعت از اجرای غیرمجاز install.sh بدون دسترسی root و هدایت خطا به stderr.
  3. استقرار اولیه و تک‌نتیجه‌بودن (Idempotency): اجرای بار اول و دوم install.sh و اطمینان از موفقیت هر دو با کد خروج 0.
  4. سناریوهای خودترمیمی (Self-healing): شبیه‌سازی شرایط خرابی (مانند خالی‌ماندن دایرکتوری venv، حذف باینری pip، یا آسیب دیدن پکیج Flask) و اطمینان از اینکه install.sh محیط را ترمیم می‌کند.
  5. رفتار کلاینت (client.sh): آزمون ساب‌کامندهای health و status، دریافت کد خروج 2 برای ورودی‌های نامعتبر، و دریافت کد خروج 1 به همراه پیام در stderr هنگام خاموش بودن سرویس.
  6. تارگت‌های Makefile: اجرای بدون خطای make health و make client.
  7. استقرار و Idempotency با Ansible (در صورت وجود): اجرای متوالی Playbook و اطمینان از بازگشت changed=0 در اجرای دوم.

در صورت قبولی، در انتهای خروجی پیام سبز رنگ زیر نمایش داده می‌شود:

1  checks: XX; passed: XX; failed: 0
2  RESULT: PASSED

گام ۷ — ساختار تحویل و Pull Request

مستندات و فایل‌های مربوط به این تمرین را در فورک مخزن تمرین‌ها، روی شاخه‌ی week-4 و با ساختار دایرکتوری زیر قرار دهید:

 1<your-github-username>/
 2└── 4/
 3    ├── 01-manual-test.md
 4    ├── 02-installation.md
 5    ├── 03-client.md
 6    ├── 04-makefile.md
 7    ├── 05-ansible.md (اختیاری)
 8    └── assets/
 9        ├── install.sh
10        ├── client.sh
11        ├── statusapi.service
12        ├── Makefile
13        └── ansible/ (در صورت انجام بخش اختیاری)
14            ├── inventory.ini
15            └── playbook.yml

چک‌لیست - نمایشی

پیش از ارسال نهایی PR، مطمئن شوید تمام موارد زیر را بررسی کرده‌اید:

  • وب‌سرویس روی پورت 8090 و فقط روی 127.0.0.1 پاسخ می‌دهد.
  • اسکریپت install.sh با set -euo pipefail نوشته شده و نیاز به مجوز root دارد.
  • پروسه پایتون با کاربر سیستمی و غیر لاگین statusapi اجرا می‌شود (نه با root).
  • اجرای دو بار متوالی sudo ./install.sh بدون خطا و با کد خروج 0 پایان می‌یابد (آزمون Idempotency).
  • اسکریپت install.sh در صورت وجود دایرکتوری ناقص یا نامعتبر (مانند نبود باینری pip یا عدم امکان import پکیج flask)، آن را به‌صورت خودکار ترمیم و بازسازی می‌کند (Self-healing).
  • اسکریپت client.sh از کدهای وضعیت HTTP و jq برای بررسی پاسخ استفاده می‌کند.
  • فایل Makefile وظایف اصلی را با کاراکترهای Tab استاندارد اجرا می‌کند.
  • (اختیاری) پلی‌بوک انسیبل در اجرای مجدد changed=0 را نشان می‌دهد.
  • اسکریپت verify.sh را روی پوشه‌ی assets/ اجرا کرده‌ام و نتیجه‌ی RESULT: PASSED دریافت شده است.
  • تمام فایل‌های اسکریپت و کانفیگ درون پوشه assets/ تحویل داده شده‌اند.
  • Pull Request مربوط به هفته‌ی ۴ در گیت‌هاب ایجاد شده است.