رفتن به محتوا
LoopX

آزمون بخش ۶: حرفه‌ای‌تر

این آزمون هر ۹ درس بخش «حرفه‌ای‌تر» را می‌سنجد. جواب هر سؤال همان لحظه با توضیح نشان داده می‌شود و نتیجه‌ات در همین مرورگر ذخیره می‌شود (پیشرفت من).

؟ آزمون بخش ۶
  1. چرا RUN rm -rf در لایه‌ی جدا حجم image را کم نمی‌کند؟

  2. مؤثرترین کار برای کوچک کردن یک image پایتونی؟

  3. اگر Dockerfile دستور USER نداشته باشد، پروسه با کدام کاربر اجرا می‌شود؟

  4. کدام روش برای راز زمان build درست است؟

  5. docker run --read-only چه می‌کند؟

  6. اصل least privilege برای capabilities؟

  7. چرا mount کردن docker.sock خطرناک است؟

  8. در گزارش اسکن، Fixed Version مقدار دارد. یعنی…

  9. برای شکستن CI با Trivy کدام را می‌گذاری؟

  10. کد خروج ۱۳۷ یعنی…

  11. اپ داخل کانتینر روی 127.0.0.1 گوش می‌کند و -p هم زده‌ای. نتیجه؟

  12. اگر کانتینر از سقف --memory رد شود چه می‌شود؟ و از --cpus؟

  13. logging driver پیش‌فرض و سقف آن؟

  14. برای به‌روزرسانی سرویس بدون از دست رفتن داده؟

  15. چرا در dockerfile و Compose به‌جای latest، tag دقیق می‌گذاریم؟

🏁 چالش: سرویس سخت‌شده و مقاومسخت

یک سرویس را با تمام عادت‌های این بخش اجرا و بررسی کن:

۱. 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 چند ثانیه بعد بخوان.

راه‌حل
Terminal window
docker rm -f lx-ch6 >/dev/null 2>&1
mkdir -p ch6 && cat > ch6/server.py <<'LXEOF'
import http.server
import 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()
LXEOF
cat > ch6/Dockerfile <<'LXEOF'
FROM python:3.12-alpine
RUN adduser -D -u 10001 app
WORKDIR /srv
RUN echo ok > index.html && chown app:app /srv
COPY server.py /opt/server.py
USER 10001
EXPOSE 8000
HEALTHCHECK --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"]
LXEOF
docker build -q -t lx-ch6 ch6 >/dev/null
docker 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/null
wait_healthy() { for i in $(seq 40); do [ "$(docker inspect lx-ch6 --format '{{.State.Health.Status}}')" = healthy ] && return 0; sleep 1; done; return 1; }
wait_healthy
chk() { 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>&1
sleep 5
wait_healthy
echo "بعد از کرش: 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/null
خروجی
PASS کاربر غیر root
PASS فایل‌سیستم فقط‌خواندنی
PASS cap-drop ALL
PASS سقف حافظه ۶۴ مگابایت
PASS چرخش لاگ
PASS restart policy
PASS سالم (healthy)
بعد از کرش: RestartCount=1 وضعیت=running سلامت=healthy