Docker Ninja – Telegram
Docker Ninja
1.05K subscribers
30 photos
91 links
По всем вопросам обращаться к @nesudimov_eu
Download Telegram
Please open Telegram to view this post
VIEW IN TELEGRAM
🤞 Last hope 🤞

Бывало так. Приходишь в офис, наливаешь себе спокойно кофе и думаешь:
- Ну, вчерашний релиз мы успешно пережили. Сегодня будет хороший день!

Но тут залетает PO и говорит, что какой-то умник ломает наше приложение. Id сессии можно увидеть лишь только в логах.

- Отлично, - думаешь ты, - сейчас глянем вывод docker logs. Если только...
Да, именно так - любимый коллега забыл прокинуть логирование в stdout.

- Не проблема. Таким меня не сломаешь! - тут же сам себя успокоил, - найдем их через псевдотерминал.

А вот и нет! В базовом образе контейнера не завезли оболочку. Да, и такое бывает - оптимизация, мать ее за ногу!
И вот, ты уже совсем поник и не знаешь что делать, как вдруг О великий и могучий чатгпт stackoverflow рассказывает нам про команду docker cp, которая позволяет дешево и сердито копировать файлы туда-сюда между контейнером и хостом!

Синтаксис простой как три копейки:
# Из контейнера на хост
docker cp my_container:/path/to/file ./local_path

# С хоста в контейнер
docker cp ./local_file my_container:/path/inside


И да, копировать можно даже целые папки:
docker cp my_container:/app/logs ./debug_logs


Ну и самое интересно, что команда работает независимо от того, запущен контейнер или висит мертвым грузом. Главное — узнать его ID или имя, например с помощью docker ps! Ай, хорошо...!!!

Зачем это нужно?
Реальные кейсы из окопов DevOps-а:
- Приложение легло, а тебе нужно вытащить дамп памяти или логи для анализа
- Срочно подкинуть исправленный конфиг без пересборки образа
- Забэкапить данные перед обновлением
- Вытащить артефакты сборки из билд-контейнера


Ставь 👍, если спас твой стул от следов возгорания!


🥷 Docker Ninja 🥷
👍172
Новый разработчки вручную настроил рабочую среду внутри контейнера и хочет сохранить все изменения в новый образ. Какая команда поможет создать образ из текущего состояния запущенного контейнера?
Anonymous Quiz
22%
docker save my_container my_new_image:v1
27%
docker commit my_container my_new_image:v1
21%
docker export my_container > my_new_image:v1
30%
docker build -t my_new_image:v1 my_container
🔬 Проникаем в СИЗО🔬

Мы уже не раз задавались вопросом, как Docker умудряется так ловко изолировать контейнеры друг от друга? И уже дошли до того, что все эти контейнеры — обычные процессы в хостовой системе, так почему же они не видят друг друга?

Внимание! За кулисами работают механизмы Системной ИЗОляции - Linux Namespaces 🕵️

В команду великих комбинаторов входят:
🔹 PID namespace — каждый контейнер видит только свои процессы. Твой nginx думает, что он единственный на свете!
🔹 Mount namespace — файловая система контейнера изолирована от хоста. Можешь крушить что угодно внутри — хост останется цел!
🔹 Network namespace — вот почему порты контейнеров не конфликтуют с хостом! У каждого свой сетевой стек!
🔹 IPC namespace — изоляция межпроцессного взаимодействия. Никто не подслушает твои сообщения!
🔹 UTS namespace — каждый контейнер может иметь свой hostname, не мешая соседям.
🔹 User namespace — мапинг пользователей между контейнером и хостом.

Зная это становится понятно, что Docker это вовсе не чорное колдунство, а просто виртуозное использование совсем не новых возможностей Linux ядра для создания изолированных процессов! 🧙‍♂️

Ставь 👌, если тайны изоляции стали чуточку понятнее!

🥷 Docker Ninja 🥷
👌10👎1🔥1
💊Игра на нервах💊

Сегодня поговорим о высоком - о тонком искусстве заставить ваших коллег тихо плакать в туалетной кабинке после каждого PR важих докерфайлов! Я говорю об искусстве наговнокодить в Dockerfile.

И первый наш кейс - контекст выполнения команд внутри контейнера во время сборки.

