عندما بدأت استخدام Docker لأول مرة، لم تكن أكبر أخطائي تتعلق بالأوامر أو التكوين. لقد كانت قرارات تسببت لاحقًا في حدوث مشكلات أمنية وصور منتفخة وساعات من تصحيح الأخطاء. في ذلك الوقت، كان هدفي الوحيد هو تشغيل الحاويات. لم أفكر في أفضل الممارسات أو كيف ستؤثر هذه الاختيارات المبكرة على الأداء والأمان على المدى الطويل.
من خلال الخبرة، أدركت أن Docker هو أكثر من مجرد أداة تعبئة؛ إنه سير عمل يحتاج إلى تخطيط دقيق. على الرغم من أن النقل بالحاويات يضمن بيئات متسقة ويجعل النشر أسهل، إلا أنه يقدم أيضًا تحديات مثل الثغرات الأمنية ومشاكل الشبكات وحتى التعارضات مع شبكات VPN.
في هذه المقالة، سأشارك أكبر الأخطاء التي ارتكبتها مع Docker وكيف أدى إصلاحها إلى تعزيز إنتاجيتي.
اختيار الصورة الأساسية الخاطئة
أحد أكبر الدروس التي تعلمتها في وقت مبكر هو أن الصورة الأساسية التي تختارها تؤثر على كل شيء، مثل السحب والبناء والنشر والمسح الضوئي وحتى تصحيح الأخطاء. في البداية، استخدمت صور نظام التشغيل الكاملة مثل “ubuntu:latest” لأنها ببساطة تبدو مألوفة. لكن هذه الصور الكبيرة جاءت بتكاليف خفية: عمليات بناء أبطأ، وعمليات نشر أثقل، وحاويات نهائية كبيرة الحجم.
عندما انتقلت إلى الصور البسيطة والمخصصة لهذا الغرض مثل “Alpine” أو “Slim” أو الصور الرسمية الخاصة بلغة معينة، كان الفرق فوريًا. أصبحت صوري أصغر حجمًا، وانتهت عمليات البناء بشكل أسرع، وأظهرت عمليات الفحص الأمني عددًا أقل من نقاط الضعف.
بالطبع، الحد الأدنى من الصور ليس دائمًا هو الخيار الصحيح؛ تحتاج بعض المشاريع حقًا إلى المكتبات التي تأتي مع Ubuntu أو Debian. إن الزيادة الحقيقية في الإنتاجية تأتي من اختيار الصورة الأساسية الخاصة بك عن قصد، وليس من باب العادة. اختر الصورة التي تناسب الاحتياجات الفعلية لمشروعك، وستشعر بالتحسن عبر سير العمل بأكمله.
أسرار التشفير وبيانات الاعتماد
كانت قيم تكوين الترميز الثابت واحدة من أكبر الأخطاء التي ارتكبتها في وقت مبكر. اعتدت أن أضع أشياء مثل عناوين URL لقاعدة البيانات ومفاتيح API مباشرة داخل ملف Dockerfile لأنه كان مناسبًا.
لكن القيام بذلك يعني أن تلك الأسرار تم تخزينها داخل الصورة وانتهى بها الأمر في النهاية في التحكم في الإصدار. يمكن لأي شخص لديه حق الوصول إلى الصورة أو المستودع رؤيتها، وهي مشكلة أمنية خطيرة.
الطريقة الأكثر أمانًا هي الحفاظ على ملف Dockerfile خاليًا من المعلومات الحساسة وتمرير القيم السرية الفعلية فقط عند تشغيل الحاوية. على سبيل المثال، بدلاً من كتابة قيم حقيقية داخل ملف Dockerfile، يمكنك تعيين متغيرات بيئة فارغة.
# Keep Dockerfile clean
ENV DATABASE_URL=""
ENV API_KEY=""
ثم تقوم بتوفير القيم الحقيقية في وقت التشغيل مثل هذا.
docker run -e DATABASE_URL="postgres://user:pass@localhost:5432/appdb" -e API_KEY="my_real_key_here" myapp
يؤدي ذلك إلى الاحتفاظ بالأسرار خارج الصورة، وتجنب دفع البيانات الحساسة إلى Git، وتسهيل تحديث القيم دون إعادة بناء أي شيء.
استخدام أحدث العلامات بدلاً من الإصدارات المحددة
يبدو استخدام أحدث علامة أمرًا سهلاً، ولكنه غالبًا ما يؤدي إلى تصميمات غير متوقعة. يمكن أن يتصرف نفس ملف Dockerfile بشكل مختلف من يوم لآخر لأن الصورة الأساسية تتغير بهدوء في الخلفية. على سبيل المثال، الكتابة FROM node:latest قد يعمل اليوم، ولكن غدًا يمكن لـ Docker سحب إصدار Node أحدث، وقد يفشل البناء الخاص بك دون أي تغييرات من جانبك.
أصبحت الأمور أكثر سلاسة عندما بدأت في استخدام إصدارات محددة مثل هذه.
FROM node:20
FROM python:3.10
وهذا يضمن إنشاءات مستقرة، ويجعل تصحيح الأخطاء أسهل، ويمنع المشكلات المفاجئة الناجمة عن التحديثات المخفية. كما أنه يوفر الوقت لأنك تعرف دائمًا البيئة التي يعمل عليها تطبيقك بالضبط.
مفقود أو تم تكوينه بشكل خاطئ.dockerignore
أحد الأخطاء التي ارتكبتها في وقت مبكر هو عدم استخدام ملف dockerignore. افتراضيًا، يقوم Docker بتضمين مجلد مشروعك بالكامل في سياق البناء، كل شيء بدءًا من “node_modules” و”.git” إلى الملفات المؤقتة وحتى مجموعات البيانات الكبيرة التي نسيتها. وهذا يمكن أن يجعل عمليات البناء بطيئة والصور كبيرة بشكل غير ضروري.
لتجنب مثل هذه المواقف، قم بإنشاء ملف “.dockerignore” وأخبر Docker بما لا يجب تضمينه. يوصى دائمًا بتجاهل المجلدات مثل “.git” و”node_modules” والسجلات وذاكرة التخزين المؤقت والملفات المؤقتة.

