Pull to refresh
71.42

GO приложение в кластере k8s

Reading time8 min
Views7.5K

Golang приложение в кластере kubernetes


Привет! Я — golang разработчик в Каруне. Kubernetes сегодня — звезда среди систем оркестровки и контейнеризации приложений. Важно понимать, как с ним работать. Поделюсь примером демонстрационного api приложения, которое написано на golang, и покажу способы взаимодействия с ним.


Но сначала — страшная история о том, как я жил без него. Много лет назад, в начале моей карьеры, когда ещё не появился kubernetes, доставка кода до production была весьма проблемной задачей. Бывало так, что создание нового приложения для меня начиналось не с работы в моей любимой IDE, а с заказа процессора, материнской платы, и всё это собиралось вручную. Затем я вставлял сервер в стойку, настраивал порты на cisco L3 маршрутизаторе. И это была только начальная фаза. После этого приходилось новоиспеченную node подключать к кластеру proxmox, накатывать операционную систему, ставить nginx и проводить ещё множество разных настроек.

После череды очень утомительных манипуляций можно было попасть на ip адрес хоста и увидеть, что всё работает, но пока ещё без кода, т.е. nginx отдавал default страничку. Совсем забыл: не всегда стоит в продакшене держать default приложение и вообще открытые порты, а значит нужно было не забыть настроить файрвол. Теперь можно было писать приложение и определяться с доставкой кода. Например, изменения попадали в master ветку, а затем отправлялись в продакшн методом копирования файлов по ssh. Звучит страшно, но тем не менее, такое бывало. Из-за скорости доставки файлов изменения могли скопироваться, скажем так, не консистентно. И пока шло копирование файлов, клиенты получали непредсказуемые ошибки. По этой причине такие действия выполнялись сначала на одну реплику, а в конфигурационный файл nginx вносились необходимые изменения, чтобы отключить реплику с новой версией приложения. Затем, когда файлы были скопированы, nginx снова настраивался — но так, чтобы большая часть запросов шла на старую версию, а на новую версию попадало меньшинство запросов.

В общем, схем достаточно много, в разных местах работы использовали свою специфическую, адаптированную под текущие реалии. Т.е. все решали проблемы наиболее актуальным способом: использовали “сине-зеленый деплой” или, например, “канареечный деплой”, а где-то и вовсе свои особые схемы. И это только те проблемы, которые касались процесса deploy. Можно сказать, что процедура доставки новой версии приложения в продакшен представляла серьёзную проблему, и по пятницам эту процедуру было запрещено выполнять. Kubernetes решил множество проблем, и процесс отправки новой версии приложения в production стал намного комфортней.

Хочу отметить: моё приложение носит демонстрационный характер, потому оно умеет отдавать ip адрес конкретной реплики. Это сделано для того, чтобы визуализировать балансировку нагрузки между инстансами приложения. Думаю, статья может быть полезной тем разработчикам, которые либо только знакомятся с kubernetes, либо тем, кто не до конца понимает большинство моментов, связанных с kubernetes. Далее я планирую на наглядном примере продемонстрировать работы нескольких объектов kubernetes: services и ingress controller.

В качестве тестовой среды буду использовать minikube и gcloude. В данной статье я не планирую акцентировать внимание на процедуре установки этих приложений, т.к. в сети достаточно материала, и сам процесс установки тривиален. Я перечислю инструменты, которые нам понадобятся: docker, docker-compose, kubectl, gcloud.

