Девопсолог | DevOps, GitOps и прочий Ops
272 subscribers
60 photos
5 videos
2 files
91 links
Пишу про docker, k8s, gitops и прочие инфраструктурные штуки

Чат канала: https://t.me/AppliedTryndology
Download Telegram
Чат канала

Раз уж я сегодня разразился постами - у меня есть еще один)

У нас есть чат канала - https://t.me/AppliedTryndology

Изначально он создавался для комментариев, но нас уже достаточно много - добавляйтесь. Будем общаться в более свободной форме
🔥4👍1
Flux CD - wait: true

Я тут весь в делах и переделке домашней инфраструктуры, поэтому пост про Postgres в кластере немного буксует.
Но я решил сегодня с вами поделиться еще одним маленьким лайфхаком.

Тут я писал как правильно определить порядок применения манифестов в кластере. Но я обнаружил, что некоторые манифесты начинают применяться до того, как предыдущий шаг выполнен. Чтобы заставить Flux вести себя как подобает, мы добавим еще одну опцию:

wait: true

Это заставляет Flux начинать применять следующий манифест только тогда, когда все ресурсы предыдущего шага прошли healthcheck проверки.

Смотрите коммит.

Stay tuned!
👍5
Устанавливаем Postgres в кластер

Storage в кластере мы настроили. Пришла пора установить Postgres.
Делать мы это будем с помощью проекта cloudnative-pg. Давайте приступим:

1. В каталоге cluster переименовываем 07-app.yaml в 10-app.yaml
2. Добавляем 07-app-example-namespace.yaml. В каталоге components создаем app-example-namespace, туда переносим файл namespace.yaml из app-example. Это нужно для того, чтобы установить наш экземпляр postgres в namespace приложения. Поэтому мы отдельным шагом сначала создаем namespace
3. Добавляем в каталог cluster файл 08-postgres-operator.yaml. Создаем в components каталог postgres-operator. Там будет два традиционных файла для установки оператора через helm - namespace.yaml и hr-cnpg-operator.yaml. Операторы в кубе - это специальный софт, который добавляет в кластер свои кастомные ресурсы, с помощью которых можно конфигурировать и создавать то, чем оператор управляет. В нашем случае - это postgres. Подробнее про операторы можно почитать тут и тут
4. Добавляем в каталог cluster 09-postgres.yaml. Создаем в components каталог postgres. Там будет лежать единственный файл с настройками нашего инстанса СУБД - postgres.yaml. Здесь мы указываем, что хотим 1 инстанс, указываем какой storageClass нужно использовать для хранения данных - local-path. Его мы добавляли в этом посте. И указываем объем места, который будет использоваться для нашей БД.
5. Вносим изменения в kustomization.yaml
6. Пушим все в наш инфраструктурный репозиторий и отслеживаем статус через flux get all -A

Проверяем, что БД успешно создалась, вводим kubectl get po -n app-example. Должен появиться под с именем app-example-db-1. Это инстанс нашей СУБД.
Данные для подключения автоматически сгенерировались и хранятся в секрете с именем app-example-db-app.

Мы молодцы! База у нас теперь есть. В следующем посте будем подключать ее к приложению.

Stay tuned!
👍5🤝1
Подключаем БД в приложение

Постгрес у нас есть. Теперь давайте его состыкуем с нашим приложением.

1. Добавляем базу в приложение и делаем api эндпоинт, перейдя по которому мы увидим текст, полученный из БД. Я приведу здесь весь коммит, но его можно не изучать целиком. Важные моменты с инфраструктурной точки зрения:

- Добавляются ENV переменные, необходимые для подключения к БД

- В Dockerfile в секцию CMD добавляем запуск миграций, перед тем как запустить RoadRunner. Для dev среды такой подход оправдан, так как у нас одна реплика приложения. Этот момент исправим, когда будем делать prod кластер

2. Осталось передать реальные ENV переменные, которые будут прокинуты в контейнер при запуске приложения в кластере:

Поправим helm chart приложения. Нам нужен файл deployment.yaml. В раздел containers добавляем секцию env

env:
- name: APP_ENV
value: prod
- name: DB_NAME
valueFrom:
secretKeyRef:
name: app-example-db-app
key: dbname
- name: DB_USER
valueFrom:
secretKeyRef:
name: app-example-db-app
key: user
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-example-db-app
key: password
- name: DB_HOST
valueFrom:
secretKeyRef:
name: app-example-db-app
key: host


Переменная APP_ENV передается напрямую, а вот данные для подключения к базе берутся из k8s секрета app-example-db-app. Таким образом наше приложение подключается к готовой базе и мы даже не знаем с какими доступами, так как секрет сгенерировался автоматически при создании экземпляра БД.

