المفاهيم
هنفهم إيه؟ لو التطبيق شغال على جهازك وفشل بعد النشر، هتتعلم تثبت طريقة تشغيله، تبني artifact واحداً، وتروّجه بين البيئات مع مراقبة التغيير. هنغطي containers و/ وdeployments، مع التركيز على مشاكل الجاهزية، الأسرار، وترحيل قاعدة البيانات.
قبل ما تبدأ: image حزمة تشغيل، وcontainer عملية تعمل منها، وpipeline خطوات آلية للبناء والفحص والنشر. اعرف أوامر الطرفية الأساسية، والفرق بين كود التطبيق وإعدادات البيئة. أمثلة Docker تستخدم Bash؛ راجع الأوامر قبل تشغيلها على مشروعك.
المصطلحات اللي تحتها خط منقّط تقدر تضغط عليها لمعرفة معناها، وترجع تكمل من نفس مكانك.
#Containers و VMs: بتعزل إيه؟Containers and VMs: what is isolated?
مشكلة «شغال عندي» بتقل لما تشحن التطبيق مع runtime و dependencies في image معروفة. الـ container process معزول بيشارك kernel الـ host؛ الـ عندها guest و kernel خاص. Linux containers على Windows عادة بتشتغل جوه Linux VM، مش على Windows kernel مباشرة.
الـ VM شبه بيت مستقل بمرافقه، والـ container شبه شقة بحدود منفصلة ومرافق مشتركة. التشبيه يشرح التكلفة، لكن مش ضمان أمان.
| المقارنة | Container | VM |
|---|---|---|
| الوحدة | processes و filesystem معزولة | آلة افتراضية بنظام تشغيل |
| الكثافة | عادة أخف وأسرع في البدء | تكلفة guest OS أكبر |
| التوافق | محتاج kernel و architecture متوافقين | مرونة أكبر في guest OS |
container مش sandbox كامل ضد كل تهديد، ومش backup ولا orchestrator. ماتستخدمش privileged mode لمجرد حل permission error؛ افهم الـ mount والـ user المطلوبين.
#Images و Layers و Volumes و NetworksImages, layers, volumes and networks
الـ image قالب مكوّن من layers، والـ container بيضيف writable layer مؤقتة. الـ tag اسم ممكن يتغير؛ digest بيحدد المحتوى. layers بتتشارك وبتتخزن في build cache، لكن secret اتحذف في layer جديدة ممكن يفضل موجود في layer قديمة.
الأوامر دي لـ Bash مع Docker، بعد وجود image محلية اسمها store-api:study. التطبيق بيسمع على 8080.
docker network create store-backend # (1)
docker volume create store-data # (2)
docker run -d --name store-api --network store-backend \
-p 127.0.0.1:8080:8080 store-api:study # (3)
docker logs store-api
docker inspect store-api
docker stats --no-stream store-api
- (1) network خاصة بتدي containers discovery بالأسماء. اسم db جوه network مش localhost؛ localhost هو الـ container نفسه.
- (2) volume بتعيش مستقلة عن container؛ إنشاءها لوحده مش بيعمل mount، هنربطها بالـ database في Compose.
- (3) نشر البورت على loopback للـ host. EXPOSE في Dockerfile توثيق بس، مش نشر للبورت.
bind mount بيربط path من الجهاز، و volume Docker بيديرها. الاتنين مش بديل عن backup واختبار restore. logs تروح stdout و stderr، مش ملفات جوا writable layer.
#Dockerfile متعدد المراحل لـ ASP.NET Core 10A multi-stage ASP.NET Core 10 Dockerfile
الشحن بالـ بيزود حجم وسطح هجوم من غير فايدة وقت التشغيل. المثال لـ واحدة اسمها Store.Api.csproj في build context root، من غير project references أو central package files. لو عندك dependencies في projects تانية، انسخ ملفاتها وملفات restore configuration قبل restore. حط bin و obj و.git وملفات الأسرار في .dockerignore.
FROM mcr.microsoft.com/dotnet/sdk:10.0-noble AS build
WORKDIR /src
COPY Store.Api.csproj ./
RUN dotnet restore Store.Api.csproj # (1)
COPY . .
RUN dotnet publish Store.Api.csproj -c Release --no-restore \
-o /out /p:UseAppHost=false # (2)
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled-extra
WORKDIR /app
COPY --from=build /out/ ./
USER $APP_UID # (3)
ENV ASPNETCORE_HTTP_PORTS=8080
EXPOSE 8080
ENTRYPOINT ["dotnet", "Store.Api.dll"] # (4)
- (1) restore layer بتتعمل من جديد لما dependency inputs تتغير، مش عند كل تعديل source.
- (2) publish Release بيطلع ناتج framework-dependent؛ الـ SDK والـ source مش بيتنسخوا للمرحلة النهائية.
- (3) مستخدم app الموجود في images الحديثة بيشغل التطبيق من غير root. أي writable directory لازم تدي له الصلاحيات المناسبة.
- (4) exec-form ENTRYPOINT بيوصل signals للـ dotnet process مباشرة.
chiseled مافيهاش shell أو package manager؛ نسخة extra فيها dependencies للـ globalization زي ICU و tzdata. ماتكتبش healthcheck بـ curl أو CMD-SHELL من غير binary موجود. استخدم probe خارجي. في releases حقيقية ثبّت base images بالـ digest وجدول تحديثها وفحصها؛ version tags هنا للتوضيح. توثيق chiseled.
#SDK container publishing من غير DockerfileSDK container publishing without a Dockerfile
لو صورة التطبيق محتاجة ناتج publish فوق base image بس، الـ يقدر يبنيها من غير Dockerfile. المثال Bash لـ project من الكارت اللي فات، مع 10 SDK و local Docker daemon.
dotnet publish Store.Api.csproj -c Release --os linux --arch x64 \
/t:PublishContainer \
-p:ContainerRepository=store-api \
-p:ContainerImageTag=study \
-p:ContainerBaseImage=mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled-extra
PublishContainer بيعمل image، و ContainerRepository اسمها و ContainerImageTag الـ tag. الـ SDK publishing يقدر يطلع archive أو ينشر لregistry بإعداداته؛ daemon مش مطلوب لكل أشكال النشر. راجع port و user و architecture بدل افتراض تطابقهم مع Dockerfile.
| Dockerfile | SDK publishing |
|---|---|
| تحكم في مراحل build و RUN | إعداد أقل لتغليف تطبيق .NET |
| مناسب لو فيه native packages أو build steps خاصة | مناسب لو base image جاهزة ومش محتاج RUN |
النهجين لسه محتاجين scanning و secrets خارج الصورة و artifact identity ثابت. توثيق SDK container publishing.
#Compose: الجاهزية مش مجرد بدء processCompose: readiness is more than process startup
بدء database container مش معناه إنها جاهزة للاتصال. المثال local development، مع Dockerfile السابق و package Npgsql provider في التطبيق. عرّف DB_PASSWORD في البيئة قبل التشغيل، وماتحطش قيمتها في Git.
services:
api:
build: .
ports: ["127.0.0.1:8080:8080"]
environment:
ConnectionStrings__Default: >-
Host=db;Database=store;Username=store;Password=${DB_PASSWORD:?Set DB_PASSWORD}
depends_on:
db:
condition: service_healthy # (1)
db:
image: postgres:17
environment:
POSTGRES_DB: store
POSTGRES_USER: store
POSTGRES_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD}
volumes: ["pgdata:/var/lib/postgresql/data"] # (2)
healthcheck:
test: ["CMD-SHELL", "pg_isready -U store -d store"] # (3)
interval: 5s
timeout: 3s
retries: 10
start_period: 10s
volumes:
pgdata:
- (1) Compose يستنى healthcheck وقت بدء الـ . ده مش علاج لانقطاع database بعد كده.
- (2) بيانات PostgreSQL 17 على volume؛ down العادي مابيمسحهاش، لكن down -v يمسحها.
- (3) pg_isready موجود في PostgreSQL image، مش في chiseled API image. الفحص بيثبت قبول connections، مش وجود migrations ولا صلاحية كل query.
شغّل docker compose up --build -d وافحص logs. الـ API محتاجة readiness endpoint يفحص dependencies المطلوبة، و retry محدود للـ transient errors. متغيرات البيئة مناسبة للمثال المحلي؛ production secrets تتحقن من secret store. ترتيب التشغيل في Compose.
#CI/CD: ابني مرة وروّج نفس الناتجCI/CD: build once and promote the same artifact
- كل push يشغّل بناء المشروع وفحوصه تلقائيًا؛ ده جزء من لكشف كسر التغييرات بدري، وليس ضمانًا وحده إن النشر آمن.
- بعد نجاح التحقق، احتفظ بنفس artifact ذي الهوية الثابتة للانتقال من بيئة الاختبار إلى الإنتاج. إعادة البناء لكل بيئة قد تدخل اختلافًا لم تختبره.
- Continuous delivery يجعل الإصدار جاهزًا للنشر مع إمكانية قرار بشري، بينما continuous deployment ينشر المؤهل تلقائيًا. في الحالتين جهز إعدادات البيئة وخطة التعامل مع الفشل وتوافق قاعدة البيانات.
CI بتدمج تغييرات صغيرة مع build و tests تلقائي. Continuous delivery بتخلي النسخة جاهزة للنشر بموافقة، و continuous deployment بينشر كل تغيير ناجح تلقائياً. المثال GitHub Actions لـ repo فيه solution و tests و Dockerfile في root؛ test projects مضبوطة لتشتغل بـ dotnet test. tags بتاعة actions للتوضيح؛ ثبّتها على full commit SHA متراجع في pipeline حقيقية.
جزء بيفترض Container Apps موجودة للـ staging وproduction، وكل واحدة single-revision mode ومضبوطة تسحب الصورة من GHCR؛ لو package خاصة، اضبط registry credentials منفصلة. عرّف في كل GitHub environment متغيرات AZURE_CLIENT_ID وAZURE_TENANT_ID وAZURE_SUBSCRIPTION_ID وRESOURCE_GROUP وAPP_NAME وHEALTH_URL. اضبط federation لكل environment وصلاحية deployment محدودة، وrequired reviewers للـ production. المثال مش بينشئ infrastructure ولا يشغل migrations؛ طبق التغييرات المتوافقة بخطوة منفصلة قبل rollout.
name: ci-cd
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
verify:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- run: dotnet restore
- run: dotnet build -c Release --no-restore -warnaserror
- run: dotnet test -c Release --no-build # (1)
image:
needs: verify
if: github.event_name == 'push'
runs-on: ubuntu-24.04
outputs:
image: ${{ steps.publish.outputs.image }}
permissions:
contents: read
packages: write
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_USER: ${{ github.actor }}
REPOSITORY: ${{ github.repository }}
REVISION: ${{ github.sha }}
steps:
- uses: actions/checkout@v4
- name: Build and push
id: publish
shell: bash
run: |
image="ghcr.io/${REPOSITORY,,}:$REVISION" # (2)
printf '%s' "$GH_TOKEN" | docker login ghcr.io \
-u "$GH_USER" --password-stdin
docker build --pull -t "$image" .
docker push "$image" # (3)
digest=$(docker inspect --format='{{index .RepoDigests 0}}' "$image")
echo "image=$digest" >> "$GITHUB_OUTPUT"
deploy-staging:
needs: image
runs-on: ubuntu-24.04
environment: staging # (4)
concurrency: deploy-staging
permissions:
contents: read
id-token: write
env:
IMAGE: ${{ needs.image.outputs.image }}
GROUP: ${{ vars.RESOURCE_GROUP }}
APP: ${{ vars.APP_NAME }}
HEALTH_URL: ${{ vars.HEALTH_URL }}
steps:
- uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
- run: az extension add --name containerapp --upgrade
- run: az containerapp update -g "$GROUP" -n "$APP" --image "$IMAGE"
- run: curl --fail --retry 5 --retry-connrefused "$HEALTH_URL" # (5)
deploy-production:
needs: [image, deploy-staging]
runs-on: ubuntu-24.04
environment: production # (6)
concurrency: deploy-production
permissions:
contents: read
id-token: write
env:
IMAGE: ${{ needs.image.outputs.image }}
GROUP: ${{ vars.RESOURCE_GROUP }}
APP: ${{ vars.APP_NAME }}
HEALTH_URL: ${{ vars.HEALTH_URL }}
steps:
- uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
- run: az extension add --name containerapp --upgrade
- run: az containerapp update -g "$GROUP" -n "$APP" --image "$IMAGE"
- run: curl --fail --retry 5 --retry-connrefused "$HEALTH_URL"
- (1) tests بوابة قبل بناء الصورة. Docker متاح في runner القياسي للاختبارات اللي محتاجاه؛ راقب زمن وتكلفة integration tests.
- (2) اسم registry lowercase، والـ tag مربوط بالـ commit. ماتمررش مدخلات غير موثوقة جوه script مباشرة.
- (3) الصورة بتتدفع بعد النجاح على main؛ PRs مش بتاخد صلاحية نشر. بنحفظ digest في output بدل ترقية tag متحركة.
- (4) OIDC بيدي job هوية مؤقتة؛ متغيرات staging بتحدد resource المستهدفة.
- (5) smoke check بسيط للجاهزية. زوّده بتحقق من نسخة التطبيق وسيناريو business مناسب، مش health بس.
- (6) production تستنى staging وتستخدم نفس digest. الموافقة لازم تتضبط في GitHub environment؛ كتابة الاسم لوحدها مش بتفرض reviewers.
الـ workflow بتسلسل releases لنفس ref علشان rollout قديم وجديد مايشتغلوش في نفس الوقت. زوّد image scanning وفحص dependencies حسب policy الفريق، وحدّث actions وbase images بانتظام. vulnerability report لوحده مش gate إلا لو policy بتفشل الـ job. أمان GitHub Actions.
#Promotion و Deployment strategiesPromotion and deployment strategies
إعادة build لكل environment معناها إن production بتاخد حاجة مختلفة عن اللي اتاختبرت. خزن config والأسرار برّه artifact، وروّج نفس image digest، مع release record يحدد version و config و migration status.
| الطريقة | الميزة | التكلفة أو الشرط |
|---|---|---|
| Rolling | تبديل replicas بالتدريج | old و new شغالين مع بعض؛ محتاج spare capacity |
| Blue-green | تحويل traffic لبيئة جاهزة | تكلفة بيئتين ومشكلة الداتا المشتركة |
| Canary | نسبة صغيرة الأول ومراقبة | routing ومقاييس واضحة ومعيار إيقاف |
| فصل deploy عن إتاحة الميزة | اختبر الحالتين وشيل flags المنتهية |
- نسخة جديدة تبدأ وتعدّي readiness، مش مجرد process running.
- وجّه traffic تدريجياً وراقب error rate و tail ومعيار business.
- وقت الإيقاف، اسحب instance من routing واديها وقت تخلص الطلبات.
- لو المقاييس اتدهورت، وقف rollout أو ارجع للنسخة المتوافقة.
rollback للصورة مش بيرجع database ولا refund للدفع. عرّف خطة recovery للداتا والعمليات الخارجية قبل النشر.
#Database migrations من غير قطع الخدمةDatabase migrations without service interruption
أثناء rolling deployment فيه كود قديم وجديد بيستخدموا نفس الـ . حذف column أو rename مباشر ممكن يكسر القديم فوراً. استخدم expand و migrate و contract بدل التغيير المدمر مرة واحدة.
- Expand: ضيف column جديد nullable أو بقيمة افتراضية مناسبة؛ راجع locking وتكلفة على engine الحقيقي.
- انشر كود متوافق مع القديم والجديد. لو فيه dual-write، خلي التحديثات متسقة وخطط للفشل الجزئي.
- Backfill دفعات صغيرة قابلة للاستكمال، وراقب و locks.
- حوّل القراءة للجديد بعد التحقق من اكتمال الداتا، واستنى انتهاء rollback window وكل old instances.
- Contract: احذف القديم في release لاحقة، مع backup وخطة restore مجربة.
شغّل migrations من job واحدة بصلاحية مخصصة، مش من كل replica عند startup. script مش ضمان إنه سريع أو من غير locks. اختبر migration على حجم قريب من الحقيقي، وما تفترضش إن Down migration آمنة أو بترجع الداتا المحذوفة.
#Kubernetes: desired state و Health probesKubernetes: desired state and health probes
Kubernetes بيدير desired state على cluster؛ مش بيصلح business bugs. Pod وحدة scheduling فيها container أو أكتر بيشاركوا network namespace؛ Deployment بيدير replicas و rollouts؛ Service عنوان discovery ثابت وتوجيه للـ endpoints الجاهزة؛ Ingress قواعد محتاجة controller. ConfigMap للإعدادات، و Secret للداتا الحساسة، لكن base64 مش تشفير.
المثال fragment جوه Pod template في Deployment؛ image لازم تتبدل بإصدارك الحقيقي، والـ لازم تعرض endpoints المذكورة.
containers:
- name: api
image: registry.example.com/store-api:release-1
ports:
- containerPort: 8080
resources:
requests: { cpu: "250m", memory: "256Mi" } # (1)
limits: { cpu: "1", memory: "512Mi" }
startupProbe:
httpGet: { path: /health/live, port: 8080 }
failureThreshold: 30
periodSeconds: 2
readinessProbe:
httpGet: { path: /health/ready, port: 8080 } # (2)
livenessProbe:
httpGet: { path: /health/live, port: 8080 } # (3)
- (1) requests بتأثر على scheduling، و limits بتحد الموارد؛ الأرقام مثال محتاج قياس، مش sizing recommendation.
- (2) readiness الفاشلة بتشيل الـ Pod من endpoints الجاهزة؛ مش بتعمل restart لوحدها.
- (3) liveness الفاشلة باستمرار بتؤدي لإعادة تشغيل container. startupProbe بيدي وقت للبدء قبل تفعيل الفحصين.
ماتربطش liveness بكل external dependency فتعمل restart storm وقت عطل database. HPA بيغير replicas بناء على metrics، ومش بيزوّد قدرة database تلقائياً. Kubernetes مفيد لما التشغيل محتاج قدراته؛ managed container platform ممكن تكون أبسط.
#Git: تاريخ مفهوم وقرارات قابلة للرجوعGit: understandable history and reversible decisions
Git بيسجل snapshots و relationships بين commits. merge بيجمع histories، وممكن يكون fast-forward من غير merge commit؛ rebase بيعيد إنشاء commits فوق base جديد، فهوياتها بتتغير. تجنب إعادة كتابة shared history إلا بتنسيق صريح.
| Workflow | مناسب لإيه |
|---|---|
| Trunk-based | branches قصيرة ودمج متكرر و |
| GitHub Flow | main قابل للنشر، و لكل تغيير |
| GitFlow | release lines مجدولة؛ فروع وتنسيق أكتر |
الأوامر Bash داخل repository تجريبية؛ غيّر أسماء الـ refs حسب الحالة. reset بيغير branch pointer وقد يغيّر index و working tree حسب الـ mode؛ ماتستخدموش لإلغاء commit منشور على main.
git switch -c feature/order-limits
git rebase main # (1) replay this private branch
git revert HEAD # (2) create a new inverse commit
git bisect start
git bisect bad
git bisect good v1.0.0 # (3) known-good tag must exist
# Test each selected revision; mark it with git bisect good or bad.
git bisect reset
- (1) rebase للـ branch الخاص؛ عند conflict افهم النتيجة واختبرها، مش مجرد قبول جانب.
- (2) revert بيضيف commit يعكس التغيير ويحافظ على التاريخ؛ ممكن يعمل conflict ومش بيرجع داتا production.
- (3) bisect بيضيّق مجموعة commits بين good و bad باستخدام اختبار قابل للتكرار؛ اعمل skip للنسخ غير القابلة للاختبار.
Conventional commits زي feat(orders): add booking limit و fix(payments): reject duplicate capture بتوضح النية وتساعد automation. جودة الرسالة والـ PR أهم من prefix لوحده؛ main تحتاج review و وحماية branches.
#IIS و Linux مع NginxIIS and Linux with Nginx
الـ hosting chain لازم تبقى مفهومة علشان تشخص 502 و redirect loops. على Windows ثبّت Hosting Bundle المناسب بعد ، واستخدم app pool بإعداد No Managed Code لتطبيق ASP.NET Core. الـ ASP.NET Core Module بيستضيف in-process جوه w3wp أو يمرر لـ Kestrel في out-of-process؛ صلاحيات identity و web.config المنشور مهمة.
على Linux شغّل dotnet كـ service تحت systemd أو container orchestrator، وخلي Nginx قدام Kestrel للـ و routing. المثال fragment داخل Nginx server block للـ المحلي؛ TLS configuration مطلوبة للنشر العام.
location / {
proxy_pass http://127.0.0.1:5000; # (1)
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; # (2)
}
- (1) Kestrel بيسمع على loopback، ومش مفتوح للعالم مباشرة.
- (2) headers بتنقل معلومات الطلب الأصلية. فعّل Forwarded Headers قبل redirection، وثق في proxy addresses المعروفة بس.
لو Nginx و Kestrel في containers مختلفة، loopback مش هيوصل بينهم؛ استخدم service و network خاصة. WebSockets محتاجة upgrade configuration إضافية. Data Protection keys لازم تستمر وتتشارك بأمان لما فيه replicas أو deploys بتحافظ على login cookies. دليل Nginx الرسمي.
أسئلة الانترفيو
مفيش نتايج
راجع فهمك
ليه الاختيار ده مناسب؟ إمتى ممكن ماينفعش؟ وإيه اللي هيتغير لو الحمل زاد أو ظهر فشل؟
22.1How is a container different from a VM?Junior
container process معزول على kernel مشتركة؛ معاها guest و kernel. اختار حسب compatibility والعزل والتشغيل.
I see a container as an isolated process environment that shares the host kernel, while a includes a guest operating system and kernel. Containers usually start faster and offer higher density, but require compatible operating-system and targets. Linux containers on Windows normally use a Linux VM underneath. I choose between them based on , compatibility and operational needs rather than assuming a container provides the same boundary as a virtual machine.
22.2What is the difference between an image and a container?Junior
image قالب layered، و container instance مع writable layer. tag قابل للتغيير، و digest هوية للمحتوى.
I describe an image as a read-only layered template containing application files and runtime dependencies. A container is an instance of that image with process and a writable layer. Changes in that layer should be treated as disposable. I use volumes or external stores for durable data and identify deployed image content by digest. Tags are convenient labels, but they can move, so a tag alone is weaker evidence of what actually ran.
22.3What makes a good .NET Dockerfile?Mid
multi-stage، و restore cache، و runtime-only final image، و non-root، و.dockerignore، و secrets برّه الصورة.
I use an stage to restore and publish, then copy only published output into an ASP.NET runtime stage. I copy dependency inputs before source to preserve restore caching, run as a non-root user and exclude build output and secrets from the context. I consider chiseled images when their missing shell and package tools fit the application. I pin release inputs, scan and update images, and verify globalization, filesystem permissions and shutdown behavior.
22.4When would you use PublishContainer instead of a Dockerfile?Mid
لما المطلوب تغليف publish output فوق base image جاهزة؛ Dockerfile لو محتاج RUN أو build stages خاصة.
I use container publishing when the image mainly consists of publish output on a suitable base image. It reduces Dockerfile maintenance and supports configuring the repository, tag, base image and target platform. I use a Dockerfile when I need custom build stages or operating-system changes that require RUN instructions. Both approaches still need controlled base-image updates, external secrets and deployment verification; changing the packaging tool does not remove those responsibilities.
22.5Does EXPOSE publish a port?Junior
لأ؛ EXPOSE بيوثق البورت. Docker run -p أو ports في Compose بينشره، والتطبيق لازم يسمع على interface مناسبة.
I treat EXPOSE as image metadata documenting the intended listening port. It does not publish that port on the host or make an application listen there. With Docker I publish through the run port mapping or Compose ports setting, and ensure the application binds to the correct interface inside the container. I also choose the host binding deliberately: a loopback binding is useful behind a local , while a public binding exposes a larger surface.
22.6How do you keep data when containers are replaced?Mid
volume أو external storage؛ writable layer مؤقتة. volume مش backup، ولازم restore مجرب.
I put durable data on managed storage, a database service or an explicitly mounted volume rather than a container's writable layer. A bind mount maps a host directory, while a named volume is managed by Docker. I document the storage lifecycle and avoid destructive cleanup commands during routine deployment. Persistence alone is not a backup strategy, so I also define retention, where needed, and regular restore tests against the required recovery objectives.
22.7Why is depends_on alone insufficient for database startup?Mid
process بدأ مش معناها database جاهزة. service_healthy مع healthcheck بيظبط startup بس، مش outages بعده.
I distinguish a started container from a ready dependency. Basic depends_on orders startup, while a service_healthy condition waits for the dependency's . Even that only proves what the check measures; pg_isready does not prove migrations are applied. I retain bounded connection retries and application readiness checks because the database may become unavailable after startup. I also ensure the health-check executable exists rather than assuming a minimal application image includes curl or a shell.
22.8What is CI/CD?Junior
build و tests مع الدمج، و delivery جاهزية للنشر، و deployment نشر تلقائي بعد البوابات.
I use continuous integration to build and test small changes frequently so integration problems surface early. Continuous delivery keeps passing artifacts ready for deployment, often with a production approval. Continuous deployment automatically deploys changes that pass the release gates. My pipeline produces a versioned artifact, verifies it in staging and promotes the same content to production. I separate environment configuration from the artifact and define rollback and observability before enabling automatic releases.
22.9What does build once, deploy many mean?Senior
نفس digest يعدّي staging و production؛ configuration برّه artifact، وتسجيل نسخة الإعدادات مهم.
I build one artifact from a reviewed revision, record its content identity and promote that same artifact through environments. I inject configuration and secrets at deployment instead of recompiling for staging and production. That reduces the chance of releasing untested content. It does not mean the environments are identical: I still verify configuration, permissions, database compatibility and infrastructure. I record those inputs alongside the artifact digest so a deployment can be audited and reproduced.
22.10How do rolling, blue-green and canary deployments differ?Senior
rolling تبديل تدريجي للنسخ، و blue-green تحويل بين بيئتين، و canary نسبة صغيرة مع قياس قبل التوسيع.
I use rolling updates to replace replicas gradually while maintaining capacity. Blue-green prepares a second environment and switches traffic after validation, at the cost of extra capacity and shared-data considerations. Canary deployment exposes a small traffic share first and expands only when metrics remain acceptable. All three need readiness, compatible schemas and a recovery plan. I choose based on traffic control, risk and operational capability rather than assuming any strategy guarantees zero downtime by itself.
22.11How do you deploy a breaking database change safely?Senior
expand ثم backfill وتحويل تدريجي، وبعد خروج القديم وانتهاء rollback window اعمل contract.
I use expand and contract so old and new application versions can coexist. I first add compatible , deploy code that tolerates both representations, backfill in resumable batches and switch reads after verification. I remove the old structure only after old instances and the rollback window are gone. I run migrations through one controlled job and test lock behavior on realistic data. Reverting the application image cannot restore deleted data, so recovery needs separate planning.
22.12What are the main Kubernetes objects a developer should know?Mid
Pod للتشغيل، و Deployment للنسخ، و Service للاكتشاف والتوجيه، و Ingress لقواعد مع controller، و ConfigMap و Secret للإعدادات.
I use Pods as scheduling units, Deployments to maintain replicas and roll out changes, and Services for stable discovery and routing to ready endpoints. Ingress describes external routing but needs a controller. ConfigMaps provide configuration and Secrets hold sensitive values with access controls. I also understand resource requests, limits and probes because they directly affect scheduling and availability. Kubernetes automates reconciliation, but application correctness and secure configuration remain the team's responsibility.
22.13How do readiness and liveness probes differ?Mid
readiness بتحدد دخول traffic؛ liveness بتحدد الحاجة للـ restart؛ startup بتحمي وقت البدء.
I use readiness to decide whether an instance should receive traffic and liveness to decide whether its container needs restarting. A startup probe allows slow initialization before the other probes become active. I avoid making liveness depend on a shared database because a database outage could restart every application instance without fixing anything. Readiness can reflect dependencies needed to serve requests, but its design should also consider whether removing all replicas would make an outage worse.
22.14What is the difference between merge and rebase?Mid
merge يجمع التاريخ وقد يعمل fast-forward؛ rebase يعيد إنشاء commits وهوياتها. ماتعيدش كتابة shared history من غير اتفاق.
I use merge to combine branch histories; it may create a merge commit or simply fast-forward when possible. Rebase replays commits on a different base and gives them new identities, producing a more linear history. I rebase private work when that helps review, but avoid rewriting history that colleagues already depend on. For either operation I resolve conflicts by understanding the intended behavior and running checks rather than blindly choosing one side.
22.15When should you use revert rather than reset?Junior
revert لإلغاء تغيير منشور بcommit جديد؛ reset لتحريك branch محلي مع فهم تأثير mode على الملفات.
I use revert to undo a published change because it adds a new commit with the inverse change and preserves shared history. Reset moves a branch pointer and can also change the index or working tree depending on its mode, so it is mainly a local history tool. Neither operation reverses production side effects or database changes. I also check whether later commits depend on the reverted behavior before treating the revert as a complete fix.
22.16How would you diagnose a deployment returning 502?Senior
امشي في الـ chain: proxy logs، و process status، و upstream port، و binding، و permissions، و health. ماتبدأش بتوسيع الصلاحيات عشوائياً.
I the request from the proxy to the application. I check proxy errors, process or service status, startup logs, the configured upstream port and whether Kestrel is listening on the expected interface. On I also inspect Hosting Bundle and application identity permissions. I test local reachability before changing public routing. If startup succeeds but readiness fails, I inspect required dependencies and configuration rather than repeatedly restarting an instance without preserving evidence.
اختبر نفسك
إجابات الاختبار وعلامات إكمال المحاور بتتحفظ على المتصفح ده، ومش بتتنقل لأجهزة تانية.
What does a multi-stage Dockerfile keep out of the final image?
Why does a curl healthcheck fail in an unmodified chiseled ASP.NET image?
Which identity best selects exactly the image tested in staging?
A failed readiness probe normally causes what?
First step before renaming a database column during rolling deployment?
A bad commit is already shared on main. Which Git operation preserves history?
Which statement about Compose service_healthy is correct?
Which Git tool narrows down a regression between good and bad revisions?
What does a feature flag separate?
What should a proxy deployment do with forwarded headers?