Docker Ninja – Telegram
Docker Ninja
1.05K subscribers
30 photos
91 links
По всем вопросам обращаться к @nesudimov_eu
Download Telegram
🙈If i ignore it, it will go away🙈

Бывает, собираешь образ, а 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
©️Хорошие копируют, великие воруют🦝

Мы с вами уже довольно хорошо погрузились в различные аспекты написания Dockerfile. Все может казаться просто и лаконично: захотел закинуть сорсы в контейнер - используй COPY; надо закинуть что-то из архива - втыкай ADD; слишком тяжелая сборка - пробуй multistage build.

Но порою, меняешь одну строчку в коде, а сборка после этого идет 15 минут. Как будто Docker внезапно забыл про все свои слои и решил: "А давайте-ка пересоберем все с нуля!"

А ведь проблема часто кроется в бездумных COPY в твоем Dockerfile.

Так шо сегодня рассмотрим best practices для COPY, которые превратят твою сборку в пушку ракету!🚀

Правило №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🔥52😁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
👍42🆒2
😱 Игра началась 😱

Помнится, в самом начале моего девопсерского пути меня долго мучал вопрос, нафига нужен 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👍82
Вопросошная

В
пятницу вечером один из подписчиков задал вопрос к последнему посту: работает ли 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: понедельники без тяжести💊

Сидишь ты значит, деплоишь в продакшен очередной микросервис, потирая красные от недосыпа глаза, как вдруг, ИБ-ешник присылает отчет 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? Ставь 🔥!

Этот пост лишь маленькая часть серии из 3-х постов про distroless и scratch образы. Ссылки на все части ты можешь найти в этом посте.

🥷 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 (где хранить слои образов)
⚙️ Log driver (куда сливать логи контейнеров)
⚙️ Registry mirrors (зеркала для быстрого пулла)
⚙️ Insecure registries (приватные реестры без HTTPS)

Простейший пример:
{
"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🔥72
При работе с 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
🛸Ограничиваем мыслительные ресурсы🛸

Представь, заапускаешь ты такой на проде "безобидный" контейнер с 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👍154😁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 к ядру хоста. Как будто бы мы запустили этот самый бинарь прямо на хосте.

Но не забывай:
➡️ Бинарник должен быть статически скомпилирован (все зависимости внутри)
➡️ Никакого shell для дебага - только логи
➡️ Нет стандартных утилит типа 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👍102😁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


А кейсы то будут,?
➡️ Nginx/Apache часто нужно биндиться на 80/443 порт → NET_BIND_SERVICE
➡️ VPN-приложения ковыряются в маршрутизации → NET_ADMIN
➡️ Мониторинг-тулзы читают системную инфу → SYS_ADMIN
➡️ Бекапы работают с файловыми атрибутами → DAC_OVERRIDE

Хоба и ты умеешь гибко настраивать безопасность, а кому нужны лишние терки с коллегами из ИБ по середине рабочей недели?? Правильно - никому. Поэтому смело ставь реакт за полезняшку!🤑

🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍14🔥63🤔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:
...


Здесь мы указали:
Имя, с которым будет создан новый том. В компоузе будем обращаться по имени cache
Тип драйвера
Различные опции для этого драйвера

Зачем это нужно?
➡️ Базы данных: данные переживут пересоздание контейнера
➡️ Development: bind mount для live reload кода
➡️ Логи: складываем на хост для мониторинга
➡️ Кэши: если используем build в компоузе, то сваливаем в том кэш загруженных зависимостей

Volumes - это база любого production compose-файла. А в связке с build получается полноценная среда разработки! Поэтому знать, понимать и помнить это просто необходимо!

А на сегодня у меня все. Как обычно, не забывайте ставить свои реакты и всем хороших выходных.🍺

🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍8🍾4🔥32
🍋 Easy peasy lemon squeezy 🍋

Однажды составлял 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 поста!😐 Так как контейнер это всего лишь процесс, то exec форма работает изнутри как системный вызов execve.

Запомни правило:
В минималистичных образах всегда используй exec форму ["команда", "аргумент1", "аргумент2"] вместо shell формы команда аргумент1 аргумент2.

Теперь твои контейнеры будут стартовать с загадочными ошибками, а не падать! 😄

Ставь свои реакты, если уже тоже наступал на эти грабли! Если не наступал тоже ставь! А на этом я откланяюсь и хорошей вам рабочей недели!

🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍15🔥62
В твоем проекте есть Docker Compose файл с несколькими сервисами. Ты хочешь проверить, корректно ли составлен файл перед запуском. Какую команду использовать?
Anonymous Quiz
26%
docker compose validate
32%
docker compose check
22%
docker compose config
20%
docker compose verify
👍6🔥3
🧙‍♀️Берём укропу, потом кошачью... 25 картошек, 17 ... ведро воды и ..., охапку дров - компоуз готов 🧙‍♀️

Все совпадения случайны! Ни один ПМ-м ни капли не похож на демогоргона. В среду все девопсы думают исключительно о работе и только о работе!

Среда Маленькая пятница. Неделя подошла к своей медиане, а ты уже душой на даче в Лосево, смотришь с котом под пледом новый сезон Очень странных дел... Но тут тебя затягивает в Изнанку очередной звонок Димы Горгина - 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


Зачем заморачиваться?
Потому что без дублирования кода ты получаешь элегантное управление окружениями! Одна база, куча вариаций.
➡️Dev-у нужны дебаг порты? - Пжалста.
➡️Staging-у отдельная БД? - Легко.
➡️Проду кластер из трёх реплик? - Да не вопрос!

🍲А теперь заряжаем наш котел всеми нужными ингредиентами:🍲
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😁42
В 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
👍175🔥3