Для примера, посмотрим на код.
FROM ubuntu:20.04

RUN cd /app && mkdir logs
COPY . /app/

RUN cd /app && npm install
CMD cd /app && npm start


Почему же это плохо?

1. На каждый RUN необходимо указывать контекст исполнения - cd /app &&.... Привет принципы DRY.
2. В случае использвания других директив, наподобие COPY, необходимо будет прописать полный путь до нужной папки. То есть поведение остальных инструкций совсем не явная история.
3. Из предыдущих двух пунктов вытекает 3 - сопровождать такой Dockerfile неудобно от слова "горите в Оду, авторы этого чуда".

А вот, правильный вариант:
FROM ubuntu:20.04

WORKDIR /app
RUN mkdir logs
COPY . .
RUN npm install
CMD npm start


И чем это лучше?

1) Получаем постоянство контекста. Установив раз рабочую директорию в /app мы будем производить все действий только в ней, то тех пор пока не переназначим. А это минус cd /app в каждом блоке команд, да и самих таких блоков станет гораздо меньше.
2) Не нужны лишние RUN-ы чтобы создавать папку. Если папки нет, то WORKDIR создает ее автоматически
3) Такой код более читаемый и предсказуемый
4) Так мы можем использовать относительные пути для других дирректив файла
...
WORKDIR /app
COPY . ./subdir/
...



Так что, берите на заметку и ваши коллеги вам скажут спасибо👌🏻
А впереди у нас выходнульки, значит дружно ставим 🔥


🥷 Docker Ninja 🥷
🔥15
🆘 Спасите наши push-и 🆘

Представь:
Ты геройски настроил все, что хотел твой тимлид, на уже запущенном контейнере. Но тут, посреди бела дня у тебя вырубает электричество (ты конечно же сидишь на удаленке - понедельник же!!!).
И вот, интернета нет, комп отсчитывает последние 10 минут оставшиеся на бесперебойнике. Весь фронт работ отразить в Dockerfile или compose не успеешь, а хорошо бы было сохранить все каким-то образом и донести до офисного компа. И ты начинаешь тихо материться под нос...

Но погоди паниковать! У нас есть старый добрый docker save - команда, которая упакует твой образ в tar-архив быстрее, чем ты скажешь "надо было читать канал Docker Ninja, там точно был ответ!".

🎯 Как это работает:

Базовый синтаксис не замысловатый:
docker save -o nginx.tar nginx:latest


Или через перенаправление, как истинный пигвин из Мадагаскара🐧:
docker save nginx:latest > nginx.tar


Хочешь сохранить сразу несколько образов? Не вопрос:
docker save -o my_stack.tar nginx:latest postgres:13 redis:alpine


🤔 Шо та такое ты уже рассказывал!...

🔹О да! Давным давно, в посте про команду docker export, которая создает архив файловой системы контейнера. В отличие от него, docker save сохраняет полный образ со всеми его слоями, метаданными и историей. Это как разница между копированием папки и созданием полноценной резервной копии диска.

🔹Кстати, у docker save есть команда антоним, как docker import для экспорта. Но это уже история для другого поста!

🔹А еще мы можем вспомнить docker commit, который вместо пушей, спасает наши нервы, путем сохранения всех изменений из работающего контейнера в образ.🤡


Теперь то ты точно сохранишь свои труды в целости! Поставь реакцию, если сразу захотел записать образ на дискету!


🥷 Docker Ninja 🥷
1👍6🔥3
Зачем оно вообще нужно!?

Понимаю возможно возникший у вас вопрос. Кому нафиг это может понадобиться. 21 век на дворе, а ты про архивы.

Но есть несколько щепетильных ситуаций...⬇️
👍8
Ты работаешь с legacy приложением в контейнере. Необходимо создать backup всей файловой системы контейнера в tar-архив для миграции на другой сервер. Какую команду использовать?
Anonymous Quiz
29%
docker save container_name > backup.tar
44%
docker export container_name > backup.tar
12%
docker commit container_name backup_image
15%
docker cp container_name:/ backup.tar
🐶 На вайбах Хатико 🐶

