Делаем безопасный backup конфига перед изменением!
Перед правкой nginx, systemd unit, docker-compose.yml или любого важного конфига полезно сначала сохранить копию. Это занимает секунды, но сильно упрощает откат.
Зададим путь к файлу:
Добавим timestamp:
Соберём имя backup-файла:
Перед копированием проверим, что файл существует:
Теперь создаём копию с сохранением прав и владельца:
После этого можно редактировать конфиг:
Если это nginx, сначала проверяем конфигурацию:
И только потом перезагружаем сервис:
Если что-то пошло не так, откат простой:
Для удобства можно посмотреть последнюю копию:
Backup перед изменением конфига это маленькая привычка, которая часто экономит часы восстановления после неудачной правки.
➡️ DevOps Ready | #практика
Перед правкой nginx, systemd unit, docker-compose.yml или любого важного конфига полезно сначала сохранить копию. Это занимает секунды, но сильно упрощает откат.
Зададим путь к файлу:
file="/etc/nginx/nginx.conf"
Добавим timestamp:
stamp="$(date +%Y%m%d-%H%M%S)"
Соберём имя backup-файла:
backup="${file}.${stamp}.bak"Перед копированием проверим, что файл существует:
test -f "$file" || {
echo "Файл не найден: $file"
exit 1
}Теперь создаём копию с сохранением прав и владельца:
sudo cp -a "$file" "$backup"
После этого можно редактировать конфиг:
sudo nano "$file"
Если это nginx, сначала проверяем конфигурацию:
sudo nginx -t
И только потом перезагружаем сервис:
sudo systemctl reload nginx
Если что-то пошло не так, откат простой:
sudo cp -a "$backup" "$file"
sudo systemctl reload nginx
Для удобства можно посмотреть последнюю копию:
ls -lt /etc/nginx/nginx.conf.*.bak | head
Backup перед изменением конфига это маленькая привычка, которая часто экономит часы восстановления после неудачной правки.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍5🔥4
Знали, зачем в Bash-скриптах иногда включают noclobber?
В shell-скриптах легко случайно перезаписать файл через обычное перенаправление. Особенно если путь собирается из переменных или скрипт запускается в cron.
Например, такая команда всегда перезапишет файл:
Если report.txt уже существовал, старое содержимое пропадёт без предупреждения.
Для защиты можно включить режим noclobber:
После этого обычное перенаправление через > не сможет перезаписать существующий файл:
Если файл уже есть, shell завершит команду ошибкой. Это полезно для отчётов, lock-файлов, backup-метаданных и любых артефактов, которые нельзя случайно затереть.
Когда перезапись действительно нужна, её можно сделать явно через >|:
Так в коде сразу видно намерение. Обычный путь защищён, а опасное действие становится заметным.
Часто noclobber используют локально в небольшом блоке:
А если скрипт должен продолжить работу с обычным поведением, режим можно выключить:
Важно помнить, что noclobber защищает именно перенаправление shell. Он не мешает программе внутри команды самой открыть файл на запись.
➡️ DevOps Ready | #совет
В shell-скриптах легко случайно перезаписать файл через обычное перенаправление. Особенно если путь собирается из переменных или скрипт запускается в cron.
Например, такая команда всегда перезапишет файл:
echo "ready" > report.txt
Если report.txt уже существовал, старое содержимое пропадёт без предупреждения.
Для защиты можно включить режим noclobber:
set -o noclobber
После этого обычное перенаправление через > не сможет перезаписать существующий файл:
set -o noclobber
echo "ready" > report.txt
Если файл уже есть, shell завершит команду ошибкой. Это полезно для отчётов, lock-файлов, backup-метаданных и любых артефактов, которые нельзя случайно затереть.
Когда перезапись действительно нужна, её можно сделать явно через >|:
echo "ready" >| report.txt
Так в коде сразу видно намерение. Обычный путь защищён, а опасное действие становится заметным.
Часто noclobber используют локально в небольшом блоке:
set -o noclobber
echo "$payload" > "$target"
А если скрипт должен продолжить работу с обычным поведением, режим можно выключить:
set +o noclobber
Важно помнить, что noclobber защищает именно перенаправление shell. Он не мешает программе внутри команды самой открыть файл на запись.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤5🔥4🤝1
Netshoot - набор сетевых инструментов для диагностики контейнеров!
В репозитории собран Docker-образ для сетевой отладки в Docker и Kubernetes. Внутри есть tcpdump, tshark, termshark, curl, httpie, grpcurl, nmap, netcat, socat, iproute2, mtr, iperf, openssl и другие утилиты.
Оставляю ссылочку на GitHub
➡️ DevOps Ready | #репозиторий
В репозитории собран Docker-образ для сетевой отладки в Docker и Kubernetes. Внутри есть tcpdump, tshark, termshark, curl, httpie, grpcurl, nmap, netcat, socat, iproute2, mtr, iperf, openssl и другие утилиты.
Оставляю ссылочку на GitHub
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍5❤3
Знали, зачем для одноразовых контейнеров часто добавляют docker run --rm?
Когда контейнер запускают для короткой проверки, он после завершения остаётся в системе. Сам процесс уже не работает, но запись о контейнере и его writable layer остаются.
Например так:
Если делать такие запуски часто, docker ps ничего лишнего не покажет, потому что контейнеры уже остановлены. Но они всё ещё видны через docker ps -a.
Проверить можно так:
Со временем таких остановленных контейнеров становится много. Они мешают смотреть историю запусков, занимают место и создают мусор при отладке.
Для одноразовых команд добавляют --rm:
Теперь контейнер автоматически удалится после завершения команды. Это удобно для curl-проверок, временных shell-сессий, миграций, утилит и быстрых запусков.
Например для сетевой проверки:
Но --rm не стоит добавлять везде бездумно. Если контейнер падает и нужно посмотреть его состояние, логи или файлы после завершения, автоматическое удаление только помешает.
Для отладки иногда лучше оставить контейнер:
Для коротких одноразовых команд --rm помогает держать Docker чистым. Для расследования падений лучше сначала сохранить контейнер и удалить его вручную позже.
➡️ DevOps Ready | #совет
Когда контейнер запускают для короткой проверки, он после завершения остаётся в системе. Сам процесс уже не работает, но запись о контейнере и его writable layer остаются.
Например так:
docker run alpine echo ready
Если делать такие запуски часто, docker ps ничего лишнего не покажет, потому что контейнеры уже остановлены. Но они всё ещё видны через docker ps -a.
Проверить можно так:
docker ps -a
Со временем таких остановленных контейнеров становится много. Они мешают смотреть историю запусков, занимают место и создают мусор при отладке.
Для одноразовых команд добавляют --rm:
docker run --rm alpine echo ready
Теперь контейнер автоматически удалится после завершения команды. Это удобно для curl-проверок, временных shell-сессий, миграций, утилит и быстрых запусков.
Например для сетевой проверки:
docker run --rm curlimages/curl \
curl -I https://example.com
Но --rm не стоит добавлять везде бездумно. Если контейнер падает и нужно посмотреть его состояние, логи или файлы после завершения, автоматическое удаление только помешает.
Для отладки иногда лучше оставить контейнер:
docker run --name debug-app my-image
Для коротких одноразовых команд --rm помогает держать Docker чистым. Для расследования падений лучше сначала сохранить контейнер и удалить его вручную позже.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍4🔥1
Грамотная структура конфигов помогает избежать путаницы между development, staging и production, снизить риск ошибок и упростить сопровождение инфраструктуры. На картинке 7 практик: от разделения конфигураций и секретов до использования переменных среды, слоёв и переопределений, автоматизации загрузки, документации и регулярных проверок окружений.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥6❤4🤝1
Знали, зачем для одноразовых контейнеров часто добавляют docker run --rm?
Когда контейнер запускают для короткой проверки, он после завершения остаётся в системе. Сам процесс уже не работает, но запись о контейнере и его writable layer остаются.
Например так:
Если делать такие запуски часто, docker ps ничего лишнего не покажет, потому что контейнеры уже остановлены. Но они всё ещё видны через docker ps -a.
Проверить можно так:
Со временем таких остановленных контейнеров становится много. Они мешают смотреть историю запусков, занимают место и создают мусор при отладке.
Для одноразовых команд добавляют --rm:
Теперь контейнер автоматически удалится после завершения команды. Это удобно для curl-проверок, временных shell-сессий, миграций, утилит и быстрых запусков.
Например для сетевой проверки:
Но --rm не стоит добавлять везде бездумно. Если контейнер падает и нужно посмотреть его состояние, логи или файлы после завершения, автоматическое удаление только помешает.
Для отладки иногда лучше оставить контейнер:
Для коротких одноразовых команд --rm помогает держать Docker чистым. Для расследования падений лучше сначала сохранить контейнер и удалить его вручную позже.
➡️ DevOps Ready | #совет
Когда контейнер запускают для короткой проверки, он после завершения остаётся в системе. Сам процесс уже не работает, но запись о контейнере и его writable layer остаются.
Например так:
docker run alpine echo ready
Если делать такие запуски часто, docker ps ничего лишнего не покажет, потому что контейнеры уже остановлены. Но они всё ещё видны через docker ps -a.
Проверить можно так:
docker ps -a
Со временем таких остановленных контейнеров становится много. Они мешают смотреть историю запусков, занимают место и создают мусор при отладке.
Для одноразовых команд добавляют --rm:
docker run --rm alpine echo ready
Теперь контейнер автоматически удалится после завершения команды. Это удобно для curl-проверок, временных shell-сессий, миграций, утилит и быстрых запусков.
Например для сетевой проверки:
docker run --rm curlimages/curl \
curl -I https://example.com
Но --rm не стоит добавлять везде бездумно. Если контейнер падает и нужно посмотреть его состояние, логи или файлы после завершения, автоматическое удаление только помешает.
Для отладки иногда лучше оставить контейнер:
docker run --name debug-app my-image
Для коротких одноразовых команд --rm помогает держать Docker чистым. Для расследования падений лучше сначала сохранить контейнер и удалить его вручную позже.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤5🔥3😁1
Знали, зачем в скриптах использовать install вместо touch плюс chmod?
В shell-скриптах часто нужно создать файл или директорию сразу с правильными правами. Например, конфиг, lock-файл, каталог для данных или место под секреты.
Обычно пишут в несколько шагов:
На первый взгляд всё нормально, но между командами файл уже существует с правами по умолчанию. В плохом сценарии это короткое окно может быть лишним, особенно если речь про секреты.
Для таких случаев есть install:
Команда создаёт файл и сразу выставляет нужные права. /dev/null здесь используется как пустой источник.
Для директорий тоже можно сразу указать режим:
А если нужно задать владельца и группу:
Это делает deploy-скрипт короче и безопаснее. Права, владелец и сам факт создания описаны в одной команде, а не размазаны по нескольким строкам.
➡️ DevOps Ready | #совет
В shell-скриптах часто нужно создать файл или директорию сразу с правильными правами. Например, конфиг, lock-файл, каталог для данных или место под секреты.
Обычно пишут в несколько шагов:
touch /etc/myapp/token
chmod 600 /etc/myapp/token
На первый взгляд всё нормально, но между командами файл уже существует с правами по умолчанию. В плохом сценарии это короткое окно может быть лишним, особенно если речь про секреты.
Для таких случаев есть install:
install -m 600 /dev/null /etc/myapp/token
Команда создаёт файл и сразу выставляет нужные права. /dev/null здесь используется как пустой источник.
Для директорий тоже можно сразу указать режим:
install -d -m 750 /var/lib/myapp
А если нужно задать владельца и группу:
install -o app -g app -m 750 -d /var/lib/myapp
Это делает deploy-скрипт короче и безопаснее. Права, владелец и сам факт создания описаны в одной команде, а не размазаны по нескольким строкам.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍9🔥6
Знали, почему порядок COPY в Dockerfile может сильно влиять на скорость сборки?
Docker собирает образ слоями и старается переиспользовать кеш. Если слой не изменился, он берётся из кеша, а следующая команда не выполняется заново.
Проблема часто появляется в Node, Python, Java и других проектах, где зависимости устанавливаются до копирования всего исходного кода.
Неудачный Dockerfile может выглядеть так:
Теперь любое изменение в одном файле проекта сбивает кеш для COPY . . После этого npm ci запускается заново, даже если package.json вообще не менялся.
Лучше сначала копировать только файлы зависимостей:
Этот слой будет пересобираться только тогда, когда реально изменились зависимости. Правки в исходниках больше не заставят Docker каждый раз скачивать и устанавливать пакеты.
Исходный код копируют уже после установки:
Такая же идея работает и для других стеков. В Python сначала копируют requirements.txt или pyproject.toml, в Java отдельно копируют pom.xml или gradle-файлы.
Например для Maven:
Редко меняющиеся файлы ставим выше, часто меняющийся код ниже. Тогда кеш Docker начинает реально помогать, а сборки в CI идут заметно быстрее.
➡️ DevOps Ready | #совет
Docker собирает образ слоями и старается переиспользовать кеш. Если слой не изменился, он берётся из кеша, а следующая команда не выполняется заново.
Проблема часто появляется в Node, Python, Java и других проектах, где зависимости устанавливаются до копирования всего исходного кода.
Неудачный Dockerfile может выглядеть так:
COPY . .
RUN npm ci
RUN npm run build
Теперь любое изменение в одном файле проекта сбивает кеш для COPY . . После этого npm ci запускается заново, даже если package.json вообще не менялся.
Лучше сначала копировать только файлы зависимостей:
COPY package*.json ./
RUN npm ci
Этот слой будет пересобираться только тогда, когда реально изменились зависимости. Правки в исходниках больше не заставят Docker каждый раз скачивать и устанавливать пакеты.
Исходный код копируют уже после установки:
COPY . .
RUN npm run build
Такая же идея работает и для других стеков. В Python сначала копируют requirements.txt или pyproject.toml, в Java отдельно копируют pom.xml или gradle-файлы.
Например для Maven:
COPY pom.xml ./
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package
Редко меняющиеся файлы ставим выше, часто меняющийся код ниже. Тогда кеш Docker начинает реально помогать, а сборки в CI идут заметно быстрее.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍8🔥4🤝1
K9s - удобный терминальный интерфейс для Kubernetes!
Этот репозиторий содержит CLI-инструмент, который открывает интерактивный terminal UI для работы с Kubernetes-кластерами. Через него удобно смотреть Pod, Deployment, Service, логи, события и состояние ресурсов без постоянного набора kubectl-команд.
Оставляю ссылочку на GitHub
➡️ DevOps Ready | #репозиторий
Этот репозиторий содержит CLI-инструмент, который открывает интерактивный terminal UI для работы с Kubernetes-кластерами. Через него удобно смотреть Pod, Deployment, Service, логи, события и состояние ресурсов без постоянного набора kubectl-команд.
Оставляю ссылочку на GitHub
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍8❤7
Шпаргалка по командам Helm!
Например, helm install ставит chart в кластер, helm upgrade обновляет релиз, а helm rollback помогает быстро откатиться на предыдущую рабочую версию.
На картинке собраны основные команды Helm. Есть установка и удаление приложений, работа с repo, поиск chart, обновление релизов, rollback, просмотр values, hooks, manifest и управление плагинами.
Сохрани, чтобы не потерять!
➡️ DevOps Ready | #ресурс
Например, helm install ставит chart в кластер, helm upgrade обновляет релиз, а helm rollback помогает быстро откатиться на предыдущую рабочую версию.
На картинке собраны основные команды Helm. Есть установка и удаление приложений, работа с repo, поиск chart, обновление релизов, rollback, просмотр values, hooks, manifest и управление плагинами.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥4❤3
Делаем простой release через symlink!
Иногда приложение нужно выкладывать так, чтобы новая версия появлялась почти мгновенно, а откат занимал одну команду. Для этого часто используют директории releases и ссылку current.
Структура может быть такой:
Сначала создаём новую папку релиза:
Потом копируем туда собранные файлы:
До переключения current пользователи всё ещё смотрят на старую версию. Это удобно, потому что подготовка релиза не ломает рабочее приложение.
Переключение делается через ln -sfn:
Теперь current указывает на новую директорию. Само переключение происходит быстро, потому что меняется ссылка, а не копируются файлы поверх боевой папки.
Если нужен откат, можно вернуть ссылку на прошлый релиз:
После переключения обычно перезапускают сервис или отправляют reload, если приложение умеет подхватывать файлы без полного рестарта.
Такой подход полезен для простых серверов, статических сайтов, внутренних тулов и приложений без сложной deploy-платформы.
➡️ DevOps Ready | #практика
Иногда приложение нужно выкладывать так, чтобы новая версия появлялась почти мгновенно, а откат занимал одну команду. Для этого часто используют директории releases и ссылку current.
Структура может быть такой:
/opt/app/releases/2026-08-29_1200
/opt/app/current -> /opt/app/releases/2026-08-28_1800
Сначала создаём новую папку релиза:
release="/opt/app/releases/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$release"
Потом копируем туда собранные файлы:
rsync -a ./dist/ "$release/"
До переключения current пользователи всё ещё смотрят на старую версию. Это удобно, потому что подготовка релиза не ломает рабочее приложение.
Переключение делается через ln -sfn:
ln -sfn "$release" /opt/app/current
Теперь current указывает на новую директорию. Само переключение происходит быстро, потому что меняется ссылка, а не копируются файлы поверх боевой папки.
Если нужен откат, можно вернуть ссылку на прошлый релиз:
ln -sfn /opt/app/releases/2026-08-28_1800 /opt/app/current
После переключения обычно перезапускают сервис или отправляют reload, если приложение умеет подхватывать файлы без полного рестарта.
Такой подход полезен для простых серверов, статических сайтов, внутренних тулов и приложений без сложной deploy-платформы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤7🔥3
Media is too big
VIEW IN TELEGRAM
Linux Journey - маршрут по Linux с практическими темами!
На сайте собраны уроки по командной строке, файловой системе, процессам, permissions, пакетам, устройствам, networking, DNS, routing, logging и другим темам, которые нужны DevOps-инженеру и backend-разработчику.
Разделы идут как большая карта обучения. Можно открыть тему, пройти объяснение, перейти к упражнениям и потом двигаться дальше по связанным главам без обязательной регистрации.
➡️ DevOps Ready | #ресурс
На сайте собраны уроки по командной строке, файловой системе, процессам, permissions, пакетам, устройствам, networking, DNS, routing, logging и другим темам, которые нужны DevOps-инженеру и backend-разработчику.
Разделы идут как большая карта обучения. Можно открыть тему, пройти объяснение, перейти к упражнениям и потом двигаться дальше по связанным главам без обязательной регистрации.
Оставляю ссылочку на Linux Journey
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍3🔥3
Разбираем gh CLI для GitHub Actions и релизов!
gh помогает работать с GitHub прямо из терминала. Через него удобно смотреть запуски workflow, читать логи, вручную запускать pipeline, управлять секретами и выпускать релизы.
В этой шпоре собраны run list, run watch, run view, workflow run, secret set, release create и api.
➡️ DevOps Ready | #шпора
gh помогает работать с GitHub прямо из терминала. Через него удобно смотреть запуски workflow, читать логи, вручную запускать pipeline, управлять секретами и выпускать релизы.
В этой шпоре собраны run list, run watch, run view, workflow run, secret set, release create и api.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3🔥3🤝1
Слишком большое количество алертов быстро превращается в шум и мешает команде замечать действительно важные проблемы. На картинке 7 практик: от выбора значимых сигналов и настройки порогов до группировки, дедупликации, добавления контекста, маршрутизации, оценки качества и регулярного тестирования оповещений.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍8🔥6
Media is too big
VIEW IN TELEGRAM
Penguin Gym Linux - тренировка Linux-команд!
На сайте можно практиковать Linux-команды прямо в браузере. Есть виртуальный terminal, пошаговые уроки, задания, квизы, материалы по beginner Linux, LPIC-1 и отдельный маршрут в сторону DevOps.
Ресурс полезен для прокачки базовых команд. Можно тренировать файловую систему, права, процессы, поиск, архивы, сетевые команды и другие навыки, которые постоянно нужны в инфраструктуре.
➡️ DevOps Ready | #ресурс
На сайте можно практиковать Linux-команды прямо в браузере. Есть виртуальный terminal, пошаговые уроки, задания, квизы, материалы по beginner Linux, LPIC-1 и отдельный маршрут в сторону DevOps.
Ресурс полезен для прокачки базовых команд. Можно тренировать файловую систему, права, процессы, поиск, архивы, сетевые команды и другие навыки, которые постоянно нужны в инфраструктуре.
Оставляю ссылочку на Penguin Gym
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤8🔥3🤝1
Правильное разделение настроек помогает безопасно управлять разными окружениями, не хранить секреты в репозитории и не создавать хаос в конфигурации. На картинке показаны 7 практик: от классификации параметров и принципов 12-Factor до работы с секретами, разделения dev, staging и prod, автоматической проверки и документирования конфигурации. Главное правило: код хранится в Git, значения приходят через ENV, а секреты находятся в защищённом хранилище.Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤6🔥3
Знали, почему readinessProbe не стоит заменять livenessProbe?
В Kubernetes часто добавляют health checks, но readinessProbe и livenessProbe нужны для разных вещей.
livenessProbe нужна, чтобы понять, жив ли контейнер вообще. Если приложение зависло и уже не может восстановиться, Kubernetes перезапустит Pod.
Простой пример проверки:
readinessProbe решает другую задачу. Она говорит, можно ли прямо сейчас отправлять трафик в этот Pod.
Например, приложение уже запустилось, но ещё прогревает кэш, ждёт миграции, подключение к базе или загрузку конфигурации. Перезапускать его в этот момент не нужно.
Для этого лучше сделать отдельный endpoint:
Если readiness падает, Pod просто убирается из endpoints сервиса. Новые запросы туда не идут, но контейнер продолжает работать и может вернуться в строй.
А если slow start долгий, добавляют startupProbe:
Она даёт приложению время на старт и не позволяет livenessProbe убить контейнер слишком рано.
Состояние проб удобно смотреть через describe:
liveness отвечает за перезапуск, readiness отвечает за трафик, startupProbe отвечает за долгий старт.
➡️ DevOps Ready | #совет
В Kubernetes часто добавляют health checks, но readinessProbe и livenessProbe нужны для разных вещей.
livenessProbe нужна, чтобы понять, жив ли контейнер вообще. Если приложение зависло и уже не может восстановиться, Kubernetes перезапустит Pod.
Простой пример проверки:
livenessProbe:
httpGet:
path: /health/live
port: 8080
readinessProbe решает другую задачу. Она говорит, можно ли прямо сейчас отправлять трафик в этот Pod.
Например, приложение уже запустилось, но ещё прогревает кэш, ждёт миграции, подключение к базе или загрузку конфигурации. Перезапускать его в этот момент не нужно.
Для этого лучше сделать отдельный endpoint:
readinessProbe:
httpGet:
path: /health/ready
port: 8080
Если readiness падает, Pod просто убирается из endpoints сервиса. Новые запросы туда не идут, но контейнер продолжает работать и может вернуться в строй.
А если slow start долгий, добавляют startupProbe:
startupProbe:
httpGet:
path: /health/startup
port: 8080
failureThreshold: 30
periodSeconds: 2
Она даёт приложению время на старт и не позволяет livenessProbe убить контейнер слишком рано.
Состояние проб удобно смотреть через describe:
kubectl describe pod api-7f9c
liveness отвечает за перезапуск, readiness отвечает за трафик, startupProbe отвечает за долгий старт.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤4👍4