Пушим в репо, приложение собирается и деплоится в кластер. Переходим по адресу https://app-example.example.com/api/v1/get-string-from-db и получаем json из картинки к посту.

В dev кластере нам осталось добавить сбор логов и минимальный мониторинг.

Не переключайтесь :)
👍52
Heredoc в Dockerfile. Важное дополнение

В июле прошлого года я написал пост о возможности избавиться от && в Dockerfile и писать красиво с помощью Heredoc синтаксиса.
С тех пор везде продвигал этот метод.
На Пыхапе, во время выступления на открытом микрофоне, меня спросили:

А разве в этом случае сборка будет останавливаться при возникновении ошибки?

С уверенностью сказал, что да, будет. С этим нет никаких проблем.

Однако вчера, во время отладки одной сборки, я обнаружил, что это не всегда так.

Допустим у нас есть такой блок

RUN <<EOF
apt-get update
apt-get install --no-install-recommends -y \
openssh-client \
rsync \
non-existent-package
apt-get clean
EOF


Сборка в этом случае не прервется, хотя non-existent-package в репозитории не найден и на этом блоке мы должны упасть.

Чтобы это поправить, достаточно в такой многострочный RUN добавлять set -e. Это заставит скрипт немедленно прерваться при возникновении ошибки.

Правильный вариант:

RUN <<EOF
set -e
apt-get update
apt-get install --no-install-recommends -y \
openssh-client \
rsync \
non-existent-package
apt-get clean
EOF


Раньше я этого не замечал, потому что копипастил из своих докерфайлов, где уже был set -xe.

Будьте внимательны, всем отличных выходных и стабильных сборок!
👍125
Сегодня будет крутой эфир про Talos Linux. Это дистрибутив, специально заточенный под k8s. Я буду о нем рассказывать, когда перейдем к prod кластеру. Ну а пока присоединяйтесь вечером к просмотру! https://www.youtube.com/watch?v=liso5CNn4G4
🔥6
k9s

Что-то у меня не хватило на этой неделе сил на полноценный пост, поэтому сегодня делюсь с вами прикольной утилитой - k9s.
На стриме в прошлом году Павел Бучнев из фартанов мне ее посоветовал и у меня наконец дошли руки попробовать.

Штука очень прикольная. Это как Midnight Commander, но для кубов. Можно провалиться в каждый под, посмотреть логи, потребляемые ресурсы (Для этого в кластере должен быть установлен metrics server), describe пода и другое. Присутствует удобное переключение между namespace. На сайте проекта можно посмотреть демки и подробнее ознакомиться с инструментом.

Enjoy!
🔥73
Добавляем Grafana Loki в кластер

Сегодня будем добавлять в кластер подсистему логирования. Я уже несколько лет использую стэк Loki + Promtail + Grafana. Рассмотрим первый кусочек этого стэка - Loki

Приступим:

1. Добавляем в наш инфраструктурный репозиторий файл 11-loki.yaml

В нем, как и в 10-app-example.yaml, мы указываем, что sops должен расшифровывать наши секреты

2. Прописываем loki в kustomization.yaml

3. Создаем каталог loki в components

4. Первым файлом в нем будет традиционный namespace.yaml

5. Вторым файлом будет секрет, в котором будут храниться данные для подключения к S3 хранилищу. Именно в S3 мы будем хранить логи.

В Dev среде я использую minio в качестве S3 Object Storage.
В minio создаем учетные данные для подключения loki и три бакета - loki-dev-admin, loki-dev-chunks и loki-dev-ruler.
Создаем файл секрета следующего содержания:
apiVersion: v1
kind: Secret
metadata:
name: loki-envs
namespace: loki
stringData:
S3_LOKI_ENDPOINT: "s3.example.com"
S3_LOKI_DSN: "https://ваш-access-key:ваш-secret-key@s3.example.com."
S3_LOKI_REGION: "local"
S3_LOKI_SECRET_ACCESS_KEY: "ваш-secret-key"
S3_LOKI_ACCESS_KEY_ID: "ваш-access-key"
S3_LOKI_INSECURE: "false"


Шифруем его с помощью sops: sops --encrypt --encrypted-regex '^(data|stringData)$' --pgp 'B1B740FC8FCA25D9BE0C118CED0FB16FAF7A8471' --in-place s3-secret.yaml

6. Ну и наконец третий файл - hr-loki.yaml

Мы будем деплоить loki в режиме SingleBinary, когда все компоненты собраны в одном бинарном файле.
Для dev среды этого более чем достаточно, так как отказоустойчивость и разделение на чтение/запись нам тут не нужны.
Подробнее о режимах loki можно почитать в официальной документации.

