
Нас все частіше запитують про створення мікросервісів в Kubernetes. Розробники, особливо інтерпретованих мов, хочуть швидко поправити код у улюбленій IDE і без очікування складання/деплою побачити результат — просто натиснувши на F5. І коли йшлося про монолітну програму, достатньо було локально підняти базу даних і веб-сервер (у Docker, VirtualBox ...), після чого - відразу ж насолоджуватися розробкою. З розпилюванням монолітів на мікросервіси і приходом Kubernetes, з появою залежностей один від одного, все . Що більше цих мікросервісів, то більше проблем. Щоб знову насолодитися розробкою, потрібно підняти вже не один і не два Docker-контейнери, а іноді навіть не один десяток… Загалом, на все це може витрачатись досить багато часу, оскільки потрібно ще й підтримувати в актуальному стані.
У різні часи ми пробували різні рішення проблеми. І почну я з накопичених workarounds або просто «милиць».
1. Милиці
Більшість IDE мають можливість правити код прямо на сервері за допомогою FTP/SFTP. Такий шлях дуже очевидний і ми одразу вирішили ним скористатися. Суть його зводиться до такого:
- У pod'і у оточення для розробки (dev/review) запускається додатковий контейнер з доступом по SSH і прокиданням публічного SSH-ключа того розробника, що комітувати/деплоїти додаток.
- На init-стадії (в рамках контейнера
prepare-app) переносимо код уemptyDir, щоб мати доступ до коду з контейнерів з додатком та SSH-сервера.

