Docker Ninja – Telegram
Docker Ninja
1.05K subscribers
30 photos
91 links
По всем вопросам обращаться к @nesudimov_eu
Download Telegram
Какой механизм 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
📋 Это мой кандидатский сценарий. Слушай devops, слушай пролетарий 📋

Однажды мы с вам касались вопроса, как работают 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
🚜 Едут, едут комбайнеры, едут, едут на поля 🚜

Помнишь те славные времена, когда твоя любимая компания "Рога и копыта" была маленьким стартапом из 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

Хоба, и твой контейнер теперь работает с сетевым хранилищем! 📦

Преимущества этого решения
➡️ Enterprise интеграция: подключаешься к существующим уже инфраструктурным решениям без костылей
➡️ Гибкость: расширяешь Docker под свои нужды, а не наоборот
➡️ Совместимость: используешь корпоративные системы хранения и сети
➡️ Масштабируемость: один раз настроил плагин - используешь везде

Короче, плагины - это способ сделать Docker действительно enterprise-ready без переписывания всего с нуля! В production среде без них часто просто никуда - стандартных драйверов не хватает для серьезных задач.

ПыСы: помни, что плагины работают с правами хоста, так что не качай левые сборки из интернетов - потом не говори, что не предупреждал! 😏

Ставь реакт, если было интересно! А то я буду думать Да ниче не буду думать, просто буду тихо рыдать под душем, чтобы не было видно слез.😭 Потому что истинные комбайнеры не плачут, истинные комбайнеры ссу.. принимают гигиенические процедуры для лица посредством ресурсов собственного тела!💪

🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍51🗿1
🔄СтопуемСтаруем!🔄

И снова пятница! К твоему счастью все релизы закрыты и ты уже спокойно собираешь свои вещички в недолгое путешествие по скайриму, чтобы получить хоть какое-то новогодонее настроение. Но Талмор не дремлет и подкидывает тебе новые квесты, чтобы ты никогда не смог помочь имперцам вернуть былое величие! 😠

На этот раз к тебе подходит некий Аркадий Рукожопов (совсем не говорящая фамилия, неет), который отвечал за последнюю релизнутую фичу, со словами: "Ты знаешь, я забыл проверить кое какую штуковину в конфиге. Так то все работает, но в некоторые моменты может сильно нагрузить систему. Можем сейчас подредачить на бою и перезапустить. Заодно и проверим, на выходных как оно работает."

Ух... отлично, потестить на проде... Вариант ответа "Отправить пососировать бибоний" для тебя заблокирован из-за недостаточно развитого красноречия, поэтому ты стоически берешся за эту задачу. 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


Видишь? Никаких новых контейнеров, никаких потерянных данных. Просто берешь и продолжаешь с того места, где остановился!

Зачем это нужно в реальной жизни?
➡️ Сохранение состояния приложения: разрабатываешь веб-приложение с базой данных внутри контейнера? Start позволяет сохранить все данные между перезапусками
➡️ Экономия ресурсов в CI/CD: переиспользование контейнеров с предустановленными зависимостями сокращает время инициализации тестовых сред
➡️ Отладка production-инцидентов: можно остановить проблемный контейнер для анализа логов, затем запустить снова без пересоздания
➡️ Управление ресурсами сервера: в средах с ограниченными ресурсами позволяет временно останавливать неиспользуемые сервисы и запускать по требованию

Не забывай юзать docker ps для просмотра статуса контейнеров и docker rm для окончательного удаления остановленных контейнеров.

ПыСы: помни — docker start работает только с контейнерами, которые уже существуют. Если контейнер удален через rm, то никакой магии не будет, придется создавать заново.

А на этом я раскланяюсь, до встречи на следующей неделе и хороших вам выходных!

🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥7👌2
🕸Сети не путать! Сети изучать!🕸

Давным давно, когда я был совсем зеленый и несмышленный, а сервисы в нашей конторе только начинали переезжать с винды в контейнеры, мне удалось поучаствовать в развороте очередного микросервиса на проде. Ничто не предвещало беды, ведь локально то я у себя все запустил. И я со всего разбегу полетел запускать сервис таким же макаром.

docker run -d my_container - и вот я уже потираю ручки от того, какой же я DEVOPS! Но тут мне прилетает сообщение от разраба: "Не робит... Как будто этот сервис не может достучаться до другого внутреннего сервиса". А они то на одном хосте!!!

Все мои тщетные потуги решить проблему самостоятельно не оправдались. Поэтому пришлось вызывать моего личного DevOps Сенпая. Недолго думая, он написал одну единственную команду и все стало ясно - какой же я балбес...


Той командой был docker network ls. И проблема была в том, что для connectivity сервисов нужно было добавить их в единую docker сеть (если мы конечно хотим сделать все правильно с точки зрения безопасности и лучших практик).

