این آزمون هر ۹ درس بخش «حرفهایتر» را میسنجد. جواب هر سؤال همان لحظه با توضیح نشان داده میشود و نتیجهات در همین مرورگر ذخیره میشود (پیشرفت من).
چرا RUN rm -rf در لایهی جدا حجم image را کم نمیکند؟
ساخت و پاککردن را در یک RUN انجام بده یا از multi-stage استفاده کن.
مؤثرترین کار برای کوچک کردن یک image پایتونی؟
base معمولاً بیشترین حجم را دارد.
اگر Dockerfile دستور USER نداشته باشد، پروسه با کدام کاربر اجرا میشود؟
پیشفرض root است.
کدام روش برای راز زمان build درست است؟
ENV و ARG در متادیتا و تاریخچهی image میمانند؛ secret mount نه.
docker run --read-only چه میکند؟
مهاجم نمیتواند فایلهای اپ را عوض کند.
اصل least privilege برای capabilities؟
قدرت اضافه یعنی دامنهی خسارت بیشتر.
چرا mount کردن docker.sock خطرناک است؟
میتواند کانتینر دلخواه (حتی با mount کل دیسک) بسازد.
در گزارش اسکن، Fixed Version مقدار دارد. یعنی…
اگر خالی باشد هنوز رفعی نیست.
برای شکستن CI با Trivy کدام را میگذاری؟
با پیدا شدن آسیبپذیری کد خروج ۱ میدهد.
کد خروج ۱۳۷ یعنی…
۱۳۷ = ۱۲۸ + ۹؛ OOMKilled را در inspect ببین.
اپ داخل کانتینر روی 127.0.0.1 گوش میکند و -p هم زدهای. نتیجه؟
127.0.0.1 فقط برای خود کانتینر است.
اگر کانتینر از سقف --memory رد شود چه میشود؟ و از --cpus؟
حافظه سقف سخت و CPU سقف نرم است.
logging driver پیشفرض و سقف آن؟
بدون max-size/max-file لاگ بینهایت رشد میکند.
برای بهروزرسانی سرویس بدون از دست رفتن داده؟
فقط سرویسهای تغییرکرده دوباره ساخته میشوند و volume میماند.
چرا در dockerfile و Compose بهجای latest، tag دقیق میگذاریم؟
یا حتی digest برای تضمین مطلق.
یک سرویس را با تمام عادتهای این بخش اجرا و بررسی کن:
۱. imageای از python:3.12-alpine بساز که با کاربر غیر root (uid 10001) اجرا شود، HEALTHCHECK داشته باشد و یک سرور HTTP ساده روی پورت 8000 اجرا کند (python -m http.server).
۲. با docker run آن را با این ویژگیها اجرا کن: --read-only با --tmpfs /tmp، --cap-drop ALL، --security-opt no-new-privileges، سقف حافظه 64m، --pids-limit 50، چرخش لاگ (max-size=100k، max-file=2) و --restart unless-stopped.
۳. یک اسکریپت PASS/FAIL بنویس که این هفت ویژگی را از روی docker inspect تأیید کند (کاربر، فقطخواندنی، cap-drop، حافظه، لاگ، restart policy و healthy بودن).
۴. اپ را کرش بده (سرور را طوری بنویس که با درخواست به /crash با کد ۱ خارج شود) و نشان بده خودش برگشت (RestartCount ≥ ۱) و دوباره سالم شد. (نکته: docker kill و docker stop را داکر «توقف دستی» حساب میکند و restart نمیکند؛ برای آزمایش باید خود برنامه بمیرد.)
راهنمایی
برای انتظار تا سالم شدن از حلقهی docker inspect --format '{{.State.Health.Status}}' استفاده کن. RestartCount را بعد از docker kill چند ثانیه بعد بخوان.
راهحل
docker rm -f lx-ch6 >/dev/null 2>&1mkdir -p ch6 && cat > ch6/server.py <<'LXEOF'import http.serverimport os
class Handler(http.server.SimpleHTTPRequestHandler): def do_GET(self): if self.path == "/crash": os._exit(1) super().do_GET()
os.chdir("/srv")http.server.HTTPServer(("0.0.0.0", 8000), Handler).serve_forever()LXEOFcat > ch6/Dockerfile <<'LXEOF'FROM python:3.12-alpineRUN adduser -D -u 10001 appWORKDIR /srvRUN echo ok > index.html && chown app:app /srvCOPY server.py /opt/server.pyUSER 10001EXPOSE 8000HEALTHCHECK --interval=2s --timeout=2s --retries=3 CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/', timeout=1)"CMD ["python", "/opt/server.py"]LXEOFdocker build -q -t lx-ch6 ch6 >/dev/nulldocker run -d --name lx-ch6 --read-only --tmpfs /tmp --cap-drop ALL --security-opt no-new-privileges \ --memory 64m --pids-limit 50 --log-opt max-size=100k --log-opt max-file=2 --restart unless-stopped lx-ch6 >/dev/nullwait_healthy() { for i in $(seq 40); do [ "$(docker inspect lx-ch6 --format '{{.State.Health.Status}}')" = healthy ] && return 0; sleep 1; done; return 1; }wait_healthychk() { if [ "$2" = "$3" ]; then echo "PASS $1"; else echo "FAIL $1 (got: $2)"; fi; }chk "کاربر غیر root" "$(docker inspect lx-ch6 --format '{{.Config.User}}')" "10001"chk "فایلسیستم فقطخواندنی" "$(docker inspect lx-ch6 --format '{{.HostConfig.ReadonlyRootfs}}')" "true"chk "cap-drop ALL" "$(docker inspect lx-ch6 --format '{{.HostConfig.CapDrop}}')" "[ALL]"chk "سقف حافظه ۶۴ مگابایت" "$(docker inspect lx-ch6 --format '{{.HostConfig.Memory}}')" "67108864"chk "چرخش لاگ" "$(docker inspect lx-ch6 --format '{{.HostConfig.LogConfig.Config}}')" "map[max-file:2 max-size:100k]"chk "restart policy" "$(docker inspect lx-ch6 --format '{{.HostConfig.RestartPolicy.Name}}')" "unless-stopped"chk "سالم (healthy)" "$(docker inspect lx-ch6 --format '{{.State.Health.Status}}')" "healthy"docker exec lx-ch6 python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/crash', timeout=3)" >/dev/null 2>&1sleep 5wait_healthyecho "بعد از کرش: RestartCount=$(docker inspect lx-ch6 --format '{{.RestartCount}}') وضعیت=$(docker inspect lx-ch6 --format '{{.State.Status}}') سلامت=$(docker inspect lx-ch6 --format '{{.State.Health.Status}}')"docker rm -f lx-ch6 >/dev/null; docker rmi lx-ch6 >/dev/nullPASS کاربر غیر rootPASS فایلسیستم فقطخواندنیPASS cap-drop ALLPASS سقف حافظه ۶۴ مگابایتPASS چرخش لاگPASS restart policyPASS سالم (healthy)بعد از کرش: RestartCount=1 وضعیت=running سلامت=healthy