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

آزمون بخش ۳: ساختن image

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

؟ آزمون بخش ۳
  1. در docker build -t myapp:1.0 ./site، «./site» چیست؟

  2. ARG در کانتینر در حال اجرا…

  3. برای کپی ساده‌ی فایل از context کدام بهتر است؟

  4. فرم exec در برابر shell برای CMD؟

  5. با ENTRYPOINT ["ping","-c","2"] و CMD ["localhost"]، دستور docker run img 8.8.8.8 چه اجرا می‌کند؟

  6. اگر لایه‌ی سوم Dockerfile باطل شود، لایه‌های بعد از آن…

  7. ترتیب بهینه برای یک اپ Node؟

  8. چرا RUN rm در یک لایه‌ی جدا حجم image را کم نمی‌کند؟

  9. مهم‌ترین فایده‌ی امنیتی .dockerignore؟

  10. در .dockerignore ترتیب درست برای ignore کردن همه‌ی md به‌جز README.md؟

  11. در multi-stage کدام مرحله image نهایی است؟

  12. چرا در Dockerfile باید npm ci بزنیم نه npm install؟

  13. در Dockerfile پایتون، PYTHONUNBUFFERED=1 چه می‌کند؟

  14. در localhost:5301/lx/app:1.0 کدام بخش registry است؟

  15. برای production کدام tag بهتر است؟

🏁 چالش: از کد تا registryسخت

یک سرویس کوچک را از صفر تا registry ببر:

۱. پروژه‌ای با page.html.tmpl (حاوی {{NAME}}) و اسکریپت build.py بساز که قالب را با نام LoopX پر کند و dist/index.html بنویسد. ۲. یک Dockerfile چندمرحله‌ای بنویس: مرحله‌ی build با python:3.12-slim (اجرای build.py) و مرحله‌ی نهایی python:3.12-slim که dist را کپی می‌کند، با کاربر غیر root (uid 1001) و python -m http.server 8000 --bind 0.0.0.0 اجرا می‌شود. یک .dockerignore هم بگذار. ۳. یک registry محلی روی پورت 5302 (lx-ch-reg) بالا بیاور و image را با اسم localhost:5302/lx/challenge:1.0 push کن. ۴. image های محلی را پاک کن، دوباره از registry pull کن و روی پورت 8342 اجرا کن؛ ثابت کن صفحه جواب می‌دهد و پروسه غیر root است.

راهنمایی

برای ثابت کردن غیر root بودن از docker exec ... id -u استفاده کن. برای پر کردن قالب می‌توانی از str.replace در Python کمک بگیری.

راه‌حل
Terminal window
mkdir -p ch
echo '<h1>سلام {{NAME}}</h1>' > ch/page.html.tmpl
printf 'from pathlib import Path\nPath("dist").mkdir(exist_ok=True)\nPath("dist/index.html").write_text(Path("page.html.tmpl").read_text().replace("{{NAME}}", "LoopX"))\n' > ch/build.py
printf '__pycache__\n.env\n.git\ndist\n' > ch/.dockerignore
cat > ch/Dockerfile <<'LXEOF'
FROM python:3.12-slim AS build
WORKDIR /src
COPY page.html.tmpl build.py ./
RUN python build.py
FROM python:3.12-slim
WORKDIR /srv
COPY --from=build /src/dist .
RUN useradd -m -u 1001 web
USER web
EXPOSE 8000
CMD ["python", "-m", "http.server", "8000", "--bind", "0.0.0.0"]
LXEOF
docker run -d --name lx-ch-reg -p 5302:5000 registry:2 >/dev/null; sleep 2
docker build -q -t localhost:5302/lx/challenge:1.0 ./ch >/dev/null 2>&1
docker push localhost:5302/lx/challenge:1.0 2>&1 | tail -1 | cut -c1-80
docker rmi localhost:5302/lx/challenge:1.0 >/dev/null
docker run -d --name lx-ch1 -p 8342:8000 localhost:5302/lx/challenge:1.0 2>&1 | tail -1 | cut -c1-12
sleep 3
curl -s localhost:8342
docker exec lx-ch1 id -u
docker rm -f lx-ch1 lx-ch-reg >/dev/null; docker rmi localhost:5302/lx/challenge:1.0 >/dev/null
خروجی
1.0: digest: sha256:4725f651e910ed59b6326ea5867686fdc03ff6129edeb2637667f0b07f2f
dfd2b318601f
<h1>سلام LoopX</h1>
1001