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

Чат канала: https://t.me/AppliedTryndology
Download Telegram
С Новым Годом!

С Новым Годом, дорогие подписчики!

Стабильно работающего и красивого кода, меньше овертаймов на работе и неуемного интереса к изучению нового! Ура 🎄🎄🎄
🔥10🎄54👍1🍾1
FluxCD. Правильный порядок применения манифестов в кластере

На стриме рассказывал как обеспечить правильный порядок применения манифестов в кластере. Пришло время написать об этом пост.

В каталоге cluster у нас есть файлы, пронумерованные в том порядке, в котором мы хотим применять их в кластере. Но на деле сейчас ничего не применяется по порядку, все применяется одновременно. Чтобы обеспечить нужный нам порядок, в сущности Kustomization мы можем указать директиву dependsOn. Давайте реализуем это в нашем dev кластере:

1. Разделим установку и конфигурацию metallb на два этапа - metallb-install и metallb-config, при этом укажем, что config должен выполняться после install:
  dependsOn:
- name: metallb-install

2. Укажем, что ingress-nginx должен выполняться после того, как будет выполнен metallb-config
3. Укажем, что app должен выполняться после того, как будет установлен ingress-nginx

Готово! Пушим в репозиторий, проверяем статус с помощью flux get all -A. Убеждаемся, что все применяется в нужном порядке
👍6
Приходите на пыхап! Я там тоже буду
Forwarded from Пых (Валентин Удальцов)
Пыхап 8 февраля!

Друзья, через 2.5 недели пройдёт второй Пыхап! В программе у нас 3 доклада и новая секция:

🤔 Шардирование в RabbitMQ
Антон Растрыгин расскажет, как разбирать очередь параллельно, но последовательно.

🤝 Гибкий проект с фича-флагами Unleash
Рустэм Ахметзянов объяснит, почему «друзья не позволяют друзьям делать самописную систему фича-флагов».

🤹 Реализация нейронной сети на PHP
Алексей Нечаев покажет, как создать нейронку, не написав ни строчки кода на Python!

🎤 Открытый микрофон (только офлайн)
В конце митапа любой участник сможет на 5-10 минут завладеть флипчартом и поделиться насущной проблемой, элегантным решением или историей про то, как уронил прод накануне в пятницу.

Пыхап пройдёт там же — в уютном лофте «Событие» на Таганке. В этот раз решили попробовать субботу, поэтому собираемся пораньше, в 16:30. Регистрация откроется на канале Пых в следующий понедельник в 15:00, не пропустите. Входной билет — 500₽. Ну и конечно же митап будет транслироваться на YouTube и VK Видео с записью.

Спонсор второго Пыхапа — PremiumBonus. PremiumBonus — эволюция управления клиентским опытом. Весь спектр цифровых маркетинговых инструментов для выстраивания эффективной коммуникации с клиентами. Уникальные продукты на основе самых актуальных современных трендов, таких как предиктивная аналитика и автоматизация маркетинговых акций с помощью ИИ.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍4🔥2
Работа с docker на удаленной машине через ssh

Пост про cert-manager в кубе немного застрял, поэтому сегодня будет пост про докер :)
Возможно не все знают, но можно управлять удаленным docker демоном через ssh. На днях попробовал этот способ. Это удобно во всяких CI системах для деплоя на сервер.

Как сделать:

1. Добавляем контекст remote

docker context create remote --docker host=ssh://${SSH_USER}@${SSH_HOST}:${SSH_PORT}

2. Запускаем docker compose up на удаленной машине, находясь при этом у себя в локальном окружении билда в CI

docker --context remote compose -f docker-compose.prod.yaml up -d

При этом compose файлик хранится у вас на gitlab-runner локально, его не нужно никуда копировать
Также вы можете передать нужные ENVы и все прекрасно сработает. Мне кажется это очень удобно

Enjoy!
👍9🔥2
Получение SSL сертификата для нашего приложения в k8s с помощью cert-manager

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

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

1. Устанавливаем в кластер компонент cert-manager:

В инфраструктурном репозитории, в каталоге cluster, переименовываем 04-app.yaml в 06-app.yaml
Добавляем в этот же каталог kustomization для cert-manager, он будет устанавливаться после ingress-nginx
В components создаем каталог cert-manager и добавляем туда namespace.yaml и hr-cert-manager.yaml

2. Теперь нам нужно создать такую сущность как ClusterIssuer, чтобы выпускать сертификаты с помощью Lets Encrypt

