На нескольких проектах я сталкивался с ситуацией, когда есть Kubernetes с разными окружениями типа dev, stage, prod и т.д.
Код сервисов в эти самые окружения попадает в процессе CI/CD: то есть мы мержим какую-то ветку с разрабатываемой фичей или исправлением бага в ветку, которая “привязана” к окружению и дальше наш код деплоится в кластер. Думаю, для многих — это уже стандартная история.
Давайте представим, что нужно сделать задачу, относящуюся к какому-нибудь микросервису, эта задача подразумевает запрос по сети к другому микросервису, а тот, в свою очередь, посылает запрос к еще другим микросервисам. Как быть, когда мы хотим, чтобы нам были доступны данные из других микросервисов, чтобы протестировать то, что мы сделали не в тестах с моками, а в условиях, похожих на “боевые”. Тут самым очевидным, как мне кажется, является разворачивание локально микросервиса, код которого мы “ковыряем” и проброс портов до целевого микросервиса в dev кластере (или в другом кластере, предназначенным для тестирования), например:
kubectl port-forward service/some-service 8001:8001
Только надо не забыть поменять переменные в микросервисе, код которого, мы ковыряем, в которых хранятся хост и порт целевого микросервиса на localhost и порт, который вы указали при пробросе.
Так, кажется, что всё, что мы напрограммировали работает. Но теперь мы хотим каким-то образом поменять ответ от микросервиса, к которому мы обращаемся в рамках нашей задачи. Как быть? Можно, конечно, поменять данные, которыми оперирует этот микросервис, например, через интерфейс к БД или какому-то другому хранилищу. Но как быть, если с этой связкой микросервисов работаете не только вы и копание в данных микросервиса может зааффектить работу других разработчиков и тестировщиков, которые работают с этим же контуром k8s?
Для себя я нашел следующее решение: локально поднятый Kubernetes с развертыванием только необходимых в рамках задачи служб и разработкой внутри контейнера в кластере, чтобы все изменения подхватывались, как говорится, налету.
Какую альтернативу тут еще я вижу? Например, можно собрать все нужные микросервисы и их зависимости в большой docker-compose.yml и поднимать их все командой docker compose up. Можно? — Да, конечно, но, как по мне, скучно 🙂 Поэтому, вариант с локальным k8s и разработкой в нем дальше и рассмотрим…
Мы имеем:
-
несколько микросервисов, которые взаимодействуют друг с другом неким образом для процессинга данных: синхронно или асинхронно — неважно;
-
у каждого микросервиса свой репозиторий;
-
для каждого микросервиса есть
docker-compose.ymlдля удобства локальной разработки этого микросервиса; -
все сторонние интеграции, включая общение с другими микросервисами в тестах “замоканы”.
Нам нужно:
-
развернуть локальный Kubernetes;
-
задеплоить туда наши сервисы;
-
научиться разрабатывать в контейнере приложения, чтобы все изменения применялись сразу без пересборки образа контейнера и деплоя нового контейнера приложения в кластер.
Существует несколько решений для упрощенного поднятия локального Kubernetes. В этой статье есть ссылки на самые распространенные. Мне из этого списка нравится Minikube. Устанавливаем его к себе на машину по документации, там все просто, например, для MacOS — brew install minikube и все готово. Запускаем локальный кластер:
minikube start
Для удобства работы с нашим локальным кластером я буду использовать TUI утилиту k9s. Можете использовать инструменты с графическим интерфейсом наподобие Lens — кому что нравится.
Давайте теперь установим Telepresence — инструмент, который позволит нам работать с сервисом в кластере так, чтобы все изменения применялись “налету”.
Для вашей системы лучше посмотреть документацию на официальном сайте, для MacOS просто:
brew install telepresenceio/telepresence/telepresence-oss
Далее для установки Telepresence в наш кластер выполним:
telepresence helm install
Итак, запускаем k9s и, если все хорошо, то увидим примерно следующее:

