يعتمد المثال على خادم Python يقرأ عدد الملاحظات من PostgreSQL، ونريد تشغيل المكونات نفسها عند كل عضو في الفريق. سنصف البناء والإعدادات والشبكة والبيانات الأولية باستخدام Docker وCompose، ثم نحدد ما يجب فحصه بعد التشغيل. التجربة محلية، وخادمها التعليمي ليس إعداد إنتاج؛ وجود الحاويتين لا يثبت جاهزية القاعدة أو صحة الاتصال.

جهّز أربعة ملفات وملف إعداد محليًا

أنشئ compose.yaml وDockerfile وapp.py وinit.sql. ضع كلمة مرور محلية طويلة مولّدة في .env تحت المفتاح POSTGRES_PASSWORD، واستبعد هذا الملف من Git. ارفع .env.example باسم المفتاح فقط وتعليمات ملئه، دون كلمة مرور مستخدمة. لا تضع قواعد إنتاج أو بيانات طلاب في تجربة التشغيل الأولى.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: demo
      POSTGRES_USER: demo
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set a local password}
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U demo -d demo"]
      interval: 3s
      timeout: 3s
      retries: 20
  web:
    build: .
    environment:
      PGHOST: db
      PGDATABASE: demo
      PGUSER: demo
      PGPASSWORD: ${POSTGRES_PASSWORD:?Set a local password}
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:8000:8000"
volumes:
  db_data:

اسم db هو عنوان الخدمة داخل شبكة Compose، بينما 127.0.0.1:8000 هو منفذ الويب على جهازك. لا نفتح منفذ قاعدة البيانات إلى الشبكة الخارجية. توضح وثائق Docker أن بدء الحاوية ليس مساويًا لجاهزية الخدمة، لذلك نعتمد service_healthy بعد فحص الجاهزية.

ابنِ صورة التطبيق وقراءة فعلية من القاعدة

FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir "psycopg[binary]==3.3.6"
COPY app.py .
CMD ["python", "app.py"]

الإصدار مثبت هنا كي يكون المثال واضحًا، وليس إعلانًا بأنه أحدث إصدار. راجع التحديثات قبل استعمال أطول، وثبّت صورك بالبصمة إذا احتجت إعادة بيئة بعينها بدقة. يشرح دليل Psycopg خيار الحزمة الثنائية ومتطلبات النظام. محتوى app.py:

import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import psycopg

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path != "/health":
            self.send_error(404)
            return
        try:
            with psycopg.connect(connect_timeout=3) as connection:
                count = connection.execute(
                    "SELECT COUNT(*) FROM notes").fetchone()[0]
            body = json.dumps({"database": "ready", "notes": count}).encode()
            status = 200
        except psycopg.Error:
            body = b'{"database":"unavailable"}'
            status = 503
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

ThreadingHTTPServer(("0.0.0.0", 8000), Handler).serve_forever()

الخادم تعليمي محلي، ويعيد فشلًا واضحًا عند تعذر القراءة دون كشف كلمة المرور أو نص الخطأ. في init.sql ضع:

CREATE TABLE notes (
  id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  title text NOT NULL
);
INSERT INTO notes(title) VALUES ('First demo note');

شغّل وافحص وظيفة النظام

docker compose config --quiet
docker compose up --build -d
docker compose ps
curl -i http://127.0.0.1:8000/health
docker compose logs --tail 30 web
docker compose down

تحقق من رد 200 ومن جسم يبين أن القاعدة جاهزة وبها سجل التجربة عند تهيئة volume جديد. ثم أوقف خدمة القاعدة في تجربتك المحلية وافحص أن الويب يعيد 503؛ لا تكتفِ بأن الحاويتين تحملان حالة تشغيل. لا تعرض النتيجة المتوقعة بوصفها نتيجة فعلية في التقرير قبل تنفيذ الأوامر.

افهم البيانات التي تبقى بين التشغيلات

ينفذ مسار التهيئة عند إنشاء بيانات PostgreSQL لأول مرة، ولا يعيد إنشاء الجداول مع كل تشغيل لقاعدة مهيأة سابقًا. وتبقى البيانات في volume المسمى عند إيقاف الخدمات بالطريقة المعتادة. لذلك تعديل init.sql ليس نظام migrations. سجّل حالة البيانات التي يحتاجها الاختبار، وضع ترحيلات واضحة للتغييرات اللاحقة بدل مسح التخزين لإخفاء المشكلة.

لا تحذف volumes تحتوي بيانات مهمة لتجربة المثال. إذا احتجت بيئة نظيفة، أنشئ مشروع Compose تجريبيًا مستقلًا أو نسخة بيانات مصرحًا بإزالتها، وافهم أثر أي أمر حذف قبل تنفيذه. احتفظ بنسخة احتياطية وخطة استعادة عندما يخرج الاستخدام من التجربة المحلية.

ماذا توثق للفريق؟

سجّل إصدار Docker وCompose ومتطلبات الموارد وأسماء المتغيرات وطريقة التهيئة والفحص والإيقاف، وبيّن ما يبقى محفوظاً. نجح فحص docker compose config --quiet وتحليل صياغة app.py على Python 3.12.10. توفر Docker Client 29.2.1، لكن daemon لم يكن متاحاً؛ لذلك لم تُبن الصور أو تُشغل الحاويات أو يُختبر اتصال القاعدة. ولطلب إعداد بيئة المشروع البرمجي، أرفق ملفات البناء والإعداد وما ظهر عند محاولة التشغيل.

المصادر

مراجعة المصادر: .

اختبار المثال وحدوده

نجح docker compose config --quiet على إعداد المثال، ونجح تحليل صياغة app.py على Python 3.12.10. Docker Client 29.2.1 موجود، لكن daemon غير متاح؛ لم يُختبر بناء الصور أو اتصال PostgreSQL وتشغيل الحاويات.

مقالات ذات صلة

الخدمة المرتبطة: تطوير المشاريع البرمجية الجامعية.

أرسل متطلبات مشروعك