Из важного в конфиге:

- В данной секции мы говорим loki, чтобы он брал настройки из env переменных, содержащихся в ранее созданном секрете:

      extraArgs:
- -config.expand-env=true
extraEnvFrom:
- secretRef:
name: loki-envs


- Обязательно задаем requests and limits для каждого контейнера. Умолчания в helm чарте loki не позволяют нам запуститься с имеющимися у нас ресурсами и они скорее подходят для prod конфигуарции. В dev режиме loki потребляет значительно меньше, поэтому я снизил запросы и лимиты до разумных пределов.

- Далее идет конфиг самого loki. Здесь указываем из каких переменных мы должны брать настройки для подключения к S3 и тюним некоторые параметры. При тюнинге я руководствовался этой статьей. Она уже устарела, но некоторые вещи из нее все еще можно почерпнуть

- Срок хранения логов устанавливаем в 7 дней

Пушим всё в репозиторий, дожидаемся применения. Если все прошло успешно, увидим следующие запущенные поды:

loki-0
loki-canary-vmtvs
loki-chunks-cache-0
loki-gateway-f5b6b9dd8-xzlds
loki-results-cache-0


Первый кирпичик в нашей системе логирования готов! В след. посте будем настраивать отправку логов кластера в loki, не переключайтесь!
👍8
Полезное от Сергея Предводителева. Я не знал некоторых вещей
🌿 Про доменную зону для локальной разработки

Часто для локальной разработки используют различные доменные зоны. Кто-то придумывает их сам (я раньше использовал .ll и .lll 🤦‍♂️), где-то применяются исторически сложившиеся варианты. Но иногда это может привести к проблемам.

Например, часто используют .local, что не есть хорошо. .local — специальная доменная зона, которая зарезервирована для Multicast DNS (технология для автоматического обнаружения устройств в локальной сети). Доменные имена в зоне .local обрабатываются особым образом: вместо обычного DNS-запроса, отправляется групповой запрос, который получат другие устройства в локальной сети.

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

Какую же зону использовать? На самом деле всё уже давно придумано и описано. RFC 2606 резервирует 4 доменные зоны, которые никогда не будут использованы в глобальном пространстве имён:

- .test
- .example
- .invalid
- .localhost

… и рекомендует использовать доменную зону .test в целях тестирования. А RFC 6761 уточняет, что прикладное ПО (те же браузеры) должно обрабатывать зону .test также, как обычную доменную зону.

Таким образом, для локальной разработки нужно использовать .test. Это позволит избежать конфликтов имён и гарантирует корректную работу доменного имени в системе.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥5🤔2
Promtail - отправляем логи в loki

Loki у нас в кластере теперь есть, пришла пора туда что-нибудь отправить. Для этого мы будем использовать инструмент promtail. В нашем стэке он отвечает за сбор логов со всех подов кластера и отправку их в loki

Приступим:

С этого поста и дальше я не буду описывать в каких директориях создаются файлы, вы уже наверняка сами знаете где :) А если забыли - можно посмотреть в предыдущих постах или в репозитории на гитхабе

1. Создаем файл 12-promtail.yaml, установка promtail будет идти после установки loki
2. Прописываем его в kustomization.yaml
3. И создаем hr-promtail.yaml. Там указываем запросы и лимиты для подов promtail и указываем ему, что логи нужно писать в формате json

namespace мы тут не создаем, так как поды promtail будут запускаться в неймспейсе loki

Пушим в репозиторий, убеждаемся, что поды корректно создались. Мы должны увидеть два пода, по одному на каждую ноду в кластере. Этот режим запуска в k8s называется daemonset

Вот так просто мы добавили отправку логов! В след. посте установим графану и наконец-то сможем посмотреть на логи, которые прилетают к нам от подов

Stay tuned!
👍6🔥1
Немного запоздало, но сегодня продолжение прошлого стрима по Talos Linux. Практическая часть. Можно посмотреть как все работает в лайв-демо. Сам смотрю не сначала. Буду в записи смотреть после окончания стрима

https://www.youtube.com/watch?v=tw7rg5MazcQ
👍2
Заменяем promtail на fluentbit

Под постом про отправку логов @gam6itko подметил, что promtail объявлен как deprecated и завершит свою жизнь в 26 году

Сама графана предлагает как замену использовать ее продукт alloy. Я пощупал и мне не понравилось

Во-первых это комбайн, он занимается не только отправкой логов, во-вторых кушает больше ресурсов

Поэтому мы будем менять promtail на fluentbit. Он легковесный и прекрасно справляется со своей задачей

