Шо по докерфайлам?
(Якщо ваш Dockerfile починається з FROM node:20 і закінчується COPY . . без .dockerignore, то це пост для вас. Ще більше таких дискусійних тем на каналі @mamkin_architect.)
Dockerfile це такий артефакт, який пишеться один раз, копіпейститься потім років п’ять, і ніхто його більше не читає. А дарма, бо зазвичай там є простір для покращень, за які майбутні покоління будуть згадувати вас із вдячністю. Ось наприклад:
1. Пхати всюди Alpine не варто. Так, воно мале, це зрозуміло. Але Alpine на musl libc, а не на glibc, ми можемо не розуміти цю різницю, але наші Python або Node її відчують на собі. Нативні залежності або перекомпілюються з нуля, або мовчки працюють повільніше, бо готових wheels під musl часто просто немає. Краще брати -slim (типу debian-slim), розмір приблизно такий же, проблем нуль. Але якщо у вас Go-бінарники чи подібні статично злінковані речі, то там Alpine рулить.
2. Порядок команд має значення. Спочатку COPY lock файлу, потім install, і тільки потім COPY решти коду. В результаті залежності не будуть зтягуватись кожного разу, як ви поміняєте таби на пробіли.
3. Multi-stage білди це не просто «best practice заради галочки», а реальна причина, чому прод-образ не тягне за собою gcc, хедери і 400 мегабайт тулчейну. В білдер-стейдж навалюємо все що треба для збірки, а потім звідти у фінальний стейдж переносимо лише артефакти та рантайм. Маємо на виході маленький образ, який швидко деплоїться.
4. COPY . . насправді нормально, якщо ваш .dockerignore написано по-людськи. Більшість болю зазвичай від того, що люди забувають виключити node_modules, .git, локальні логи і купу сміття. Фіксити треба ignore, а не COPY.
5. Піньте базовий образ по digest, а не по тегу. node:20 сьогодні і node:20 через пів року це два різних образи. Прод впав через оновлення тега, на яке ви не підписувались, а як же так сталось?! Digest тримає все під вашим контролем, все оновиться саме коли ви вирішите, а не о другій ночі першого січня.
6. BuildKit cache mounts (--mount=type=cache) це та фіча, про яку чомусь майже ніхто не говорить. Кеш pip, apt, cargo, npm живе між білдами і при цьому не потрапляє у фінальний шар, тобто образ залишається чистим, а повторні білди прискорюються в рази. Люди годинами тюнять CI/CD пайплайни, виносять кеш в окремі воркери, пишуть костилі, а одна директива в RUN робить те саме зрозумілішим і швидшим способом. Якщо ви про це ще не чули, то це, мабуть, та єдина порада з усіх тут, яку справді варто спробувати сьогодні ввечері.
Шо скажете? Дізнались щось нове?
6 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарівЕм. Використовувати ignore замість копіювати ТІЛЬКИ потрібне — обов’язково колись призведе до витоку небажаних локальних файлів в докер імідж.
Це як використовувати в файрволі «deny ... / allow any» замість правильного «allow ... / deny any»
Ще одна стаття про Docker і знову нічого про distroless.
Цей пост спіздили звідси:
* www.linkedin.com/...vity:7449687179037102080
* x.com/...tatus/2044277151147422122
Ні, там рулить
FROM scratchякщо у вашому докерфайлі немає
--only-binary=:all:, то це набагато більша проблема, ніж просто Alpine :)Насправді це ніколи не нормально — це стандартна проблема blacklist vs whitelist. Якщо хтось забуде проапдейтити blacklist, все буде працювати як раніше і цього ніхто не побачить. Якщо хтось забуде проапдейтити whitelist для СВОЇХ змін, то це відразу впаде і, відповідно, буде відразу вилікувано тим, хто ці зміни робив
.dockerignore — також потрібен, але виключно як оптимізація білда, а не як оптимізація фінального образу