Использовать для эксперимента приложение minikube крайне удобно: оно позволяет делать всё необходимое на локальной «машине» без каких-либо материальных вложений в платформы типа google cloud или amazon aws. Например, в моей Linux системе это приложение устанавливается одной командой. Да, конечно, если есть желание, можно усложнить процесс, скачать исходники и собрать приложение из них. Ещё в программе minikube мне нравится великолепная документация (“https://minikube.sigs.k8s.io/docs/”) и возможность одной командой включать дополнения. Это очень удобный инструмент. Ниже я перечислю примеры управления minikube:


minikube -h
minikube start — запустить minikube
minikube stop — остановить minikube
minikube ssh — залогинится под пользователем docker внутри контейнера minikube
minikube addons list — список дополнений

Google предлагает свои услуги и за них требует некоторую плату. Кстати, платить необязательно, если вы собираетесь просто провести эксперимент или познакомиться ближе с их продуктом. Для этого они предлагают trial версию, где выдаётся некоторая сумма и промежуток времени, в течение которого можно воспользоваться их предложением. Затем, конечно же, придётся платить. Ниже можно посмотреть основные команды, которые могут понадобиться для работы с kubernetes кластером на платформе google cloud:


gcloud init — подготовительная стадия и авторизация на платформе
gcloud config set project go-echo
gcloud projects list — показать список проектов
gcloud container cluster create  dev-go-echo --num-nodes=3 — создаём кластер с тремя nodes
gcloud container cluster get-credentials cluster-1 — переключиться на кластер
gcloud container cluster list — список кластеров

Образ целевого golang приложения можно скачать так:


docker pull yvv4docker/goecho:v1.0.0

Исходные коды приложения находятся здесь: https://github.com/yvv4git/go-echo
В директории k8s можно найти манифесты для kubernetes, которые описывают различные объекты kubernetes.


Кластер gke


GKE — это система управления и оркестровки, используемая в google cloud. Есть множество способов установить утилиту gcloude, но лично мне ближе установка из репозитория snap:


snap install google-cloud-sdk --classic.  
gcloud init
gcloud container clusters get-credentials cluster-1 --zone us-central1-c

Последняя команда создаст соответствующий файл в ~/.kube/config, что позволит использовать утилиту kubectl для управления кластером и позволит выполнить deploy.


Создадим кластер:


gcloud container clusters create goecho --num-nodes=3

После того, как кластер создан, можно применить манифесты kubernetes, которые создадут deployment и можно будет взаимодействовать с приложением.





Запуск приложения


Чтобы развернуть наше приложение в kubernetes кластере, необходимо выполнить следующую команду:


kubectl apply -f k8s/deployment_goecho.yaml.

В результате мы получим deployment, в котором будет 3 реплики этого приложения. Количество реплик я задал в файле «deployment_goecho.yaml». Чтобы проверить, что приложение запущено, можно сделать так:


kubectl get pods.


Зайдём внутрь контейнера и проверим, работает ли вообще приложение:


kubectl exec -it echo-54c8b57455-4jd9p — sh


Чтобы проверить, работает ли приложение, можно поднять специальный pod, содержащий контейнер с различными полезными утилитами: ping, curl и т.д. Это может быть полезно, если в целевом контейнере отсутствуют необходимые утилиты.


Внутри контейнера можно запустить утилиту netstat и сделать выводы о том, что приложение физически запущено, и узнать, на каком порту оно работает. Всё, как в файлах манифеста kubernetes. К сожалению, в данном контейнере отсутствует утилита curl, соответственно из него постучаться в приложение не получится. Есть, конечно, методы, но я их здесь рассматривать не буду. Я сделаю иначе: запущу вспомогательный контейнер в отдельном pod, который будет напичкан разными сетевыми утилитами. Это некоторый инструмент, который может прийти на помощь, чтобы целевой контейнер был «лёгким» и безопасным. Например, на случай, если моё приложение будет скомпрометировано, т.е. в целях безопасности.


Для этого выполним следующую команду:


kubectl apply -f k8s/pod_watcher.yaml — так появится новый pod с приложением watcher.


Заходим в контейнер, который содержит множество сетевых инструментов:


kubectl exec -it watcher -- bash и пробуем достучаться до нашего целевого приложения.


На screenshot прекрасно видно, что приложение отвечает на запрос. Всё замечательно. Но какой толк от этого? Как можно развернуть приложение и предоставить клиентам или другим приложениям в кластере доступ к нему? Для этого необходимо на практике рассмотреть понятие сервиса.


Service ClusterIP


Далее мы попробуем использовать три типа сервисов: ClusterIP, NodePort и LoadBalancer. Для начала рассмотрим ClusterIP. Нам нужно выполнить следующую команду:


kubectl apply -f k8s/svc_cluster_ip.yaml 
kubectl get svc


На screenshot выдан ip адрес внутри кластера. Попасть на него можно, например, с любого другого приложения в кластере. Воспользуемся приложением, которое было запущено для таких целей — watcher. Попытки связаться с приложением проходят удачно. Ещё можно заметить, что в ответе мы получаем разные ip ардеса. Это подтверждает тот факт, что имеет место балансировка запросов между репликами приложения. В файле манифеста kubernetes, который отвечает за deployment моего приложения, указано 3 реплики. И, например, если мы целенаправленно или случайно сломаем одну из реплик, система поднимет новую. Это позволяет поддерживать приложение в рабочем состоянии и балансировать нагрузку.




Service NodePort


Теперь попробуем другой тип services, который называется NodePort. Выполним необходимые команды:


kubectl delete -f k8s/svc_cluster_ip.yaml
kubectl apply -f k8s/svc_node_port.yaml
kubectl get svc


По указанному cluster ip можно слать запросы приложению, но особенность NodePort в другом. Данный тип сервиса открывает порт на nodes и позволяет связаться с приложением снаружи, например, из public internet. Внешний порт можно узнать следующей командой:


kubectl describe nodes gke-goecho-default-pool-5cee0175-9kmp |grep -i external

Затем отправляем запрос к нашему приложению:


curl 'http://34.147.0.120:31124/v1/address' 

Аналогично ClusterIP ip адрес в возвращаемом ответе будет отличаться, что говорит о том, что имеет место балансировка нагрузки. Кстати, если вы используете не google cloud, а развернули всё это локально в minikube, то может возникнуть вопрос — а где взять node ip? Всё просто — данный ip адрес можно узнать командой:


minikube ip


Service LoadBalancer


Далее я бы хотел рассмотреть другой тип сервиса Load Balancer. В указанном репозитории имеется соответствующий файл манифеста kubernetes, необходимо им воспользоваться:


kubectl delete -f k8s/svc_cluster_ip.yaml
kubectl apply -f k8s/svc_load_balancer.yaml


Важно: «external-ip» появится не сразу, надо подождать. Например, в google cloud время ожидания может быть несколько секунд. Если же мы имеем дело с minikube, то здесь ip адрес автоматически не появится. Сначала надо узнать ip адрес интерфейса, на котором работает minikube, а затем использовать его как «external-ip»:


minikube ip
kubectl patch service echo -n default -p '{"spec": {"type": "LoadBalancer", "externalIPs":["192.168.49.2"]}}"

После этого можно будет обращаться к приложению через «external-ip». Например, так:


curl 'http://echo.local:30722/v1/address' 

Можно заметить, что я обращаюсь не к ip 192.168.49.2, а к hostname, который прописал в /etc/hosts файле. В случае с GKE можно обращаться к нашему приложение из public internet. Это очень удобно, когда мы имеем одно приложение, которое нужно открыть для клиентов. Но если приложений много, и между ними требуется более сложная логика маршрутизации запросов, использовать только сервисы будет неудобно и накладно.




Ingress controller


Представим, что всё-таки у нас несколько приложений, и между ними нужно маршрутизировать запросы. Например, когда запросы с префиксом «/goapp» нужно отправлять на приложение go-app, а запросы с префиксом «watcher» требуется отправить в другое приложение. Для решения этой проблемы понадобится другая сущность kubernetes, которая называется «ingress controller».


Выполняем следующие команды:


kubectl delete -f k8s/pod_watcher.yaml 
kubectl apply -f k8s/deployment_watcher.yaml
kubectl apply -f k8s/ingress.yaml 
kubectl get ingress -o wide


В списке ingress контроллеров можно увидеть наш контроллер. Попробуем теперь достучаться до приложения watcher:


curl -v -X GET ‘http://echo.local/watcher’'


Теперь попробуем отправить запрос на echo сервис:


curl -X GET ‘http://echo.local/goapp/v1/address’

Таким образом мы попадаем на нужный нам сервис внутри кластера. Это может быть крайне полезно, если внутри кластера работает множество приложений, и необходимо как-то централизовано маршрутизировать запросы между ними.


Заключение


Сегодня процесс доставки кода до production сильно упростился и стал намного безопаснее. Kubernetes позволяет из коробки решить массу проблем, на решение которых раньше уходило очень много времени. Теперь можно сразу приступать к разработке приложения, минуя лишние рутинные этапы. В данной статье я написал простенькое web приложение, на примере которого golang разработчик может ближе познакомиться с доставкой кода в production средствами kubernetes. В демонстрационном приложении можно внести правки в конфигурационные файлы, настроить процесс deployment, задать требуемое количество реплик и выбрать способ взаимодействия с сервисом по сети: ClusterIP, NodePort, LoadBalancer, а так же Ingress controller.

Tags:
Hubs:
Total votes 12: ↑6 and ↓6+3
Comments6

Articles

Information

Website
karuna.group
Registered
Founded
Employees
201–500 employees
Location
Россия