Для кращого розуміння технічної реалізації такої схеми наведу фрагменти задіяних YAML-конфігурацій Kubernetes.
Зміни
1.1. values.yaml
ssh_pub_key:
vasya.pupkin: <ssh public key in base64>
Тут vasya.pupkin - Це значення змінної ${GITLAB_USER_LOGIN}.
1.2. deployment.yaml
...
{{ if eq .Values.global.debug "yes" }}
volumes:
- name: ssh-pub-key
secret:
defaultMode: 0600
secretName: {{ .Chart.Name }}-ssh-pub-key
- name: app-data
emptyDir: {}
initContainers:
- name: prepare-app
{{ tuple "backend" . | include "werf_container_image" | indent 8 }}
volumeMounts:
- name: app-data
mountPath: /app-data
command: ["bash", "-c", "cp -ar /app/* /app-data/" ]
{{ end }}
containers:
{{ if eq .Values.global.debug "yes" }}
- name: ssh
image: corbinu/ssh-server
volumeMounts:
- name: ssh-pub-key
readOnly: true
mountPath: /root/.ssh/authorized_keys
subPath: authorized_keys
- name: app-data
mountPath: /app
ports:
- name: ssh
containerPort: 22
protocol: TCP
{{ end }}
- name: backend
volumeMounts:
{{ if eq .Values.global.debug "yes" }}
- name: app-data
mountPath: /app
{{ end }}
command: ["/usr/sbin/php-fpm7.2", "--fpm-config", "/etc/php/7.2/php-fpm.conf", "-F"]
...
1.3. secret.yaml
{{ if eq .Values.global.debug "yes" }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Chart.Name }}-ssh-pub-key
type: Opaque
data:
authorized_keys: "{{ first (pluck .Values.global.username .Values.ssh_pub_key) }}"
{{ end }}
фінальний штрих
Після цього залишиться лише передати :
dev:
stage: deploy
script:
- type multiwerf && source <(multiwerf use 1.0 beta)
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf deploy
--namespace ${CI_PROJECT_NAME}-stage
--set "global.env=stage"
--set "global.git_rev=${CI_COMMIT_SHA}"
--set "global.debug=yes"
--set "global.username=${GITLAB_USER_LOGIN}"
tags:
- build
Вуаля: розробник, що запустив деплой, може підключитися на ім'я сервісу (як безпечно видавати доступи до кластера, ) зі свого робочого столу по SFTP і правити код без очікування його доставки в кластер.
Це цілком робоче рішення, проте з погляду реалізації має очевидні мінуси:
- необхідність у доопрацюванні Helm-чарта, що надалі ускладнює його читання;
- використовувати може лише той, хто задеплоїв сервіс;
- необхідно не забути потім синхронізувати його з локальною директорією з кодом і комітнути в Git.
2. Telepresence
Проект відомий досить давно, проте всерйоз спробувати його на ділі у нас, як то кажуть, «не доходили руки». Однак попит зробив свою справу і тепер ми раді поділитися досвідом, який може стати корисним читачам нашого блогу — тим більше, що на хабрі досі не було інших матеріалів про Telepresence.
Якщо стисло, то все виявилося не так страшно. Усі дії, які вимагають виконання з боку розробника, ми розмістили у текстовому файлі Helm-чарта, названому NOTES.txt. Таким чином, розробник після деплою сервісу в Kubernetes бачить інструкцію із запуску локального dev-оточення в лозі job'а GitLab:
!!! Разработка сервиса локально, в составе Kubernetes !!!
* Настройка окружения
* * Должен быть доступ до кластера через VPN
* * На локальном ПК установлен kubectl ( https://kubernetes.io/docs/tasks/tools/install-kubectl/ )
* * Получить config-файл для kubectl (скопировать в ~/.kube/config)
* * На локальном ПК установлен telepresence ( https://www.telepresence.io/reference/install )
* * Должен быть установлен Docker
* * Необходим доступ уровня reporter или выше к репозиторию https://gitlab.site.com/group/app
* * Необходимо залогинится в registry с логином/паролем от GitLab (делается один раз):
#########################################################################
docker login registry.site.com
#########################################################################
* Запуск окружения
#########################################################################
telepresence --namespace {{ .Values.global.env }} --swap-deployment {{ .Chart.Name }}:backend --mount=/tmp/app --docker-run -v `pwd`:/app -v /tmp/app/var/run/secrets:/var/run/secrets -ti registry.site.com/group/app/backend:v8
#########################################################################Не будемо докладно зупинятися на описаних у цій інструкції кроках… крім останнього. Що відбувається під час запуску Telepresence?
Робота з Telepresence
При старті (за останньою командою, вказаною в інструкції вище) ми задаємо:
- простір імен (namespace), у якому запущено мікросервіс;
- імена deployment'а та контейнера, до якого хочемо проникнути.
Інші аргументи опціональні. Якщо наш сервіс взаємодіє з Kubernetes API та для нього , нам необхідно змонтувати сертифікати/токени на свій робочий стіл. Для цього використовується опція --mount=true (або --mount=/dst_path), яка змонтує корінь (/) з контейнера Kubernetes до нас на desktop. Після цього ми можемо (залежно від ОС та способу запуску програми) скористатися ключами від кластера.
Спочатку розглянемо найуніверсальніший варіант запуску програми — в Docker-контейнері. Для цього скористаємося ключем --docker-run та примонтуємо директорію з кодом у контейнер: -v `pwd`:/app
Зверніть увагу, що тут мається на увазі запуск із каталогу з проектом. Код програми буде змонтований у директорію /app у контейнері.
Далі: -v /tmp/app/var/run/secrets:/var/run/secrets — для монтування директорії із сертифікатом/токеном у контейнер.
За цією опцією слід, нарешті, образ, в якому запускатиметься додаток. NB: При складанні образу треба обов'язково вказати CMD або ENTRYPOINT!
Що ж, власне, станеться далі?
- У Kubernetes для вказаного Deployment'а кількість реплік буде змінено на 0. Замість нього запуститься новий Deployment — із підміненим контейнером
backend. - На десктопі запустяться 2 контейнери: перший - з Telepresence (він здійснюватиме проксування запитів з/в Kubernetes), другий - з додатком, що розробляється.
- Якщо exec'нуться в контейнер з додатком, то нам будуть доступні всі ENV-змінні, передані Helm'ом при депло, а також доступні всі сервіси. Залишається лише правити код у улюбленій IDE та насолоджуватися результатом.
- Наприкінці роботи досить просто закрити термінал, у якому запущено Telepresence (оборвати сесію по Ctrl+C), — на робочому столі зупиняться Docker-контейнери, а в Kubernetes все повернеться до початкового стану. Залишиться лише комітнути, оформити MR і передати його на review/merge/… (залежно від ваших робочих процесів).
Якщо ми не хочемо запускати програму в Docker-контейнері — наприклад, ми розробляємо не на PHP, а на Go, і все-таки збираємо його локально, — запуск Telepresence буде ще простіше:
telepresence --namespace {{ .Values.global.env }} --swap-deployment {{ .Chart.Name }}:backend --mount=trueЕсли приложение обращается к Kubernetes API, потребуется смонтировать директорию с ключами (https://www.telepresence.io/howto/volumes). Для Linux есть утилита :
proot -b $TELEPRESENCE_ROOT/var/run/secrets/:/var/run/secrets bash Після запуску Telepresence без опції --docker-run всі змінні оточення будуть доступні в поточному терміналі, тому запуск програми необхідно робити саме в ньому.
NB: При використанні, наприклад, PHP, потрібно не забувати відключати для розробки різні op_cache, apc та інші акселератори - інакше редагування коду не призводитиме до бажаного результату.
Підсумки
Локальна розробка з Kubernetes – проблема, потреба у вирішенні якої зростає пропорційно поширенню цієї платформи. Отримуючи відповідні запити з боку розробників (від наших клієнтів), ми почали їх вирішувати першими засобами, які, однак, не зарекомендували себе на довгій дистанції. Благо, це стало очевидним не тільки зараз і не тільки нам, тому у світі вже з'явилися більш підходящі кошти, і Telepresence — найвідоміший з них (до речі, є ще від Google). Наш досвід його використання ще не такий великий, але вже дає підстави рекомендувати колегам по цеху - спробуйте!
P.S.
Інше з циклу K8s tips & tricks:
- «»;
- «»;
- «»;
- «»;
- «».
Джерело: habr.com