По сути, это ни что иное как docker network list. То есть она показывает нам ID, имя, тип драйвера и область видимости каждой сети.

Вот как это выглядит в деле:
# Просмотр всех сетей на хосте
docker network ls
# Выводит NETWORK ID, NAME, DRIVER, SCOPE для каждой сети


Можем фильтрануть вывод по нужным нам данным:
# Форматированный вывод только имен сетей
docker network ls --format "table {{.Name}}\t{{.Driver}}\t{{.Scope}}"
# Кастомная таблица для focused analysis определенных атрибутов


Видишь? Как помнишь по умолчанию у тебя всегда есть три системные сети: bridge (дефолтная), host (прямой доступ к сети хоста) и none (полная изоляция). А дальше - все что создал сам или Docker Compose.

А вот тут становится интересно! Если видишь кучу кастомных bridge networks - значит, у тебя микросервисная архитектура с сегментацией или с чьей-то забывчивостью. Overlay networks - это multi-host deployment, скорее всего Swarm. А если только дефолтный bridge - то либо все просто, либо кто-то не подумал о безопасности.

Зачем это нужно?
➡️ Диагностика connectivity проблем - быстро видишь доступные сети для troubleshooting межсервисного взаимодействия
➡️ Аудит сетевой безопасности - проверяешь изоляцию между разными tenant networks и ловишь потенциальные дыры
➡️ Планирование архитектурных изменений - анализируешь текущую топологию перед scaling и оптимизацией
➡️ Автоматизация мониторинга - интегрируешь в скрипты для контроля соответствия корпоративным политикам

Так что теперь, когда тебе приходит коллега с вопросом "почему сервисы друг друга не видят?", ты знаешь с чего начать! Первым делом - docker network ls, а потом уже разбираться в деталях. Ставь свои сердечки и огонечки, если зашло, и спокойного тебе прода! И не забывай писать свои вопрсы в директ канала или мне в личку - @nesudimov_eu.🔥

🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥12👍3💯2
📦VOLUME me baby one more time📦

Ремесло девопса заключается не только в автоматизации, но и в выпрямлении и упрощении кривых рабочих процессов. Упростить для нас, это значит сделать настолько элементарным, что даже самый неподготовленный тестировщик специалист справится с работой используя только документацию.

Для этого, просто необходимо минимизировать количество входных параметров. И конечно же, разработчики докер понимают эту боль и дают нам возможности с ней справляться.

Однажды мы с вами уже говорили про EXPOSE, который вроде бы ничего не делает, но позволяет стандартизировать работу с портами. Сегодня же пришло время разобраться с томами, поскольку их указание важно и может послужить точкой отказа при деплое.


Сегодня у нас директива VOLUME в Dockerfile, которая дает нам возможность прямо в образе указать, что и куда монтировать.

Синтаксис простой как тыква:
VOLUME /path/to/directory/inside/container

# Или можем указать сразу несколько точке
VOLUME ["/path1", "/path2"]


Вот как это выглядит в деле:
# Создает точку монтирования для логов веб-сервера
FROM nginx:alpine
VOLUME /var/log/nginx


# Создает две точки монтирования для пользовательских файлов и кеша
FROM node:16
WORKDIR /app
VOLUME ["/app/uploads", "/app/cache"]


Видишь? Ты этой директивой говоришь Docker создать анонимный том с уникальным ID и автоматически примонтировать его к указанному пути. Данные в таком томе переживут смерть и воскрешение контейнера!

Но тут есть один хитрый момент! VOLUME работает не как bind mount через -v[], где ты сам указываешь, что куда монтировать. Здесь Docker создает анонимные тома и сам ими управляет. Это удобно для стандартизации, но может удивить новичков.

Зачем это нужно?
➡️ Автоматическая персистентность данных - шобы никто при запуске контейнера не забыл указать сохранять логи в отдельную папочку
➡️ Стандартизация точек монтирования - очень полезно, когда у вас множество однотипных сервисов (логи сюда, конфиги туда, картинки с мемасиками в images)
➡️ Упрощение оркестрации - все как и для первого пункта, только в контексте Docker Compose (забыл прописать в файле тома, а они все равно создались)
➡️ Изоляция данных от container layer - если бэкапим стейт контейнера через docker export

Директива VOLUME тесно связана с типами томов в Docker, секцией volumes в Docker Compose, директивой COPY для копирования данных в образ.

В общем директива VOLUME отлично подходит, как "защита от дурака" - меньше флагов или инструкций в docker compose, спокойнее вечера! Юзай на здоровье! Но есть у для нее кейсы и по-веселее. А на этом я с тобой прощаюсь, хорошего дня!

🥷 Docker Ninja 🥷
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍5🔥3