Ты создаешь Dockerfile для веб-приложения. Нужно скопировать конфигурационный файл config.json из локальной папки /configs в контейнер по пути /app/config.json. Какую директиву использовать правильнее всего?
Anonymous Quiz
9%
VOLUME /configs/config.json /app/config.json
11%
ADD /configs/config.json /app/config.json
8%
RUN cp /configs/config.json /app/config.json
72%
COPY /configs/config.json /app/config.json
👌4👍2
⏰ Жди меня, и я вернусь ⏰
Пятница, конец недели, мозги уже настроены на выходные, а тут еще и контейнеры какие-то надо один за другим запускать - один отработал, врубить другой и тд. А настроенице то такое, чтобы весь мир подождал до понедельника, а дальше это уже проблемы завтрашнего Гомера...
Кажется, товарищам из команды разработки докера ничто человеческое не чуждо. Именно поэтому (я просто уверен) была придумана команда, которая может терпеливо ждать завершения контейнера и даже скажет, с каким кодом он завершился?
Прошу любить и жаловать -
Основы использования:
Команда вернет exit code контейнера. 0 — все ОК, любое другое число — что-то пошло не так.
Зачем это нужно?
🔹В скриптах автоматизации часто нужно дождаться завершения одного контейнера перед запуском следующего. Представь: у тебя есть контейнер с миграциями БД, и только после их успешного завершения можно поднимать основное приложение.
🔹Тестовые пайплайны в CI/CD: запускается контейнер с тестами, а скрипт с помощью docker wait ожидает его завершения, чтобы по коду возврата определить, упали тесты или прошли успешно, и принять решение о продвижении сборки.
🔹Оркестрация зависимых сервисов: когда нужно гарантировать, что контейнер-инициатор какой-либо задачи (например, обработки данных) завершил работу, прежде чем запускать контейнер-потребитель результатов.
Помнишь наш пост про docker kill? Так вот,
Команда работает только с запущенными контейнерами. Если контейнер уже завершился,
Простая команда, а сколько пользы для автоматизации! 🚀
🥷 Docker Ninja 🥷
Пятница, конец недели, мозги уже настроены на выходные, а тут еще и контейнеры какие-то надо один за другим запускать - один отработал, врубить другой и тд. А настроенице то такое, чтобы весь мир подождал до понедельника, а дальше это уже проблемы завтрашнего Гомера...
Кажется, товарищам из команды разработки докера ничто человеческое не чуждо. Именно поэтому (я просто уверен) была придумана команда, которая может терпеливо ждать завершения контейнера и даже скажет, с каким кодом он завершился?
Прошу любить и жаловать -
docker wait. Простая, но очень полезная команда для тех, кто любит порядок в своих скриптах! 🎯Основы использования:
# Ждем завершения одного контейнера
docker wait my_container
# Ждем несколько контейнеров сразу
docker wait container1 container2 container3
Команда вернет exit code контейнера. 0 — все ОК, любое другое число — что-то пошло не так.
Зачем это нужно?
🔹В скриптах автоматизации часто нужно дождаться завершения одного контейнера перед запуском следующего. Представь: у тебя есть контейнер с миграциями БД, и только после их успешного завершения можно поднимать основное приложение.
🔹Тестовые пайплайны в CI/CD: запускается контейнер с тестами, а скрипт с помощью docker wait ожидает его завершения, чтобы по коду возврата определить, упали тесты или прошли успешно, и принять решение о продвижении сборки.
🔹Оркестрация зависимых сервисов: когда нужно гарантировать, что контейнер-инициатор какой-либо задачи (например, обработки данных) завершил работу, прежде чем запускать контейнер-потребитель результатов.
Помнишь наш пост про docker kill? Так вот,
wait — его полная противоположность. Вместо принудительной остановки мы терпеливо ждем естественного завершения 🧘Команда работает только с запущенными контейнерами. Если контейнер уже завершился,
wait моментально вернет его последний exit code. Простая команда, а сколько пользы для автоматизации! 🚀
🥷 Docker Ninja 🥷
🔥6👍2
🚦 Зависимые отношения 🚦
Ты пушишь в прод свежий
На такой случай имеем директиву
Базовый пример:
Польза данной диррективы в том, она гарантирует порядок запуска: сначала поднимутся db и redis, потом уже web.
Теперь веб дождется, когда контейнер базы стартанет и начнет стартовать! 🎯
Но есть нюанс — это НЕ означает, что PostgreSQL будет готов принимать коннекты! Как решать такие проблемы, разберем в следующих постах.
Зачем юзать?
🔹 Избегаешь race conditions между сервисами на уровне инфраструктуры
🔹 Контролируешь сложные зависимости (API → DB → Cache)
🔹 Спасаешься от факапов с "недоступной базой"
Ставь 🔥 если тоже страдал от преждевременных стартов!
🥷 Docker Ninja 🥷
Ты пушишь в прод свежий
docker-compose up -d, а через секунду получаешь unhealthy статус и сообщение в логах: "Connection to database failed". Вот это поворот... Твое веб-приложение стартануло быстрее PostgreSQL и упало так и не дождавшись готовности базы. Как бы сказал великий классик: "Ha, ha, classic"! Уж простите за тафтологию.На такой случай имеем директиву
depends_on!Базовый пример:
services:
web:
image: nginx
depends_on:
- db
- redis
db:
image: postgres:15
redis:
image: redis:alpine
Польза данной диррективы в том, она гарантирует порядок запуска: сначала поднимутся db и redis, потом уже web.
Теперь веб дождется, когда контейнер базы стартанет и начнет стартовать! 🎯
Но есть нюанс — это НЕ означает, что PostgreSQL будет готов принимать коннекты! Как решать такие проблемы, разберем в следующих постах.
Зачем юзать?
🔹 Избегаешь race conditions между сервисами на уровне инфраструктуры
🔹 Контролируешь сложные зависимости (API → DB → Cache)
🔹 Спасаешься от факапов с "недоступной базой"
Ставь 🔥 если тоже страдал от преждевременных стартов!
🥷 Docker Ninja 🥷
👍9🔥4
👴🏼Тряхнем стариной👴🏼
Если говорить честно, то механизм depends_on существовал не всегда, но и у него были альтернативы.
Узнать, что за механизм и зачем тебе о нем знать, ты можешь нажав на кнопку ниже⬇️
Если говорить честно, то механизм depends_on существовал не всегда, но и у него были альтернативы.
Узнать, что за механизм и зачем тебе о нем знать, ты можешь нажав на кнопку ниже⬇️
🔥9
В чем основное отличие виртуализации от контейнеризации с точки зрения архитектуры?
Anonymous Quiz
20%
Виртуальные машины имеют лучшую изоляцию процессов
2%
Контейнеры потребляют больше ресурсов, чем виртуальные машины
1%
Виртуальные машины быстрее запускаются, чем контейнеры
76%
Контейнеры используют общее ядро ОС, виртуальные машины - отдельные ядра
👍3🤔2👎1🤡1
📚 Все дороги ведут в Registry 📚
Помнишь старые времена, когда образы передавали флешками и ссылками на Dropbox? Не помнишь?! И правильно, потому что никогда такого не было! Все потому, что разработчики docker придумали Docker Registry, который стал центральной нервной системой контейнерной вселенной. Но что он из себя представляет под капотом?
🔹Registry - это библиотека образов с блек джеком и прочими прелестями!
Если коротко, то Docker Registry - это специализированное веб-приложение (REST API), которое управляет хранением и распределением Docker-образов по определенному стандарту (OCI Distribution Spec). Это не просто файловое хранилище вроде S3 или FTP, а интеллектуальная система, которая понимает все нюансы Docker-образов.
🔹Архитектура: слоеный пирог
Фишка Registry в том, что образы хранятся не целиком, а слоями! Каждый слой - это дифф изменений файловой системы. Когда несколько образов используют одинаковую базу (например, Ubuntu), Registry умно дедуплицирует слои. Один слой - много ссылок. Экономия дискового пространства на лицо!
🔹Push/Pull
При пуше Docker разбивает образ на слои, хеширует их и отправляет только новые в виде tar.gz архива. При пулле скачиваются только недостающие слои в том же виде и собираются обратно в образ. Магия дедупликации работает и тут - если у тебя уже есть слой с nginx:alpine, он не будет скачиваться повторно для другого образа!
🔹Теги и версионирование
Система тегов - это не Git, это проще! Один и тот же по составу образ может иметь множество тегов, которые просто указывают на один манифест. Тег
🔹Манифест:
Каждый образ содержит "инструкция по сборке" - манифест. Изнутри это JSON-файл, который содержит метаданные — список всех слоев, их хеши, размер, а также конфигурацию контейнера (например, переменные окружения, точку входа)
Когда ты делаешь docker pull, Docker сначала загружает манифест, а затем по списку в нем скачивает необходимые слои.
🔹Приватные vs публичные
Docker Hub удобен для открытых проектов, но для продакшена лучше приватный registry. Harbor, AWS ECR, Azure Container Registry - все они работают по одному API, но дают контроль над безопасностью и retention policies.
Понимание Registry - это понимание того, как живет весь Docker-экосистем!
Жми реакт, если Registry больше не кажется черной магией!
🥷 Docker Ninja 🥷
Помнишь старые времена, когда образы передавали флешками и ссылками на Dropbox? Не помнишь?! И правильно, потому что никогда такого не было! Все потому, что разработчики docker придумали Docker Registry, который стал центральной нервной системой контейнерной вселенной. Но что он из себя представляет под капотом?
🔹Registry - это библиотека образов с блек джеком и прочими прелестями!
Если коротко, то Docker Registry - это специализированное веб-приложение (REST API), которое управляет хранением и распределением Docker-образов по определенному стандарту (OCI Distribution Spec). Это не просто файловое хранилище вроде S3 или FTP, а интеллектуальная система, которая понимает все нюансы Docker-образов.
🔹Архитектура: слоеный пирог
Фишка Registry в том, что образы хранятся не целиком, а слоями! Каждый слой - это дифф изменений файловой системы. Когда несколько образов используют одинаковую базу (например, Ubuntu), Registry умно дедуплицирует слои. Один слой - много ссылок. Экономия дискового пространства на лицо!
🔹Push/Pull
При пуше Docker разбивает образ на слои, хеширует их и отправляет только новые в виде tar.gz архива. При пулле скачиваются только недостающие слои в том же виде и собираются обратно в образ. Магия дедупликации работает и тут - если у тебя уже есть слой с nginx:alpine, он не будет скачиваться повторно для другого образа!
🔹Теги и версионирование
Система тегов - это не Git, это проще! Один и тот же по составу образ может иметь множество тегов, которые просто указывают на один манифест. Тег
latest не последняя версия, а просто алиас, который может указывать на что угодно.🔹Манифест:
Каждый образ содержит "инструкция по сборке" - манифест. Изнутри это JSON-файл, который содержит метаданные — список всех слоев, их хеши, размер, а также конфигурацию контейнера (например, переменные окружения, точку входа)
Когда ты делаешь docker pull, Docker сначала загружает манифест, а затем по списку в нем скачивает необходимые слои.
🔹Приватные vs публичные
Docker Hub удобен для открытых проектов, но для продакшена лучше приватный registry. Harbor, AWS ECR, Azure Container Registry - все они работают по одному API, но дают контроль над безопасностью и retention policies.
Понимание Registry - это понимание того, как живет весь Docker-экосистем!
Жми реакт, если Registry больше не кажется черной магией!
🥷 Docker Ninja 🥷
👍8❤3
Ты создал контейнер с веб-приложением и хочешь скопировать лог-файл из контейнера на хост для анализа. Какая команда позволит это сделать?
Anonymous Quiz
31%
docker copy container_name:/app/logs/app.log ./app.log
3%
docker transfer container_name:/app/logs/app.log ./app.log
64%
docker cp container_name:/app/logs/app.log ./app.log
1%
docker move container_name:/app/logs/app.log ./app.log
👍5🔥3😱1
⏸️ Стоп слово - Fluggegecheimen ⏸️
Представь: у тебя крутится ресурсоемкая задача по обработке данных, а тут метрики хоста выдают алерт по CPU. Что же делать? Убить контейнер? Потеряешь прогресс. Проигнорировать? Ляжет весь хост...
Мда, ситуация на уровне "вилкой в глаз или...". На такие случаи важно знать стоп-слово.
Пожалуйста,
Как это работает:
В отличие от
Чем отличается от stop:
🔹
🔹
🔹 Stop освобождает ресурсы, pause — оставляет все в памяти
Когда юзать?
🔹 Отладка: заморозил, подключился, изучил состояние
🔹 Экстренное освобождение CPU без потери данных
🔹 Миграция контейнеров между хостами
🔹 Создание снапшотов состояния для анализа
Важный нюанс: замороженный контейнер продолжает занимать память! Это не гибернация, а именно пауза. Сетевые соединения могут таймаутиться, пока контейнер спит.
Кстати, помнишь наш разговор про docker compose pause? Тот же принцип, только для одного контейнера!
Жми палец вверх, если пригодилось!
🥷 Docker Ninja 🥷
Представь: у тебя крутится ресурсоемкая задача по обработке данных, а тут метрики хоста выдают алерт по CPU. Что же делать? Убить контейнер? Потеряешь прогресс. Проигнорировать? Ляжет весь хост...
Мда, ситуация на уровне "вилкой в глаз или...". На такие случаи важно знать стоп-слово.
Пожалуйста,
docker pause - твое спасение на случай важных переговоров!Как это работает:
# Замораживаем контейнер
docker pause my-container
# Размораживаем обратно
docker unpause my-container
В отличие от
docker stop, который отправляет SIGTERM процессам, pause использует cgroups freezer — механизм ядра Linux. Все процессы контейнера буквально замораживаются на месте! Никаких сигналов, никакого graceful shutdown. Просто стоп-кадр всей жизнедеятельности.Чем отличается от stop:
🔹
docker stop — завершает порождающий процесс контейнера🔹
docker pause — ставит все процессы на паузу без предупреждения🔹 Stop освобождает ресурсы, pause — оставляет все в памяти
Когда юзать?
🔹 Отладка: заморозил, подключился, изучил состояние
🔹 Экстренное освобождение CPU без потери данных
🔹 Миграция контейнеров между хостами
🔹 Создание снапшотов состояния для анализа
Важный нюанс: замороженный контейнер продолжает занимать память! Это не гибернация, а именно пауза. Сетевые соединения могут таймаутиться, пока контейнер спит.
Кстати, помнишь наш разговор про docker compose pause? Тот же принцип, только для одного контейнера!
Жми палец вверх, если пригодилось!
🥷 Docker Ninja 🥷
👍13❤2😁2
🏃♂️ Утром бегит, пресс качац, анжуманя 🏃♂️
Коллега, все мы знаем, что с нашей сидячей работой очень важно следить за физической активностью. Иначе, есть перспектива навайбкодить себе мозоль не только на пузе, но и на вечно подгорающей точке притяжения приключений.🍑
Отсюда вывод, больше бегаешь = меньше весиш.
Кажется, такого девиза придерживаются и те, кто любит исчеркать Dockerfile бездумными вызовами
Так что сегодня, давайте разберемся в сущности такой простой директивы как
🔥 Что это вообще такое?
Есть две формы записи:
И как же это оптимизировать:
👉🏻Плохо (каждый RUN = отдельный слой):
👉🏻Хорошо (один RUN = один слой):
Так и в чем же разница?
Для этого надо вспомнить про кэш сборки. Так вот, каждый
💥 Значит каждый отдельный
💥 В общем
Отсюда и экономия пространства.
Так что, используй
🥷 Docker Ninja 🥷
Коллега, все мы знаем, что с нашей сидячей работой очень важно следить за физической активностью. Иначе, есть перспектива навайбкодить себе мозоль не только на пузе, но и на вечно подгорающей точке притяжения приключений.🍑
Отсюда вывод, больше бегаешь = меньше весиш.
Кажется, такого девиза придерживаются и те, кто любит исчеркать Dockerfile бездумными вызовами
RUN команд, а потом удивляются, почему их образ весит как слон после новогодних праздников!Так что сегодня, давайте разберемся в сущности такой простой директивы как
RUN в Dockerfile.🔥 Что это вообще такое?
RUN выполняет команды во время сборки образа и создает новый слой с результатами. Каждый RUN = новый слой = +размер к образу.Есть две формы записи:
# Shell форма (через /bin/sh -c)
RUN apt-get update && apt-get install -y nginx
# Exec форма (прямое выполнение)
RUN ["apt-get", "update"]
И как же это оптимизировать:
👉🏻Плохо (каждый RUN = отдельный слой):
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y vim
RUN rm -rf /var/lib/apt/lists/*
👉🏻Хорошо (один RUN = один слой):
RUN apt-get update && \
apt-get install -y curl vim && \
rm -rf /var/lib/apt/lists/*
Так и в чем же разница?
Для этого надо вспомнить про кэш сборки. Так вот, каждый
RUN кэшируется отдельно.💥 Значит каждый отдельный
RUN оставляет следы в общем слоеном пироге нашего образа, не смотря на то, что в примере мы удаляем кэш пакетов.💥 В общем
RUN мы получаем один слой в котором уже есть установленные пакеты и отсуствует кэш этих пакетов.Отсюда и экономия пространства.
Так что, используй
RUN с умом и не забудь размяться после прочтения поста! 💪🥷 Docker Ninja 🥷
1👍15🤮1
В CI/CD пайплайне нужно автоматически очищать старые образы после деплоя, чтобы не засорять диск агента. Какая команда удалит все неиспользуемые образы одной строкой?
Anonymous Quiz
48%
docker image rm $(docker images -q)
13%
docker rmi --force
25%
docker system prune -a —volumes
14%
docker volume prune
🔥3
🐧 Что дозволено пингвину, не дозволено киту 🐳
Помнишь, мы запускали контейнеры с флагом --memory? Как думаешь, Docker сам по себе следит за памятью? А вот и нет! Docker — это всего лишь красивая обертка над всемогущим Linux ядром.
Конкретно в данном случае работает механизм Control Groups или cgroups
Хочешь заглянуть под капот? Запусти контейнер:
А теперь подсмотри, что творится в недрах системы:
Хоба, и там целая иерархия папок! Каждая — это отдельная cgroup для твоего контейнера. Docker автоматически создает группы:
- 🧠 Памяти (
- ⚡️ CPU (
- 💾 Дискового I/O (
Зачем это знать?
Когда твой контейнер внезапно прибивается или мониторинг показывает странности с ресурсами, именно в эти файлы стоит заглянуть. Помнишь docker stats? Он как раз читает данные из cgroups! А если вдруг docker cli по какой-то причине недоступны, то раскуривать остается только файлы cgroups.
А еще это объясняет, почему контейнеры работают только на Linux — без cgroups и namespaces вся изоляция превращается в тыкву 🎃
Ставь 🔥, если хочешь узнать подробнее как, где и что копать в cgroups под Docker.
🥷 Docker Ninja 🥷
Помнишь, мы запускали контейнеры с флагом --memory? Как думаешь, Docker сам по себе следит за памятью? А вот и нет! Docker — это всего лишь красивая обертка над всемогущим Linux ядром.
Конкретно в данном случае работает механизм Control Groups или cgroups
Хочешь заглянуть под капот? Запусти контейнер:
docker run -d --name test-container --memory 512m nginx
А теперь подсмотри, что творится в недрах системы:
# Найдем ID контейнера
docker inspect test-container | grep Id
# Заглянем в cgroups
ls /sys/fs/cgroup/memory/docker/
# Найдем выставленный нами лимит памяти
cat /sys/fs/cgroup/memory/docker/conatainer_id/memory.limit_in_bytes
Хоба, и там целая иерархия папок! Каждая — это отдельная cgroup для твоего контейнера. Docker автоматически создает группы:
- 🧠 Памяти (
/sys/fs/cgroup/memory/docker/)- ⚡️ CPU (
/sys/fs/cgroup/cpu/docker/)- 💾 Дискового I/O (
/sys/fs/cgroup/blkio/docker/)Зачем это знать?
Когда твой контейнер внезапно прибивается или мониторинг показывает странности с ресурсами, именно в эти файлы стоит заглянуть. Помнишь docker stats? Он как раз читает данные из cgroups! А если вдруг docker cli по какой-то причине недоступны, то раскуривать остается только файлы cgroups.
А еще это объясняет, почему контейнеры работают только на Linux — без cgroups и namespaces вся изоляция превращается в тыкву 🎃
Ставь 🔥, если хочешь узнать подробнее как, где и что копать в cgroups под Docker.
🥷 Docker Ninja 🥷
🔥26👍2🤯1
Какой сигнал Docker отправляет процессу в контейнере первым при выполнении команды docker stop?
Anonymous Quiz
40%
SIGTERM
36%
SIGSTOP
9%
SIGINT
14%
SIGKILL
😁3🤔1
🍻За связь без брака🍻
Как и обещал в прошлый понедельник, размещаю пост для любителей поковыряться в legacy.
До появления пользовательских сетей контейнеры жили в изоляции даже между собой. И тогда на арену вышел механизм links - примитивыный, но действенный способ познакомить контейнеры друг с другом!
Вот как выглядел этот винтаж:
Что творилось под капотом:
🔗 Docker пробрасывал записи в
🌍 Создавал переменные окружения типа
А как же зависимости?
Главная проблема этой архаики в том, что работала она только в рамках одного хоста. Зато сетевая изоляция на уровне!
И, как вы видите, links - это не столько механизм порядка запуска, сколько сам механизм сети. И в данном случае, порядок запуска обеспечивался самым простым костылем - баш скриптом, который проверяет доступность сервиса по хостнейму, указанному в линке.
Например, вот так:
Так что, если увидишь данное чудо (в версиях компоуза до 2), не пугайся, смело переходи на более свежий компоуз и используй современные пользовательские сети + depends_on!
Жми 👍🏻, если рассказал своему деду про links, а он прослезился!
🥷 Docker Ninja 🥷
Как и обещал в прошлый понедельник, размещаю пост для любителей поковыряться в legacy.
До появления пользовательских сетей контейнеры жили в изоляции даже между собой. И тогда на арену вышел механизм links - примитивыный, но действенный способ познакомить контейнеры друг с другом!
Вот как выглядел этот винтаж:
version: '2'
services:
web:
image: nginx
links:
- db:database
- redis:cache
db:
image: postgres
redis:
image: redis
Что творилось под капотом:
🔗 Docker пробрасывал записи в
/etc/hosts контейнера web:172.17.0.2 db database
172.17.0.3 redis cache
🌍 Создавал переменные окружения типа
DATABASE_PORT_5432_TCP_ADDRА как же зависимости?
Главная проблема этой архаики в том, что работала она только в рамках одного хоста. Зато сетевая изоляция на уровне!
И, как вы видите, links - это не столько механизм порядка запуска, сколько сам механизм сети. И в данном случае, порядок запуска обеспечивался самым простым костылем - баш скриптом, который проверяет доступность сервиса по хостнейму, указанному в линке.
Например, вот так:
bash -c "while ! nc -z db 5432; do sleep 1; done && python app.py"
Так что, если увидишь данное чудо (в версиях компоуза до 2), не пугайся, смело переходи на более свежий компоуз и используй современные пользовательские сети + depends_on!
Жми 👍🏻, если рассказал своему деду про links, а он прослезился!
🥷 Docker Ninja 🥷
👍10❤2
🧅 Сидит дед, в сто шуб одет 🧅
Мы уже не раз касались такой темы как Layered File System в Docker (6, 19, 41, 64). И уже хорошо знаем, что благодаря этому механизму обеспечивается приличное количество фич, упрощающих процесс разработки. Особенно в условиях новомодного микросервисного ада!🤯
Но как же это реализовано изнутри?? Давайте глянем.
Как мы уже говорили, есть image layer и writable layer. Если быть честным, то и того и другого слоев будет несколько. Просто то, что было сделано в базовом образе, называется image layer и по своей сути является неизменным (read-only). Writable layer же - это чистое поле для экспериментов и каждое изменение фиксируется в нем как отдельный слой со своим хэш-ом - названием (наподобие commit hash в git-е).
Как хранится?
Docker хранит эти слои как отдельные директории в /var/lib/docker/driver_name/
За всем этим колдунством стоит так называемый
CoW:
Операции I/O реализованны через стратегию Copy-on-Write
🔹Read: файл читается из read-only слоев
🔹Write: когда мы пытаемся изменить файл в базовом образе, он копируется в верхний writable слой, и изменяется именно копия исходного файла
🔹Delete: создается "whiteout" файл, скрывающий нижний слой
Хеширование и дедупликация:
Каждый слой идентифицируется SHA256 (об этом чутка упоминал выше). Одинаковые слои физически хранятся один раз, независимо от количества образов!
Зачем эта сложность?
🔹Пересобираются только измененные слои
🔹Скачиваются только новые слои
🔹Один слой на много образов = оптимизация хранения
Теперь ты знаешь, почему docker pull иногда показывает "Already exists" - Docker просто переиспользует существующие слои!
Ставь 🤯, если ничего не понятно, но очень интересно и ты просто требуешь пояснительной бригады в виде длино-поста с красивыми картинками!🤓
🥷 Docker Ninja 🥷
Мы уже не раз касались такой темы как Layered File System в Docker (6, 19, 41, 64). И уже хорошо знаем, что благодаря этому механизму обеспечивается приличное количество фич, упрощающих процесс разработки. Особенно в условиях новомодного микросервисного ада!🤯
Но как же это реализовано изнутри?? Давайте глянем.
Как мы уже говорили, есть image layer и writable layer. Если быть честным, то и того и другого слоев будет несколько. Просто то, что было сделано в базовом образе, называется image layer и по своей сути является неизменным (read-only). Writable layer же - это чистое поле для экспериментов и каждое изменение фиксируется в нем как отдельный слой со своим хэш-ом - названием (наподобие commit hash в git-е).
Как хранится?
Docker хранит эти слои как отдельные директории в /var/lib/docker/driver_name/
/var/lib/docker/overlay2/
├── abc123.../diff # Слой с изменениями
├── def456.../diff # Еще один слой
├── ......
└── merged/ # Итоговая FS
За всем этим колдунством стоит так называемый
UnionFS. Storage driver-ы склеивают слои через механизм union mount. Верхние слои "перекрывают" нижние. Если файл меняется в нескольких слоях - побеждает верхний. Таким образом обеспечивается актуальность изменений.CoW:
Операции I/O реализованны через стратегию Copy-on-Write
🔹Read: файл читается из read-only слоев
🔹Write: когда мы пытаемся изменить файл в базовом образе, он копируется в верхний writable слой, и изменяется именно копия исходного файла
🔹Delete: создается "whiteout" файл, скрывающий нижний слой
Хеширование и дедупликация:
Каждый слой идентифицируется SHA256 (об этом чутка упоминал выше). Одинаковые слои физически хранятся один раз, независимо от количества образов!
Зачем эта сложность?
🔹Пересобираются только измененные слои
🔹Скачиваются только новые слои
🔹Один слой на много образов = оптимизация хранения
Теперь ты знаешь, почему docker pull иногда показывает "Already exists" - Docker просто переиспользует существующие слои!
Ставь 🤯, если ничего не понятно, но очень интересно и ты просто требуешь пояснительной бригады в виде длино-поста с красивыми картинками!🤓
🥷 Docker Ninja 🥷
🤯15🔥1
Ты разворачиваешь веб-приложение в контейнере и хочешь убедиться, что оно корректно запускается и отвечает на запросы. Какая директива Dockerfile поможет Docker автоматически проверять состояние приложения?
Anonymous Quiz
8%
CMD curl -f http://localhost:8080/health || exit 1
12%
RUN curl -f http://localhost:8080/health || exit 1
71%
HEALTHCHECK --interval=30s CMD curl -f http://localhost:8080/health || exit 1
9%
EXPOSE 8080 && curl -f http://localhost:8080/health
🕳 Если долго смотреть в cgroup, cgroup начинает смотреть в тебя 🕳
По вашим заявкам в посте про cgroups продолжаем углубляться в кроличью нору дальше. Что ж, мои дорогие любители покопаться в кишочках, давайте приступим. 🙏🏻
🔍 Находим нужную cgroup
Ищем ID контейнера, чтобы знать в какую папку стучать
🤿 Теперь ныряем в его метрики:
💾 Метрики памяти
🖥 CPU метрики
💿 Block I/O метрики
🥶Наш любимый freezer
Как мы уже разобрали в первом посте про cgroups, docker stats и флаг --memory работают именно с этими файлами.
Но, линукс не линукс, если бы все было так просто... Данная файловая структура актуальна для
🥷 Docker Ninja 🥷
По вашим заявкам в посте про cgroups продолжаем углубляться в кроличью нору дальше. Что ж, мои дорогие любители покопаться в кишочках, давайте приступим. 🙏🏻
🔍 Находим нужную cgroup
Ищем ID контейнера, чтобы знать в какую папку стучать
ddocker inspect test-container | grep Id
🤿 Теперь ныряем в его метрики:
💾 Метрики памяти
# Текущее использование памяти
cat /sys/fs/cgroup/memory/docker/CONTAINER_ID/memory.usage_in_bytes
# Лимит памяти контейнера
cat /sys/fs/cgroup/memory/docker/CONTAINER_ID/memory.limit_in_bytes
# Детальная статистика памяти
cat /sys/fs/cgroup/memory/docker/CONTAINER_ID/memory.stat
# Пиковое потребление памяти
cat /sys/fs/cgroup/memory/docker/CONTAINER_ID/memory.max_usage_in_bytes
# Swap использование
cat /sys/fs/cgroup/memory/docker/CONTAINER_ID/memory.memsw.usage_in_bytes
🖥 CPU метрики
# Общее время CPU в наносекундах
cat /sys/fs/cgroup/cpuacct/docker/CONTAINER_ID/cpuacct.usage
# CPU usage по ядрам
cat /sys/fs/cgroup/cpuacct/docker/CONTAINER_ID/cpuacct.usage_percpu
# Детальная статистика CPU
cat /sys/fs/cgroup/cpu/docker/CONTAINER_ID/cpu.stat
# Время в user/system mode
cat /sys/fs/cgroup/cpuacct/docker/CONTAINER_ID/cpuacct.stat
# CPU throttling статистика
cat /sys/fs/cgroup/cpu/docker/CONTAINER_ID/cpu.throttling_data
💿 Block I/O метрики
# Статистика по чтению/записи
cat /sys/fs/cgroup/blkio/docker/CONTAINER_ID/blkio.throttle.io_service_bytes
# IOPS счетчики
cat /sys/fs/cgroup/blkio/docker/CONTAINER_ID/blkio.throttle.io_serviced
# Время обслуживания I/O
cat /sys/fs/cgroup/blkio/docker/CONTAINER_ID/blkio.time
🥶Наш любимый freezer
# Текущее состояние контейнера
cat /sys/fs/cgroup/freezer/docker/CONTAINER_ID/freezer.state
# PID родительского процесса контейнера
cat /sys/fs/cgroup/freezer/docker/CONTAINER_ID/cgroup.procs
# Список всех потоков (threads), принадлежащих контейнеру (в старых версиях ядра).
cat /sys/fs/cgroup/freezer/docker/CONTAINER_ID/tasks
Как мы уже разобрали в первом посте про cgroups, docker stats и флаг --memory работают именно с этими файлами.
Но, линукс не линукс, если бы все было так просто... Данная файловая структура актуальна для
cgroups v1. Поэтому, ставь 🔥 если хочешь узнать про то, как работать с файлами cgroups v2.🥷 Docker Ninja 🥷
🔥20😁4🤣1🙈1
🧼 Моя оборона! 🧼
Я где-то слышал, что практически каждый второй Docker-образ, будь то Docker Hub или же приватные registry содержит критические уязвимости, но мы же продолжаем пулить их как ни в чем не бывало!
Проверять это утверждение я конечно же не буду, но не удивлюсь, если это окажется правдой... Да и как предлог заколлабиться с безопасниками и реализовать что-то новенькое для своего портфолио хороший!😏
Так шо сегодня разберем с вами Docker Scout - встроенный сканер безопасности докер образов aka "нет пробития"! Ага, прикиньте, есть такой. Я сам однажды офигел!!!
🔐 Запускаем сканирование
После docker login можем сканировать приватные образы:
📊 Детальный анализ
💡Что еще умеет?
🔹 Scout анализирует не только OS-пакеты, но и зависимости языков (Node.js, Python, Java, а это уже вполне себе такой Software Composition Analisys)
Кстати, тул умеет выгружать эту аналитику в sbom файл, который потом можно грузануть в какую-нибудь систему аналитики уязвимостей (типа Dependency Track или DefectDojo)
🔹 Интегрируется с Docker Desktop для GUI-анализа
🔹 Поддерживает webhook-и для автоматических уведомлений
Теперь об обороне стало думать легче, тылы прикрыты, так что можно спокойно ронять мыло в общественных местах💪🏻
Ставь 😎 если уже представляешь, как твой security-отдел будет тебя благодарить!
🥷 Docker Ninja 🥷
Я где-то слышал, что практически каждый второй Docker-образ, будь то Docker Hub или же приватные registry содержит критические уязвимости, но мы же продолжаем пулить их как ни в чем не бывало!
Проверять это утверждение я конечно же не буду, но не удивлюсь, если это окажется правдой... Да и как предлог заколлабиться с безопасниками и реализовать что-то новенькое для своего портфолио хороший!😏
Так шо сегодня разберем с вами Docker Scout - встроенный сканер безопасности докер образов aka "нет пробития"! Ага, прикиньте, есть такой. Я сам однажды офигел!!!
🔐 Запускаем сканирование
# Сканируем локальный образ
docker scout cves nginx:latest
# Получим что-то типа такого
✔️ Image stored for indexing
┌───────────────┬────────┬──────────┬───────────────┐
│ CVE │ Score │ Severity │ Package │
├───────────────┼────────┼──────────┼───────────────┤
│ CVE-2023-1234 │ 8.2 │ HIGH │ libc6 │
│ CVE-2023-5678 │ 6.5 │ MEDIUM │ openssl │
│ CVE-2023-9012 │ 4.3 │ LOW │ zlib │
└───────────────┴────────┴──────────┴───────────────┘
Summary: 15 vulnerabilities found (3 critical, 5 high, 4 medium, 3 low)
# Или прямо при сборке
docker scout cves local://my-app:v1.0
После docker login можем сканировать приватные образы:
docker scout cves registry.company.com/my-private-app:latest
📊 Детальный анализ
# Сканирование с рекомендациями по исправлению
docker scout recommendations nginx:latest
# Анализ по критичности (только HIGH и CRITICAL)
docker scout cves --severity high,critical node:18-alpine
# Сравнение двух версий образа
docker scout compare nginx:1.20 --to nginx:1.21
# Анализ конкретного слоя
docker scout cves --layer-details postgres:15
## Вывод довольно читабельный
Layer 1: base image (debian:bullseye)
├── CVE-2023-1234 (HIGH) in libc6
└── CVE-2023-5678 (MEDIUM) in openssl
Layer 3: application dependencies
├── CVE-2023-9012 (CRITICAL) in python3.9
└── CVE-2023-3456 (HIGH) in postgresql-15
💡Что еще умеет?
🔹 Scout анализирует не только OS-пакеты, но и зависимости языков (Node.js, Python, Java, а это уже вполне себе такой Software Composition Analisys)
🔹 Интегрируется с Docker Desktop для GUI-анализа
🔹 Поддерживает webhook-и для автоматических уведомлений
Теперь об обороне стало думать легче, тылы прикрыты, так что можно спокойно ронять мыло в общественных местах💪🏻
Ставь 😎 если уже представляешь, как твой security-отдел будет тебя благодарить!
🥷 Docker Ninja 🥷
😁7😎4👍2🤣1
Твое приложение в контейнере потребляет слишком много памяти и часто падает. Ты хочешь ограничить использование RAM до 2024 МБ. Какой флаг использовать при запуске?
Anonymous Quiz
26%
docker run --memory 2024m my-app
33%
docker run --mem-limit 2024m my-app
6%
docker run --ram 2024m my-app
34%
docker run --max-memory 2024m my-app
😁4🙈3🌚1🗿1
Коллеги, думаю многие из вас пережили на этой неделе рабочую 6-дневку. Я, как и вы, не исключение. Поэтому, предлагаю хорошенько почилить и порасслабонить в доставшиеся нам за такие муки, 3 выходных дня!!! А в среду снова начнем бой во славу кровавого энтерпрайза!🤼♂️
С праздником всех причастных!
А не причастным "Счастливого хеллоуина" и побольше сладостей!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🍾2👍1
🐧Некоторым птицам не место в контейнере. У них слишком яркие перья🐧
Ну и заключительный пост про файлы cgroups (первый, второй).
Начиная с версии ядра Linux 4.5 мы взаимодействуем с cgroups v2, который стал более структурированный, чем первая версия.
Выглядит это дело так:
🎯Определяем директорию нашего контейнера:
🧠Memory
⚡️CPU
💾I/O
🧊Freezer
🚨Контроль процессов
В большинстве случаев, вы столкнетесь именно с
Как видим, изменения почти не коснулись метрик памяти. Но вот по остальным есть довольно много нюансов. И если копать в эту сторону еще глубже, то мы, в любом случае, выйдем на линукс. А это уже выходит за рамки тематики данного канала. Да и сам линукс - это уж очень глубокая штука, которую надо разбирать в отдельном канале.
Но, если есть желание закопаться еще глубже, то ставьте ваши 👍🏻 на пост. 25+ 👍🏻 станут для меня знаком, что стоит копнуть еще и в линукс.
🥷 Docker Ninja 🥷
Ну и заключительный пост про файлы cgroups (первый, второй).
Начиная с версии ядра Linux 4.5 мы взаимодействуем с cgroups v2, который стал более структурированный, чем первая версия.
Выглядит это дело так:
🎯Определяем директорию нашего контейнера:
# Запускаем контейнер
docker run -d --name test-app nginx
# Путь к cgroup контейнера
CGROUP_PATH="/sys/fs/cgroup/system.slice/docker-$(docker inspect -f '{{.Id}}' test-app).scope"
🧠Memory
# Текущее потребление памяти
cat $CGROUP_PATH/memory.current
# 52428800 (50MB в байтах)
# Максимальное потребление с момента старта
cat $CGROUP_PATH/memory.max
# max (без лимитов)
# Детальная статистика памяти
cat $CGROUP_PATH/memory.stat
# anon 12582912
# file 8388608
# kernel_stack 32768
⚡️CPU
# Статистика использования CPU
cat $CGROUP_PATH/cpu.stat
# usage_usec 1542340
# user_usec 890123
# system_usec 652217
# Помечен ли процесс контейнера как "с минимальным приоритетом"
cat $CGROUP_PATH/cpu.idle
# Текущий вес процесса
cat $CGROUP_PATH/cpu.weight
# 100
💾I/O
# Статистика ввода-вывода
cat $CGROUP_PATH/io.stat
# 8:0 rbytes=1048576 wbytes=4096 rios=64 wios=8
# Текущий I/O pressure
cat $CGROUP_PATH/io.pressure
# some avg10=0.00 avg60=0.00 avg300=0.00 total=0
🧊Freezer
# Проверяем текущее состояние
cat $CGROUP_PATH/cgroup.freeze
# 0 (разморожен)
# Замораживаем контейнер без docker cli
echo 1 > $CGROUP_PATH/cgroup.freeze
# После выполнения попробуй зайти в терминал контейнера
# Проверяем состояние
cat $CGROUP_PATH/cgroup.freeze
# 1 (заморожен)
# Размораживаем обратно
echo 0 > $CGROUP_PATH/cgroup.freeze
🚨Контроль процессов
# Список PID-ов в контейнере
cat $CGROUP_PATH/cgroup.procs
# 1234
# 1235
# События cgroup (убийства OOM, миграции и проч.)
cat $CGROUP_PATH/cgroup.events
# populated 1
# frozen 0
В большинстве случаев, вы столкнетесь именно с
cgroups v2. Поэтому полезно углубиться именно в этот вариант каталогов.Как видим, изменения почти не коснулись метрик памяти. Но вот по остальным есть довольно много нюансов. И если копать в эту сторону еще глубже, то мы, в любом случае, выйдем на линукс. А это уже выходит за рамки тематики данного канала. Да и сам линукс - это уж очень глубокая штука, которую надо разбирать в отдельном канале.
Но, если есть желание закопаться еще глубже, то ставьте ваши 👍🏻 на пост. 25+ 👍🏻 станут для меня знаком, что стоит копнуть еще и в линукс.
🥷 Docker Ninja 🥷
👍21❤3😁2👎1
Твоя команда разрабатывает микросервис и хочет минимизировать размер итогового образа. У вас есть этап компиляции Go-приложения и этап создания runtime-образа. Какой подход поможет создать максимально облегчит итоговый образ?
Anonymous Quiz
7%
Использовать один большой Dockerfile с установкой всех зависимостей
20%
Добавить .dockerignore для исключения ненужных файлов
3%
Использовать базовый образ ubuntu:latest вместо alpine
70%
Применить multi-stage builds для разделения сборки и runtime