إنها خطوة صغيرة تصنع فرقًا كبيرًا.
ترتيب الطبقات غير الفعال
هناك خطأ آخر يستحق تجنبه وهو ترتيب تعليمات Dockerfile بالترتيب الخاطئ. يقوم Docker بإنشاء طبقة جديدة لكل تعليمات. إذا تغيرت الطبقة المبكرة، فسيتم إعادة بناء كل شيء بعد ذلك. في الماضي، كتبت Dockerfiles مثل هذا.
# Poor layering. Any code change forces a full rebuild
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]
هنا، COPY .. يتم وضعها في وقت مبكر جدا. حتى لو قمت بتغيير ملف JavaScript واحد، كان على Docker إعادة تثبيت جميع التبعيات لأنه تم إبطال ذاكرة التخزين المؤقت. هذا جعل بنياتي بطيئة بلا داع.
الطريقة الأفضل هي فصل التبعيات عن كود التطبيق حتى يتمكن Docker من تخزينها مؤقتًا بشكل صحيح.
# Improved layering. Dependencies are cached separately
FROM node:18-alpine
WORKDIR /app
# Copy only the dependency files first
COPY package*.json ./
RUN npm install
# Copy the rest of the application afterward
COPY . .
CMD ["npm", "start"]
ولزيادة التحسين، يمكنك تجميع التعليمات بناءً على عدد مرات تغييرها.
# System packages (hardly ever change)
RUN apk add --no-cache git bash
# App dependencies (usually change monthly)
COPY package*.json ./
RUN npm ci --only=production
# Application source code (changes frequently)
COPY . .
من خلال وضع الطبقات الأكثر استقرارًا أولاً والطبقات المتغيرة بشكل متكرر أخيرًا، يمكن لـ Docker إعادة استخدام الخطوات المخزنة مؤقتًا.
تعبئة كل شيء في مرحلة واحدة
عندما بدأت استخدام Docker لأول مرة، لم أدرك مقدار الوزن الذي أضيفه إلى صوري من خلال وضع كل شيء: أدوات التطوير، والمترجمين، ومتسابقي الاختبار، وبناء القطع الأثرية، في ملف Dockerfile واحد. لقد قمت بشحن صور ضخمة، وبطيئة في السحب، وبالتأكيد ليست صديقة للإنتاج. لم يكن من المفترض أن ينتهي الأمر بمعظم هذه الأشياء إلى الإنتاج، لكنها بقيت هناك ببساطة لأنني بنيت كل شيء في مرحلة واحدة.
بمجرد أن تعلمت كيفية عمل البناء متعدد المراحل، تغيرت الأمور على الفور. يمكنني تنفيذ جميع الخطوات الثقيلة في مرحلة واحدة ثم إنشاء صورة نهائية نظيفة ومبسطة تحتوي فقط على ما يحتاجه التطبيق للتشغيل. وهذا جعل صوري أسرع في النشر وأكثر أمانًا وأصغر بكثير.
تشغيل الحاويات كجذر
في البداية، لم أفكر كثيرًا في المستخدم الذي كانت الحاوية الخاصة بي تعمل به. يعمل Docker افتراضيًا على الوصول إلى الجذر، لذلك ذهبت معه للتو. أدركت لاحقًا أن هذا كان خطأً فادحًا. إن التشغيل كجذر يمنح الحاوية قدرًا أكبر من التحكم مما تحتاج إليه معظم التطبيقات على الإطلاق، وقد يؤدي أي خطأ بسيط في التكوين إلى تعريض نظامك لمخاطر غير ضرورية.
على سبيل المثال، يُظهر الإخراج التالي أن الحاوية تعمل كمستخدم جذر، مما يعني أنها تتمتع بامتيازات المستخدم المتميز. يمكنه تعديل مناطق النظام الحساسة، والوصول إلى أجهزة النظام، وحتى التفاعل مع المجموعات على مستوى الأجهزة، وهو ما يمثل خطرًا أمنيًا خطيرًا على أي بيئة إنتاج.