Добавим в каталог cluster kustomization
В components создадим каталог letsencrypt и добавим туда issuer.yaml
ВАЖНО! Для тестов и во избежание временной блокировки со стороны lets encrypt в параметре server: сначала лучше указать https://acme-staging-v02.api.letsencrypt.org/directory
Когда сертификат будет успешно получен - можно заменить обратно на значение, которое приведено в issuer.yaml

3. В файле 06-app.yaml меняем зависимость c ingress-nginx на letsencrypt

4. Создаем файл cert.yaml в components/app-example. Это наш сертификат, который будет получен от Lets Encrypt. Он будет сохранен в k8s secret под названием app-example-tls

5. Пушим всё в репозиторий, отслеживаем статус через flux get all -A. Когда все пройдет успешно - проверим, что сертификат создан:
kubectl get secret -n app-example

Вы должны увидеть следующую строку:
NAME            TYPE              DATA   AGE
app-example-tls kubernetes.io/tls 2 5m6s


6. Осталось только поправить ingress.yaml и values.yaml в helm чарте нашего приложения. Смотрите коммит

Пушим в репозиторий приложения, дожидаемся деплоя и проверяем.
Теперь приложение должно открываться по адресу https://app-example.example.com и иметь действительный сертификат!

В след. посте начнем подключать БД к нашему приложению и устанавливать в кластер PostgreSQL (На тестовых средах это нормально. В проде не рекомендую дежрать БД в кластере)
👍4🤔1
Добавляем в кластер поддержку хранения данных с помощью local-path-provisioner

Для нашего тестового приложения в dev кластере нам потребовалась БД.

Так как кластер тестовый - мы можем разместить СУБД прямо в кластере, а не где-то на серверах снаружи.

Чтобы СУБД было где хранить данные - мы сегодня займемся добавлением персистентного хранилища в наш кластер.

В кубе за хранение данных отвечают такие сущности как Storage Class, Persistent Volume и Persistent Volume Claim.

Также есть различный софт, который интегрирует разные системы хранения с вышеуказанными сущностями куба.

Мы воспользуемся одним из самых простых - local-path-provisioner. Данный софт просто создает папку на локальном диске, подключенном к ноде кластера и пишет данные туда. Не поддерживает ограничение размера запрошенного Persistent Volume, не умеет переевозить PV с ноды на ноду, но в тестовом кластере нам это не нужно.

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

1. В каталоге cluster снова переименуем 06-app.yaml в 07-app.yaml и поменяем там зависимость с letsencrypt на local-path-provisioner
2. Добавим файл 06-local-path-provisioner.yaml в каталог cluster
3. Внесем необходимые изменения в файл kustomization.yaml
4. В components создадим папку local-path-provisioner и добавим туда namespace.yaml
5. Создадим Helm Release для local-path-provisioner.

Тут есть одна хитрость. Helm chart лежит не где-то в репозитории чартов, а прямо в репозитории с исходным кодом.
Но это не проблема. FluxCD позволяет установить чарт в кластер и в этом случае. В документации описано как можно провернуть данную затею.

Создаем GitRepository и указываем, что Flux должен игнорировать все, кроме указанной папки в git репозитории.

В Helm Release ссылаемся на наш git репозиторий и указываем путь, где искать чарт.

6. Пушим все в репозиторий, дожидаемся синхронизации и проверяем, что все прошло успешно:

Выполняем kubectl get storageclass

Должен появиться storage class с именем local-path

Вот и всё! В следующем посте установим PostgreSQL в кластер и подключим базу к нашему приложению

Stay tuned!
👍7
Deptrac внезапно сменил репозиторий

Сегодня утром обнаружил, что инструмент deptrac внезапно и без каких-либо объявлений сменил репозиторий с https://github.com/qossmic/deptrac на https://github.com/deptrac/deptrac/

Насколько я понял репозиторий мигрировал целиком и скорее всего все хорошо. Но будьте бдительны, возможно это вредоносная активность.
На packagist пакет пока находится по старому имени, но устанавливается из нового репа.

Как разберусь с ситуацией подробнее - напишу
👍7
Deptrac в порядке

Я создал issue для того, чтобы разобраться в ситуации.
Еще один представитель организации qossmic (не связанный с тем, что осуществил перенос репозитория) ответил, что у компании ребрендинг и они решили выделить deptrac в отдельную организацию.

Полагаю, что злонамеренных действий тут нет. У Qossmic действительно сейчас ребрендинг и их старый сайт ведет на сайт, который указан в комментарии к моему issue.

Ждем пока появится на packagist как deptrac/deptrac и можно обновляться
👍6
Чат канала

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

У нас есть чат канала - 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