Кубер. Зачем?
Постам про кубер быть. И прежде чем тащить технологию к себе в компанию, нужно ответить на вопрос - зачем?
Кубер вам не нужен, если:
1. Проект только зарождается и вы не прогнозируете со старта бурный рост
2. У вас простая серверная архитектура и ей можно запросто управлять вручную или с простой автоматизацией
3. У вас нет жестких требований к простою во время обслуживания. Если сервер ночью приляжет на полчасика - ничего страшного
4. Нет высоких нагрузок и нет требований к автоматическому скейлингу инстансов приложения
5. У вас не микросервисы
Для всех вышеперечисленных случаев подойдет
Кубер вам пригодится, если:
1. Серверов стало слишком много и ими довольно сложно управлять
2. Высокие требования к простою. Нужна отказоустойчивость. SLA 99.9
3. Highload
4. Куча микросервисов
Почему кубер, а не что-то другое (Docker swarm, Hashicorp nomad, etc):
1. Это уже индустриальный стандарт и вам будет гораздо проще найти специалиста для поддержки на рынке
2. Просто огромное количество инструментов на все случаи жизни, поддержка со стороны софта из коробки (RabbitMQ, Grafana, etc)
3. Возможность автоскейлинга. Причем при определенных настройках и поддержке со стороны облачного провайдера - кубер даже сам может заказывать виртуалки, когда нужно и потом их гасить, если они больше не требуются
4. Kubernetes ориентированные ОС, где нет ничего лишнего, они созданы, чтобы только запускать кубы. Если у вас жесткие требования по безопасности - это может быть хорошим решением. Самый яркий представитель таких ОС сейчас - Talos Linux
5. Если вы доросли до собственного ЦОД - куб даже можно использовать для построения своего приватного облака. С интересом наблюдаю за проектом cozystack
Постам про кубер быть. И прежде чем тащить технологию к себе в компанию, нужно ответить на вопрос - зачем?
Кубер вам не нужен, если:
1. Проект только зарождается и вы не прогнозируете со старта бурный рост
2. У вас простая серверная архитектура и ей можно запросто управлять вручную или с простой автоматизацией
3. У вас нет жестких требований к простою во время обслуживания. Если сервер ночью приляжет на полчасика - ничего страшного
4. Нет высоких нагрузок и нет требований к автоматическому скейлингу инстансов приложения
5. У вас не микросервисы
Для всех вышеперечисленных случаев подойдет
docker swarm или docker-compose. Или вообще по старинке без контейнеровКубер вам пригодится, если:
1. Серверов стало слишком много и ими довольно сложно управлять
2. Высокие требования к простою. Нужна отказоустойчивость. SLA 99.9
3. Highload
4. Куча микросервисов
Почему кубер, а не что-то другое (Docker swarm, Hashicorp nomad, etc):
1. Это уже индустриальный стандарт и вам будет гораздо проще найти специалиста для поддержки на рынке
2. Просто огромное количество инструментов на все случаи жизни, поддержка со стороны софта из коробки (RabbitMQ, Grafana, etc)
3. Возможность автоскейлинга. Причем при определенных настройках и поддержке со стороны облачного провайдера - кубер даже сам может заказывать виртуалки, когда нужно и потом их гасить, если они больше не требуются
4. Kubernetes ориентированные ОС, где нет ничего лишнего, они созданы, чтобы только запускать кубы. Если у вас жесткие требования по безопасности - это может быть хорошим решением. Самый яркий представитель таких ОС сейчас - Talos Linux
5. Если вы доросли до собственного ЦОД - куб даже можно использовать для построения своего приватного облака. С интересом наблюдаю за проектом cozystack
👍4
Mailpit вместо Mailhog
Чтобы тестировать отправку писем локально при разработке есть удобный инструмент - mailhog.
Отправляешь ему письма по протоколу SMTP и смотришь в веб-интерфейсе что пришло. В интеграционных тестах можно использовать api, чтобы проверить, что письмо корректно отправилось.
Однако проект заброшен, баги не фиксятся (Привет сортировка писем в режиме maildir).
Сегодня нашел вариант на замену - mailpit. Он вдохновлен мэйлхогом и поддерживает все те же фишки и имеет более приятный интерфейс. Ну и самое главное - проект активно развивается и поддерживается.
Чтобы тестировать отправку писем локально при разработке есть удобный инструмент - mailhog.
Отправляешь ему письма по протоколу SMTP и смотришь в веб-интерфейсе что пришло. В интеграционных тестах можно использовать api, чтобы проверить, что письмо корректно отправилось.
Однако проект заброшен, баги не фиксятся (Привет сортировка писем в режиме maildir).
Сегодня нашел вариант на замену - mailpit. Он вдохновлен мэйлхогом и поддерживает все те же фишки и имеет более приятный интерфейс. Ну и самое главное - проект активно развивается и поддерживается.
👍4🔥2❤1
Php cs fixer научился в параллельность
php-cs-fixer наконец-то научили в распараллеливание проверок. И если на рабочей машине обычно с этим нет проблем, так как есть кэш, то в CI мы проверяем без кэша и на большом проекте проверка может занять довольно продолжительное время. Ранее я распараллеливал этот процесс костылями, но теперь достаточно добавить в конфиг
php-cs-fixer наконец-то научили в распараллеливание проверок. И если на рабочей машине обычно с этим нет проблем, так как есть кэш, то в CI мы проверяем без кэша и на большом проекте проверка может занять довольно продолжительное время. Ранее я распараллеливал этот процесс костылями, но теперь достаточно добавить в конфиг
->setParallelConfig(ParallelConfigFactory::detect()) и фиксер начнет использовать все доступные ядра процессора для проверки кодстайла. Можно этот параллелизм настроить и более гибко. Подробнее в документации - https://cs.symfony.com/doc/usage.html🔥5👍4
Создаем "виртуалки" для нашего Dev кластера с помощью Terraform
И так. Мы захотели завести себе k8s кластер. И чтобы как следует со всем разобраться мы начнем с Dev кластера. В прод пихать кубы пока рано. У нас будет две машины:
Чтобы не возиться ручками - создавать "виртуалки" мы будем как всегда с применением подхода Infrastructure as a Code. Для этого есть прекрасный инструмент под названием Terraform от компании Hashicorp.
Сервера мы будем заказывать у нашего доморощенного облака на базе Proxmox (Это специализированный дистрибутив линукса, который делает из вашего железного сервера/серверов среду для выполнения виртуальных машин и не только).
Приступим:
1. Устанавливаем на нашу рабочую машину
2. Создаем файлик main.tf. Здесь в начале идет секция с провайдерами (У каждого уважающего себя облака есть провайдер для терраформа). Дальше описываем параметры подключения к
3. Открываем консоль и набираем
4. Далее запускаем
5. Если все окей и нас устраивает - делаем
Вот и всё, мы получили сервера под наш кластер. В следующем выпуске будем устанавливать k8s и настраивать его для дальнейшей работы с помощью инструмента
И так. Мы захотели завести себе k8s кластер. И чтобы как следует со всем разобраться мы начнем с Dev кластера. В прод пихать кубы пока рано. У нас будет две машины:
k8s-master для служебных нужд и управления кластером (В терминах кубера это называется control-plane) и k8s-worker для нашей прикладной нагрузки. Чтобы не возиться ручками - создавать "виртуалки" мы будем как всегда с применением подхода Infrastructure as a Code. Для этого есть прекрасный инструмент под названием Terraform от компании Hashicorp.
Сервера мы будем заказывать у нашего доморощенного облака на базе Proxmox (Это специализированный дистрибутив линукса, который делает из вашего железного сервера/серверов среду для выполнения виртуальных машин и не только).
Приступим:
1. Устанавливаем на нашу рабочую машину
terraform. Пакет есть во всех популярных дистрибутивах линукса2. Создаем файлик main.tf. Здесь в начале идет секция с провайдерами (У каждого уважающего себя облака есть провайдер для терраформа). Дальше описываем параметры подключения к
proxmox. Юзер и пароль задается в переменных окружения. Это подробно описано в документации. Ну и дальше описываем какие машины мы хотим получить, думаю там все очевидно. Если нет - добро пожаловать с вопросами в комментарии к посту. Ранее я написал виртуалки в кавычках, потому что это не совсем виртуальные машины. Это LXC контейнеры, предшественники докера. Они не используют виртуализацию и запускаются на ядре хост машины.3. Открываем консоль и набираем
terraform init. Здесь терраформ будет качать нужные провайдеры и создавать свои служебные файлики. Из РФ репозиторий с провайдерами недоступен, поэтому на этом шаге потребуется VPN.4. Далее запускаем
terraform plan и смотрим на план, который был для нас построен.5. Если все окей и нас устраивает - делаем
terraform apply. Подтверждаем и ждем. Через некоторое время запрошенные машины будут созданы. Провайдер немного глючный, поэтому иногда приходится после создания писать start = false, делать apply, потом снова ставить start = true и снова применять изменения, чтобы машины стартанули.Вот и всё, мы получили сервера под наш кластер. В следующем выпуске будем устанавливать k8s и настраивать его для дальнейшей работы с помощью инструмента
ansible. При желании можно создание серверов тоже запихнуть куда-нибудь в CI/CD систему, чтобы вообще руками ничего не делать и только дождаться выполнения pipeline🔥2👍1
Heredoc в Dockerfile
Недавно узнал, что в Dockerfile уже достаточно давно поддерживается Heredoc синтаксис.
Т.е. вместо того, чтобы писать амперсанды:
можно делать вот так:
Пользуйтесь, очень удобно!
Недавно узнал, что в Dockerfile уже достаточно давно поддерживается Heredoc синтаксис.
Т.е. вместо того, чтобы писать амперсанды:
RUN set -xe \
&& apt-get update && apt-get install --no-install-recommends --no-install-suggests -q -y \
gnupg2 \
libicu-dev \
libpq-dev \
libzip-dev \
postgresql-client \
unzip \
$PHPIZE_DEPS \
&& groupmod --gid=${GID} www-data \
&& usermod --uid=${UID} --gid=${GID} www-data \
&& chown www-data:www-data /var/www \
&& docker-php-ext-enable \
opcache \
&& docker-php-ext-install \
intl \
pdo_pgsql \
sockets \
zip \
можно делать вот так:
RUN <<EOF
set -xe
apt-get update
apt-get install --no-install-recommends --no-install-suggests -q -y \
gnupg2 \
libicu-dev \
libpq-dev \
libzip-dev \
postgresql-client \
unzip \
$PHPIZE_DEPS
groupmod --gid=${GID} www-data
usermod --uid=${UID} --gid=${GID} www-data
chown www-data:www-data /var/www
docker-php-ext-enable \
opcache
docker-php-ext-install \
intl \
pdo_pgsql \
sockets \
zip
EOF
Пользуйтесь, очень удобно!
👍15🔥6
mkcert — удобный способ делать доверенные ssl сертификаты для локальной разработки
Когда мы разрабатываем проект локально — нам часто нужны самоподписанные ssl сертификаты. И желательно чтобы браузер/система им доверяла. Ранее я генерировал такие сертификаты через openssl и добавлял какими-то страшными костылями в доверенные системные серты. Это не всегда работало нормально. А потом моим страданиям пришел конец, я узнал про прекрасную утилиту — mkcert. Спешу и с вами поделиться.
Делаем:
И всё! Генерируются сертификаты и добавляются в доверенные. Остается только нужные домены в
P.S. Посты про кубер на пару недель на паузе. С LXC контейнерами и разворачиванием в них k8s слишком много возни. Будем делать через обычные виртуалки. Я сейчас вдали от своего тестового стенда, а внутри VirtualBox Proxmox работает не совсем корректно с виртуалками, поэтому продолжим как только вернусь к настоящим железкам.
Когда мы разрабатываем проект локально — нам часто нужны самоподписанные ssl сертификаты. И желательно чтобы браузер/система им доверяла. Ранее я генерировал такие сертификаты через openssl и добавлял какими-то страшными костылями в доверенные системные серты. Это не всегда работало нормально. А потом моим страданиям пришел конец, я узнал про прекрасную утилиту — mkcert. Спешу и с вами поделиться.
Делаем:
mkcert -install
mkcert -cert-file ./some-dir/example.localhost.crt -key-file ./some-dir/example.localhost.key "*.example.localhost"
И всё! Генерируются сертификаты и добавляются в доверенные. Остается только нужные домены в
/etc/hosts внести и пользоваться.P.S. Посты про кубер на пару недель на паузе. С LXC контейнерами и разворачиванием в них k8s слишком много возни. Будем делать через обычные виртуалки. Я сейчас вдали от своего тестового стенда, а внутри VirtualBox Proxmox работает не совсем корректно с виртуалками, поэтому продолжим как только вернусь к настоящим железкам.
👍8
.dockerignore
Я уже ссылался на то, как пишу файлы
Я уже ссылался на то, как пишу файлы
.dockerignore в своих проектах в рамках статей по бест-практикам по сборке докер образов. Но решил все таки написать и разъяснить отдельным постом дополнительно про этот файл. Как удобно его писать? Вместо того, чтобы постоянно добавлять то, что мы игнорируем - можно сделать иначе. Заигнорить все, а потом добавить исключения, т.е. то, что попасть в образ все таки должно. Таким образом мы гарантируем, что в сборку не просочится мусор, который мы не учли. Делается это вот так (на примере проекта на symfony):## Ignore all
*
## Except
!/bin
!/config
!/docker
!/public
!/src
!.env
!.env.local
!composer.json
!composer.lock
!symfony.lock
👍8💯2👏1
Виртуалки для кластера. Дубль 2. Теперь настоящие :)
Первое, что нам нужно сделать - подготовить шаблон для ВМ.
Я делал по вот этой инструкции - ссылка. Соответственно поменял имя с
Также, чтобы не делать руками каждый раз пункт 14 из инструкции - после 2 шага делаем следующее:
Ну а после подготовки шаблона делаем все тоже самое, что делали в этом посте. Только с поправленным main.tf. На этот раз виртуалки создались корректно и сами стартанули без плясок с бубном.
P.S. Долго готовил этот пост, потому как у меня не хотела работать сеть в ВМ на моем стенде. Тому виной был скопированный конфиг для
Первое, что нам нужно сделать - подготовить шаблон для ВМ.
Я делал по вот этой инструкции - ссылка. Соответственно поменял имя с
debian12-cloudinit на debian12.vm и storage с local-lvm на local. Тут нужно поправить в соотвествии с тем как у вас настроен proxmox. Делаем это все на сервере, где у нас будут жить ВМ.Также, чтобы не делать руками каждый раз пункт 14 из инструкции - после 2 шага делаем следующее:
apt install libguestfs-tools -y
virt-customize -a debian-12-generic-amd64.qcow2 --install qemu-guest-agent
Ну а после подготовки шаблона делаем все тоже самое, что делали в этом посте. Только с поправленным main.tf. На этот раз виртуалки создались корректно и сами стартанули без плясок с бубном.
P.S. Долго готовил этот пост, потому как у меня не хотела работать сеть в ВМ на моем стенде. Тому виной был скопированный конфиг для
terraform и мои ограниченные познания в сетях в линуксе. Спасибо ребятам из русскоязычного сообщества proxmox, они помогли оперативно разобраться.👍3
Разворачиваем dev cluster kubernetes с помощью ansible
И так. У нас есть виртуальные машины, теперь самое время засетапить на них кластер куба.
Вручную конечно же мы это делать не хотим, поэтому прибегнем к ansible.
Также будем для настройки нашего кластера в дальнейшем использовать подход GitOps, т.е. все, что мы коммитим в специальный репозиторий - будет отражаться в нашем кластере. Для этого будем использовать инструмент FluxCD. Приступим.
1. В гитлабе создаем репозиторий, в котором будут храниться настройки кластера (Гитлаб у нас не облачный, а развернутый собственноручно - self-hosted)
2. В профиле пользователя делаем Personal Access Token c доступом
3. Берем мой плэйбук для разворачивания кластера - https://github.com/Etherlord/k8s-dev-cluster-bootstrap
4. Создаем файл
5. Выполняем
6. Выполняем
7. Удаляем из гитлаба токен, он нужен только на время установки FluxCD
Готово! Можно зайти на сервер
Должна получиться примерно такая картина:
Кластер готов и работает. Но он пока пустой. Для его полноценного функционирования нужны дополнительные настройки. Этим мы займемся в следующих постах. И будем работать уже через наш репозиторий, изменение которого будет влиять на кластер
И так. У нас есть виртуальные машины, теперь самое время засетапить на них кластер куба.
Вручную конечно же мы это делать не хотим, поэтому прибегнем к ansible.
Также будем для настройки нашего кластера в дальнейшем использовать подход GitOps, т.е. все, что мы коммитим в специальный репозиторий - будет отражаться в нашем кластере. Для этого будем использовать инструмент FluxCD. Приступим.
1. В гитлабе создаем репозиторий, в котором будут храниться настройки кластера (Гитлаб у нас не облачный, а развернутый собственноручно - self-hosted)
2. В профиле пользователя делаем Personal Access Token c доступом
api, read_repository, write_repository3. Берем мой плэйбук для разворачивания кластера - https://github.com/Etherlord/k8s-dev-cluster-bootstrap
4. Создаем файл
hosts.yaml по примеру из hosts.yaml.dist. Там нужно заполнить ip адреса машин, имя юзера, который будет создан на виртуалках, путь до публичной части вашего ssh ключа, кастомный номер порта для ssh и переменные, которые касаются гитлаба. Все описано в README. ansible_user у нас будет terraform. Он был создан в предыдущем посте, когда мы создавали виртуальные машины.5. Выполняем
make cluster. Дожидаемся успешного выполнения плэйбука6. Выполняем
make install-flux. Дожидаемся успешного выполнения7. Удаляем из гитлаба токен, он нужен только на время установки FluxCD
Готово! Можно зайти на сервер
k8s-master под пользователем из hosts.yaml и выполнить sudo kubectl get node.Должна получиться примерно такая картина:
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 23h v1.30.3
k8s-worker Ready <none> 23h v1.30.3
Кластер готов и работает. Но он пока пустой. Для его полноценного функционирования нужны дополнительные настройки. Этим мы займемся в следующих постах. И будем работать уже через наш репозиторий, изменение которого будет влиять на кластер
👍5
Балансировщик нагрузки Metallb
Кластер у нас есть. Давайте начнем его конфигурировать. Чтобы заруливать http трафик в наш кластер нам нужна такая сущность, как ingress. Мы будем использовать самый популярный
При установке кластера через
1. Давайте настроим систему так, чтобы она подхватывала изменения из репозитория раз в минуту, вместо 10 минут по умолчанию. Для этого редактируем вот эту строчку. В моем репозитории она уже отредактирована. Коммитим, пушим, ждем 10 минут пока изменение применится.
2. В каталоге cluster создаем
3. Далее заходим в документацию Flux и смотрим на способ установки чего-либо в кластер через Helm (Это что-то вроде пакетного менеджера для куба). Нас интересует конфигурация
3.1. Берем из доки строчку
3.2. Берем следующую строчку
Все это пушим, проверяем статус и ошибки с помощью команды
4. Осталось только сконфигурировать установленный
Готово! Балансировщик установлен и настроен. В следующем посте будем устанавливать
Кластер у нас есть. Давайте начнем его конфигурировать. Чтобы заруливать http трафик в наш кластер нам нужна такая сущность, как ingress. Мы будем использовать самый популярный
ingress для куба на базе ingress-nginx. Но для того чтобы он корректно работал - нам потребуется еще одна сущность куба - load balancer. В облаке он есть по умолчанию. А нам на виртуалках придется установить балансировщик для железных серверов - metallb (Есть способы обойтись без балансировщика, но я решил сделать все максимально близким к тому, как будет работать в облаке). Приступим.При установке кластера через
ansible мы также установили систему FluxCD, чтобы использовать подход GitOps для настройки всего, что нам необходимо. Flux при инициализации создал репозиторий, в котором есть папка flux-system. 1. Давайте настроим систему так, чтобы она подхватывала изменения из репозитория раз в минуту, вместо 10 минут по умолчанию. Для этого редактируем вот эту строчку. В моем репозитории она уже отредактирована. Коммитим, пушим, ждем 10 минут пока изменение применится.
2. В каталоге cluster создаем
namespace для metallb с помощью конфигурационного файла namespace.yaml. Коммитим, пушим, через минуту проверяем, что namespace создался с помощью команды sudo kubectl get ns на мастер сервере нашего кластера.3. Далее заходим в документацию Flux и смотрим на способ установки чего-либо в кластер через Helm (Это что-то вроде пакетного менеджера для куба). Нас интересует конфигурация
HelmRepository и HelmRelease. Копируем примеры в файлик hr-metallb.yaml. Далее идем в документацию metallb и ищем там способ установки через helm. Правим файлик примеров под наш случай:3.1. Берем из доки строчку
helm repo add metallb https://metallb.github.io/metallb и в нашем конфиге HelmRepository меняем поля name, namespace и url в соответствии с этой командой.3.2. Берем следующую строчку
helm install metallb metallb/metallb и в соответствии с ней правим в конфиге HelmRelease. Тут также надо поменять name, namespace. Их делаем такими же, как в HelmRepository. Далее меняем поля chart и sourceRef.name. Их берем из команды установки - metallb/metallb. До слэша это chart, после sourceRef.name. В поле version в dev среде можно ставить '*'. В продакшне тут должна быть конкретная версия устанавливаемого софта. Все это пушим, проверяем статус и ошибки с помощью команды
sudo flux get all -n metallb-system. В поле Ready должно быть True по завершению. В противном случае в поле Message будет описание ошибки.4. Осталось только сконфигурировать установленный
metallb. Смотрим раздел доки Configuration. Нас интересует простейшая - Layer 2 Configuration. Создаем файлик metallb-configuration.yaml. В addresses указываем ip адреса, которые metallb сможет выдавать через себя сервисам куба. Пушим. Проверяем командой sudo kubectl get ipaddresspools.metallb.io -n metallb-system что пул адресов создался и содержит правильные значения.Готово! Балансировщик установлен и настроен. В следующем посте будем устанавливать
ingress-nginx👍3
Устанавливаем ingress-nginx в кластер
Пришло время установить
1. Создаем на верхнем уровне каталог
2. Для того, чтобы
3. Создаем файл kustomization.yaml и указываем там, что в кластер нужно применять файл
4. Пушим изменения в репозиторий. Проверяем что
5. Теперь установим
6. В каталоге
7. Пушим все в репозиторий. Некоторое время ждем и проверяем командой
8. Дальше в каталоге
9. Пушим в репо. Отслеживаем статус установки через команду
10. Как только статус
Здесь нас интересует
Вот и все!
Пришло время установить
ingress-nginx в наш кластер, но прежде чем это сделать - мы сделаем еще одно важное изменение. Разобьем наш репозиторий на компоненты, чтобы не сваливать все в одну кучу. Приступим1. Создаем на верхнем уровне каталог
components. В нем подкаталог metallb. Переносим файлы, связанные с metallb, туда2. Для того, чтобы
flux видел наши компоненты - в каталоге cluster создаем файл 01-metallb.yaml, где указываем, что нужно подтягивать изменения из каталога components/metallb в кластер3. Создаем файл kustomization.yaml и указываем там, что в кластер нужно применять файл
01-metallb.yaml и все, что находится в каталоге flux-system4. Пушим изменения в репозиторий. Проверяем что
metallb по прежнему установлен и работает. Способ проверки описан в предыдущем посте. Если вдруг metallb не заработает - удаляем файл metallb-configuration.yaml, пушим в репозиторий, чтобы flux переустановил metallb. Проверяем статус установки flux get all -A. Как только все установится - снова пушим metallb-configuration.yaml в репо5. Теперь установим
ingress-nginx. В каталоге components создаем подкаталог ingress-nginx. Там создаем файл namespace.yaml6. В каталоге
cluster создаем файл 02-ingress-nginx.yaml, там указываем путь к нашему новому компоненту. В kustomization.yaml добавляем 02-ingress-nginx.yaml7. Пушим все в репозиторий. Некоторое время ждем и проверяем командой
kubectl get ns, что неймспейс был создан8. Дальше в каталоге
components/ingress-nginx создаем файл hr-ingress-nginx.yaml. Создаем его по тому же принципу, что был описан в предыдущем посте для metallb. Документацию по установке через helm можно найти тут9. Пушим в репо. Отслеживаем статус установки через команду
flux get all -A10. Как только статус
Ready везде станет True - смотрим какой ip выдался для ingress-nginx командой kubectl get svc -n ingress-nginx. Должно получиться примерно следующее:NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.109.132.65 192.168.0.200 80:32547/TCP,443:32076/TCP 32m
ingress-nginx-controller-admission ClusterIP 10.102.137.72 <none> 443/TCP 32m
Здесь нас интересует
TYPE LoadBalancer, поле EXTERNAL-IP. Видим, что metallb успешно выдал адрес для ingress-nginx. Переходим в браузере по этому адресу и видим знакомый статус 404 от nginxВот и все!
ingress-nginx установлен и работает. Финальный вид репозитория можно посмотреть в этой ветке. В следующих постах будем упаковывать php приложение в helm и пробовать задеплоить его в кластер❤3👍2
Упаковываем php приложение в helm chart и деплоим в k8s. Часть 1
Мы базово подготовили кластер к работе и теперь нам не терпится задеплоить туда наш код.
Для этого мы сделаем helm chart в репозитории приложения, настроим там деплой во внутреннее хранилище пакетов gitlab и внесем изменения в инфраструктурный репозиторий кластера, чтобы наш чарт устанавливался и обновлялся в кластере при пуше в гитлаб.
Начнем:
1. Заходим в гитлаб, в репозиторий приложения. Там открываем раздел Settings -> Repository -> Deploy tokens. Создаем три токена:
2. В репозитории приложения создаем папку .helm. Тут будет лежать наш helm chart. Он состоит из следующих файлов:
2.1. Chart.yaml - здесь лежит описание чарта, его тип, версия чарта и версия приложения. Мы будем в дальнейшем использовать только версию чарта
2.2. values.yaml - здесь хранятся дефолтные настройки чарта. Мы будем переопределять при деплое image, из которого будет деплоится приложение и image tag. Также обратите внимание на параметр
2.3. .helmignore - думаю понятно для чего этот файл. Взят дефолтный из конструктора чарта (Команда
2.4. templates/deployment.yaml - здесь описана базовая сущность куба - deployment. В этом файле описывается в скольких репликах запускать приложение, из какого образа, на каком порту контейнер принимает подключения, healthchecks и ограничения по ресурсам, на основе которых куб решает на какую ноду деплоить приложение. Все значения тут - плэйсхолдеры, которые подставляются при установке чарта из
2.5. templates/service.yaml - создается также базовая сущность k8s - service. Тут мы говорим кластеру, что данный сервис принимает подключения на
2.6. Ну и наконец templates/ingress.yaml - настраиваем
3. Возвращаемся в gitlab и в разделе Settings -> CI/CD -> Variables создаем две переменные
4. Правим .gitlab-ci.yml. Тут у нас будет три шага:
4.1. Собираем production образ приложения (На самом деле не совсем production, пока мы не переопределям
4.2. Пушим в gitlab registry. Тэг ставим по тэгу текущего коммита в сокращенной форме
4.3. Подменяем адрес image и image tag в
5. Закидываем изменения в гитлаб, ждем выполнения pipeline. В секции Deploy -> Package registry проверяем наличие helm chart, в секции Deploy -> Container registry должен лежать образ приложения с нужным тэгом.
Мы базово подготовили кластер к работе и теперь нам не терпится задеплоить туда наш код.
Для этого мы сделаем helm chart в репозитории приложения, настроим там деплой во внутреннее хранилище пакетов gitlab и внесем изменения в инфраструктурный репозиторий кластера, чтобы наш чарт устанавливался и обновлялся в кластере при пуше в гитлаб.
Начнем:
1. Заходим в гитлаб, в репозиторий приложения. Там открываем раздел Settings -> Repository -> Deploy tokens. Создаем три токена:
app-example-pull с правом read_registry, helm с правом read_package_registry и helm-push с правом write-package-registry. При создании токенов будут сгенерированы пароли для каждого. Запишите их в надежное хранилище паролей. Далее они нам понадобятся.2. В репозитории приложения создаем папку .helm. Тут будет лежать наш helm chart. Он состоит из следующих файлов:
2.1. Chart.yaml - здесь лежит описание чарта, его тип, версия чарта и версия приложения. Мы будем в дальнейшем использовать только версию чарта
2.2. values.yaml - здесь хранятся дефолтные настройки чарта. Мы будем переопределять при деплое image, из которого будет деплоится приложение и image tag. Также обратите внимание на параметр
ingress.host. По этому адресу будет доступно приложение из браузера. 2.3. .helmignore - думаю понятно для чего этот файл. Взят дефолтный из конструктора чарта (Команда
helm create)2.4. templates/deployment.yaml - здесь описана базовая сущность куба - deployment. В этом файле описывается в скольких репликах запускать приложение, из какого образа, на каком порту контейнер принимает подключения, healthchecks и ограничения по ресурсам, на основе которых куб решает на какую ноду деплоить приложение. Все значения тут - плэйсхолдеры, которые подставляются при установке чарта из
values.yaml и переопределенных значений. 2.5. templates/service.yaml - создается также базовая сущность k8s - service. Тут мы говорим кластеру, что данный сервис принимает подключения на
80 порту и перенаправляет трафик на поды (Еще одна базовая сущность куба, по сути стручок с контейнерами; пока у нас в стручке будет один контейнер) приложения на порт 8080. На какие именно поды отправлять трафик задается в секции selector. Тут указываются labels, которые заданы в deployment, чтобы сервис и поды могли друг-друга найти.2.6. Ну и наконец templates/ingress.yaml - настраиваем
ingress так, чтобы трафик приходящий на домен app-example.local перенаправлялся на наш сервис, который в свою очередь зарулит все в нужные контейнеры.3. Возвращаемся в gitlab и в разделе Settings -> CI/CD -> Variables создаем две переменные
HELM_USER со значением helm-push и HELM_PASS с паролем этого Deploy token, его мы создавали на первом шаге. Переменную с паролем помечаем как masked, чтобы в логах pipeline не светилось ее значение.4. Правим .gitlab-ci.yml. Тут у нас будет три шага:
4.1. Собираем production образ приложения (На самом деле не совсем production, пока мы не переопределям
APP_ENV, будем делать это позже, когда подключим БД)4.2. Пушим в gitlab registry. Тэг ставим по тэгу текущего коммита в сокращенной форме
4.3. Подменяем адрес image и image tag в
values.yaml чарта. К сожалению, сам helm при запаковке в архив подменять значения не умеет. Это возможно только при установке, но мы будем ставить чарт автоматом через flux. Далее добавляем helm repo, запаковываем чарт, при этом подменяя последнюю цифру версии на ID текущей Job`ы гитлаба (Это нужно для того, чтобы flux автоматически обновлял приложение в кластере). Ну и пушим архив в гитлаб. На машине с gitlab-runner должен быть установлен helm и плагин cm-push. Плагин устанавливается след. командой helm plugin install https://github.com/chartmuseum/helm-push под юзером gitlab-runner5. Закидываем изменения в гитлаб, ждем выполнения pipeline. В секции Deploy -> Package registry проверяем наличие helm chart, в секции Deploy -> Container registry должен лежать образ приложения с нужным тэгом.
Упаковываем php приложение в helm chart и деплоим в k8s. Часть 2
6. Осталось настроить только выкатку этого добра через flux.
Тут все практически аналогично установке
Из отличий:
6.1. Файл image-pull-secret.yaml - тут мы создаем secret (сущность куба для хранения чувствительных данных) для скачивания образов приложения из gitlab container registry. Тут необходимо в секцию
6.1.1. Логинимся в registry с помощью команды
6.1.2. Делаем
6.1.3. Удаляем папку
6.2. В файле hr-app.yaml тоже есть создание секрета. Но тут мы уже напрямую указываем логин
Все эти секреты нужны, чтобы скачивать образы приложения и helm chart из приватных хранилищ гитлаба. Так как это у нас инфраструктурный репозиторий - я считаю допустимым тут указывать секреты прямо в репо. Возможно есть более правильные способы создать секреты и не пушить их в репозиторий, но я пока о таких не знаю.
7. Пушим в инфраструктурный репозиторий наши изменения, смотрим статус
8. С помощью команды
Если все окей добавляем в локальный DNS или
Открываем браузер и проверяем, что приложуха отвечает по нужному домену. Должна быть надпись
Фуф, мы молодцы. В след. посте прикрутим к этому всему добру SSL сертификат, получаемый через
6. Осталось настроить только выкатку этого добра через flux.
Тут все практически аналогично установке
metallb и ingress-nginx. Смотрим этот коммит.Из отличий:
6.1. Файл image-pull-secret.yaml - тут мы создаем secret (сущность куба для хранения чувствительных данных) для скачивания образов приложения из gitlab container registry. Тут необходимо в секцию
.dockerconfigjson вставить строку, подготовленную след. образом:6.1.1. Логинимся в registry с помощью команды
docker --config deploy login registry.example.com. Используем токен app-example-pull, созданный на первом шаге6.1.2. Делаем
base64 deploy/config.json, получаем искомую строку6.1.3. Удаляем папку
deploy6.2. В файле hr-app.yaml тоже есть создание секрета. Но тут мы уже напрямую указываем логин
helm и пароль для этого токена. Все эти секреты нужны, чтобы скачивать образы приложения и helm chart из приватных хранилищ гитлаба. Так как это у нас инфраструктурный репозиторий - я считаю допустимым тут указывать секреты прямо в репо. Возможно есть более правильные способы создать секреты и не пушить их в репозиторий, но я пока о таких не знаю.
7. Пушим в инфраструктурный репозиторий наши изменения, смотрим статус
flux get all -A. Как только везде будет Ready = True - переходим к след. шагу.8. С помощью команды
kubectl get ing -n app-example проверяем настроен ли наш ingress для работы с доменом app-example.local. Видим что-то подобное:NAME CLASS HOSTS ADDRESS PORTS AGE
app-example-ingress nginx app-example.local 192.168.0.200 80 47h
Если все окей добавляем в локальный DNS или
/etc/hosts своей машины соответствующую запись. У меня это 192.168.0.200 app-example.localОткрываем браузер и проверяем, что приложуха отвечает по нужному домену. Должна быть надпись
Welcome to example application. Фуф, мы молодцы. В след. посте прикрутим к этому всему добру SSL сертификат, получаемый через
letsencrypt. Домен тоже придется сделать настоящий)👍4
Опрос в догонку. Сложность постов возрастает, объяснить все в маленьком количестве текста становится сложно. Нужны ли видео на ютубе, где все вышеизложенное будет наглядно показано?
Anonymous Poll
52%
Нужны
35%
И текстом норм
13%
Мне все равно
В декабре буду выступать с докладом на PHP Russia 2024!
Расскажу как подготовить своё PHP приложение к работе в облаке.
Если кто-то планирует быть оффлайн - с радостью пообщаюсь.
Расскажу как подготовить своё PHP приложение к работе в облаке.
Если кто-то планирует быть оффлайн - с радостью пообщаюсь.
🎉7👍5🔥5
Шифрованные секреты в инфраструктурном репозитории
Мне не давала покоя мысль о том, что в нашем инфраструктурном git репозитории не должно быть секретов в открытом виде. Все best practice твердят нам это. Я почитал доку и сейчас мы будем делать шифрованные секреты в репозитории, чтобы затем они расшифровывались в кластере и попадали в нужное место. Я выбрал вариант с использованием gpg и утилиты sops.
Приступим:
1. Заходим на мастер машину нашего кластера и создаем там gpg ключ
2. Получаем отпечаток нашего ключа
Видим следующее:
3. Сохраняем его в env переменную
4. Экспортируем ключ в кластер
5. Экспортируем публичную часть ключа и сохраняем его в репозитории в файл cluster/flux-system/.sops.pub.asc
6. Удаляем ключи с мастер машины кластера. Они тут нам больше не нужны
7. Теперь пришло время зашифровать наши секреты и настроить flux так, чтобы он их расшифровывал и в расшифрованном виде сохранял в кластер. Первым делом добавляем в 03-app.yaml следующие строчки:
Здесь мы указываем кластеру имя секрета, где хранится секретный ключ gpg, который будет использоваться для расшифровки файлов из репозитория
8. Из файла hr-app.yaml убираем секрет и кладем его в
9. Импортируем публичную часть ключа уже на нашей рабочей машине
10. Ставим утилиту sops. И шифруем наши секреты
Получаем зашифрованные версии наших конфигов секретов. helm-pull-secret.yaml и image-pull-secret.yaml
11. Вот и все. Пушим в репо и проверяем статус командой
Для того, чтобы проверить все ли работает - можно запустить деплой приложения в гитлабе и убедиться, что все по прежнему деплоится и функционирует. Конечно это нужно было сделать с самого начала и у нас в истории коммитов остались открытые секреты, но больше мы так делать не будем.
Stay tuned ;)
Мне не давала покоя мысль о том, что в нашем инфраструктурном git репозитории не должно быть секретов в открытом виде. Все best practice твердят нам это. Я почитал доку и сейчас мы будем делать шифрованные секреты в репозитории, чтобы затем они расшифровывались в кластере и попадали в нужное место. Я выбрал вариант с использованием gpg и утилиты sops.
Приступим:
1. Заходим на мастер машину нашего кластера и создаем там gpg ключ
export KEY_NAME="cluster.yourdomain.com"
export KEY_COMMENT="flux secrets"
gpg --batch --full-generate-key <<EOF
%no-protection
Key-Type: 1
Key-Length: 4096
Subkey-Type: 1
Subkey-Length: 4096
Expire-Date: 0
Name-Comment: ${KEY_COMMENT}
Name-Real: ${KEY_NAME}
EOF
2. Получаем отпечаток нашего ключа
gpg --list-secret-keys "${KEY_NAME}"Видим следующее:
pub rsa4096 2024-09-23 [SCEA]
AD02237C200DCF7465E0FA88AF8CB328D6E19757
uid [ultimate] dev flux (flux secrets)
sub rsa4096 2024-09-23 [SEA]
3. Сохраняем его в env переменную
export KEY_FP=AD02237C200DCF7465E0FA88AF8CB328D6E197574. Экспортируем ключ в кластер
gpg --export-secret-keys --armor "${KEY_FP}" |
sudo kubectl create secret generic sops-gpg \
--namespace=flux-system \
--from-file=sops.asc=/dev/stdin5. Экспортируем публичную часть ключа и сохраняем его в репозитории в файл cluster/flux-system/.sops.pub.asc
gpg --export --armor "${KEY_FP}" > /home/user/.sops.pub.asc6. Удаляем ключи с мастер машины кластера. Они тут нам больше не нужны
gpg --delete-secret-and-public-keys "${KEY_FP}"rm /home/user/.sops.pub.asc7. Теперь пришло время зашифровать наши секреты и настроить flux так, чтобы он их расшифровывал и в расшифрованном виде сохранял в кластер. Первым делом добавляем в 03-app.yaml следующие строчки:
decryption:
provider: sops
secretRef:
name: sops-gpg
Здесь мы указываем кластеру имя секрета, где хранится секретный ключ gpg, который будет использоваться для расшифровки файлов из репозитория
8. Из файла hr-app.yaml убираем секрет и кладем его в
helm-pull-secret.yaml9. Импортируем публичную часть ключа уже на нашей рабочей машине
gpg --import cluster/flux-system/.sops.pub.asc10. Ставим утилиту sops. И шифруем наши секреты
cd components/app-example
sops --encrypt --encrypted-regex '^(data|stringData)$' --pgp 'AD02237C200DCF7465E0FA88AF8CB328D6E19757' --in-place helm-pull-secret.yaml
sops --encrypt --encrypted-regex '^(data|stringData)$' --pgp 'AD02237C200DCF7465E0FA88AF8CB328D6E19757' --in-place image-pull-secret.yaml
Получаем зашифрованные версии наших конфигов секретов. helm-pull-secret.yaml и image-pull-secret.yaml
11. Вот и все. Пушим в репо и проверяем статус командой
flux get all -AДля того, чтобы проверить все ли работает - можно запустить деплой приложения в гитлабе и убедиться, что все по прежнему деплоится и функционирует. Конечно это нужно было сделать с самого начала и у нас в истории коммитов остались открытые секреты, но больше мы так делать не будем.
Stay tuned ;)
🔥6
Видео с конференции по безопасности контейнеров и контейнерных сред (БЕКОН)
Пока что адски перегружен и никак не могу продолжить писать следующий пост. Но без контента вас не оставлю :)
Держите офигенные доклады по безопасности с конференции БЕКОН 2024
https://www.youtube.com/watch?v=V7wOfQeghpQ&list=PL80eyh4Ug9W-bg3wco8e9UNpawrQlnkAk
Пока что адски перегружен и никак не могу продолжить писать следующий пост. Но без контента вас не оставлю :)
Держите офигенные доклады по безопасности с конференции БЕКОН 2024
https://www.youtube.com/watch?v=V7wOfQeghpQ&list=PL80eyh4Ug9W-bg3wco8e9UNpawrQlnkAk
YouTube
Латаем огрехи в образах приложений с помощью Kubernetes - Анатолий Карпенко | БеКон 2024
"Латаем огрехи в образах приложений с помощью Kubernetes", Анатолий Карпенко, Luntry
Обычная ситуация — вам достался образ, который вот совсем не по best practice по безопасности. И вы отказаться от него не можете и поправить в нем ничего не можете. Или…
Обычная ситуация — вам достался образ, который вот совсем не по best practice по безопасности. И вы отказаться от него не можете и поправить в нем ничего не можете. Или…
👍4
Идеальный Dockerfile
В очередной раз переосмыслил для себя каким должен быть Dockerfile.
Вовсе не обязательно делать отдельно под локальную разработку и под prod.
Достаточно использовать мультистадийную сборку и локально собирать с одним
По сути мы наследуем все что собираем для локалки и добавляем слои, которые нужны для прода.
А
В очередной раз переосмыслил для себя каким должен быть Dockerfile.
Вовсе не обязательно делать отдельно под локальную разработку и под prod.
Достаточно использовать мультистадийную сборку и локально собирать с одним
target, а для прода с другим.По сути мы наследуем все что собираем для локалки и добавляем слои, которые нужны для прода.
А
CMD можно вынести за скобки в docker-compose.yaml, .gitlab-ci.yml и т.д.Gist
Dockerfile
Dockerfile. GitHub Gist: instantly share code, notes, and snippets.
👍12
Healthcheck для php-fpm
Я уже несколько лет везде использую roadrunner. Но не так давно пришлось поработать с php-fpm в докере.
Думал как же проверять его здоровье, но оказалось, что уже все придумано. Есть такой вот скрипт - php-fpm-healthcheck.
Использование предельно просто:
Чтобы это работало - в php-fpm должен быть включен
Я уже несколько лет везде использую roadrunner. Но не так давно пришлось поработать с php-fpm в докере.
Думал как же проверять его здоровье, но оказалось, что уже все придумано. Есть такой вот скрипт - php-fpm-healthcheck.
Использование предельно просто:
healthcheck:
test: [ "CMD", "php-fpm-healthcheck" ]
interval: 5s
timeout: 5s
retries: 5
Чтобы это работало - в php-fpm должен быть включен
status и в докер образе должна стоять библиотечка для работы с fcgi. Для Debian ставим libfcgi-bin👍5🔥3
Symfony + docker. Когда компилировать DI контейнер?
Недавно созванивались с Валентином Удальцовым и обсуждали этот вопрос.
Сначала я компилировал DI контейнер сразу в
Потом вынес этот момент из
Когда же лучше это делать?
Если у вас нет специфичных настроек DI, зависящих от переменной APP_ENV или еще каких-то переменных окружения, которые влияют на сборку DI контейнера - можно и нужно компилировать DI контейнер в
Если такие настройки есть - то компиляцию DI контейнера лучше вынести вне сборки образа и сделать при запуске приложения.
P.S. Когда я это все тестировал - обнаружил любопытный момент. Linux кэширует ENV переменные для запущенного процесса и если мы поменяем переменную в уже запущенном docker контейнере, то в приложении ничего не изменится, так как значение переменной уже закэшировано для процесса, который запускает php скрипты, будь то
Недавно созванивались с Валентином Удальцовым и обсуждали этот вопрос.
Сначала я компилировал DI контейнер сразу в
Dockerfile, что обеспечивало быстрый запуск docker контейнера с приложением из уже подготовленного образа.Потом вынес этот момент из
Dockerfile в запуск приложения, т.е. сначала делаем cache:clear, а потом запускаем roadrunner. Но это замедляет старт docker контейнера.Когда же лучше это делать?
Если у вас нет специфичных настроек DI, зависящих от переменной APP_ENV или еще каких-то переменных окружения, которые влияют на сборку DI контейнера - можно и нужно компилировать DI контейнер в
Dockerfile.Если такие настройки есть - то компиляцию DI контейнера лучше вынести вне сборки образа и сделать при запуске приложения.
P.S. Когда я это все тестировал - обнаружил любопытный момент. Linux кэширует ENV переменные для запущенного процесса и если мы поменяем переменную в уже запущенном docker контейнере, то в приложении ничего не изменится, так как значение переменной уже закэшировано для процесса, который запускает php скрипты, будь то
roadrunner или php-fpm👍8🔥2
На канале FartTime сегодня стрим по нашей излюбленной тематике!