На днях коллега спрашивает: "Слушай, как мне подключиться к контейнеру, который уже запущен? docker exec же только новые процессы создает!" И тут я понял - настало это время!!! Пора рассказать про команду, которая может как спасти твой день, так и безжалостно убить весь контейнер одним неосторожным Ctrl+C!

Речь пойдет о docker attach. Команде для подключения к основному процессу уже запущенного контейнера.

Базовый синтаксис прост как валенок:
docker attach richard_gere:2009


Например, запустили контейнер в фоне:
docker run -d --name professor parker:wilson
docker attach professor


И хоба! Ты видишь логи процесса в реальном времени, можешь взаимодействовать с основным процессом. Но фишка тут в том, что attach подключает тебя именно к процессу с PID 1 (тому самому, что указан в CMD/ENTRYPOINT), а не создает новую сессию как docker exec!

🎯 Зачем это нужно?

1. Дебаг интерактивных приложений - основной процесс ждем, что ты ему введешь какие-то данные.
2. Работа с legacy-контейнерами - где нету встроенной терминальной оболочки
3. Мониторинг в реальном времени - например контейнер постоянно падает и через docker logs ты не успеваешь увидеть его логи

⚠️ Главная ловушка: нажал Ctrl+C в attach-сессии = отправил SIGINT основному процессу! Это может его убить и завалить весь контейнер. Чтобы безопасно отключиться, используй Ctrl+P, Ctrl+Q.


Помни: attach = привязка к существующему процессу, exec = новый процесс. Выбирай с умом!


🥷 Docker Ninja 🥷
👍6🔥42
Ты создаешь 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
Жди меня, и я вернусь

Пятница, конец недели, мозги уже настроены на выходные, а тут еще и контейнеры какие-то надо один за другим запускать - один отработал, врубить другой и тд. А настроенице то такое, чтобы весь мир подождал до понедельника, а дальше это уже проблемы завтрашнего Гомера...

Кажется, товарищам из команды разработки докера ничто человеческое не чуждо. Именно поэтому (я просто уверен) была придумана команда, которая может терпеливо ждать завершения контейнера и даже скажет, с каким кодом он завершился?

Прошу любить и жаловать - 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
🚦 Зависимые отношения 🚦

Ты пушишь в прод свежий 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 существовал не всегда, но и у него были альтернативы.

Узнать, что за механизм и зачем тебе о нем знать, ты можешь нажав на кнопку ниже⬇️
🔥9
📚 Все дороги ведут в 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, это проще! Один и тот же по составу образ может иметь множество тегов, которые просто указывают на один манифест. Тег latest не последняя версия, а просто алиас, который может указывать на что угодно.

🔹Манифест:

Каждый образ содержит "инструкция по сборке" - манифест. Изнутри это JSON-файл, который содержит метаданные — список всех слоев, их хеши, размер, а также конфигурацию контейнера (например, переменные окружения, точку входа)

Когда ты делаешь docker pull, Docker сначала загружает манифест, а затем по списку в нем скачивает необходимые слои.

🔹Приватные vs публичные

Docker Hub удобен для открытых проектов, но для продакшена лучше приватный registry. Harbor, AWS ECR, Azure Container Registry - все они работают по одному API, но дают контроль над безопасностью и retention policies.


Понимание Registry - это понимание того, как живет весь Docker-экосистем!

Жми реакт, если Registry больше не кажется черной магией!

🥷 Docker Ninja 🥷
👍83
Ты создал контейнер с веб-приложением и хочешь скопировать лог-файл из контейнера на хост для анализа. Какая команда позволит это сделать?
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. Что же делать? Убить контейнер? Потеряешь прогресс. Проигнорировать? Ляжет весь хост...

Мда, ситуация на уровне "вилкой в глаз или...". На такие случаи важно знать стоп-слово.

Пожалуйста, 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 🥷
👍132😁2
🏃‍♂️ Утром бегит, пресс качац, анжуманя 🏃‍♂️

Коллега, все мы знаем, что с нашей сидячей работой очень важно следить за физической активностью. Иначе, есть перспектива навайбкодить себе мозоль не только на пузе, но и на вечно подгорающей точке притяжения приключений.🍑
Отсюда вывод, больше бегаешь = меньше весиш.

Кажется, такого девиза придерживаются и те, кто любит исчеркать 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

Хочешь заглянуть под капот? Запусти контейнер:
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