بمجرد أن فهمت ذلك، قمت بالتحويل إلى إنشاء مستخدم مخصص داخل الصورة وتشغيل التطبيق من خلال هذا المستخدم بدلاً من الجذر.
# Create a safer user and group for the app
RUN addgroup -S webgroup && adduser -S webuser -G webgroup
# Copy project files and assign correct ownership
COPY --chown=webuser:webgroup . /app
# Run the container as the non-root user
USER webuser
بهذه الطريقة، فإن استخدام مستخدم غير جذري يجعل الحاوية أكثر أمانًا، ويقلل من مخاطر الامتيازات، ويتبع أفضل ممارسات الأمان، دون إضافة تعقيد.
عدم وضع حدود للموارد
بدون حدود، يمكن للحاويات أن تستهلك جميع موارد النظام، مما يؤدي إلى إبطاء مضيفك أو تعطله. لقد واجهت هذا أثناء البناء الثقيل. أدت إحدى الحاويات الهاربة إلى توقف كل شيء.
لتجنب ذلك، قم دائمًا بتعيين حدود الموارد بحيث تظل حاوياتك ضمن الحدود الآمنة. يمكنك القيام بذلك باستخدام أعلام مثل --memory, --cpus، و --memory-swap عند بدء الحاوية. على سبيل المثال، يحدد الأمر التالي الحاوية بـ 500 ميجابايت من ذاكرة الوصول العشوائي (RAM) ويسمح لها باستخدام نواة وحدة المعالجة المركزية (CPU) واحدة فقط.
docker run --name my-app --memory="500m" --cpus="1.0" node:18-alpine
الإفراط في استخدام الوضع المميز
عندما واجهت مشاكل مع حاويات Docker لأول مرة، فكرت في استخدام --privileged كان حلاً سريعًا. شعرت وكأنه سحر، فجأة كل شيء يعمل!
docker run --privileged my-container
لكنني أدركت بسرعة أن هذا يمنح الحاوية وصولاً غير محدود تقريبًا إلى النظام المضيف. وهذا خطر أمني كبير. في كثير من الأحيان، كل ما أحتاجه هو قدرة صغيرة مثل SYS_ADMIN، وليس الوصول المميز الكامل.
docker run --cap-add=SYS_ADMIN my-container
استخدام --privileged كانت مبالغة. ولذلك، فإن منح الأذونات الضرورية فقط يبقي المضيف أكثر أمانًا مع السماح للحاوية بالعمل بشكل صحيح.
لذا، قم بتخطيط إعداد Docker الخاص بك بعناية من البداية. من خلال تجنب هذه الأخطاء الشائعة، ستصبح حاوياتك أكثر أمانًا وسرعة وأسهل بكثير في الصيانة، مما يتيح لك التركيز على إنشاء تطبيقات رائعة ونشرها بدلاً من إصلاح المشكلات باستمرار.
اكتشاف المزيد من موقع اشراقات- التقنية تشرق
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.