Присупим:

1. Переименовываем 12-promtail.yaml в 12-fluentbit.yaml. Там меняем название kustomization и путь до компонента

2. Не забываем переименовать также и в kustomization.yaml

3. Переименовываем директорию promtail в fluentbit в components

4. Добавляем туда hr-fluentbit.yaml. Здесь есть несколько важных моментов:

- Мы должны указать кубу, чтобы поды fluentbit могли запускаться на master ноде кластера. Делается это указанием следующих tolerations:

tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule



- Указываем fluentbit'у, что он должен писать логи в loki. Настраиваем labels, чтобы было удобнее потом смотреть логи по конкретным namespace, pod и так далее:

[OUTPUT]
Name loki
Match *
Host loki.loki.svc
Port 3100
Retry_Limit False
Labels namespace=$kubernetes['namespace_name'], node=$kubernetes['host'], pod=$kubernetes['pod_name'], container=$kubernetes['container_name']
Auto_kubernetes_labels On


5. Пушим всё в инфраструктурный репозиторий. Проверяем, что создалось 2 пода - на мастере и на воркер ноде

Готово! Всегда пользуйтесь актуальными и поддерживаемыми продуктами ;)
👍4🔥2
Добавляем grafana в кластер

Мы добавили loki для хранения логов, fluentbit для отправки логов в loki. Теперь пришел черед добавить графану, чтобы логи можно было смотреть

Давайте приступать:

1. Добавляем файл 13-grafana.yaml. Указываем, что устанавливать будем после fluentbit и добавляем раздел decryption, так как нам потребуются секреты

2. Прописываем графану в kustomization.yaml

3. В компонентах создаем namespace.yaml

4. Добавляем cert.yaml. Он нам понадобится для защищенного доступа к графане через ingress

5. Создаем admin-password-secret.yaml. Здесь прописываем две ENV переменные для графаны, которые содержат имя пользователя и пароль администратора для доступа через веб-интерфейс

Шифруем через sops:

sops --encrypt --encrypted-regex '^(data|stringData)$' --pgp 'B1B740FC8FCA25D9BE0C118CED0FB16FAF7A8471' --in-place admin-password-secret.yaml

6. Добавляем ingress.yaml, чтобы получить доступ к графане извне. Не забываем прописать tls секцию и имя секрета с сертификатом

7. Ну и наконец hr-grafana.yaml. Здесь обратите внимание на раздел envValueFrom, где задаются env переменные, содержащие логин и пароль к графане. Мы указываем, что брать их нужно из нашего секрета, созданного на 5 шаге. Также в разделе datasource мы сразу указываем loki и не даем его изменять из веб-интерфейса

8. Пушим всё в репозиторий. Дожидаемся применения в кластере. Если все прошло по плану - по адресу grafana.example.com (само собой нужно заменить на свой домен) вы увидите веб-интерфейс графаны. Логинимся с указанным нами логином и паролем. Заходим в раздел Explore, в разделе Label filters выбираем namespace, по подам которого мы хотим посмотреть логи и нажимаем Run Query. Получаем картину со скрина к посту

Мы молодцы! В след. постах начнем подключать мониторинг кластера

Stay tuned!
👍6
Добавляем Prom++ в кластер

Праздники закончились. Пора снова писать посты :) Графана есть. Логи собираются. Теперь нужно настроить маломальский мониторинг

Раньше для этого использовался Prometheus, сейчас модно использовать Victoria Metrics, так как эта система потребляет меньше ресурсов. Но не так давно ребята из компании Флант зарелизили свой prometheus совместимый инструмент, еще более экономичный. В прод его тащить рановато, но ничто нам не мешает попробовать запустить prompp в dev кластере

Начнем:

Первым делом нам нужно поставить kube-prometheus-stack. Данный helm чарт включает в себя много всего, но мы будем пока что использовать следующий набор компонентов:

kube-state-metrics - отвечает за сбор разных метрик кластера
prometheus-operator - управляет созданием инстансов прометеуса. Им мы будем создавать инстанс prompp
prometheus-node-exporter - экспортер метрик хостовой системы на нодах нашего кластера

1. Добавляем 14-kube-prometheus-stack.yaml

2. Прописываем его в kustomization.yaml

3. Добавляем namespace.yaml. В этом namespace у нас будут жить все компоненты мониторинга

4. Добавляем kube-prometheus-stack.yaml

Здесь отключаем установку графаны, алертменеджера (алертами займемся позже) и самого prometheus, так как мы будем ставить prompp через оператор

Теперь мы можем установить сам prompp:

