😱 Игра началась 😱
Помнится, в самом начале моего девопсерского пути меня долго мучал вопрос, нафига нужен
Но как и в случае с "необязательным EXPOSE-ом", тут оказалось не так все просто...
Так что сегодня мы с вами слепим грузина с чемоданом и раз и навсегда разберемся в том, зачем нам
Exec vs Shell форма
Как и с нашим старым знакомцем CMD, у ENTRYPOINT есть две формы записи:
Комбинирование с CMD
А вот тут и начинается вся свистопляска...
Зачем это нужно?
ENTRYPOINT директива далеко не обязательная, но очень полезная. Из самых базовых кейсов можно привести следующие:
1️⃣ Нужно сделать из контейнера самостоятельную софтину.
2️⃣ Когда нужно гарантированно выполнить какой-либо скрипт.
3️⃣ Для правильной обработки сигналов ОС.
Как обычно, ставьте ваши реакты, если хочется побольше таких постов! Всем peace✌🏻 и хороших выходных.
🥷 Docker Ninja 🥷
Помнится, в самом начале моего девопсерского пути меня долго мучал вопрос, нафига нужен
ENTRYPOINT если уже есть CMD? Преимущества второго ведь на лицо - его можно изменить при запуске контейнера.Но как и в случае с "необязательным EXPOSE-ом", тут оказалось не так все просто...
Так что сегодня мы с вами слепим грузина с чемоданом и раз и навсегда разберемся в том, зачем нам
ENTRYPOINT. Но для начала мини обзорчик как это дело функционирует.Exec vs Shell форма
Как и с нашим старым знакомцем CMD, у ENTRYPOINT есть две формы записи:
# Exec форма (рекомендуемая)
ENTRYPOINT ["nginx", "-g", "daemon off;"]
# Shell форма
ENTRYPOINT nginx -g "daemon off;"
# Exec форма работает напрямую с ядром, без лишних оберток — быстрее и надежнее!
Комбинирование с CMD
А вот тут и начинается вся свистопляска...
ENTRYPOINT ["python", "app.py"]
CMD ["--help"]
# docker run myapp → выполнит python app.py --help
# docker run myapp --version → выполнит python app.py --version
# docker run myapp --config prod.conf → выполнит python app.py --config prod.conf
# ENTRYPOINT остается неизменным, а `CMD` становится аргументами по умолчанию!
Зачем это нужно?
ENTRYPOINT директива далеко не обязательная, но очень полезная. Из самых базовых кейсов можно привести следующие:
1️⃣ Нужно сделать из контейнера самостоятельную софтину.
docker run уже запускает нужный нам бинарник, а мы лишь назначаем аргументы в cmd (смотри пример выше)
2️⃣ Когда нужно гарантированно выполнить какой-либо скрипт.
Например делаем контейнер для запуска ансибла (такое практикуют если рабочи комп на винде). В `ENTRYPOINT` ставим скрипт, который грузит зависимые ansible модули из requirements, а в CMD указываем команды ансибла
3️⃣ Для правильной обработки сигналов ОС.
Для этого ставим в `ENTRYPOINT` то что мы собираемся запускать в контейнере (nginx, python, node). В `CMD` ставим его аргументы (my_app.py, server.js). В таком случае, если мы прервем работу контейнера штатными средствами (pause, stop), то сигнал получит не shell, а непосредственно то, что мы указали в `ENTRYPOINT`. А значит, мы получаем более корректное завершение работы нашего приложения.
Как обычно, ставьте ваши реакты, если хочется побольше таких постов! Всем peace✌🏻 и хороших выходных.
🥷 Docker Ninja 🥷
4🔥15👍8❤2
В пятницу вечером один из подписчиков задал вопрос к последнему посту: работает ли shell и exec формы в Distroless и From Scratch образах?
Вопрос хороший и очень интересный для разбора! Тем более, что, скорее всего, многие не знают что такое Distroless и From Scratch.
Давайте разберем этот момент в трех постах:
1️⃣ Что такое Distroless образы?
2️⃣ Что такое from scratch образы?
3️⃣ Как в данных образах запускается что либо, если они совсем пустые?
Please open Telegram to view this post
VIEW IN TELEGRAM
💊ДетралексDistroless: понедельники без тяжести💊
Distroless - это образы без дистрибутива. Звучит как сапожник без сапог, но тем не менее. Внутри только runtime-зависимости и все. Никаких shell-ов(да мы с вами об этом уже говорили - тык, брык), package manager-ов, лишних библиотек. Только то, что нужно твоему приложению для работы.
Сравни сам через docker images:
Результат: образ сжался с 72MB до 2MB! 🎯
Зачем юзать:
💊 Меньше уязвимостей - меньше головной боли с security
💊 Микроскопический размер - быстрее пуллится и стартует
💊 Невозможно зайти в контейнер через shell - дополнительная защита
💊 Отлично сочетается с multi-stage builds
Google предоставляет варианты на любой вкус:
🔹
🔹
🔹
🔹
Подобрать вариант под себя можно вот тут.
Минус только один: дебажить сложнее, так что обрадуйте своих любителей дебажить на проде - лафа закончилась😏
Попробовал Distroless? Ставь 🔥!
Этот пост лишь маленькая часть серии из 3-х постов про distroless и scratch образы. Ссылки на все части ты можешь найти в этом посте .
🥷 Docker Ninja 🥷
Сидишь ты значит, деплоишь в продакшен очередной микросервис, потирая красные от недосыпа глаза, как вдруг, ИБ-ешник присылает отчет Docker Scout с полным набором критических уязвимостей. Половина из них - в пакетах Ubuntu, которые твое приложение вообще никогда не юзает! Curl, wget, package manager - зачем это все в контейнере, если твой бинарник статически слинкован?
Первое что приходит на ум это аппнуть базовый образ - авось все уязвимые пакеты там пропатчены.
Но что, если образ уже последней версии? Будешь создавать свой образ Ubuntu в котором вырежешь все дырявые пакеты? Ну да, вариант, но до очередной уязвимости. А как будешь следить за патчами пакетов и самой ОС?
Как ты понимаешь, проблем тут возникает вагон и маленькая тележка. Но и на такой случай придумали решение
Distroless - это образы без дистрибутива. Звучит как сапожник без сапог, но тем не менее. Внутри только runtime-зависимости и все. Никаких shell-ов(да мы с вами об этом уже говорили - тык, брык), package manager-ов, лишних библиотек. Только то, что нужно твоему приложению для работы.
Сравни сам через docker images:
docker pull ubuntu:20.04
docker pull gcr.io/distroless/static-debian11
docker images
# Было (Ubuntu base)
ubuntu 20.04 b7bab04fd9aa 7 months ago 72.8MB
# Стало (Distroless)
gcr.io/distroless/static-debian12 latest e021002e4213 N/A 2.08MB
Результат: образ сжался с 72MB до 2MB! 🎯
Зачем юзать:
💊 Меньше уязвимостей - меньше головной боли с security
💊 Микроскопический размер - быстрее пуллится и стартует
💊 Невозможно зайти в контейнер через shell - дополнительная защита
💊 Отлично сочетается с multi-stage builds
Google предоставляет варианты на любой вкус:
🔹
/static (без какого-либо рантайма, хорошо подходит для go) 🔹
/java, 🔹
/python, 🔹
/nodejsПодобрать вариант под себя можно вот тут.
Минус только один: дебажить сложнее, так что обрадуйте своих любителей дебажить на проде - лафа закончилась😏
Попробовал Distroless? Ставь 🔥!
🥷 Docker Ninja 🥷
2👍10🔥6🆒3
Какой механизм Linux использует Docker для ограничения ресурсов контейнеров?
Anonymous Quiz
29%
Linux Namespaces
9%
AppArmor
53%
Linux cgroups
9%
chroot
Помните мы с вами однажды рассматривали флаг --validate? Я тут полистал свои старые посты и подумал, не порядок - как конфиг валидировать знаем, а что настроить в этом самом конфиге вообще не в курсе.По дефолту Docker работает с базовыми настройками, а файл daemon.json мы создаем сами, когда нужно что-то подкрутить в Docker Engine под свои нужды.
Таки пришло время разобрать этот момент. Слишком глубоко копать не будем, чтобы не перегреть наши светлые головки в самой середине недели!
Где искать этого неуловимого зверя?
Linux: /etc/docker/daemon.json
Windows: C:\ProgramData\docker\config\daemon.json
macOS: ~/.docker/daemon.json
Если Магомет не идет к горе, то гора не придет и подавно
Но это совсем не про нашу ситуацию, ведь мы с вами проактивные девопсеры!
Как уже говорили выше, если файла нет, смело создаем его сами:
sudo mkdir -p /etc/docker
sudo touch /etc/docker/daemon.json
Что можно настроить?
Простейший пример:
{
"storage-driver": "overlay2",
"log-driver": "json-file"
}После правок обязательно рестартуем демон:
sudo systemctl restart docker
Не забываем провалидировать конфиг - сэкономим нервы!
Зачем это надо?
В продакшене дефолтные настройки часто не катят. Нужно настроить логирование, сменить storage driver под конкретную файловую систему, добавить корпоративные registry. Без daemon.json придется делать это через флаги командной строки и после нескольких раз ты будешь молить бога релизов, чтобы он сжалился над тобой и дал умереть без мучений.
Так что обязательно юзайте и помните, что демонов боятся только те, кто не умеет ими управлять! Ставьте ваши реакты, если понравился пост! А на этом у меня все, хорошего рабочего дня!👌🏻
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍8🔥7❤2
При работе с Docker Registry ты хочешь загрузить образ ubuntu:20.04 на локальную машину для последующего использования. Какая команда выполнит эту задачу?
Anonymous Quiz
8%
docker download ubuntu:20.04
74%
docker pull ubuntu:20.04
5%
docker fetch ubuntu:20.04
13%
docker get ubuntu:20.04
🛸Ограничиваем мыслительные ресурсы🛸
Как это работает?
В отличие от --cpu-shares (который работал по принципу "кто первый встал, того и тапки"), --cpus дает жесткий лимит в количестве ядер:
Под капотом это всеми любимые Linux cgroups крутят ручки CFS (Completely Fair Scheduler). Контейнер получает определенный time slice и не может его превысить, даже если остальные ядра простаивают!
Кейсы:
• Мультитенантность: изолируем нагрузку между клиентами
• CI/CD: ограничиваем тесты, чтобы не убить билд-агенты
• Микросервисы: гарантируем, что один сервис не захватит все ресурсы
• Debugging: воспроизводим условия слабых серверов локально
А теперь, тряхнем стариной. Если нужно изменить лимит на лету - есть docker update:
А в связке с ограничением памяти получается идеальная изоляция ресурсов!
ПыСы: используй дробные значения осознанно. CPU 0.1 - это реально мало, подходит только для совсем легких задач типа health-check-ов.
Теперь, когда ты умеешь ограничивать мыслительные ресурсы своих подопечных, задача трех тел для тебя станет нипочем, если ты понимаешь о чем я!👽
Как обычно ставь свои пальчики, сердешки и огонечки, чтобы твой покорный слуга все выходные ждал понедельника, дабы написать свой новый пост.🙇
🥷 Docker Ninja 🥷
Представь, заапускаешь ты такой на проде "безобидный" контейнер с ML-моделью, чтобы она отвечала коллегам на сообщения "Сломалось - почини", а он сжирает все 16 ядер и превращает остальные сервисы в овощи?🍆 Или когда один разработчик запустил криптомайнер... тьфу, тесты CPU-интенсивного алгоритма, и вся команда сидит без CI перед важным релизом.
И тут ты потихоньку начинаешь чувствовать мягкий металлический привкус медного тазика, которым накрывается твой пятничный трип по барам на Рубинштейна.🍺
Отставить панику! На помощь приходит флаг --cpus - надежный помощник страждущего под конец недели девопса! 💪
Как это работает?
В отличие от --cpu-shares (который работал по принципу "кто первый встал, того и тапки"), --cpus дает жесткий лимит в количестве ядер:
# Ограничиваем контейнер половиной CPU
docker run --cpus="0.5" nginx
# Даем полтора ядра для тяжелых вычислений
docker run --cpus="1.5" my-ml-model
# Четверть ядра для легких задач
docker run --cpus="0.25" redis
Под капотом это всеми любимые Linux cgroups крутят ручки CFS (Completely Fair Scheduler). Контейнер получает определенный time slice и не может его превысить, даже если остальные ядра простаивают!
Кейсы:
• Мультитенантность: изолируем нагрузку между клиентами
• CI/CD: ограничиваем тесты, чтобы не убить билд-агенты
• Микросервисы: гарантируем, что один сервис не захватит все ресурсы
• Debugging: воспроизводим условия слабых серверов локально
А теперь, тряхнем стариной. Если нужно изменить лимит на лету - есть docker update:
docker update --cpus="2.0" my_container
А в связке с ограничением памяти получается идеальная изоляция ресурсов!
ПыСы: используй дробные значения осознанно. CPU 0.1 - это реально мало, подходит только для совсем легких задач типа health-check-ов.
Теперь, когда ты умеешь ограничивать мыслительные ресурсы своих подопечных, задача трех тел для тебя станет нипочем, если ты понимаешь о чем я!👽
Как обычно ставь свои пальчики, сердешки и огонечки, чтобы твой покорный слуга все выходные ждал понедельника, дабы написать свой новый пост.🙇
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍15❤4😁4🔥2
Кто плотно сидел на java или dotnet, тот будет приятно удивлен тому, что например в go вся наша вайб-код писанина удобно укомплектовывается в один единственный бинарный файл. И что самое интересное, никаких тебе рантаймов для работы этого бинарника не нужно - все уже положили внутрь!
После таких вот вундервафель может возникнуть закономерный вопрос. А можно в таком случае тот самый ультратонкий distroless (который, напомню, содержит в себе необходимый минимум + runtime) раздеть до самых носков? Чтобы размер нашего образа сводился лишь к размеру получившегося бинаря!
И вот, в продолжение нашей серии постов, встречайте его величество Scratch-образы! Тип образов, в котором не то что оболочки, в нем даже мокрого пятнышка не осталось!
Серьезно, это не шутка.
scratch - это спецобраз без операционной системы, без shell, без /bin/sh, без ВООБЩЕ НИЧЕГО:FROM scratch
COPY ./my-static-binary /
ENTRYPOINT ["/my-static-binary"]
Да как это вообще работает!?
Docker запускает твой бинарник напрямую как PID 1. Никакой магии, просто голый syscall к ядру хоста. Как будто бы мы запустили этот самый бинарь прямо на хосте.
Но не забывай:
ls, cat, ps, да и не нужны они раз shell-а нет😅Зато результат - образы размером в несколько мегабайт вместо гигабайт!
Зачем это нужно?
Идеально для production микросервисов на Go/Rust, которые компилируются в standalone бинарники. Меньше attack surface, быстрее пуллится, меньше места на диске.
Кстати, Scratch идеально подходит для финального образа в multi-stage builds:
# Этап сборки приложения
FROM golang:1.21-alpine AS builder
...
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /app/main .
# Финальный этап - минимальный образ
FROM scratch
...
COPY --from=builder /app/main .
CMD ["./main"]
А на этом у меня все! Удачного начала дня! И по классике, не забывайте ставить ваши реакты, а то я буду рыдать горькими слезками
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
3🔥16👍10❤2😁2
Ты хочешь отследить, какие файлы изменились в контейнере после его запуска для диагностики проблем. Какая команда поможет тебе увидеть все изменения в файловой системе?
Anonymous Quiz
12%
docker logs container_name
23%
docker inspect container_name
49%
docker diff container_name
17%
docker history container_name
Ох уж эта вечная дилемма: либо даешь процессу полный root и он творит что хочет с системой, либо запускаешь под обычным юзером и потом часами разбираешься, почему оно не может открыть сокет или примонтировать том.В контексте докера это реализуется через флаг
Но Linux-боги подумали об этом и придумали штуку под названием capabilities - это какталончик на краковскую колбасуVIP-пропуска в ночной клуб, только для процессов!🎫
--cap-add!Что такое capabilities?
Это набор конкретных привилегий, которые можно выдавать процессам по отдельности. Типа "можешь биндить на привилегированные порты", "можешь менять сетевые настройки", но при этом никакого доступа к дискам.
Как юзать --cap-add:
# Даем возможность биндиться на порты < 1024
docker run --cap-add NET_BIND_SERVICE nginx
# Позволяем менять сетевые настройки
docker run --cap-add NET_ADMIN my-vpn-app
# Даем права на работу с raw сокетами (для ping например)
docker run --cap-add NET_RAW alpine ping google.com
А кейсы то будут,?
NET_BIND_SERVICENET_ADMIN SYS_ADMINDAC_OVERRIDEХоба и ты умеешь гибко настраивать безопасность, а кому нужны лишние терки с коллегами из ИБ по середине рабочей недели?? Правильно - никому. Поэтому смело ставь реакт за полезняшку!
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍14🔥6❤3🤔2
В процессе разработки ты изменил код и пересобрал образ. При запуске контейнера заметил, что приложение работает в старой директории. Какую директива Dockerfile надо использовать, чтобы установить рабочую директорию?
Anonymous Quiz
6%
RUN cd /app
75%
WORKDIR /app
13%
ENV PATH=/app
5%
COPY . /app
В мире IT существует довольно много идеалистических концепций, внедрив которые их авторы обещают золотые горы и кисельные берега. Одной из таких концепций является 12-factor app, в целом, и ее подпункт stateless, в частности. Штука очень полезная, но реальность оказывается гораздо прозаичнее, поскольку есть приложения и сервисы, которые по своей природе stateful.
Поэтому, запускаете вы контейнеры на проде или на тесте, всегда задавайте себе вопрос, а не stateful ли данное приложение. И если ответ положительный, то к контейнеру необходимо примонтировать том.
Возвращаясь к посту про типы томов, в compose, естественно, есть ручки, дергая за которые мы можем подключить тома к любому из описанных нами контейнеров.
Синтаксис:
services:
postgres:
image: postgres:15
volumes:
- pgdata:/var/lib/postgresql/data # именованный том
- ./logs:/var/log # bind mount
volumes:
pgdata: # объявляем именованный том
Кастомизируем именованный том:
services:
app:
...
volumes:
cache:
name: my_new_volume
driver: local
driver_opts:
...
Здесь мы указали:
Зачем это нужно?
Volumes - это база любого production compose-файла. А в связке с build получается полноценная среда разработки! Поэтому знать, понимать и помнить это просто необходимо!
А на сегодня у меня все. Как обычно, не забывайте ставить свои реакты и всем хороших выходных.
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍8🍾4🔥3❤2
🍋 Easy peasy lemon squeezy 🍋
Давайте проникнемся shell и exec формами команд!
Когда ты пишешь
Что же с exec формой?
То же самое касается ENTRYPOINT:
Так же и с RUN. Если вы вдруг удумали собирать что-то в distroless/scratch образах (господь вам в помощь, отчаянные) его так же пишем в exec форме.
Но как же тогда работает exec?
Если что distroless, что scratch гол-ы, как сокол-ы, то как же вообще в нем запускается хоть что либо??
Тут все просто! Настолько просто что мы аж растянули это на 3 поста!😐 Так как контейнер это всего лишь процесс, то exec форма работает изнутри как системный вызов
Запомни правило:
В минималистичных образах всегда используй exec форму
Теперь твои контейнеры будут стартовать с загадочными ошибками, а не падать!😄
Ставь свои реакты, если уже тоже наступал на эти грабли! Если не наступал тоже ставь! А на этом я откланяюсь и хорошей вам рабочей недели!
🥷 Docker Ninja 🥷
Однажды составлял Dockerfile для приложения с distroless образом. Конечно же я не был подписан на ваш любимый и неповторимый Docker Ninja, поэтому, по незнанию воткнул там вот такое CMD go run main.go. И конечно же, контейнер не поднялся...
Ну что может пойти не так?
И тут я могу вам сказать, что мы наконец докопались до самой сути серии постов, отвечающих на вопрос подписчика. Напомню, вопрос звучал так: работает ли shell и exec формы в Distroless и From Scratch образах?
Давайте проникнемся shell и exec формами команд!
Когда ты пишешь
CMD go run main.go (shell форма), Docker пытается выполнить это через /bin/sh -c "go run main.go". А тк в distroless и FROM scratch образах нет ни shell, ни /bin/sh, то запускаться это дело не будет.# ❌ Факапится в distroless
FROM gcr.io/distroless/static
COPY myapp /
CMD myapp --config prod.yaml
# Получаем:
exec /bin/sh: no such file or directory
Что же с exec формой?
# ✅ А она работает как часы
FROM gcr.io/distroless/static
COPY myapp /
CMD ["/myapp", "--config", "prod.yaml"]
То же самое касается ENTRYPOINT:
# ❌ Провал
ENTRYPOINT ./start.sh
# ✅ Успех
ENTRYPOINT ["./start.sh"]
Так же и с RUN. Если вы вдруг удумали собирать что-то в distroless/scratch образах (господь вам в помощь, отчаянные) его так же пишем в exec форме.
Но как же тогда работает exec?
Если что distroless, что scratch гол-ы, как сокол-ы, то как же вообще в нем запускается хоть что либо??
Тут все просто! Настолько просто что мы аж растянули это на 3 поста!
execve.Запомни правило:
В минималистичных образах всегда используй exec форму
["команда", "аргумент1", "аргумент2"] вместо shell формы команда аргумент1 аргумент2.Теперь твои контейнеры будут стартовать с загадочными ошибками, а не падать!
Ставь свои реакты, если уже тоже наступал на эти грабли! Если не наступал тоже ставь! А на этом я откланяюсь и хорошей вам рабочей недели!
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍15🔥6❤2
В твоем проекте есть Docker Compose файл с несколькими сервисами. Ты хочешь проверить, корректно ли составлен файл перед запуском. Какую команду использовать?
Anonymous Quiz
26%
docker compose validate
32%
docker compose check
22%
docker compose config
20%
docker compose verify
👍6🔥3
СредаМаленькая пятница. Неделя подошла к своей медиане, а ты уже душой на даче в Лосево, смотришь с котом под пледом новый сезон Очень странных дел... Но тут тебя затягивает в Изнанку очередной звонок Димы Горгина - PM-а: 'Слушай, а можешь быстренько поднять staging версию приложения? Только там порты другие нужны, и базу отдельную, и логи в другое место... А две?!'
А потом еще и продакшн со своими капризами подтянется! 😅
Хорошая новость - не нужно плодить docker-compose файлы! На такой случай юзаем override файлы для гибкого слияния конфигураций.
ДА, Docker Compose умеет накладывать конфигурации друг на друга не привлекая внимания санитаров:
# docker-compose.yml (база)
version: '3.8'
services:
app:
image: myapp:latest
ports:
- "3000:3000"
# docker-compose.override.yml (автоматом подхватывается)
version: '3.8'
services:
app:
ports:
- "8080:3000" # перезапишет базовый порт
environment:
- NODE_ENV=development
Для прода создаем отдельный файл:
# docker-compose.prod.yml
version: '3.8'
services:
app:
environment:
- NODE_ENV=production
deploy:
replicas: 3
Зачем заморачиваться?
Потому что без дублирования кода ты получаешь элегантное управление окружениями! Одна база, куча вариаций.
docker compose -f docker-compose.yml -f docker-compose.prod.yml up
Хоба, и видишь финальный результат слияния!
Кстати, помнишь наши посты про depends_on и volumes? Все эти секции тоже отлично переопределяются через override файлы!
Теперь у тебя есть конфиг на все случаи жизни, а у меня твой реакт, репост и хорошее настроение! 🎉
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥15👍8😁4❤2
В production среде твой контейнер потребляет слишком много RAM и влияет на другие сервисы. Контейнер уже запущен. Как ограничить память без остановки?
Anonymous Quiz
70%
Использовать команду docker update --memory
15%
Перезапустить контейнер с флагом --memory
11%
Изменить файлы в /sys/fs/cgroup/ вручную
5%
Остановить контейнер и пересобрать образ
Вчера копался в старом legacy-проекте и наткнулся на докерфайл с директивой MAINTAINER. А звучит то как мейн-тей-нер! Сразу вспомнил школу, как классе эдак в пятом все друг друга спрашивали, а какая у тебя роспись и ты как маститый райтер достаешь маркер и портишь школьное иммущество свои личным тэгом.
Тем не менее, культура подписывать свое творение существует и у нас в ИТ-шке. Поэтому, если не хочешь прослыть лицемерной мгазью, которая лезет к нам в ИТ, давай посмотрим как же правильно подписывать докерфайлы.
FROM ubuntu:14.04
MAINTAINER "Вася Пупкин <vasya@example.com>"
RUN apt-get update
Бац, и все подумали, что мы теперь настоящие DevOps-ы!
Но Docker давно похоронил эту директиву и пометил как deprecated еще в версии 1.13. Почему? А цимес в том, что
MAINTAINER была слишком специфичной — только для автора, и всё. А что если нужно добавить версию, описание, ссылки на документацию?Тут на смену приходит LABEL 📝
Правильный современный подход использовать LABEL:
FROM ubuntu:22.04
LABEL maintainer="vasya@example.com"
LABEL version="1.0.0"
LABEL denoscription="Мой крутой микросервис"
LABEL org.opencontainers.image.source="https://github.com/vasya/my-app"
Зачем это нужно? 🤔
Когда у тебя в продакшне крутится сотня контейнеров, а в 3 утра что-то упало — метаданные твой спаситель! Быстро понять, кто автор, какая версия, где исходники. Плюс, многие CI/CD системы парсят эти лейблы для автоматизации.
Ну а уж если ты на досуге что-то разрабатываешь, публикуя на гитхаб, то сам бог велел пометить, что именно ты придумал очердной экстравагантный способ поднимать дженкинс в контейнере.
Ставь свой бесценный реакт, если не метишь там, где не положено и делаешь это всегда только по ветру!
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤5🔥3
📋 Это мой кандидатский сценарий. Слушай devops, слушай пролетарий 📋
Что это за зверь такой?
Manifest — это метаданные образа в JSON формате (этакий паспорт).
Когда ты делаешь docker pull, сначала качается именно манифест, а потом уже слои по списку.
Хлобысь и ты видишь всю подноготную: архитектуру, размеры слоев, их SHA256 хеши и порядок восстановоения слоев.
Нафига тут SHA256?
Выше я уже упоминал про некие хэши в формате SHA256. Вся соль в том, что каждый слой образа идентифицируется по SHA256 хешу его содержимого. То есть, на основе изменений высчитывается хэш. Изменился файл - изменился хеш - новый слой! По такому же принципу работает git.
Далее мы обращаемся при push-е/pull-e через Registry API v2. Он, в свою очередь использует Content Addressable Storage, чтобы разрулить все вопросики с образами.
При push/pull операциях:
1. 📤 Клиент шлет манифест в registry
2. 🔍 Registry проверяет целостность по хешам
3. 📦 Качаются только недостающие слои
4. ✅ Проверка SHA256 на каждом шаге
Ну они и напридумывали! А зачем это все?
➡️ Безопасность: невозможно подменить слой незаметно
➡️ Эффективность: дедупликация слоев между образами
➡️ Целостность: гарантия, что скачанное = загруженному
➡️ Версионирование: каждый образ — уникальная комбинация слоев
Теперь понимаешь, почему твой
Все, больше не гружу ваши понедельничные головушки сложной информацией. Перевариваем и до встречи в следующих постах!
А ты ставь реакт, если тоже любишь копаться в архитектурных деталях! Пиши свои вопросы в директ канала! И продуктивного тебе рабочего/учебного дня!!!
🥷 Docker Ninja 🥷
Однажды мы с вам касались вопроса, как работают docker registry и там я вкинул парочку слов о неких манифестах и что мол это как инструкция к тому, как из слоев собрать полноценный образ.
Сегодня же хочу рассказать вам об этих самых манифестах чуточку подробнее, ведь если задуматься, то именно этот механизм, помимо прочих его фич, позволяет нам при пулле образа собрать все слои воедино, хотя мы качаем их по сети, где может случиться все что угодно!
Что это за зверь такой?
Manifest — это метаданные образа в JSON формате (этакий паспорт).
Когда ты делаешь docker pull, сначала качается именно манифест, а потом уже слои по списку.
# Можно даже посмотреть на структуру
docker manifest inspect nginx:latest
Хлобысь и ты видишь всю подноготную: архитектуру, размеры слоев, их SHA256 хеши и порядок восстановоения слоев.
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
...,
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 841,
"digest": "sha256:af320b2df7e2bde33bd04165a7cad0b510f6ce6461d8f2e9c906fc77f99a8d21",
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
...
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 2292,
"digest": "sha256:7de350c1fbb1f7b119a1d08f69fef5c92624cb01e03bc25c0ae11072b8969712",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
}
},
...
]
}Нафига тут SHA256?
Выше я уже упоминал про некие хэши в формате SHA256. Вся соль в том, что каждый слой образа идентифицируется по SHA256 хешу его содержимого. То есть, на основе изменений высчитывается хэш. Изменился файл - изменился хеш - новый слой! По такому же принципу работает git.
Далее мы обращаемся при push-е/pull-e через Registry API v2. Он, в свою очередь использует Content Addressable Storage, чтобы разрулить все вопросики с образами.
При push/pull операциях:
1. 📤 Клиент шлет манифест в registry
2. 🔍 Registry проверяет целостность по хешам
3. 📦 Качаются только недостающие слои
4. ✅ Проверка SHA256 на каждом шаге
Ну они и напридумывали! А зачем это все?
Теперь понимаешь, почему твой
nginx всегда одинаковый на dev и prod!? 🎯Все, больше не гружу ваши понедельничные головушки сложной информацией. Перевариваем и до встречи в следующих постах!
А ты ставь реакт, если тоже любишь копаться в архитектурных деталях! Пиши свои вопросы в директ канала! И продуктивного тебе рабочего/учебного дня!!!
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12👏3🔥2
Коллеги, в предновогодней суете совсем не успел отметить с вами здоровский факт! В четверг 04.12.25 количество подписчиков канала перевалило за отметку в 1000!!!
Для меня это не только знаменательное событие, но и сигнал к действию. Так что, я с еще большим рвением буду работать над полезным контентом. Более того, я готовлю для всех читателей небольшой подарочек на Новогодние праздники. Чтобы новый год для вас начался не только с оливьешки и Голубого огонька, но и с ударной дозы полезных знаний, которые позволят достичь новых карьерных горизонтов!
Конечно, нет худа без добра, и наоборот, добра без худа. Новые горизонты открываются и для меня. И хоть тема docker довольно обширная, но уже сейчас, я чувствую, что хотелось бы поведать и о других гранях devops ремесла. И сейчас у меня уже есть наметки новых идей. Осталось только научиться работать со всем объемом задуманного. Поэтому не серчайте сильно, если пара-тройка постов окажется не такой качественной как прежде. Ваше ожидание и вера в мои силы будет лучше наградой и окупится, как говорится, сторицей!
Что касается этого канала. Работа продолжается в том же темпе. Концепция канала меняться не будет. Но я со всей дури думаю о новых рубриках и ваши предложения по этому поводу будут как нельзя кстати! Озвучить их вы можете так же в директ канала или мне в личку - @nesudimov_eu.
На этом я откланяюсь и еще раз, плодотворной вам недели!💪🏻
Please open Telegram to view this post
VIEW IN TELEGRAM
3🎉17🔥5🏆3😁1
🚜 Едут, едут комбайнеры, едут, едут на поля 🚜
И тут на арену выходят Docker Engine plugins - модульная система расширения функциональности, которая превращает Docker из швейцарского ножика в полноценный комбайн! 🚀
По сути, эта штука позволяет Docker интегрироваться с внешними системами без хирургического вмешательства в сам движок. Это как расширения для браузера, только для контейнеров - хочешь новую функцию? Подключил плагин и вперед!
Типы плагинов
🗄 Volume plugins - интеграция с внешними системами хранения (NetApp, AWS EBS, Ceph)
🌐 Network plugins - кастомные сетевые драйверы (Weave, Calico, Flannel)
🔐 Authorization plugins - контроль доступа к Docker API
📝 Log plugins - отправка логов в внешние системы (Splunk, Fluentd)
Работаем с ними так:
Как г-рится, не так уж и страшен черт, как его молюют.
Теперыча, прокачиваем наш контейнер для работы с NFS
Хоба, и твой контейнер теперь работает с сетевым хранилищем! 📦
Преимущества этого решения
➡️ Enterprise интеграция: подключаешься к существующим уже инфраструктурным решениям без костылей
➡️ Гибкость: расширяешь Docker под свои нужды, а не наоборот
➡️ Совместимость: используешь корпоративные системы хранения и сети
➡️ Масштабируемость: один раз настроил плагин - используешь везде
Короче, плагины - это способ сделать Docker действительно enterprise-ready без переписывания всего с нуля! В production среде без них часто просто никуда - стандартных драйверов не хватает для серьезных задач.
ПыСы: помни, что плагины работают с правами хоста, так что не качай левые сборки из интернетов - потом не говори, что не предупреждал!😏
Ставь реакт, если было интересно!А то я буду думать Да ниче не буду думать, просто буду тихо рыдать под душем, чтобы не было видно слез.😭 Потому что истинные комбайнеры не плачут, истинные комбайнеры ссу.. принимают гигиенические процедуры для лица посредством ресурсов собственного тела!💪
🥷 Docker Ninja 🥷
Помнишь те славные времена, когда твоя любимая компания "Рога и копыта" была маленьким стартапом из 5-ти человек. Тогда и трава была зеленее, и снег в Питере выпадал в декабре, а блейзер казался напитком богов. Но прогресс не стоит на месте и теперь уже в вашем штате больше бухгалтеров, чем ИТ-шников. А вместо 10 контейнеров, статусы которых ты можешь посмотреть введя docker ps, тебе приходится лезть в Service Mesh.
Такие масштабы усложняют не только твою жизнь, но и подходы к организации таких базовых вещей как сборка и хранение логов, авторизация, сети со всем их вланами и политиками, системы хранения данных. А Docker хоть и мощный инструмент, но его возможности все равно не резиновые. Да и процессы в компании могут требовать гораздо больше, чем хранение данных в локальных volumes или bridge сети.
И теперь стоишь ты такой перед выбором: либо костылить интеграцию черезжепулевое колено, либо отказываться от Docker совсем в пользу "проверенных дедовских методов".
Фрустрация реальная! Особенно когда вся команда смотрит на тебя глазами "ну что, твой любимый Docker справится с нашим железом?"
И тут на арену выходят Docker Engine plugins - модульная система расширения функциональности, которая превращает Docker из швейцарского ножика в полноценный комбайн! 🚀
По сути, эта штука позволяет Docker интегрироваться с внешними системами без хирургического вмешательства в сам движок. Это как расширения для браузера, только для контейнеров - хочешь новую функцию? Подключил плагин и вперед!
Типы плагинов
🗄 Volume plugins - интеграция с внешними системами хранения (NetApp, AWS EBS, Ceph)
🌐 Network plugins - кастомные сетевые драйверы (Weave, Calico, Flannel)
🔐 Authorization plugins - контроль доступа к Docker API
📝 Log plugins - отправка логов в внешние системы (Splunk, Fluentd)
Работаем с ними так:
# Посмотрим, что уже установлено:
docker plugin ls
# Устанавливаем NFS plugin
docker plugin install trajano/nfs-volume-plugin:latest
Как г-рится, не так уж и страшен черт, как его молюют.
Теперыча, прокачиваем наш контейнер для работы с NFS
# Создаем volume с использованием плагина
docker volume create -d trajano/nfs-volume-plugin \
--opt device=192.168.1.1:/mnt/routerdrive/nfs \
--opt nfsopts=hard,proto=tcp,nfsvers=4,intr,nolock \
nfsmountvolume
# Используем в контейнере
docker run -it --name my_nfs_container \
-v nfsmountvolume:/mnt/data \
alpine sh
Хоба, и твой контейнер теперь работает с сетевым хранилищем! 📦
Преимущества этого решения
Короче, плагины - это способ сделать Docker действительно enterprise-ready без переписывания всего с нуля! В production среде без них часто просто никуда - стандартных драйверов не хватает для серьезных задач.
ПыСы: помни, что плагины работают с правами хоста, так что не качай левые сборки из интернетов - потом не говори, что не предупреждал!
Ставь реакт, если было интересно!
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍5❤1🗿1
🔄СтопуемСтаруем!🔄
Но не зря ты носишь хоть и виртуальный, но все же статус Довакина! Давным давно ты изучил секретный туум
По сути, эта команды антонимы, которые могут останавливать и запускать контейнеры без необходимости пересоздания.
Базовый синтаксис:
Вот как ты выйдешь из этой ситуации сухим:
Оп-ля и изменения применились.
А как так, мы же остановили контейнер?
Остановили, но не убили! Все изменения в запущенном контейнере пишутся в writable layer по всем заветам Layered FS. Когда мы стопаем контейнер, они остаются там же. При перезапуске через docker start или же через docker restart мы перезапускаем и процесс нашего приложения. А приложение уже перечитывает конфиг.
И кстати, если на вашем пути попался такой же новичок, но контенеров у него уже несколько, можем провернуть то же самое и со всей партией.
Видишь? Никаких новых контейнеров, никаких потерянных данных. Просто берешь и продолжаешь с того места, где остановился!
Зачем это нужно в реальной жизни?
➡️ Сохранение состояния приложения: разрабатываешь веб-приложение с базой данных внутри контейнера? Start позволяет сохранить все данные между перезапусками
➡️ Экономия ресурсов в CI/CD: переиспользование контейнеров с предустановленными зависимостями сокращает время инициализации тестовых сред
➡️ Отладка production-инцидентов: можно остановить проблемный контейнер для анализа логов, затем запустить снова без пересоздания
➡️ Управление ресурсами сервера: в средах с ограниченными ресурсами позволяет временно останавливать неиспользуемые сервисы и запускать по требованию
Не забывай юзать docker ps для просмотра статуса контейнеров и docker rm для окончательного удаления остановленных контейнеров.
ПыСы: помни — docker start работает только с контейнерами, которые уже существуют. Если контейнер удален через rm, то никакой магии не будет, придется создавать заново.
А на этом я раскланяюсь, до встречи на следующей неделе и хороших вам выходных!
🥷 Docker Ninja 🥷
И снова пятница! К твоему счастью все релизы закрыты и ты уже спокойно собираешь свои вещички в недолгое путешествие по скайриму, чтобы получить хоть какое-то новогодонее настроение. Но Талмор не дремлет и подкидывает тебе новые квесты, чтобы ты никогда не смог помочь имперцам вернуть былое величие!😠
На этот раз к тебе подходит некий Аркадий Рукожопов (совсем не говорящая фамилия, неет), который отвечал за последнюю релизнутую фичу, со словами: "Ты знаешь, я забыл проверить кое какую штуковину в конфиге. Так то все работает, но в некоторые моменты может сильно нагрузить систему. Можем сейчас подредачить на бою и перезапустить. Заодно и проверим, на выходных как оно работает."
Ух... отлично, потестить на проде... Вариант ответа "Отправить пососировать бибоний" для тебя заблокирован из-за недостаточно развитого красноречия, поэтому ты стоически берешся за эту задачу. Bсе было бы просто если бы не важные данные, которые во славу time-to-market, были успешно непрокинуты в volume.
О да! Вечер перестает быть томным...
Но не зря ты носишь хоть и виртуальный, но все же статус Довакина! Давным давно ты изучил секретный туум
docker stop/start!По сути, эта команды антонимы, которые могут останавливать и запускать контейнеры без необходимости пересоздания.
Базовый синтаксис:
docker stop [OPTIONS] CONTAINER [CONTAINER...]
docker start [OPTIONS] CONTAINER [CONTAINER...]
Вот как ты выйдешь из этой ситуации сухим:
# Заходим в контейнер
docker exec -it my_container /bin/sh
# Шурудим в конфиге
# Остановка контейнера по имени
docker stop my_container
# Запуск остановленного контейнера по имени
docker start my_container
Оп-ля и изменения применились.
А как так, мы же остановили контейнер?
Остановили, но не убили! Все изменения в запущенном контейнере пишутся в writable layer по всем заветам Layered FS. Когда мы стопаем контейнер, они остаются там же. При перезапуске через docker start или же через docker restart мы перезапускаем и процесс нашего приложения. А приложение уже перечитывает конфиг.
И кстати, если на вашем пути попался такой же новичок, но контенеров у него уже несколько, можем провернуть то же самое и со всей партией.
# Запуск нескольких контейнеров одновременно
docker start container1 container2 container3
Видишь? Никаких новых контейнеров, никаких потерянных данных. Просто берешь и продолжаешь с того места, где остановился!
Зачем это нужно в реальной жизни?
Не забывай юзать docker ps для просмотра статуса контейнеров и docker rm для окончательного удаления остановленных контейнеров.
ПыСы: помни — docker start работает только с контейнерами, которые уже существуют. Если контейнер удален через rm, то никакой магии не будет, придется создавать заново.
А на этом я раскланяюсь, до встречи на следующей неделе и хороших вам выходных!
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥7👌2