Skip to main content
CI/CD8 min read

إصلاح أخطاء اتصال Docker Compose في CI/CD

قضيت 4 ساعات في تصحيح أخطاء 'Connection refused' في Jenkins. إليك ما تعلمته عن شبكات Docker في خطوط CI.

Part ofCloud & Infrastructure->
By Jason TeixeiraJanuary 5, 2024
DockerJenkinsCI/CDTroubleshooting
Share:
On this page

تخيل هذا السيناريو: إعداد Docker Compose يعمل بشكل مثالي على جهازك المحلي. تدفع الكود إلى CI، وفجأة تفشل جميع اختبارات التكامل مع خطأ Connection refused.

حاوية قاعدة البيانات "قيد التشغيل". حاوية API "سليمة". تبدأ عملية الاختبار. ثم لا تستطيع الاتصال بالخدمة التي تحتاجها.

يبدو هذا الفشل عشوائياً حتى تتذكر شيئاً واحداً: شبكات Docker المحلية وشبكات Docker في CI ليست نفس البيئة.

الإعداد المحلي يخدعك

على جهازك، قد تتصل بـ Postgres على localhost:5432.

داخل شبكة Compose، يجب أن تتصل حاوية أخرى عادةً بـ postgres:5432، حيث postgres هو اسم الخدمة.

في CI، قد يكون مشغل الاختبار:

  • داخل شبكة Compose
  • خارج شبكة Compose على المضيف
  • داخل حاوية خدمة CI
  • داخل منفذ Docker متداخل

تستخدم هذه الحالات الأربع أسماء مضيف مختلفة.

لهذا السبب يمكن أن يكون رابط الاتصال "صحيحاً" محلياً وخاطئاً في خط الأنابيب.

أولاً، حدد أين تعمل عملية الاختبار

قبل تغيير المنافذ، اسأل سؤالاً واحداً:

هل يعمل أمر الاختبار داخل خدمة Compose أم على مضيف CI؟

إذا كانت الاختبارات تعمل داخل Compose:

code panelTXT
DATABASE_URL=postgres://user:pass@postgres:5432/app

إذا كانت الاختبارات تعمل على مضيف CI وقامت Compose بنشر المنفذ:

code panelTXT
DATABASE_URL=postgres://user:pass@127.0.0.1:5432/app

إذا كانت الاختبارات تعمل في حاوية CI منفصلة، فقد لا يعمل أي منهما حتى يتم تكوين شبكة خدمة منصة CI.

قرار شبكة CIcompose -> tests
خدمة Composeشبكةمشغل الاختبارقاعدة بيانات

يعتمد اسم المضيف الصحيح على مكان وجود مشغل الاختبار. تعمل أسماء الخدمات داخل شبكة Compose. تعمل منافذ localhost المنشورة من المضيف.

لا تثق في depends_on كجاهزية

يمكن لـ depends_on التحكم في ترتيب البدء. لكنه لا يضمن أن Postgres أو Redis أو تطبيقك جاهز لقبول الاتصالات.

النسخة السيئة الشائعة:

code panelYAML
services:
  api:
    depends_on:
      - postgres

هذا يعني فقط أن حاوية postgres تبدأ قبل api. لا يعني أن الترحيلات تم تشغيلها. لا يعني أن TCP جاهز. لا يعني أن قاعدة البيانات قبلت المصادقة.

استخدم فحوصات الصحة أو سكريبت انتظار صريح.

code panelYAML
services:
  postgres:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 5s
      retries: 12

  api:
    depends_on:
      postgres:
        condition: service_healthy

هذا لا يحل كل مشكلة منصة CI، لكنه يزيل السباق الأكثر شيوعاً.

تحقق من فئات الفشل الأربعة

عندما أرى Connection refused، أعمل بهذا الترتيب.

فحص TCP ممل لكنه مفيد:

code panelBASH
node -e "require('net').connect(5432, process.env.DB_HOST).on('connect', () => { console.log('ok'); process.exit(0) }).on('error', e => { console.error(e.message); process.exit(1) })"

إذا فشل هذا، فإن مجموعة اختبار التطبيق الخاص بك ليست الشيء الذي يجب تصحيحه بعد.

استخدم روابط اتصال مختلفة لحدود مختلفة

نمط واحد نظيف هو جعل الحدود صريحة:

code panelENV
DATABASE_URL_INTERNAL=postgres://app:app@postgres:5432/app
DATABASE_URL_HOST=postgres://app:app@127.0.0.1:5432/app

ثم تختار مهمة CI الخاصة بك الرابط الصحيح بناءً على مكان تشغيل الأمر.

هذا أقل سحرية من محاولة جعل رابط واحد يعمل في كل مكان.

ابقِ الترحيلات منفصلة عن الجاهزية

يمكن أن تكون قاعدة البيانات سليمة قبل أن يكون المخطط جاهزاً.

إذا كان تطبيقك يحتاج إلى ترحيلات، اجعلها خطوة صريحة في خط الأنابيب:

code panelBASH
docker compose up -d postgres
docker compose run --rm migrate
docker compose run --rm test

أو قم بتشغيل الاختبارات داخل خدمة تنتظر كليهما:

  • صحة قاعدة البيانات
  • اكتمال الترحيلات
  • تحميل البيانات الأولية

وإلا ستحصل على فئة أسوأ من الفشل: أخطاء اختبار متقطعة تبدو كأخطاء تطبيق لكنها في الحقيقة سباقات إعداد.

مخرجات التصحيح التي أريدها في كل فشل CI

لا تفرط في تسريب الأسرار. اطبع شكل البيئة.

المخرجات المفيدة:

  • خدمات Docker Compose وحالتها
  • سجلات الحاوية للتبعية
  • المضيف والمنفذ المحلولين، مع إخفاء كلمة المرور
  • أسماء الشبكات
  • حالة فحص الصحة
  • حالة الترحيل

مثال:

code panelBASH
docker compose ps
docker compose logs --tail=80 postgres
docker network ls

الهدف هو جعل الفشل التالي قابلاً للتشخيص في محاولة واحدة.

الدرس الإنتاجي

ألم شبكة CI هو معاينة لألم التكامل الإنتاجي.

إذا كانت اختباراتك تعتمد على الأمل، فمن المحتمل أن عمليات النشر الخاصة بك تفعل ذلك أيضاً. اجعل حدود الخدمة صريحة. أضف فحوصات الصحة. افصل الجاهزية عن الترحيلات. سجل الحقائق الصحيحة.

هذه هي الطريقة لتحويل "يعمل على جهازي" إلى شيء يمكن لخط الأنابيب إثباته.

Reader route

article -> proof -> offer

ReadClusterProofScope

cluster

Cloud & Infrastructure

intent

CI/CD

route

next step

What to do with this

Turn the note into a build path.

If this topic maps to a real business problem, keep reading the cluster, study the academy path, or route the work into a scoped engagement.

Jason Teixeira
Written by
Jason Teixeira
Founder, Sage Ideas Studio · Principal Engineer
livebuild 5d6c8652026-08-05 06:00Z
// solo studio// no analytics resold// every commit human-reviewed