TGViewer
Channel Public Channel
SRE | DevOps

SRE | DevOps

@opennet

Практические разборы Linux, Kubernetes и CI/CD: тюнинг, отладка, реальные кейсы. Без теории — только инженерные решения и рабочие конфигурации.
Subscribers
330
Photos
0
Videos
0
Links
0
Recent Posts 8 shown
Post #55 74
PSI (Pressure Stall Information): ранние алерты на деградацию CPU/Memory/IO 🧠

Проблема
Метрики уровня CPU%/memory usage запаздывают: под уже “плохой”, когда вы видите пик. OOM и latency-спайки возникают раньше — в момент stall’ов (когда процессы ждут ресурсы). Нужен сигнал, который ловит деградацию до аварии.

Решение
Использовать PSI (Linux ≥4.20, в проде обычно ≥5.x): метрики давления по CPU/Memory/IO (/proc/pressure/*). Алертить по some/full avg10 — короткому окну, чувствительному к пикам. В Kubernetes — собирать через node-exporter (включённый collector pressure) или textfile-collector.

---

Практика

Включение в node-exporter (≥1.3 уже умеет PSI):

# systemd unit (фрагмент)
ExecStart=/usr/local/bin/node_exporter \
--collector.pressure \
--collector.textfile.directory=/var/lib/node_exporter


Проверка:

curl -s localhost:9100/metrics | grep node_pressure


Пример алерта (Prometheus):

groups:
- name: psi.rules
rules:
- alert: HighMemoryPressure
expr: node_pressure_memory_some_avg10 > 0.2
for: 2m
labels:
severity: warning
annotations:
summary: "Memory pressure on {{ $labels.instance }}"
description: "avg10 > 20%: процессы часто ждут память"

- alert: CPUStallBurst
expr: node_pressure_cpu_some_avg10 > 0.3
for: 1m
labels:
severity: warning

- alert: IOFullStall
expr: node_pressure_io_full_avg10 > 0.05
for: 2m
labels:
severity: critical


> some — часть задач ждёт ресурс; full — все задачи в группе стоят (сильный сигнал).

---

Как это работает
Ядро считает долю времени, когда задачи не могут выполняться из-за нехватки ресурса.

* avg10/60/300 — скользящие окна (10с/1м/5м).
* CPU PSI отражает scheduler contention, memory — давление (reclaim/compaction), IO — ожидание диска.
В отличие от “процентов”, PSI показывает фактическую потерю прогресса.

---

Нюансы

* Пороги зависят от профиля: для latency-чувствительных сервисов memory some avg10 > 0.1 уже плохо.
* Смотрите вместе с метриками:

* Memory PSI + container_memory_working_set_bytes → близко к OOM
* CPU PSI + container_cpu_cfs_throttled_seconds_total → throttling
* IO PSI + node_disk_* → узкий диск
* В cgroup v2 можно читать PSI по конкретным группам (/sys/fs/cgroup/.../cpu.pressure) — полезно для noisy neighbor.
* Краткие всплески нормальны — используйте for: и avg10, не алертите на avg300.

---

Когда применять

✔️ multi-tenant кластеры
✔️ high-load ingress/DB/queue
✔️ раннее обнаружение деградации до OOM/timeout

Когда мало пользы

✖️ стабильные, низконагруженные системы
✖️ отсутствие реакции (если нечем масштабироваться/тюнить)

Практический эффект: PSI позволяет поднять алерты за минуты до OOM и латентностных сбоев — давая время на autoscale, перераспределение или троттлинг.
  • ❤ 2
Post #54 46
GitLab Runner autoscaling: устранение задержек старта job (VM executor)

Проблема
При autoscaling раннеров (OpenStack/VM) наблюдается лаг 3–10 минут между стартом job и фактическим выполнением. Узкие места: долгое создание ВМ, установка Docker на лету, ожидание SSH, “холодные” образы и консервативные тайминги раннера.

Решение
Сместить максимум работы в golden image, сократить provisioning до нуля и агрессивно настроить autoscaler: pre-warm (idle instances), быстрый SSH, минимальный cloud-init. Цель — time-to-first-task < 60–90 сек.

---

Практика

config.toml (GitLab Runner ≥16.x, executor docker+machine/OpenStack-подобный):

concurrent = 20
check_interval = 0

[[runners]]
name = "autoscale-os"
url = "https://gitlab.example.com"
token = "XXX"
executor = "docker+machine"

[runners.docker]
image = "alpine:3.19"
pull_policy = "if-not-present" # не тянуть каждый раз
privileged = true

[runners.machine]
IdleCount = 2 # держим прогретые ВМ
IdleTime = 600
MaxBuilds = 50 # reuse ВМ
MachineDriver = "openstack"
MachineName = "gl-runner-%s"

MachineOptions = [
"openstack-image-name=debian-13-golden-v1",
"openstack-flavor-name=m1.medium",
"openstack-network-name=private",
"openstack-ssh-user=debian",
"openstack-ssh-port=22",
"openstack-ssh-timeout=60", # быстрее fail при проблемах
]


Ключевые моменты в образе (через Packer): предустановленный Docker/containerd, git, qemu-guest-agent, отключённые интерактивные шаги, минимальный cloud-init.

Минимальный cloud-init:

#cloud-config
package_update: false
runcmd:
- systemctl enable --now docker


---

Как это работает 🧠
Autoscaler держит пул IdleCount ВМ. При приходе job она получает уже готовый хост без установки зависимостей. MaxBuilds позволяет переиспользовать ВМ, амортизируя стоимость создания. Быстрый SSH и уменьшенные таймауты сокращают “висящие” provisioning’и.

---

Нюансы / подводные камни

* Golden image — критичен: установка Docker во время job = минуты задержки.
* IdleCount: слишком маленький → холодные старты; слишком большой → лишние расходы.
* MaxBuilds: повышает скорость, но следите за “загрязнением” (чистка workspace, --rm контейнеры).
* Registry latency: добавьте локальный mirror — иначе выигрыш съест image pull.
* Quota/OpenStack: лимиты на создание ВМ могут давать скрытые очереди.
* Логи: включите debug runner’а для анализа стадий (create → provision → ready).

---

Когда применять

✔️ burst-нагрузки CI
✔️ тяжёлые job с Docker
✔️ облака с медленным provisioning

Когда не нужно

✖️ стабильная равномерная нагрузка (достаточно статических раннеров)
✖️ очень короткие job (<10–20 сек) — overhead autoscaling доминирует

Альтернатива: Kubernetes executor — быстрее старт за счёт подов, но требует зрелого кластера и сетевого/registry-тюнинга.
Post #53 26
Nexus OSS при 500k+ артефактов: тюнинг JVM и blob store

Проблема
После ~300–500k артефактов Nexus OSS (3.x) начинает “задыхаться”: GC-паузы, рост latency UI/API, долгие cleanup tasks. Типовые причины — неподходящий heap/GC и неоптимальный blob store (файловая система, layout, GC).

Решение
Фиксируем heap и GC под профиль нагрузки + выносим blob store на быстрый диск с корректными параметрами FS и включаем регулярный cleanup/compact. Цель — снизить pause time и ускорить операции с blob’ами (read/write/delete).

---

Практика

1. JVM (Java 17+, G1GC как базовый выбор):

# /opt/sonatype/nexus/bin/nexus.vmoptions
-Xms4g
-Xmx4g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
-XX:G1ReservePercent=15
-XX:+ParallelRefProcEnabled
-XX:+UseStringDeduplication

# метрики и диагностика
-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder
-XX:StartFlightRecording=filename=/nexus-data/log/jfr.jfr,settings=profile

# файловые дескрипторы/метаспейс
-XX:MaxMetaspaceSize=512m


> 4–8 GB heap обычно достаточно до ~1M артефактов при нормальном IO. Важнее стабильные паузы, чем “раздутый” heap.

2. Blob store (file-based):

* Диск: SSD/NVMe, отдельный том (/nexus-data/blobs)
* ФС: xfs (предпочтительно) или ext4 с noatime

# пример монтирования
UUID=... /nexus-data xfs defaults,noatime,nodiratime,logbufs=8 0 2


* В Nexus: создаём отдельный blob store под “тяжёлые” форматы (docker, maven-snapshots) — изоляция снижает фрагментацию и ускоряет cleanup.

3. Cleanup/Compact (через UI или tasks API):

* Cleanup policies (по возрасту/последнему скачиванию)
* Admin → Compact blob store — регулярно (ночные окна)
* Rebuild repository index — при деградации поиска

4. OS лимиты:

# /etc/security/limits.d/nexus.conf
nexus soft nofile 65536
nexus hard nofile 65536


---

Как это работает 🧠
G1 делит heap на регионы и старается держать паузы в целевом бюджете (MaxGCPauseMillis). Параметр InitiatingHeapOccupancyPercent запускает concurrent GC раньше, избегая “stop-the-world” на пике.
Blob store — это файловый бекенд; скорость операций зависит от latency диска и эффективности inode/dir-структур. xfs лучше ведёт себя при большом числе файлов и параллельных операциях.

---

Нюансы / подводные камни

* Большой heap ≠ лучше: растут паузы и время remark. Начинайте с 4–6 GB и наблюдайте JFR.
* Docker registry: много мелких слоёв → высокая нагрузка на inode; следите за df -i.
* Cleanup vs retention: агрессивные политики могут ломать кэш CI (повторные pull’ы).
* Compact блокирует операции на blob store — планируйте окна.
* Backup: файловый blob store требует согласованного бэкапа (снапшоты тома + остановка задач записи или использование storage-level snapshot).

---

Когда применять

✔️ 300k–1M+ артефактов
✔️ активные CI/CD (частые push/pull)
✔️ деградация UI/API и GC-паузы

Когда не спасёт

✖️ медленный диск (HDD/NFS с высокой latency)
✖️ неверные политики хранения (бесконечные snapshot’ы)

Альтернатива: S3-совместимый blob store (если доступен) для лучшей масштабируемости, но в OSS чаще используют file-based — там критичен именно IO и регулярная гигиена.
Post #52 20
Golden images для OpenStack: Packer + cloud-init без “снежинок” ⚙️

Проблема
Долгая и нестабильная инициализация ВМ: конфиги через user-data разрастаются, время старта плавает, воспроизводимость падает. Ручные “снежинки” усложняют отладку и масштабирование.

Решение
Собираем golden image через Packer (builder: openstack) и оставляем динамику на cloud-init. База (пакеты, агенты, hardening) — в образе; переменные окружения/секреты — в user-data при запуске.

Архитектура:
Packer → временная ВМ → provisioning → snapshot (Glance) → Nova boot + cloud-init.

---

Практика

Минимальный Packer (≥1.9):

# packer.pkr.hcl
packer {
required_plugins {
openstack = {
source = "github.com/hashicorp/openstack"
version = ">= 1.1.0"
}
}
}

variable "image_name" { default = "debian-13-golden-v1" }

source "openstack" "debian" {
auth_url = var.auth_url
username = var.username
password = var.password
tenant_name = var.project
region = var.region

image_name = var.image_name
source_image_name = "Debian 13"
flavor = "m1.small"
ssh_username = "debian"
networks = ["private"]
}

build {
sources = ["source.openstack.debian"]

provisioner "shell" {
inline = [
"set -euxo pipefail",
"apt-get update",
"apt-get install -y qemu-guest-agent cloud-init ca-certificates",
# базовый hardening/утилиты
"apt-get install -y curl vim htop",
# чистка для клонирования
"cloud-init clean --logs",
"rm -f /etc/ssh/ssh_host_*",
"truncate -s 0 /etc/machine-id",
"apt-get clean",
"rm -rf /var/lib/apt/lists/*"
]
}
}


Сборка:

packer init .
packer build \
-var "auth_url=https://keystone:5000/v3" \
-var "username=svc_packer" \
-var "password=***" \
-var "project=infra" \
-var "region=RegionOne" .


User-data для запуска (минимум динамики):

#cloud-config
package_update: false
users:
- name: app
groups: [sudo]
ssh_authorized_keys:
- ssh-ed25519 AAAA...
runcmd:
- systemctl enable --now qemu-guest-agent


---

Как это работает 🧠
Packer поднимает временную ВМ из базового образа, выполняет provisioning и публикует снапшот в Glance. При nova boot cloud-init читает метаданные (ConfigDrive/Metadata Service) и применяет user-data. Мы делим ответственность: иммутабельная база в образе и минимальная конфигурация при старте.

---

Нюансы / подводные камни

* Очистка идентификаторов: удаляйте ssh_host_keys, обнуляйте machine-id, делайте cloud-init clean — иначе клоны будут с одинаковыми ID/ключами.
* qemu-guest-agent: критичен для корректных операций (IP, shutdown) в OpenStack.
* Сеть/metadata: проверьте доступ к Metadata Service или включите ConfigDrive — без этого cloud-init не отработает.
* Версионирование: инкрементируйте image_name (или используйте свойства Glance) для откатов.
* Секреты: не bake’те в образ; используйте user-data/внешние секрет-менеджеры.
* Размер образа: чистка кэшей и логов влияет на скорость копирования и boot.

---

Когда применять

✔️ массовые запуски ВМ, autoscaling
✔️ требования к воспроизводимости и быстрым boot time
✔️ унификация базового стека (агенты, патчи, hardening)

Когда не стоит

✖️ уникальная конфигурация на каждую ВМ (лучше чистый cloud-init)
✖️ частые изменения “на лету” без пересборки (рассмотрите конфиг-менеджмент)

Альтернатива: полностью “тонкие” образы + тяжёлый cloud-init, но на high-load платите временем старта и вариативностью состояния.
Post #51 16
Тюнинг sysctl для high-load ingress (10k+ RPS)

Проблема
На ingress-узлах при 10k+ RPS типичные симптомы — рост SYN backlog, TIME_WAIT-шторм, дропы в netstat -s, скачки latency. Дефолтные значения ядра ограничивают очереди, портовый диапазон и поведение TCP, что приводит к ретрансмитам и нестабильным p99.

Решение
Поднять лимиты очередей и файловых дескрипторов, расширить ephemeral ports, ускорить обработку TIME_WAIT, включить корректный congestion control. Тюнинг ниже ориентирован на Linux ≥5.10 (cgroup v2, современный TCP стек).

---

Практика

# /etc/sysctl.d/99-ingress-tuning.conf

# Очереди соединений
net.core.somaxconn = 65535 # верхняя граница listen backlog
net.ipv4.tcp_max_syn_backlog = 262144

# Сетевые буферы
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864

# Эфемерные порты (важно для egress от ingress к upstream)
net.ipv4.ip_local_port_range = 10240 65535

# TIME_WAIT и повторное использование
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1 # безопасно для клиентов (не для NAT-роутеров)

# SYN cookies (защита при переполнении backlog)
net.ipv4.tcp_syncookies = 1

# Congestion control (если доступен)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# Общее
net.core.netdev_max_backlog = 65536


Применение:

sysctl --system


Проверка:

ss -s
netstat -s | egrep -i 'listen|overflow|drop|retrans'


---

Как это работает 🧠

* somaxconn и tcp_max_syn_backlog увеличивают очереди accept/SYN, снижая дропы при пиках.
* Буферы (rmem/wmem) уменьшают вероятность троттлинга TCP при burst-трафике.
* Расширенный ip_local_port_range предотвращает исчерпание портов при большом числе исходящих коннектов (ingress → upstream).
* tcp_tw_reuse и сниженный fin_timeout уменьшают давление от TIME_WAIT.
* fq + bbr стабилизируют latency и уменьшают retransmits на перегруженных каналах.
* netdev_max_backlog увеличивает очередь пакетов на уровне сетевого стека до обработки в softirq.

---

Нюансы

* tcp_tw_reuse не применять на NAT/балансировщиках — риск коллизий.
* BBR требует поддержки ядра и может конфликтовать с сетевыми политиками провайдера.
* Слишком большие буферы = риск bufferbloat → следите за latency (p95/p99).
* Не забывайте про ulimit -n и лимиты в ingress-контроллере (nginx/envoy) — ядро не спасёт при малых FD.
* В Kubernetes тюнинг узлов делается через DaemonSet/машинные образы; проверьте, что параметры не перетираются.

---

Когда применять

✔️ ingress-nginx / envoy при 10k–100k RPS
✔️ API-gateway с большим числом коротких соединений
✔️ кластеры с интенсивным north-south трафиком

Когда не поможет

✖️ узкое место — CPU/SSL termination (нужен offload/scale)
✖️ проблемы в приложении или upstream (долгие ответы, блокировки)

Альтернатива: горизонтальное масштабирование ingress + keep-alive/HTTP2, но без базового sysctl-тюнинга пиковая устойчивость всё равно ограничена.
Post #50 14
OOMKilled в Kubernetes: контроль памяти через cgroup v2 и requests/limits

Проблема
OOMKilled — частая причина флапающих подов и нестабильных rollout’ов. В k8s (≥1.25) с cgroup v2 поведение меняется: ядро умеет мягко ограничивать память (memory.high) до убийства (memory.max). Без настройки контейнеры упираются в hard limit и попадают под OOM killer.

Решение
Задать осмысленные requests/limits и включить использование memory.high через kubelet (--memory-qos=true). Идея: сначала “душим” контейнер троттлингом, давая шанс GC/сбросу кешей, и только затем допускаем OOM.

Связка:

* requests.memory → базовый гарант (QoS)
* limits.memory → memory.max (жёсткий предел)
* memory.high ≈ функция от request/limit (kubelet выставляет автоматически при MemoryQoS)

---

Практика

1. Включаем MemoryQoS (kubelet, k8s ≥1.27):

bash id="t3r7za"
# /var/lib/kubelet/config.yaml
memoryQoS: true


Перезапуск kubelet:

bash id="z0n7j9"
systemctl restart kubelet


2. Задаём ресурсы пода:

apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
template:
spec:
containers:
- name: app
image: ghcr.io/org/api:1.4.2
resources:
requests:
memory: "512Mi" # гарант для планирования и QoS
cpu: "200m"
limits:
memory: "1Gi" # верхняя граница (memory.max)
cpu: "1"


3. (Опционально) Управляем поведением OOM killer:

      - name: app
securityContext:
capabilities:
add: ["SYS_RESOURCE"] # если требуется тюнинг OOM (редко)


---

Как это работает 🧠
В cgroup v2 есть два ключевых порога:

* memory.high — при превышении ядро начинает throttling (pressure stall), замедляя аллокации;
* memory.max — жёсткий лимит, после которого возможен OOM kill.

С включённым memoryQoS kubelet выставляет memory.high ниже memory.max (на основе requests/limits). Это даёт приложению “буфер” на деградацию вместо мгновенного убийства. Для JVM/Go это часто означает, что GC успевает освободить память.

---

Нюансы / подводные камни

* Не ставьте limit ≈ request: без “окна” для memory.high троттлинг не успевает помочь → быстрый OOM.
* Burst-профиль: если приложение кратковременно пикает, увеличьте разницу между request и limit.
* Node pressure: при общем дефиците памяти kubelet всё равно может эвиктить поды (смотрите evictionHard/Soft).
* JVM: синхронизируйте -Xmx с limits.memory (обычно 70–80%), иначе JVM сама упрётся в cgroup.
* Метрики: ориентируйтесь на container_memory_working_set_bytes и PSI (memory.pressure), а не только RSS.
* Swap: с cgroup v2 возможен memory.swap.max, но в k8s обычно swap отключён — не рассчитывайте на него.

---

Когда применять

✔️ сервисы с GC (JVM, Go), чувствительные к кратковременным пикам
✔️ кластеры с высокой плотностью подов
✔️ ситуации, где важнее деградация, чем рестарт

Когда не поможет

✖️ memory leak (нужен фикс/рестарт-политика)
✖️ жёсткие realtime-нагрузки (троттлинг хуже, чем быстрый kill)

Альтернатива: вертикальный автоскейлинг (VPA) для подбора requests, но без MemoryQoS он не решает проблему мгновенных OOM.
Post #45 12
Ускорение image pull в Kubernetes через registry mirror + containerd ⚙️

Проблема
В кластерах с активным CI/CD и autoscaling основная задержка — image pull. Cold start, rate limits Docker Hub, сетевые RTT до внешних registry → медленные rollout’ы и “залипающий” HPA.

Решение
Ставим локальный registry mirror (proxy cache) и настраиваем containerd (≥1.7) через hosts.toml.
Узлы тянут образы из LAN-кеша, а он — из upstream (с кешированием слоёв по digest).

Схема: kubelet → containerd → mirror → upstream

---

Практика

Поднимаем простой mirror (proxy к Docker Hub):

docker run -d --name registry-mirror \
-p 5000:5000 \
-e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \
-e REGISTRY_STORAGE_DELETE_ENABLED=true \
--restart=always \
registry:2


Конфиг для containerd:

mkdir -p /etc/containerd/certs.d/docker.io


# /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://registry-1.docker.io"

[host."http://registry-mirror.local:5000"]
capabilities = ["pull", "resolve"]
skip_verify = true # допустимо только для HTTP/self-signed


Перезапуск:

systemctl restart containerd


---

Как это работает 🧠
containerd сначала обращается к mirror.
Если слой есть — он отдается локально (LAN → минимум latency).
Если нет — mirror скачивает с upstream, сохраняет по digest и в следующий раз отвечает из кеша.

Ключевой эффект — дедупликация слоёв между образами + отсутствие rate limits.

---

Нюансы

* skip_verify=true → риск MITM. В проде используйте TLS + внутренний CA
* Без garbage collection registry быстро забьёт диск
* Private registry (GHCR/ECR) → отдельная аутентификация
* Mirror должен быть в той же зоне/сети, иначе выигрыш съест latency
* Кеш работает по digest, а не по тегу (tag → resolve → digest)

---

Когда применять

✔️ частые деплои / CI
✔️ autoscaling / HPA
✔️ ограничения Docker Hub
✔️ edge / частично изолированные сети

Когда не нужно

✖️ образы уже прогреты (pre-pull через DaemonSet)
✖️ registry и так локальный и быстрый
  • 🔥 1
  • 👀 1
Post #1
Channel created

About this channel

How can I read @opennet without a Telegram account?
TGViewer shows the public web preview Telegram publishes for SRE | DevOps: recent posts, photos, videos and the subscriber count, with no app, login or account.
How many subscribers does SRE | DevOps have?
SRE | DevOps (@opennet) has 330 subscribers on Telegram, refreshed roughly every 30 minutes.
Does SRE | DevOps know I viewed it here?
No. Public channel previews carry no viewer identity, and TGViewer has no accounts or tracking of what you look up.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →