Що таке .dockerignore і навіщо він потрібен?
.dockerignore це найпростіший Docker-файл, який ти колись напишеш. Він також один з найвпливовіших: контролює, що шиппиться на daemon під час docker build і запобігає трьом класам багів (повільні білди, роздуті image, витоки secret).
Теорія
TL;DR
- Build context = директорія, що передаєш у
docker build. Усе в ній заливається на daemon перед стартом білду. - Без
.dockerignoreУСЯ директорія шиппиться:node_modules,.git, build-output, IDE-config, secret, усе. - Синтаксис
.dockerignoreяк у gitignore з одним винятком: лише один**glob-патерн, без negation у деяких Docker-версіях. - Має бути у корені build context (поряд з
Dockerfile). - Три причини, чому важить: швидкість білду, розмір image, безпека.
Швидкий приклад
# .dockerignore
node_modules
.git
dist
build
*.log
*.tmp
.env*
.DS_Store
Dockerfile*
.dockerignore
README.md
.vscode
.idea
coverage
tests
*.test.js
*.spec.tsЗ цим docker build . шле лише реальні source-файли. Без цього типовий Node-проект шле 200+ MB node_modules і .git-папку повну історії, що не треба в image.
Синтаксис патернів
# Коментар
*.log # будь-який .log на будь-якій глибині
logs/ # директорія logs і усе всередині
!important.log # негація: включити, навіть якщо вище матчить
**/temp # будь-яка 'temp'-директорія на будь-якій глибині
src/**/*.test.js # test-файли будь-де під src/Важливо: порядок важить. Пізніші правила перекривають раніші. Бери ! для винятків.
Чому кожен рядок важить
node_modules (і еквіваленти)
Найбільший контрибутор. Часто сотні MB. Dockerfile все одно перевстановлює через npm ci.
node_modules
vendor # PHP / Go / Ruby vendored deps
.venv # Python virtualenv
__pycache__ # Python bytecode cache
*.pyc.git
Повна git-історія. Часто 50-500 MB на довго-живучих репо. Майже ніколи не потрібно у image.
Виняток: якщо білд потребує git-info (commit SHA через git rev-parse), бери git rev-parse HEAD > VERSION ПЕРЕД білдом, тоді виключай .git і COPY VERSION лише.
Build-output
dist
build
out
target # Rust / JavaТи перебудовуєш їх всередині image. Жодних причин шиппити host-output.
Secret і локальні config
.env*
*.pem
*.key
secrets.yaml
config.local.json.env, що випадково COPY'ється у image, це витоковий прод-secret.
IDE / редактори / OS-сміття
.vscode
.idea
.DS_Store # macOS
Thumbs.db # Windows
*.swp # vimТести і dev-артефакти (іноді)
coverage
tests # якщо не крутиш тести всередині image
*.test.jsЗалежить від твого build-flow. Якщо RUN npm test всередині білду (multi-stage), залиш тести. Інакше скіпай.
Типові помилки
Без .dockerignore взагалі
$ docker build -t myapp .
[+] Building 0.0s
=> transferring context: 248.7MB ← занадто велико248 MB upload на daemon кожен білд. Додай .dockerignore і дивися, як це впаде до кількох MB.
Забути, що COPY . . копіює усе у context
COPY . . # копіює усе, включно з .env, якщо не у .dockerignoreЯкщо .env існує у build context І не у .dockerignore, він приземляється у image. Аудитори обожнюють їх знаходити.
Класти .dockerignore у піддиректорію
Docker читає .dockerignore лише з кореня build context. Build context це те, що передаєш у docker build (зазвичай . = поточна директорія). .dockerignore у ./api/.dockerignore ігнорується, поки не білдиш через docker build ./api.
Negate-патерни і дивуватися
*
!Dockerfile
!src/**Цей allow-listy патерн крихкий і order-dependent. Простіше брати deny-list правила (node_modules, .git, dist).
Забути, що файл впливає і на multi-stage білди
Build context визначається раз для docker build, незалежно від того, скільки стейджів у Dockerfile. Кожен стейдж бачить той самий filtered context.
Inspecting що у build context
# Подивитися, що буде заливатися
docker build --no-cache --progress=plain -t test . 2>&1 | head -10
# Шукай рядок "transferring context"
# Або dry-run з ручним tar
tar --exclude-from=.dockerignore -cf - . | wc -cЯкщо колись думав «чому мій build context 1 GB?», du -sh */ .[^.]*/ 2>/dev/null | sort -h з кореня білду каже, що найбільше.
Реальне застосування
- Кожен прод-проект: має
.dockerignore. Дефолтний starter для будь-якого нового репо це додати його перед Dockerfile. - Monorepos: ще важливіше, директорії
node_modulesper package можуть давати гігабайти. - CI білди: великий build context, помножений на кожен CI-прогон, це реальні disk- і time-витрати.
- Cloud builds (Cloud Build, GitHub Actions): шиппять context у remote-сервіс. Менший = швидше (і дешевше).
Питання для поглиблення
Q: Що відбувається, якщо я COPY файл, виключений .dockerignore?
A: Docker падає з «file not found», з точки зору Docker файл не у context.
Q: Чим .dockerignore відрізняється від .gitignore?
A: Той самий синтаксис (переважно). .gitignore контролює, що git відстежує. .dockerignore контролює, що docker build шле на daemon. Незалежні файли, часто перетинаються, але не ідентичні (наприклад, сам .git не ігнорує .gitignore, але має ігнорувати .dockerignore).
Q: Чи .dockerignore впливає на docker run -v mount?
A: Ні. .dockerignore build-time only. Bind mount при run-time монтує те, на що показуєш, незалежно від .dockerignore.
Q: Чи може .dockerignore бути в іншому місці?
A: Так, з BuildKit можна використати # syntax=docker/dockerfile:1.7 і файл <Dockerfile>.dockerignore. Корисно, коли одне репо має кілька Dockerfile з різними ignore-потребами. Дефолт це все ще .dockerignore у корені build context.
Q: (Senior) Чому строго залочений .dockerignore може сповільнити dev-workflow?
A: Якщо виключає речі, що Dockerfile очікує знайти (test-фікстури, dev-config), COPY падає, або image поводиться неправильно. Поширений підступ: виключати .git, поки build-крок потребує git log для версії. Рішення: попередньо розрахувати значення (git rev-parse HEAD > VERSION перед білдом), передати через --build-arg, або per-Dockerfile .dockerignore варіант для dev vs прод.
Приклади
Типовий .dockerignore Node-проекту
# Залежності (перебудовуються всередині image)
node_modules
bower_components
# Build-output (перебудовуються всередині image)
dist
build
out
# Логи і temp
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Environment / secret
.env
.env.*
!.env.example # лишити приклад для документації
# Редактори
.vscode
.idea
*.swp
.DS_Store
# Тести / coverage
coverage
*.test.js
*.spec.ts
# Docker
Dockerfile*
.dockerignore
compose*.yaml
# VCS
.git
.gitignore
.gitattributesРезультат: docker build context, що містить рівно потрібні source-файли. Build-час падає драматично; image менший; secret не витікає.
Замір до і після
# До .dockerignore
$ time docker build -t myapp .
[+] Building ... transferring context: 312.4MB
real 1m45s
# Додати .dockerignore з node_modules і .git
$ time docker build -t myapp .
[+] Building ... transferring context: 4.2MB
real 0m22sДва рядки у .dockerignore, 5x швидший білд. Цифри множаться між CI-прогонами.
Multi-Dockerfile проект (BuildKit)
repo/
├── api/
│ ├── Dockerfile
│ └── Dockerfile.dockerignore # специфічно для api
├── web/
│ ├── Dockerfile
│ └── Dockerfile.dockerignore # специфічно для web
└── .dockerignore # shared baselineЗ # syntax=docker/dockerfile:1.7 BuildKit авто-завантажує <Dockerfile>.dockerignore, якщо є, інакше root .dockerignore. Корисно, коли api і web мають різні exclusion-потреби.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів