Переменные окружения (ENV, .env)
Это динамические пары ключ=значение, доступные процессу во время выполнения. В Linux они хранятся в памяти процесса как null-terminated строки (например, PATH=/usr/bin).
Как это работает в Docker:
- При старте контейнера Docker Daemon добавляет переменные в process namespace через execve-системный вызов.
- Значения копируются в память процесса (PID 1 контейнера) при его создании.
Пример:
- Внутри контейнера переменная доступна через:
Нюансы безопасности:
- Переменные видны в docker inspect и через /proc/<pid>/environ,
- Никогда не передавайте секреты через environment — используйте Docker Secrets или Vault.
Продвинутые сценарии
Секреты: от Docker Secrets до Vault
Что такое секреты в контексте Docker?
Это конфиденциальные данные (пароли, токены), требующие защищенного хранения и передачи. В отличие от переменных окружения, секреты шифруются и изолируются от неавторизованного доступа.
Docker Secrets (Swarm mode)
Как это работает:
- Секреты монтируются как файлы в /run/secrets/ через tmpfs (RAM-диск).
- При монтировании устанавливаются права 000 — доступ только через docker exec.
- Шифрование: секреты передаются по TLS между менеджерами Swarm и хранятся в Raft-логе шифрованными.
Пример:
- Raft-лог: Алгоритм консенсуса для распределенных систем. В Swarm используется для синхронизации состояния секретов.
Недостатки:
- Не подходит для Compose (требует Swarm),
- Нет ротации — при обновлении секрета нужно пересоздавать сервис.
Конфигурация логирования: драйверы и их особенности
Что такое драйвер логирования?
Это модуль, определяющий, как Docker перехватывает и обрабатывает stdout/stderr контейнера. По умолчанию используется json-file, но можно подключить сторонние системы (Fluentd, Syslog).
Как это работает:
- Docker Daemon перехватывает потоки stdout/stderr через pipe (канал межпроцессного взаимодействия).
- Данные передаются в драйвер, который форматирует и отправляет их в указанное место.
Пример для gelf:
- GELF (Graylog Extended Log Format) — бинарный формат для структурированных логов.
Поддерживает поля:
Нюансы:
- UDP не гарантирует доставку — возможна потеря логов при перегрузке,
- Для надежности используйте tcp вместо udp, но снизится производительность.
#Java #middle #Docker #env
Это динамические пары ключ=значение, доступные процессу во время выполнения. В Linux они хранятся в памяти процесса как null-terminated строки (например, PATH=/usr/bin).
Как это работает в Docker:
- При старте контейнера Docker Daemon добавляет переменные в process namespace через execve-системный вызов.
- Значения копируются в память процесса (PID 1 контейнера) при его создании.
Пример:
environment:
DB_URL: jdbc:postgresql://db:5432/mydb
- Внутри контейнера переменная доступна через:
cat /proc/1/environ | tr '\0' '\n' # PID 1 — процесс Java
Нюансы безопасности:
- Переменные видны в docker inspect и через /proc/<pid>/environ,
- Никогда не передавайте секреты через environment — используйте Docker Secrets или Vault.
Продвинутые сценарии
Секреты: от Docker Secrets до Vault
Что такое секреты в контексте Docker?
Это конфиденциальные данные (пароли, токены), требующие защищенного хранения и передачи. В отличие от переменных окружения, секреты шифруются и изолируются от неавторизованного доступа.
Docker Secrets (Swarm mode)
Как это работает:
- Секреты монтируются как файлы в /run/secrets/ через tmpfs (RAM-диск).
- При монтировании устанавливаются права 000 — доступ только через docker exec.
- Шифрование: секреты передаются по TLS между менеджерами Swarm и хранятся в Raft-логе шифрованными.
Пример:
echo "my_password" | docker secret create db_password -
- Raft-лог: Алгоритм консенсуса для распределенных систем. В Swarm используется для синхронизации состояния секретов.
Недостатки:
- Не подходит для Compose (требует Swarm),
- Нет ротации — при обновлении секрета нужно пересоздавать сервис.
Конфигурация логирования: драйверы и их особенности
Что такое драйвер логирования?
Это модуль, определяющий, как Docker перехватывает и обрабатывает stdout/stderr контейнера. По умолчанию используется json-file, но можно подключить сторонние системы (Fluentd, Syslog).
Как это работает:
- Docker Daemon перехватывает потоки stdout/stderr через pipe (канал межпроцессного взаимодействия).
- Данные передаются в драйвер, который форматирует и отправляет их в указанное место.
Пример для gelf:
logging:
driver: gelf
options:
gelf-address: "udp://graylog:12201"
- GELF (Graylog Extended Log Format) — бинарный формат для структурированных логов.
Поддерживает поля:
{"version": "1.1", "host": "app", "short_message": "Error", "level": 3}
Нюансы:
- UDP не гарантирует доставку — возможна потеря логов при перегрузке,
- Для надежности используйте tcp вместо udp, но снизится производительность.
#Java #middle #Docker #env
👍4🔥1
Тонкая настройка JVM через переменные окружения
Control Groups (cgroups) — механизм ядра Linux для ограничения, учета и изоляции использования ресурсов (CPU, память, дисковый I/O) группой процессов. Docker использует cgroups для ограничения ресурсов контейнера.
Как это влияет на JVM?
- Если в контейнере установлен лимит памяти (--memory=512m), JVM не видит его по умолчанию и пытается выделить память, превышающую лимит.
Решение:
Как это работает:
- JVM читает лимиты из /sys/fs/cgroup/memory/memory.limit_in_bytes (путь внутри cgroup контейнера).
- При старте выделяет heap через mmap с учетом лимита.
Критические ошибки:
- Если -Xmx превышает лимит cgroups, JVM упадет с Native memory allocation (mmap) failed.
- Для контейнеров никогда не используйте `-Xmx` без учета cgroups.
Пример: Java-сервис с ENV и логами в volume
docker-compose.yml
Концептуальное объяснение:
1. Сеть app_net:
- Создает bridge-сеть через docker network create.
- Контейнеры app и db получают IP в подсети 172.18.0.0/16 и могут общаться по именам (db:5432).
2. Том pg_data:
- Хранится в /var/lib/docker/volumes/pg_data/_data.
- При старте PostgreSQL инициализирует данные в этом каталоге.
3. Логирование:
- Драйвер json-file пишет логи в /var/lib/docker/containers/<id>/<id>-json.log.
- При достижении 50m файл ротируется, сохраняя 3 архива.
Код Java-приложения:
Почему это работает:
- Переменные DB_URL и DB_PASSWORD передаются через process namespace, что безопаснее hardcode.
- Том app_logs изолирует логи от жизненного цикла контейнера — данные сохраняются после docker-compose down.
- JVM учитывает лимиты cgroups благодаря -XX:MaxRAMPercentage.
Best practices
1. Сети:
- Bridge — для локальной разработки,
- Overlay/CNI — для продакшена,
- Host — только для специфических задач.
2. Volumes:
- Named volumes — для БД и персистентных данных,
- Bind mounts — только для разработки (hot-reload).
3. Секреты:
- Всегда используйте Vault или Kubernetes Secrets в продакшене,
- Избегайте .env для секретов — он не шифруется.
4. Логирование:
- Настройте централизованное логирование (Fluentd + Elasticsearch),
- Используйте gelf или fluentd вместо json-file в продакшене.
5. JVM:
- Всегда ограничивайте память через -XX:MaxRAMPercentage,
- Проверяйте лимиты cgroups через cat /sys/fs/cgroup/memory/memory.limit_in_bytes.
#Java #middle #Docker #best
Control Groups (cgroups) — механизм ядра Linux для ограничения, учета и изоляции использования ресурсов (CPU, память, дисковый I/O) группой процессов. Docker использует cgroups для ограничения ресурсов контейнера.
Как это влияет на JVM?
- Если в контейнере установлен лимит памяти (--memory=512m), JVM не видит его по умолчанию и пытается выделить память, превышающую лимит.
Решение:
environment:
JAVA_TOOL_OPTIONS: "-XX:MaxRAMPercentage=75.0"
- -XX:MaxRAMPercentage указывает JVM использовать 75% от лимита cgroups, а не от общей памяти хоста.
Как это работает:
- JVM читает лимиты из /sys/fs/cgroup/memory/memory.limit_in_bytes (путь внутри cgroup контейнера).
- При старте выделяет heap через mmap с учетом лимита.
Критические ошибки:
- Если -Xmx превышает лимит cgroups, JVM упадет с Native memory allocation (mmap) failed.
- Для контейнеров никогда не используйте `-Xmx` без учета cgroups.
Пример: Java-сервис с ENV и логами в volume
docker-compose.yml
version: '3.8'
services:
app:
build: ./app
environment:
DB_URL: jdbc:postgresql://db:5432/mydb
DB_PASSWORD: ${DB_PASSWORD}
volumes:
- app_logs:/app/logs
logging:
driver: json-file
options:
max-size: "50m"
networks:
- app_net
db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pg_data:/var/lib/postgresql/data
networks:
- app_net
volumes:
app_logs:
driver: local
pg_data:
networks:
app_net:
driver: bridge
Концептуальное объяснение:
1. Сеть app_net:
- Создает bridge-сеть через docker network create.
- Контейнеры app и db получают IP в подсети 172.18.0.0/16 и могут общаться по именам (db:5432).
2. Том pg_data:
- Хранится в /var/lib/docker/volumes/pg_data/_data.
- При старте PostgreSQL инициализирует данные в этом каталоге.
3. Логирование:
- Драйвер json-file пишет логи в /var/lib/docker/containers/<id>/<id>-json.log.
- При достижении 50m файл ротируется, сохраняя 3 архива.
Код Java-приложения:
public class Main {
public static void main(String[] args) {
String dbUrl = System.getenv("DB_URL"); // Чтение из process namespace
try (Connection conn = DriverManager.getConnection(
dbUrl, "user", System.getenv("DB_PASSWORD"))) {
// Запись в файловый лог
try (FileWriter fw = new FileWriter("/app/logs/application.log", true)) {
fw.write("DB connection established\n");
}
}
}
}
Почему это работает:
- Переменные DB_URL и DB_PASSWORD передаются через process namespace, что безопаснее hardcode.
- Том app_logs изолирует логи от жизненного цикла контейнера — данные сохраняются после docker-compose down.
- JVM учитывает лимиты cgroups благодаря -XX:MaxRAMPercentage.
Best practices
1. Сети:
- Bridge — для локальной разработки,
- Overlay/CNI — для продакшена,
- Host — только для специфических задач.
2. Volumes:
- Named volumes — для БД и персистентных данных,
- Bind mounts — только для разработки (hot-reload).
3. Секреты:
- Всегда используйте Vault или Kubernetes Secrets в продакшене,
- Избегайте .env для секретов — он не шифруется.
4. Логирование:
- Настройте централизованное логирование (Fluentd + Elasticsearch),
- Используйте gelf или fluentd вместо json-file в продакшене.
5. JVM:
- Всегда ограничивайте память через -XX:MaxRAMPercentage,
- Проверяйте лимиты cgroups через cat /sys/fs/cgroup/memory/memory.limit_in_bytes.
#Java #middle #Docker #best
👍3🔥1
Сколько времени вы работаете (если работаете) за компом в день?
Anonymous Poll
23%
Более 10. Я работаю и развлекаюсь за компьютером. 🧑💻
42%
6 - 10 часов. Стараюсь уделить время и внекомпьютерным активностям. Хотя не очень получается☺️
26%
4-6 часов. Стараюсь сделать минимум работы и не сидеть больше чем нужно! 🆘
10%
Менее 4х. Навайкодил и свалил - вот мой принцип!😄 Сидеть больше - геморрой заработаешь😂
👍1
Что выведет код?
#Tasks
abstract class Animal050925 {
public Animal050925() {
System.out.print("Animal ");
makeSound();
}
abstract void makeSound();
}
class Dog050925 extends Animal050925 {
public Dog050925() {
System.out.print("Dog ");
}
void makeSound() {
System.out.print("Woof ");
}
}
public class Task050925 {
public static void main(String[] args) {
new Dog050925();
}
}
#Tasks
🤯2
Варианты ответа:
Anonymous Quiz
23%
Ошибка компиляции
8%
Animal Woof
31%
Animal Dog Woof
38%
Animal Woof Dog
🔥1🗿1
Please open Telegram to view this post
VIEW IN TELEGRAM
Сетка
Java for Beginner. Канал в Сетке
Канал для новичков в Java
👍1
Вопрос с собеседований
Что такое local inner class?🤓
Ответ:
Local inner class — класс, определенный внутри метода, с доступом к локальным переменным (если final или effectively final).
Пример:
void method() {
final int x = 10;
class Local {
void print() { System.out.println(x); }
}
new Local().print();
}
Полезен для временной логики в методе.
#собеседование
Что такое local inner class?
Ответ:
Local inner class
Пример:
void method() {
final int x = 10;
class Local {
void print() { System.out.println(x); }
}
new Local().print();
}
Полезен для временной логики в методе.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Влади́мир Алекса́ндрович Коте́льников (24 августа [6 сентября] 1908, Казань, Российская империя — 11 февраля 2005 года, Москва, Россия) — пионер теории информации и связи; теорема Котельникова (сэмплирование) — краеугольный камень цифровой обработки сигналов.
Лев Никола́евич Королёв (6 сентября 1926, Подольск — 5 января 2016, Москва) — советский и российский учёный в области радиофизики, радиотехники, электроники, информатики, радиоастрономии и криптографии, системный программист, развитие ПО и ОС для БЭСМ-6, становление программирования в СССР.
1989 — из-за компьютерной ошибки 41 тыс. парижан получили письма, извещающие о том, что ими совершены убийства и грабежи вместо нарушений правил дорожного движения.
#Biography #Birth_Date #Events #06Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
С 30.08 по 05.09
Предыдущий пост(с 23.08 по 29.08)
Воскресный мотивационный пост:
Трекер времени: кандалы или инструмент свободы?
Выбранная голосованием тема:
Введение в NoSQL базы данных
Запись встреч/видео:
не было.
Обучающие статьи:
Полиморфизм. Поведение через суперкласс и интерфейс
Полиморфизм. instanceof и приведение типов
Абстракция. Абстрактные классы и методы
Основы: ключевые инструкции в Dockerfile
Сети, Volume, ENV и логи в Docker архитектурные компоненты Docker
Полезные статьи и видео:
Создаём CRUD REST API в Spring Boot быстро и просто вместе с Amplicode
Ускорение Spring REST API на 200%
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
#memory
Предыдущий пост(с 23.08 по 29.08)
Воскресный мотивационный пост:
Трекер времени: кандалы или инструмент свободы?
Выбранная голосованием тема:
Введение в NoSQL базы данных
Запись встреч/видео:
не было.
Обучающие статьи:
Полиморфизм. Поведение через суперкласс и интерфейс
Полиморфизм. instanceof и приведение типов
Абстракция. Абстрактные классы и методы
Основы: ключевые инструкции в Dockerfile
Сети, Volume, ENV и логи в Docker архитектурные компоненты Docker
Полезные статьи и видео:
Создаём CRUD REST API в Spring Boot быстро и просто вместе с Amplicode
Ускорение Spring REST API на 200%
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
#memory
👍2
Kubernetes
Зачем миру нужен Kubernetes?
Представьте, что вы строите небоскреб. У вас есть тысячи кирпичей (контейнеров), краны (серверы), рабочие (процессы). Без грамотного архитектора и прораба всё превратится в хаос: кирпичи будут лежать криво, краны простаивать, а рабочие — спорить, кто за что отвечает.
Kubernetes (сокр. K8s) — это и есть тот самый «цифровой прораб», который автоматизирует развертывание, масштабирование и управление контейнеризированными приложениями. Но это не просто инструмент — это стандарт де-факто для оркестрации контейнеров в мире cloud-native разработки.
Почему это важно?
Когда приложения разбиваются на микросервисы (десятки или сотни независимых компонентов), ручное управление ими становится невозможным. Kubernetes решает эту проблему, превращая инфраструктуру в «самонастраивающуюся» систему, которая:
- Автоматически восстанавливает упавшие сервисы
- Масштабирует нагрузку «на лету»
- Обеспечивает непрерывную доставку кода без простоя
История: от внутренних систем Google к мировому стандарту
2014: Рождение в недрах Google
Kubernetes не появился на пустом месте. Его корни уходят в Borg — секретную систему оркестрации, которую Google использовал с 2003 года для управления своими сервисами (Поиск, Gmail, YouTube). Borg обрабатывал миллионы контейнеров ежедневно, но был закрыт для внешнего мира.
В 2014 году Google, совместно с Red Hat и Other, открыли исходный код Kubernetes (название происходит от греческого слова «κυβερνήτης» — «капитан, рулевой»). Это был не «облегченный Borg», а переработанная система с учетом опыта Google, но адаптированная для открытого использования.
2015: Передача в CNCF
Google передал Kubernetes Cloud Native Computing Foundation (CNCF) — некоммерческой организации, поддерживающей cloud-native технологии. Это был стратегический ход: чтобы система стала стандартом, она должна быть нейтральной и развиваться сообществом. Сегодня Kubernetes — самый успешный проект CNCF, с участием AWS, Microsoft, IBM и тысяч разработчиков.
Почему именно Kubernetes победил?
На момент появления существовали конкуренты (Docker Swarm, Mesos), но K8s выделялся:
- Глубокая проработка edge cases (опыт Google с миллиардами запросов)
- Декларативная модель (описывайте «что нужно», а не «как сделать»)
- Экосистема расширений (API можно расширять без изменения ядра)
Архитектура: как устроен «цифровой прораб»
Kubernetes работает по принципу control plane + data plane. Это как центр управления полетами (control plane) и самолеты (data plane).
Control Plane: «мозг» кластера
Располагается на master-нодах (хотя термин «master» устарел — теперь используется control plane node).
Состоит из:
1. API Server
Что это: Единственная точка входа для всех операций (развертывание, мониторинг).
Как работает: Принимает REST-запросы, проверяет права (через RBAC), записывает изменения в etcd.
Нюанс: Все компоненты взаимодействуют через API Server, даже сам Kubernetes. Это обеспечивает единую точку контроля и аудита.
2. etcd
Что это: Распределенное хранилище «состояния кластера» (какая нода работает, какие поды запущены).
Как работает: Хранит данные в виде ключ-значение. При изменении состояния (например, запуске нового пода) etcd рассылает события.
Нюанс: Требует нечетного числа нод (3, 5, 7) для кворума. Потеря большинства нод — катастрофа (split-brain).
3. Scheduler
Что это: «Распределитель задач». Решает, на какой ноде запустить новый под.
Как работает: Анализирует ресурсы нод (CPU, память), правила (taints/tolerations, affinity), выбирает оптимальный вариант.
Нюанс: Можно написать кастомный scheduler через API, если стандартный не подходит (например, для HPC-задач).
#Java #middle #on_request #Kubernetes
Зачем миру нужен Kubernetes?
Представьте, что вы строите небоскреб. У вас есть тысячи кирпичей (контейнеров), краны (серверы), рабочие (процессы). Без грамотного архитектора и прораба всё превратится в хаос: кирпичи будут лежать криво, краны простаивать, а рабочие — спорить, кто за что отвечает.
Kubernetes (сокр. K8s) — это и есть тот самый «цифровой прораб», который автоматизирует развертывание, масштабирование и управление контейнеризированными приложениями. Но это не просто инструмент — это стандарт де-факто для оркестрации контейнеров в мире cloud-native разработки.
Почему это важно?
Когда приложения разбиваются на микросервисы (десятки или сотни независимых компонентов), ручное управление ими становится невозможным. Kubernetes решает эту проблему, превращая инфраструктуру в «самонастраивающуюся» систему, которая:
- Автоматически восстанавливает упавшие сервисы
- Масштабирует нагрузку «на лету»
- Обеспечивает непрерывную доставку кода без простоя
История: от внутренних систем Google к мировому стандарту
2014: Рождение в недрах Google
Kubernetes не появился на пустом месте. Его корни уходят в Borg — секретную систему оркестрации, которую Google использовал с 2003 года для управления своими сервисами (Поиск, Gmail, YouTube). Borg обрабатывал миллионы контейнеров ежедневно, но был закрыт для внешнего мира.
В 2014 году Google, совместно с Red Hat и Other, открыли исходный код Kubernetes (название происходит от греческого слова «κυβερνήτης» — «капитан, рулевой»). Это был не «облегченный Borg», а переработанная система с учетом опыта Google, но адаптированная для открытого использования.
2015: Передача в CNCF
Google передал Kubernetes Cloud Native Computing Foundation (CNCF) — некоммерческой организации, поддерживающей cloud-native технологии. Это был стратегический ход: чтобы система стала стандартом, она должна быть нейтральной и развиваться сообществом. Сегодня Kubernetes — самый успешный проект CNCF, с участием AWS, Microsoft, IBM и тысяч разработчиков.
Почему именно Kubernetes победил?
На момент появления существовали конкуренты (Docker Swarm, Mesos), но K8s выделялся:
- Глубокая проработка edge cases (опыт Google с миллиардами запросов)
- Декларативная модель (описывайте «что нужно», а не «как сделать»)
- Экосистема расширений (API можно расширять без изменения ядра)
Архитектура: как устроен «цифровой прораб»
Kubernetes работает по принципу control plane + data plane. Это как центр управления полетами (control plane) и самолеты (data plane).
Control Plane: «мозг» кластера
Располагается на master-нодах (хотя термин «master» устарел — теперь используется control plane node).
Состоит из:
1. API Server
Что это: Единственная точка входа для всех операций (развертывание, мониторинг).
Как работает: Принимает REST-запросы, проверяет права (через RBAC), записывает изменения в etcd.
Нюанс: Все компоненты взаимодействуют через API Server, даже сам Kubernetes. Это обеспечивает единую точку контроля и аудита.
2. etcd
Что это: Распределенное хранилище «состояния кластера» (какая нода работает, какие поды запущены).
Как работает: Хранит данные в виде ключ-значение. При изменении состояния (например, запуске нового пода) etcd рассылает события.
Нюанс: Требует нечетного числа нод (3, 5, 7) для кворума. Потеря большинства нод — катастрофа (split-brain).
3. Scheduler
Что это: «Распределитель задач». Решает, на какой ноде запустить новый под.
Как работает: Анализирует ресурсы нод (CPU, память), правила (taints/tolerations, affinity), выбирает оптимальный вариант.
Нюанс: Можно написать кастомный scheduler через API, если стандартный не подходит (например, для HPC-задач).
#Java #middle #on_request #Kubernetes
👍5
Архитектура Kubernetes
Kubernetes работает по принципу control plane + data plane. Это как центр управления полетами (control plane) и самолеты (data plane).
Control Plane: "мозг" кластера
Располагается на master-нодах (хотя термин «master» устарел — теперь используется control plane node).
Состоит из:
1. API Server
Что это: Единственная точка входа для всех операций (развертывание, мониторинг).
Как работает: Принимает REST-запросы, проверяет права (через RBAC), записывает изменения в etcd.
Нюанс: Все компоненты взаимодействуют через API Server, даже сам Kubernetes. Это обеспечивает единую точку контроля и аудита.
2. etcd
Что это: Распределенное хранилище «состояния кластера» (какая нода работает, какие поды запущены).
Как работает: Хранит данные в виде ключ-значение. При изменении состояния (например, запуске нового пода) etcd рассылает события.
Нюанс: Требует нечетного числа нод (3, 5, 7) для кворума. Потеря большинства нод — катастрофа (split-brain).
3. Scheduler
Что это: «Распределитель задач». Решает, на какой ноде запустить новый под.
Как работает: Анализирует ресурсы нод (CPU, память), правила (taints/tolerations, affinity), выбирает оптимальный вариант.
Нюанс: Можно написать кастомный scheduler через API, если стандартный не подходит (например, для HPC-задач).
4. Controller Manager
Что это: Набор «контроллеров», следящих за состоянием кластера.
Как работает: Например, Deployment Controller следит, чтобы количество запущенных подов соответствовало желаемому. Если под падает — пересоздает его.
Нюанс: Контроллеры работают по принципу reconciliation loop: постоянно сравнивают текущее состояние с желаемым.
5. Cloud Controller Manager (опционально)
Что это: Интеграция с облачными провайдерами (AWS, GCP).
Как работает: Управляет балансировщиками нагрузки, томами, сетями через API облака.
Data Plane: "рабочие руки"
Состоит из worker nodes (рабочих нод), где запускаются приложения:
1. Kubelet
Что это: Агент на каждой ноде.
Как работает: Получает задания от API Server, запускает/останавливает контейнеры через container runtime (Docker, containerd).
Нюанс: Kubelet не перезапускает контейнеры сам — это делают контроллеры (например, через Deployment).
2. Kube-proxy
Что это: Сетевой прокси.
Как работает: Обеспечивает доступ к сервисам через iptables/IPVS. Например, при обращении к my-service перенаправляет трафик на поды.
Нюанс: В режиме IPVS используется хэширование для балансировки, что эффективнее iptables при 10k+ сервисов.
3. Container Runtime
Что это: Движок для запуска контейнеров (Docker, containerd, CRI-O).
Нюанс: Kubernetes использует CRI (Container Runtime Interface) — абстрактный API, поэтому можно менять runtime без пересборки K8s.
#Java #middle #on_request #Kubernetes
Kubernetes работает по принципу control plane + data plane. Это как центр управления полетами (control plane) и самолеты (data plane).
Control Plane: "мозг" кластера
Располагается на master-нодах (хотя термин «master» устарел — теперь используется control plane node).
Состоит из:
1. API Server
Что это: Единственная точка входа для всех операций (развертывание, мониторинг).
Как работает: Принимает REST-запросы, проверяет права (через RBAC), записывает изменения в etcd.
Нюанс: Все компоненты взаимодействуют через API Server, даже сам Kubernetes. Это обеспечивает единую точку контроля и аудита.
2. etcd
Что это: Распределенное хранилище «состояния кластера» (какая нода работает, какие поды запущены).
Как работает: Хранит данные в виде ключ-значение. При изменении состояния (например, запуске нового пода) etcd рассылает события.
Нюанс: Требует нечетного числа нод (3, 5, 7) для кворума. Потеря большинства нод — катастрофа (split-brain).
3. Scheduler
Что это: «Распределитель задач». Решает, на какой ноде запустить новый под.
Как работает: Анализирует ресурсы нод (CPU, память), правила (taints/tolerations, affinity), выбирает оптимальный вариант.
Нюанс: Можно написать кастомный scheduler через API, если стандартный не подходит (например, для HPC-задач).
4. Controller Manager
Что это: Набор «контроллеров», следящих за состоянием кластера.
Как работает: Например, Deployment Controller следит, чтобы количество запущенных подов соответствовало желаемому. Если под падает — пересоздает его.
Нюанс: Контроллеры работают по принципу reconciliation loop: постоянно сравнивают текущее состояние с желаемым.
5. Cloud Controller Manager (опционально)
Что это: Интеграция с облачными провайдерами (AWS, GCP).
Как работает: Управляет балансировщиками нагрузки, томами, сетями через API облака.
Data Plane: "рабочие руки"
Состоит из worker nodes (рабочих нод), где запускаются приложения:
1. Kubelet
Что это: Агент на каждой ноде.
Как работает: Получает задания от API Server, запускает/останавливает контейнеры через container runtime (Docker, containerd).
Нюанс: Kubelet не перезапускает контейнеры сам — это делают контроллеры (например, через Deployment).
2. Kube-proxy
Что это: Сетевой прокси.
Как работает: Обеспечивает доступ к сервисам через iptables/IPVS. Например, при обращении к my-service перенаправляет трафик на поды.
Нюанс: В режиме IPVS используется хэширование для балансировки, что эффективнее iptables при 10k+ сервисов.
3. Container Runtime
Что это: Движок для запуска контейнеров (Docker, containerd, CRI-O).
Нюанс: Kubernetes использует CRI (Container Runtime Interface) — абстрактный API, поэтому можно менять runtime без пересборки K8s.
#Java #middle #on_request #Kubernetes
👍5
Основные понятия Kubernetes
Cluster (кластер)
Что это: Группа нод (физических/виртуальных машин), управляющих приложениями.
Зачем: Объединяет ресурсы в единый «суперкомпьютер».
Нюанс: В production используют multi-zone кластеры для отказоустойчивости (ноды в разных зонах AZ).
Node (нода)
Что это: Отдельный сервер в кластере (worker или control plane).
Нюанс: Ноды могут иметь taints («отметки»), чтобы блокировать запуск подов (например, dedicated=gpu:NoSchedule).
Pod
Что это: Минимальная единица развертывания. Группа контейнеров, разделяющих сеть и томы.
Почему не один контейнер?
- Сторонние контейнеры (sidecar) для логирования, мониторинга
- Общая файловая система (например, веб-сервер + статика)
Нюанс: Pod не переживает перезагрузку ноды — его пересоздает контроллер.
Service
Что это: Абстракция для доступа к подам через стабильный IP/DNS.
Типы:
- ClusterIP (внутри кластера)
- NodePort (порт на каждой ноде)
- LoadBalancer (облачный балансировщик)
Нюанс: Service использует kube-proxy и EndpointSlice для балансировки. При 1000+ подах лучше включить EndpointSlice (уменьшает нагрузку на etcd).
Deployment
Что это: Управляет состоянием подов через ReplicaSet.
Как работает:
- Описывает желаемое состояние (например, 3 реплики)
- Обеспечивает rolling update (постепенное обновление без простоя)
- Поддерживает откат к предыдущей версии
Нюанс: Можно настроить readinessProbe (проверка готовности) и livenessProbe (проверка жизни) для корректного обновления.
ConfigMap и Secret
Что это: Хранение конфигурации и секретов.
Разница: Secret шифруется base64 (но не защищен по умолчанию — используйте etcd encryption или external secrets manager).
Нюанс: Избегайте монтирования ConfigMap как volume — при обновлении значения попадут в под с задержкой (до 1 минуты).
Как это работает: от команды до работающего приложения
1. Вы описываете желаемое состояние
Например, в YAML-манифесте Deployment указываете: replicas: 3, image: my-app:v2.
2. API Server сохраняет состояние в etcd
Все компоненты получают уведомление через watch API.
3. Scheduler назначает поды на ноды
Выбирает ноды с достаточными ресурсами, учитывая правила (например, nodeSelector: disk=ssd).
4. Kubelet запускает контейнеры
Через container runtime создает Pod с вашим приложением и sidecar-контейнерами (если есть).
5. Service направляет трафик
При обращении к my-service kube-proxy балансирует запросы между подами.
6. Контроллеры поддерживают стабильность
Если нода упала — Deployment Controller создаст новые поды на других нодах.
Ключевые особенности: почему это enterprise-ready
Декларативная модель
Вы говорите «каким должно быть приложение», а не «как его развернуть».
Например:
Kubernetes сам решает, как достичь этого состояния (запустить новые поды, убить старые).
Self-healing
- Автоматический перезапуск упавших контейнеров
- Перемещение подов с нерабочих нод
- Проверка здоровья через liveness/readiness probes
Горизонтальное масштабирование
- HPA (Horizontal Pod Autoscaler): Масштабирует поды по CPU/memory или кастомным метрикам (например, RPS)
- Cluster Autoscaler: Добавляет/удаляет ноды в облаке при нехватке ресурсов
Организация конфигурации
- Namespaces: Изоляция сред (dev, prod)
- Resource Quotas: Ограничение ресурсов на namespace
- Network Policies: Контроль трафика между подами (как firewall)
Экосистема: Kubernetes как платформа
Kubernetes — не монолит, а ядро для построения платформы.
Расширения через:
- Operators: Управление stateful-приложениями (PostgreSQL, Kafka) как нативными объектами
- CRD (Custom Resource Definitions): Добавление своих типов объектов (например, CronTab)
- Helm: Управление версиями манифестов («пакетный менеджер для K8s»)
- Istio: Сервис-меш для продвинутой маршрутизации, мониторинга
#Java #middle #on_request #Kubernetes
Cluster (кластер)
Что это: Группа нод (физических/виртуальных машин), управляющих приложениями.
Зачем: Объединяет ресурсы в единый «суперкомпьютер».
Нюанс: В production используют multi-zone кластеры для отказоустойчивости (ноды в разных зонах AZ).
Node (нода)
Что это: Отдельный сервер в кластере (worker или control plane).
Нюанс: Ноды могут иметь taints («отметки»), чтобы блокировать запуск подов (например, dedicated=gpu:NoSchedule).
Pod
Что это: Минимальная единица развертывания. Группа контейнеров, разделяющих сеть и томы.
Почему не один контейнер?
- Сторонние контейнеры (sidecar) для логирования, мониторинга
- Общая файловая система (например, веб-сервер + статика)
Нюанс: Pod не переживает перезагрузку ноды — его пересоздает контроллер.
Service
Что это: Абстракция для доступа к подам через стабильный IP/DNS.
Типы:
- ClusterIP (внутри кластера)
- NodePort (порт на каждой ноде)
- LoadBalancer (облачный балансировщик)
Нюанс: Service использует kube-proxy и EndpointSlice для балансировки. При 1000+ подах лучше включить EndpointSlice (уменьшает нагрузку на etcd).
Deployment
Что это: Управляет состоянием подов через ReplicaSet.
Как работает:
- Описывает желаемое состояние (например, 3 реплики)
- Обеспечивает rolling update (постепенное обновление без простоя)
- Поддерживает откат к предыдущей версии
Нюанс: Можно настроить readinessProbe (проверка готовности) и livenessProbe (проверка жизни) для корректного обновления.
ConfigMap и Secret
Что это: Хранение конфигурации и секретов.
Разница: Secret шифруется base64 (но не защищен по умолчанию — используйте etcd encryption или external secrets manager).
Нюанс: Избегайте монтирования ConfigMap как volume — при обновлении значения попадут в под с задержкой (до 1 минуты).
Как это работает: от команды до работающего приложения
1. Вы описываете желаемое состояние
Например, в YAML-манифесте Deployment указываете: replicas: 3, image: my-app:v2.
2. API Server сохраняет состояние в etcd
Все компоненты получают уведомление через watch API.
3. Scheduler назначает поды на ноды
Выбирает ноды с достаточными ресурсами, учитывая правила (например, nodeSelector: disk=ssd).
4. Kubelet запускает контейнеры
Через container runtime создает Pod с вашим приложением и sidecar-контейнерами (если есть).
5. Service направляет трафик
При обращении к my-service kube-proxy балансирует запросы между подами.
6. Контроллеры поддерживают стабильность
Если нода упала — Deployment Controller создаст новые поды на других нодах.
Ключевые особенности: почему это enterprise-ready
Декларативная модель
Вы говорите «каким должно быть приложение», а не «как его развернуть».
Например:
replicas: 5 # Не "запусти 5 экземпляров", а "должно быть 5 реплик"
Kubernetes сам решает, как достичь этого состояния (запустить новые поды, убить старые).
Self-healing
- Автоматический перезапуск упавших контейнеров
- Перемещение подов с нерабочих нод
- Проверка здоровья через liveness/readiness probes
Горизонтальное масштабирование
- HPA (Horizontal Pod Autoscaler): Масштабирует поды по CPU/memory или кастомным метрикам (например, RPS)
- Cluster Autoscaler: Добавляет/удаляет ноды в облаке при нехватке ресурсов
Организация конфигурации
- Namespaces: Изоляция сред (dev, prod)
- Resource Quotas: Ограничение ресурсов на namespace
- Network Policies: Контроль трафика между подами (как firewall)
Экосистема: Kubernetes как платформа
Kubernetes — не монолит, а ядро для построения платформы.
Расширения через:
- Operators: Управление stateful-приложениями (PostgreSQL, Kafka) как нативными объектами
- CRD (Custom Resource Definitions): Добавление своих типов объектов (например, CronTab)
- Helm: Управление версиями манифестов («пакетный менеджер для K8s»)
- Istio: Сервис-меш для продвинутой маршрутизации, мониторинга
#Java #middle #on_request #Kubernetes
👍6
Алексе́й Я́ковлевич Червоне́нкис (7 сентября 1938 — 22 сентября 2014) — советский и российский учёный в области информатики, кандидат физико-математических наук, ведущий сотрудник Института проблем управления имени Трапезникова, профессор колледжа Royal Holloway Лондонского университета, соавтор теории VC-размерности, фундамент машинного обучения и обобщающей способности моделей.
Дэвид Паккард (англ. David Packard; 7 сентября 1912 — 26 марта 1996) — сооснователь Hewlett-Packard; один из архитекторов компьютерной индустрии Кремниевой долины.
Не происходило вроде. Найдете - пишите в комментариях
#Biography #Birth_Date #Events #07Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Использование LLM в работе - мошенничество или обязательное условие?
Сегодня это тему не обсудил наверное только ленивый.
Наверное пришло и наше время поразмышлять об этом☺️
Много лет назад
Когда-то, когда трава была зеленее и в IT-шники брали за умение запустить IDE (по слухам), было принято в Java-проектах писать всё руками.
Все setter-ы, getter-ы, конструкторы и прочий boilerplate-код.
Но потом появился Lombok и пара аннотаций стало все это решать. И сегодня сложно встретить проект без его использования.
Уже тогда разработчики разделились на 2 лагеря. Естественно за и против.
Сегодня, даже большинство IDE по нажатию горячих клавиш сгенерирует Вам все что нужно. И да, если этим пользоваться без оглядки и понимания - это тоже может привести к проблемам как и Lombok.
И причем тут LLM?
Далее пойдет мнение автора, которое может отличаться от большинства, но ему пофиг 🙃 .
Сейчас сообщество разработчиков практически делится на 2 лагеря:
1. Те, кто считает, что использование LLM - это смерть программиста как такового из-за усыхания мозга и в конце он станет рептилоидом😂 .
2. Те, кто считает, что использование LLM - это то же самое, что Google или StackOverflow, только быстрее и глупее.
В целом, подытоживая свой поток мыслей, считаю:
- что LLM сегодня для меня, это очень востребованный и важный инструмент самообучения, поиска и помощи.
- что игнорировать его просто глупо, ведь программист точно должен смотреть в будущее, а не в прошлое.
Риски использования LLM
1. Как я и сказал выше - шанс галлюцинаций, будьте внимательны и перепроверяйте информацию.
2. Юридические риски: лицензии, утечка кода в LLM → нарушение NDA.
3. Когнитивные риски: если использовать только как "копипасту", можно забыть как учиться.
Как относиться к использованию LLM в работе
На мой скромный взгляд, нужно относиться как к молотку на стройке.
Если нужно забить гвоздь - это незаменимый и важный помощник. И человек забивающий гвозди головой, будет выглядеть как минимум странно.
Другое дело, когда надо, к примеру, разрезать стекло.
Если бездумно использовать молоток, вы совершенно точно просто все испортите. Но при тонком знании и понимании процесса, прямых руках и капельке удачи - все вполне реализуемо.
Так и с LLM.
Но решать в итоге, конечно, Вам✌️
А что вы думаете об этом?
Понравилась статья - поделись с другом, позови его на канал и будет тебе моя благодарность 🤝
😎
#motivation
Сегодня это тему не обсудил наверное только ленивый.
Наверное пришло и наше время поразмышлять об этом
Признаюсь сразу - давно и плотно использую разные LLM. Знаю много видов, периодически нахожу новые.
Но использую только бесплатные (жаль денег, за то, что можно найти бесплатно).
Использую ли в работе - конечно.
Давайте об этом и поговорим.
Много лет назад
Когда-то, когда трава была зеленее и в IT-шники брали за умение запустить IDE (по слухам), было принято в Java-проектах писать всё руками.
Все setter-ы, getter-ы, конструкторы и прочий boilerplate-код.
Но потом появился Lombok и пара аннотаций стало все это решать. И сегодня сложно встретить проект без его использования.
Уже тогда разработчики разделились на 2 лагеря. Естественно за и против.
Сегодня, даже большинство IDE по нажатию горячих клавиш сгенерирует Вам все что нужно. И да, если этим пользоваться без оглядки и понимания - это тоже может привести к проблемам как и Lombok.
И причем тут LLM?
Сейчас сообщество разработчиков практически делится на 2 лагеря:
1. Те, кто считает, что использование LLM - это смерть программиста как такового из-за усыхания мозга и в конце он станет рептилоидом
Тут я наверное не соглашусь. Ведь человечество и так преодолело барьер программных языков, перейдя к высокоабстрактным языкам. И ведь когда это начиналось, наверняка звучали прогнозы, что это разрушит будущее.
Но оно не разрушилось
2. Те, кто считает, что использование LLM - это то же самое, что Google или StackOverflow, только быстрее и глупее.
Отношу себя к этому лагерю.
Когда я начинал учить Java, LLM только проявлял себя и поэтому я учился по туториалам и ответам из StackOverflow. Но сейчас, чтобы получить ответ на распространенный вопрос - достаточно написать LLM и вуаля.
НО! Важно понимать и знать, что как и на StackOverflow, выбирая из ответов самый залайканый или подходящий к ситуации, никто не давал гарантий, что он единственно правильный и обязательно будет работать.
Или, что вставив его в свой код, пропадет нужда достичь понимания как он работает.
Так и LLM легко напишет Вам методы которых не существует. Или даст ответ который вы не понимаете.
И что, не использовать его из-за этого? (Это как удалить телеграм, ведь где-то, кого-то обманули через него😏 )
В целом, подытоживая свой поток мыслей, считаю:
- что LLM сегодня для меня, это очень востребованный и важный инструмент самообучения, поиска и помощи.
- что игнорировать его просто глупо, ведь программист точно должен смотреть в будущее, а не в прошлое.
Риски использования LLM
1. Как я и сказал выше - шанс галлюцинаций, будьте внимательны и перепроверяйте информацию.
2. Юридические риски: лицензии, утечка кода в LLM → нарушение NDA.
3. Когнитивные риски: если использовать только как "копипасту", можно забыть как учиться.
Как относиться к использованию LLM в работе
На мой скромный взгляд, нужно относиться как к молотку на стройке.
Если нужно забить гвоздь - это незаменимый и важный помощник. И человек забивающий гвозди головой, будет выглядеть как минимум странно.
Другое дело, когда надо, к примеру, разрезать стекло.
Если бездумно использовать молоток, вы совершенно точно просто все испортите. Но при тонком знании и понимании процесса, прямых руках и капельке удачи - все вполне реализуемо.
Так и с LLM.
Но решать в итоге, конечно, Вам
А что вы думаете об этом?
#motivation
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Виктор Яковлевич Пан (род. 8 сентября 1939, Москва) — советско-американский математик/информатик; алгоритмы для полиномов и быстрого матричного умножения.
Вайдьешваран Раджараман (родился в 1933 году) — пионер информатики в Индии; запуск первых академических программ по CS в IIT Канпур.
1636 — основан Гарвардский университет, старейший из университетов Нового Света.
#Biography #Birth_Date #Events #08Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Docker Compose и микросервисы
Основы: docker-compose.yaml и его архитектура
Что такое docker-compose.yaml?
Это декларативный конфигурационный файл, управляющий многоконтейнерными приложениями через Docker Compose. В отличие от ручного запуска контейнеров через docker run, Compose абстрагирует сложность оркестрации: один файл определяет сервисы, сети, тома и зависимости. При выполнении docker-compose up Docker Engine создает изолированную среду, где контейнеры взаимодействуют через виртуальные сети, а данные сохраняются в управляемых томах.
Как это работает на уровне ядра?
Когда вы запускаете docker-compose up, Docker Daemon:
1. Парсит YAML-файл и строит граф зависимостей сервисов.
2. Создает изолированные *сетевые пространства имен* (network namespaces) для каждого сервиса, если не указано иное.
3. Назначает виртуальные Ethernet-интерфейсы (veth pairs) для соединения контейнеров в bridge-сеть по умолчанию.
4. Для томов (volumes) монтирует директории хоста или управляемые Docker тома в контейнеры через bind mounts или overlayfs.
Структура docker-compose: services, volumes, networks
1. services
Определяет контейнеры как логические сервисы.
Пример:
- image — базовый образ (загружается из Docker Hub, если отсутствует локально).
- ports — проброс портов хоста в контейнер. Формат HOST:CONTAINER. При старте Docker создает iptables-правила для перенаправления трафика.
- Важно: Контейнеры в одной сети Compose общаются по имени сервиса (например, web может обращаться к db по DNS-имени db:5432). Это достигается через встроенный DNS-резолвер Docker, который динамически обновляет записи при старте/остановке сервисов.
2. volumes
Управляет данными, сохраняемыми между перезапусками контейнеров.
Пример:
- Named volumes (как pgdata) хранятся в /var/lib/docker/volumes/ и управляются Docker. При удалении контейнера данные сохраняются.
- Host mounts — явное указание пути на хосте:
Здесь изменения в /var/lib/postgresql/data контейнера отражаются на хосте в ./data. Это работает через механизм *bind mounts* ядра Linux, где inode хоста и контейнера совпадают.
3. networks
Создает изолированные сети для сервисов:
- По умолчанию Compose создает bridge-сеть, где контейнеры общаются через L2 (Ethernet).
- Внутри сети Docker внедряет *виртуальный DNS-сервер* на 127.0.0.11, обрабатывающий запросы к именам сервисов. Например, запрос db резолвится в IP-адрес контейнера db.
Переменные окружения в Compose
Использование .env и ${VAR}
Docker Compose поддерживает подстановку переменных из .env-файла:
В docker-compose.yaml:
- Как это работает: При парсинге YAML Compose ищет .env в текущей директории и заменяет ${VAR} на значения из файла. Если переменная не определена, контейнер запустится с пустым значением (если не указано ? для ошибки).
- Нюанс безопасности: .env не шифруется. Для секретов используйте Docker Secrets или инструменты вроде HashiCorp Vault.
Основы: docker-compose.yaml и его архитектура
Что такое docker-compose.yaml?
Это декларативный конфигурационный файл, управляющий многоконтейнерными приложениями через Docker Compose. В отличие от ручного запуска контейнеров через docker run, Compose абстрагирует сложность оркестрации: один файл определяет сервисы, сети, тома и зависимости. При выполнении docker-compose up Docker Engine создает изолированную среду, где контейнеры взаимодействуют через виртуальные сети, а данные сохраняются в управляемых томах.
Как это работает на уровне ядра?
Когда вы запускаете docker-compose up, Docker Daemon:
1. Парсит YAML-файл и строит граф зависимостей сервисов.
2. Создает изолированные *сетевые пространства имен* (network namespaces) для каждого сервиса, если не указано иное.
3. Назначает виртуальные Ethernet-интерфейсы (veth pairs) для соединения контейнеров в bridge-сеть по умолчанию.
4. Для томов (volumes) монтирует директории хоста или управляемые Docker тома в контейнеры через bind mounts или overlayfs.
Структура docker-compose: services, volumes, networks
1. services
Определяет контейнеры как логические сервисы.
Пример:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: example
- image — базовый образ (загружается из Docker Hub, если отсутствует локально).
- ports — проброс портов хоста в контейнер. Формат HOST:CONTAINER. При старте Docker создает iptables-правила для перенаправления трафика.
- Важно: Контейнеры в одной сети Compose общаются по имени сервиса (например, web может обращаться к db по DNS-имени db:5432). Это достигается через встроенный DNS-резолвер Docker, который динамически обновляет записи при старте/остановке сервисов.
2. volumes
Управляет данными, сохраняемыми между перезапусками контейнеров.
Пример:
volumes:
pgdata:
driver: local
- Named volumes (как pgdata) хранятся в /var/lib/docker/volumes/ и управляются Docker. При удалении контейнера данные сохраняются.
- Host mounts — явное указание пути на хосте:
volumes:
- ./data:/var/lib/postgresql/data
Здесь изменения в /var/lib/postgresql/data контейнера отражаются на хосте в ./data. Это работает через механизм *bind mounts* ядра Linux, где inode хоста и контейнера совпадают.
3. networks
Создает изолированные сети для сервисов:
networks:
app_net:
driver: bridge
- По умолчанию Compose создает bridge-сеть, где контейнеры общаются через L2 (Ethernet).
- Внутри сети Docker внедряет *виртуальный DNS-сервер* на 127.0.0.11, обрабатывающий запросы к именам сервисов. Например, запрос db резолвится в IP-адрес контейнера db.
Переменные окружения в Compose
Использование .env и ${VAR}
Docker Compose поддерживает подстановку переменных из .env-файла:
DB_PASSWORD=secure_password
В docker-compose.yaml:
services:
db:
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
- Как это работает: При парсинге YAML Compose ищет .env в текущей директории и заменяет ${VAR} на значения из файла. Если переменная не определена, контейнер запустится с пустым значением (если не указано ? для ошибки).
- Нюанс безопасности: .env не шифруется. Для секретов используйте Docker Secrets или инструменты вроде HashiCorp Vault.
👍3