5. Добавляем 15-prompp.yaml. Он будет устанавливаться после kube-prometheus-stack

6. Прописываем в kustomization.yaml

7. Добавляем prompp.yaml. Указываем storage class и объем места под хранение метрик

Пушим всё в репо, дожидаемся выполнения через flux. По итогу в namespace monitoring должны появиться поды всех компонентов. Node exporter запустится в кол-ве двух штук, по одному на ноду кластера

Вот и всё! В следующем посте будем подключать это добро к графане и добавлять необходимые дашборды
👍43
Channel name was changed to «Девопсолог | DevOps, GitOps и прочий Ops»
Ребрендинг :)

Как вы уже заметили - у меня небольшой ребрендинг. Привел название канала в соответствии с контентом и наконец-то сделал логотип.

P.S. Следующий пост немного задержался в пути, но в выходные должен доехать!
🔥7👍3🥰31💋1
Добавляем datasource prompp и дашборды в графану

В прошлом посте мы добавили систему мониторинга в наш кластер. Сегодня будем подключать ее к графане и импортировать дашборды, с помощью которых можно отслеживать состояние серверов и k8s. Другие компоненты в dev кластере мониторить не будем, иначе пост получится слишком объемным. Более подробно мониторинг всех компонентов рассмотрим при создании production кластера

Немного о том как принято организовывать мониторинг в кластерах k8s:

Создатели софта, который нативно работает в кубе обычно предоставляют в своих helm чартах специальную prometheus сущность. Это может быть ServiceMonitor или PodMonitor. В них описано куда и как стучаться, чтобы получить метрики. Prometheus автоматически подхватывает такие описания и начинает сохранять к себе метрики данного софта. Так же у сервиса или пода можно еще указать специальные аннотации, чтобы prometheus понял, что нужно получать с них метрики - prometheus.io/scrape: "true" и prometheus.io/port: "10254"

Давайте приступим к настройке:

1. В прошлом посте мы забыли выдать для prompp необходимые права для получения метрик. Давайте исправляться. Добавляем rbac.yaml и прописываем service account, который в нем создается в prompp.yaml. Также указываем прометею получать данные из всех service monitor и pod monitor. Сами мониторы уже были созданы при установке kube-prometheus-stack в прошлом посте. Их список можно получить командой kubectl get servicemonitor -n monitoring

2. Тюним kube-state-metrics, чтобы можно было получать данные по daemonset в дашборде по кубу

3. Добавляем в графану datasource prompp

4. Определяем дашборд провайдер для тех дашбордов, которые мы будем добавлять из кода

5. Ну и наконец добавляем сами дашборды. Здесь используется два пути. Популярный дашборд по мониторингу железа на нодах мы добавляем по ID с официальной страницы дашборда на сайте графаны.
Дашборд для k8s добавляем по URL с гитхаба от Артура Крюкова, советую заглянуть к нему на канал, там тоже много полезного по кубу. В production кластере мы еще будем получать дашборды из ConfigMap, но в dev кластере не вижу смысла заморачиваться

Пушим всё в репо. Дожидаемся применения. Если все прошло хорошо, то вы увидите картину как на картинке к посту. И оба дашборда будут работать

На сегодня всё! В следующем посте придумаем кастомные метрики в нашем приложении, опубликуем их через RoadRunner, напишем ServiceMonitor и сделаем простенький дашборд для графаны. Выйдет он через пару недель, так как в следующие выходные у меня перелет

Stay tuned!
👍6🔥3
Принимаем заявки на доклады!

19 сентября в Москве в Конгресс-центре ЦМТ пройдёт новая PHP-конференция для всех.

👥 400 участников • 🔢 4 зала • 🎙 28 докладов

Скоро откроется сайт конференции, где можно будет приобрести билет по стартовой цене.

А пока — подай доклад! Спикер участвует бесплатно, готовится вместе с программным комитетом и получает ценный опыт публичных выступлений.

Ориентировочный список тем:
• async и неблокирующий I/O;
• статический анализ: Psalm, PHPStan, Rector;
• производительность и highload;
• архитектура: ES, DDD, CQRS, микросервисы;
• тестирование и бенчмаркинг;
• инфраструктура: очереди, стримы, базы данных;
• DevOps: CI/CD, Docker, Kubernetes;
• AI/ML;
• фреймворки: Yii, Symfony, Laravel;
• CMS: WordPress, Drupal, Bitrix;
• IDE и плагины;
• open source: опыт, ошибки, лучшие практики.

Заявку, а лучше несколько, можно подать через Хобота до 1 июля. Мы свяжемся с тобой в течение недели и дадим обратную связь.

До встречи на Пых.конф’25!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1