🙈If i ignore it, it will go away🙈
И тут самое время заюзать, возможно знакомый вам из git-а, формат ignore файлов. В нашем случае
Этот файл работает по тому же принципу, что и
Например он может выглядеть вот так:
Паттерны:
Можно юзать wildcard или более сложные паттерны
Зачем это нужно? 🤔
🔹Во-первых, размер! Build Context — это все, что Docker отправляет демону для сборки. Чем меньше мусора, тем быстрее передача и меньше итоговый образ.
🔹Во-вторых, безопасность. Никому не нужны секреты, приватные ключи или конфиги в production образе.
🔹В-третьих, кэширование слоев работает эффективнее без постоянно меняющихся логов и временных файлов.
Фиксируем,
А на сегодня у нас все и помните: игнорировать можно все что угодно, кроме отсуствия реактов на постах от любимых подписчиков!😔
Так что, обязательно ставьте!😏
🥷 Docker Ninja 🥷
Бывает, собираешь образ, а Docker берет и тащит в контейнер все что видит в рамках контекста. Node_modules на 300 МБ, .git со всей историей коммитов, IDE конфиги, логи разработки, личную коллекцию мемов из папкиdicks_pics/🍌 ...
В итоге, образ раздувается до неприличных размеров, а во время сборки можно спокойно уходить на обед.
Конечно, для кого-то это может быть преимуществом, но мы то с вами ответственные работники, правда ведь?!😏
И тут самое время заюзать, возможно знакомый вам из git-а, формат ignore файлов. В нашем случае
.dockerignore.Этот файл работает по тому же принципу, что и
.gitignore, только вместо исключения файлов из репозитория, он исключает их из контекста сборки Docker. Создаешь файл .dockerignore в корне проекта рядом с Dockerfile (руками или через init) и прописываешь паттерны того, что Docker должен проигнорировать.Например он может выглядеть вот так:
node_modules/
*.log
.git
.env
Паттерны:
Можно юзать wildcard или более сложные паттерны
# Исключить все .md файлы, кроме README.md
*.md
!README.md
# Исключить все временные файлы
**/temp/
**/*.tmp
Зачем это нужно? 🤔
🔹Во-первых, размер! Build Context — это все, что Docker отправляет демону для сборки. Чем меньше мусора, тем быстрее передача и меньше итоговый образ.
🔹Во-вторых, безопасность. Никому не нужны секреты, приватные ключи или конфиги в production образе.
🔹В-третьих, кэширование слоев работает эффективнее без постоянно меняющихся логов и временных файлов.
Фиксируем,
.dockerignore проверяется относительно Build Context, который вы указываете в docker build!А на сегодня у нас все и помните: игнорировать можно все что угодно, кроме отсуствия реактов на постах от любимых подписчиков!
Так что, обязательно ставьте!
🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥3👏2🤯1
Ты работаешь с микросервисной архитектурой и хочешь мониторить потребление ресурсов всех запущенных контейнеров в реальном времени. Какая команда покажет CPU, память и сетевую активность?
Anonymous Quiz
12%
docker ps --format table
47%
docker stats
35%
docker top --all
6%
docker system df
©️Хорошие копируют, великие воруют🦝
пушку ракету!🚀
Правило №1: Зависимости копируем отдельно
Частный случай для следующего правила, но стоит рассмотреть его отдельно
Делаем так:
Правило №2: От редко изменяемых к часто изменяемым
Docker кэширует слои сверху вниз. Как только один слой меняется, все нижние пересобираются
Правило №3: Дружи с .dockerignore
Смотрим пост про .dockerignore и проникаемся
Правило №4: Multi-stage для чистых артефактов
Собираем в одном образе, забираем результат в другом
Зачем это нужно?
Представь: у тебя Node.js приложение, ты фиксишь баг в main.js. При правильном COPY пересоберется только один последний слой. При неправильном - весь
В реальности это означает разницу между сборкой за 10 секунд и за 10 минут. Особенно критично для CI/CD пайплайнов, где каждая секунда на счету. Да и в момент разработки дико бесит, что нужно долго ждать пересборку...
Так что, воруйте все что здесь написано и ставьте ваши реакции!!!
🥷 Docker Ninja 🥷
Мы с вами уже довольно хорошо погрузились в различные аспекты написания Dockerfile. Все может казаться просто и лаконично: захотел закинуть сорсы в контейнер - используй COPY; надо закинуть что-то из архива - втыкай ADD; слишком тяжелая сборка - пробуй multistage build.Так шо сегодня рассмотрим best practices для COPY, которые превратят твою сборку в
Но порою, меняешь одну строчку в коде, а сборка после этого идет 15 минут. Как будто Docker внезапно забыл про все свои слои и решил: "А давайте-ка пересоберем все с нуля!"
А ведь проблема часто кроется в бездумных COPY в твоем Dockerfile.
Правило №1: Зависимости копируем отдельно
Частный случай для следующего правила, но стоит рассмотреть его отдельно
# ❌ Плохо - весь контекст копируется сразу
COPY . /app
RUN npm install
Делаем так:
# ✅ Хорошо - сначала только package.json
COPY package*.json /app/
RUN npm install
COPY . /app/
Правило №2: От редко изменяемых к часто изменяемым
Docker кэширует слои сверху вниз. Как только один слой меняется, все нижние пересобираются
COPY requirements.txt /app/ # Меняется редко
RUN pip install -r requirements.txt
COPY some_noscript.sh /noscripts/ # Меняется средне
COPY src/ /app/src/ # Меняется средне
COPY main.py /app/ # Меняется часто
Правило №3: Дружи с .dockerignore
Смотрим пост про .dockerignore и проникаемся
# ❌ Опасно - копируем весь мусор, а в довесок и секреты
COPY . /app
# ✅ Безопасно - фильтруем через .dockerignore
## Создай .dockerignore рядом с Dockerfile:
node_modules
.git
*.log
.env
.idea
.vscode
dist
Dockerfile
.dockerignore
Правило №4: Multi-stage для чистых артефактов
Собираем в одном образе, забираем результат в другом
FROM golang:1.23 AS sdk
...
RUN go build -o /bin/hello ./main.go
FROM scratch
COPY /app/some_file.txt /app/file.txt
COPY --from=sdk /bin/hello /bin/hello
CMD ["/bin/hello"]
Зачем это нужно?
Представь: у тебя Node.js приложение, ты фиксишь баг в main.js. При правильном COPY пересоберется только один последний слой. При неправильном - весь
npm install заново, а это могут быть гигабайты зависимостей!В реальности это означает разницу между сборкой за 10 секунд и за 10 минут. Особенно критично для CI/CD пайплайнов, где каждая секунда на счету. Да и в момент разработки дико бесит, что нужно долго ждать пересборку...
Так что, воруйте все что здесь написано и ставьте ваши реакции!!!
🥷 Docker Ninja 🥷
2👍13🔥5❤2😁2
Твое приложение собирается через multi-stage build. На финальной стадии нужно скопировать только скомпилированные бинарные файлы из промежуточной стадии. Какая директива Dockerfile правильно выполнит эту задачу?
Anonymous Quiz
7%
ADD --from=builder /app/bin /usr/local/bin
10%
RUN cp --from=builder /app/bin /usr/local/bin
9%
WORKDIR --from=builder /app/bin
74%
COPY --from=builder /app/bin /usr/local/bin
👍4❤2🆒2
😱 Игра началась 😱
Помнится, в самом начале моего девопсерского пути меня долго мучал вопрос, нафига нужен
Но как и в случае с "необязательным 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