Дальше нам надо задеплоить необходимые для работы сервисы. Так как у нас есть готовые docker-compose.yml файлы, мы можем из них сделать деплойменты для кубера при помощи утилиты kompose. Я, правда, этим инструментом пользовался всего один раз, так как у меня есть готовые шаблоны deployment-файлов, которые мне поменять быстрее, чем пользоваться kompose 🙂 Ну, тут дело вкуса и привычки. Приведу пример одного такого deployment:
apiVersion: apps/v1 kind: Deployment metadata: name: catalog spec: replicas: 1 selector: matchLabels: app: catalog template: metadata: labels: app: catalog spec: containers: - name: catalog image: catalog-image:latest # Используйте имя образа, который вы собрали imagePullPolicy: IfNotPresent ports: - name: catalog-grpc containerPort: 50051 # Замените на порт, который использует ваше приложение command: ["python", "src/app.py"] env: - name: MONGODB_USER value: "mongouser" # Имя сервиса PostgreSQL - name: MONGODB_PASSWORD value: "mongopassword" # Замените на ваше имя пользователя - name: MONGODB_HOST value: "mongodb" # Замените на ваш пароль - name: MONGODB_PORT value: "27017" # Замените на ваше имя базы данных - name: MONGODB_AUTH_DB value: "admin" - name: MONGODB_DATABASE_NAME value: "catalog" - name: REDIS_HOST value: "redis" --- apiVersion: v1 kind: Service metadata: name: catalog spec: type: NodePort ports: - port: 50051 # Замените на порт, который использует ваше приложение targetPort: catalog-grpc nodePort: 30001 # Замените на желаемый NodePort selector: app: catalog
Теперь давайте соберем образ приложения. Перейдите в директорию вашего проекта, где находится ваш Dockerfile, и выполните команду для сборки образа:
eval $(minikube docker-env) docker build -t your-image-name .
Для Mac с M-процессорами надо добавить в команду docker build флаг --platform=linux/arm64
Теперь давайте задеплоим наш сервис в кластер:
kubectl apply -f your-deployment-file.yml
Вот такие манипуляции надо провести со всеми нужными нам сервисами. Когда все нужные нам сервисы окажутся в кластере, то увидим похожу картину на ту, что на скриншоте*:

*в моем случае namespace=default
Все, теперь у нас есть рабочий локальный кластер Kubernetes. Для сервисов нужны данные, надеюсь, они у вас есть в дампах, csv или еще в чем-то для импорта в БД.
Инструмент k9s позволяет нам пробросить порт нужного сервиса на локальную машину нажатием shift+f. Таким образом, пробросив порт, например, до Postgres, мы можем подключиться к БД в нашем кластере при помощи любимого инструмента, указав хост — localhost и порт, который вы указали про пробросе, ну, и, конечно, креды для авторизации. Вот пример подключения к Postgres с дефолтными настройками и импорт подготовленного дампа:
psql -U postgres -h postgres postgres < dump.sql
Выполнять команду нужно из директории с файлом дампа, ну это вы поняли, я думаю 🙂 Все, вот по такой аналогии заполняем данными наши сервисы и приступаем, наконец, к разработке…
Далее я рассмотрю пример, когда нужно менять код cms-service, который в свою очередь посылает запрос к cms-api, а тот уже идет к следующему сервису, пусть это будет catalog-service.
CMS_APP написано на Python, на Django. Открываем наш редактор кода с этим проектом. Переходим в терминал:
cd {path_to_project} telepresence connect telepresence intercept cms-app --port 9000:9000 -- python3 manage.py runserver 0.0.0.0:9000
Вуаля, все готово для локальной разработки нашего сервиса и моментального применения изменений в кластере без пересборки образа. В терминале вы увидите нечто подобное:
✔ Intercepted 0.1s Using Deployment cms-app Intercept name : cms-app State : ACTIVE Workload kind : Deployment Intercepting : 10.244.0.31 -> 127.0.0.1 9000 -> 9000 TCP
Открываем браузер http://127.0.0.1:9000 и там видим наше приложение.
Все, пишем код, смотрим в live-режиме все изменения, радуемся жизни 😉
После того как вы закончили, в терминале нажимаем ctrl+c чтобы прервать работу telepresence и выполняем telepresence quit для отсоединения от кластера. Как только мы нажмем ctrl+c состояние контейнера приложения вернется к исходному, которое было до начала работы и соответствующее состоянию образа. Спокойно коммитим наши изменения, пушим и закрываем таску 😉 Для обновления образа приложения с нашими изменениями надо будет заново его пересобрать и задеплоить в наш локальный кластер. Эти шаги расписаны выше, поэтому не буду еще раз их повторять.
С Telepresence, конечно, можно работать и в dev кластере, если ваши DEVOPS-инженеры не против.
На этом все, надеюсь, было интересно и, может, кому-то полезно.
ссылка на оригинал статьи https://habr.com/ru/articles/926556/
Добавить комментарий