Мир Docker и Kubernetes в аналогиях с жизнью разработчика

Статья предназначена для всех разработчиков, которым пока не довелось, но очень бы хотелось получить полное представление о платформе Kubernetes (K8s) и/или начать с ней работать. 

Делая свои первые шаги в индустрии ПО, я воспринимала Kubernetes как terra incognita. Эта сфера не имела никакого прямого отношения к моим разработкам, или же мне так только казалось. По прошествии года профессиональной деятельности я поднакопила базовые знания K8s, но все еще не могла похвастаться большим опытом практической работы. Теоретические основы были мне известны, но при этом все статьи, которые мне попадались, были слишком сложные, а курсы невероятно длительными. 

Все чаще и чаще взаимодействуя с Kubernetes, я поняла, что между этой платформой и деятельностью разработчика существуют удивительные параллели. И поскольку мне не удалось найти интересный и понятный обучающий курс, я его создала. 

Навстречу приключениям! 

Вас ждет увлекательная история об открытиях, сделанных авантюрным начинающим разработчиком в первый рабочий день. И конечно же, эта статья о K8s, так что будет интересно. 

Приложения = разработчики, предоставляющие заранее установленный продукт сторонам-участникам 

Прикладная программа (сокращенно приложение)  —  это компьютерная программа, разработанная для выполнения определенных задач и предназначенная для использования конечными пользователями. 

В каком-то смысле приложения подобны разработчикам, которые занимаются разработкой ПО для удовлетворения потребностей конечных пользователей. 

Как сделать каждого разработчика независимым и продуктивным? 

Контейнеры = портативный комплект рабочего пространства для разработчиков 

Контейнеры  —  это форма виртуализации операционной системы. Они являются исполняемыми единицами ПО, предусматривающими такой способ упаковки кода приложения, его зависимостей и конфигураций, который позволяет запускать его в любой среде. 

Они обеспечивают изоляцию процессов и оптимизируют применение ресурсов. Контейнеры не содержат образы операционной системы, поэтому они легче, портативнее и менее ресурсозатратные. 

Контейнеры аналогичны компьютерам/ноутбукам, которые обеспечивают независимость сотрудников и позволяют им эффективно предоставлять услуги. Они портативные, допускают работу из дома или офиса, а также располагают всеми необходимыми ресурсами для выполнения задач. Кроме того, они изолированы, поэтому то, что выполняется на одних компьютерах, никак не влияет на рабочие процессы в других. 

Ознакомительное руководство  —  начало всех начал 

Образы = ознакомительное руководство/план использования комплекта рабочего пространства 

Для понимания принципов работы Kubernetes следует познакомиться с понятием “образ”. 

Образ представляет собой набор исполняемых команд для создания контейнера. Это неизменяемый файл, по сути, снимок состояния контейнера, который служит руководством или шаблоном для его создания. 

Образы  —  это слои других образов, каждый из которых проистекает из предыдущего слоя, но при этом чем-то отличается. Запуская образ, вы фактически запускаете его контейнер. У вас может быть множество запущенных контейнеров одного и того же образа. 

По существу, образы подобны руководству/инструкции для запуска рабочего компьютера или плану по его сборке.  

Docker-образы и контейнеры 

Docker  —  это известная среда выполнения для создания и сборки приложений в контейнерах. С помощью Docker-образов она развертывает контейнеризированные приложения или ПО в различных средах, от разработки до тестирования и продакшн. 

Создание примера приложения Go 

Создадим базовое приложение Go и развернем его на кластере minikube

Прежде всего нам потребуется директория my-app, содержащая нижеуказанный файл main.go. В командной строке выполняем: 

go mod init 
go mod tidy


package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", start)
	err := http.ListenAndServe(":10000", nil)
	log.Fatal(err)
}

func start(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Welcome to myapp!")
}

Создание Dockerfile для приложения Go 

Для создания dockerfile обращаемся к следующему ресурсу

# syntax=docker/dockerfile:1
FROM golang:1.16-alpine
WORKDIR /app
COPY go.mod ./
COPY go.sum ./
RUN go mod download
COPY *.go ./
RUN go build -o /myapp
EXPOSE 10000
CMD [ "/myapp" ]

Сборка Docker-образа и запуск контейнера 

Для этой цели выполняем в терминале команду: 

docker build --tag myapp .
docker images

В списке появляется вновь созданный образ myapp.

Теперь запускаем образ как контейнер. Поскольку контейнеры работают изолированно, следует открыть порт внутри контейнера для порта хоста. 

В целях публикации порта для контейнера применяем флаг --publish (сокращенно -p ) в команде docker run. Формат команды --publish —  [host_port]:[container_port]. При необходимости открыть порт 8080 в контейнере для порта 3000 вне его, передаем 3000:8080 во флаге --publish.

docker run -d -p 8080:10000 myapp

В терминале открываем localhost:8080, который сообщает: 

Welcome to myapp!

Итак, теперь у нас есть представление о Docker-контейнерах и образах, т. е. шаблонов, лежащих в основе их создания. Далее рассмотрим понятие планировщиков контейнеров, которые составляют суть K8s.

Для чего нужны планировщики контейнеров? Почему K8s предпочтительнее контейнеров/Docker? 

Ранее мы уже убедились в эффективности контейнеров для изолированного запуска приложений в любой среде. Однако в продакшн могут потребоваться сотни и тысячи различных контейнеров. 

Такие системы запуска контейнеров, как Docker, только выигрывают от привлечения дополнительных технологий для оркестрации или управления всех рабочих контейнеров.  

Как обеспечить синхронное взаимодействие всех разработчиков для создания конечного продукта? 

Kubernetes = менеджер по разработке 

Kubernetes  —  это платформа с открытым исходным кодом для управления и развертывания контейнеров. Она осуществляет оркестровку кластеров виртуальных машин и планирование на них работы контейнеров с учетом имеющихся вычислительных ресурсов и потребности в них. Этот процесс можно сравнить с деятельностью менеджеров, которые планируют и координируют взаимодействия разработчиков по выпуску готового продукта и проверяют наличие всех требуемых для этого ресурсов.  

K8s предназначен для развертывания и масштабирования (или сокращения) сервисов, а также для беспростойного выпуска новой продукции. Она отличается портативностью, расширяемостью, самовосстановлением и высокой доступностью. 

Что такое “под”?

В Kubernetes под (pod)  —  это группа из одного или более контейнеров, связанных вместе в целях управления и сетевого взаимодействия. 

Проводя аналогии с рабочими реалиями, поды можно сравнить с дуэтом опытного и начинающего разработчиков, совместно решающих смежные задачи. Кроме того, они сопоставимы с разработчиком, который отлично знает систему и справляется с заданиями в одиночку. 

Узлы и кластеры = рабочая станция, поставляющая ресурсы разработчикам 

Рассмотрим ранее упомянутый пример рабочего пространства сотрудника. Для продуктивной деятельности ему нужны такие ресурсы, как монитор, стул, стол и т. д. И распределением этих ресурсов занимается менеджер. 

Узел  —  не что иное, как рабочая станция, предоставляющая такие ресурсы, а Kubernetes  —  менеджер, который распределяет эти станции по сотрудникам.  

В Kubernetes узел представляет собой рабочий компьютер, который может быть либо виртуальным, либо физическим. Он может содержать несколько подов, и Kubernetes автоматически планирует их развертывание на узлах кластера. Узлы  —  это наименьшие единицы для вычислений, которые совместно используют ресурсы с целью создания кластера.

Введение в Kubectl и Minikube 

Kubectl  —  это CLI для взаимодействия с API Kubernetes с целью создания и управления кластерами. Для его установки выполняем команду: 

brew install kubectl

Что такое Minikube?

Minikube  —  это инструмент, позволяющий работать с Kubernetes на локальном компьютере. Он представляет собой кластер с одним узлом и предназначен для разработки или экспериментов с K8s. Данный инструмент включает набор встроенных расширений, которые можно активировать/дезактивировать и открывать в локальной среде Kubernetes. 

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

brew install minikube
minikube start

Развертывание сервиса на Kubernetes 

Сначала загружаем созданный локальный Docker-образ в кэш Minikube с помощью данной команды: 

minikube cache add myapp:latest

Развертывание = цели команды и структура, определенные в начале года 

Развертывание обеспечивает декларативные обновления для подов и объекта ReplicaSets (набор реплик).

В объектеDeployment определяется требуемое состояние, и контроллер развертывания (Deployment Controller) постепенно преобразует текущее состояние в ожидаемое. Такие объекты применяются для создания новых ReplicaSets или удаления уже имеющихся Deployment и замены их на новые. 

Рассмотрим следующий файл deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
imagePullPolicy: IfNotPresent
image: myapp
ports:
- containerPort: 10000

Данный файл развертывания подобен декларативному шаблону для подов и Replicasets. Объект Deployment с именем myapp, указанном в поле {metadata.name}, создает Replicaset для запуска двух подов myapp. Теперь {spec.containers.image} выдает образ, который нужно скачать для запуска контейнера в поде, предоставленного {template.metadata.labels} app:myapp. Deployment знает, какими подами управлять благодаря {spec.selector.matchlabels} app:myapp.

Что такое ReplicaSets?

Задача объекта ReplicaSet состоит в поддержании постоянной работы установленного набора реплик подов. Вследствие этого он часто используется для обеспечения доступности определенного числа идентичных подов. 

Стандартные стратегии развертывания 

Пересоздание: уничтожаются все имеющиеся поды и создаются новые. 

Постепенная замена: поды создаются путем накатываемого обновления, медленно замещая старые экземпляры новыми. 

Создание развертывания K8s 

kubectl apply -f deployment.yaml

Проверка кластера Minikube на наличие запущенных подов 

kubectl get pods

Теперь попробуем войти в под и проверить, запущено ли приложение. 

kubectl exec -it <pod-name> sh
apk update
apk add curl
curl localhost:10000

Проверка способности Kubernetes к самовосстановлению 

kubectl delete pod <pod-name>
kubectl get pods

У нас по-прежнему должно быть два работающих пода. Поскольку один был удален, контроллер Replicaset это обнаружил и запустил еще один для поддержания требуемого состояния двух подов. 

Как внешние команды общаются друг с другом? 

Сервисы Kubernetes = SPOC (единое контактное лицо) команды, которое направляет деловые внешние сообщения разработчикам 

Поды  —  это кратковременные ресурсы. Развертывания могут динамически создавать и удалять их. Из-за неустойчивости, непостоянства, изменчивости подов мы не можем рассчитывать на то, что приложение всегда будет доступно через их IP-адреса. 

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

В Kubernetes сервис является абстракцией, определяющей логический набор подов и политику доступа к ним. Этот набор подов для сервиса обычно определяется селектором. Сервисы Kubernetes предоставляют адреса, по которым можно получить доступ к соответствующим подам. 

Рассмотрим следующий файл service.yaml:

apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
type: LoadBalancer
ports:
- protocol: TCP
port: 10000
targetPort: 10000
nodePort: 30000

Он определяет сервис, который направляет запросы на порт 10000 всех подов с меткой app:myapp.

Создание сервиса Kubernetes 

kubectl apply -f service.yaml

Команда minikube tunnel открывает сервисы LoadBalancer, и для поддержания их работы она выполняется в отдельном окне терминала. 

minikube tunnel

minikube tunnel запускается как процесс на хосте и создает сетевой маршрут к сервису кластера CIDR, используя IP-адрес кластера в качестве шлюза. Данная команда обеспечивает любому приложению на операционной системе хоста немедленный доступ к внешнему PI-адресу. 

kubectl get service myapp

После этого должен появиться внешний IP-адрес, который ранее находился в процессе обработки. 

С его помощью открываем сервис в браузере: 

minikube service --url myapp

И видим следующий результат: 

Welcome to myapp!

Раздел о сервисах остался бы неполным без аналогии с буднями разработчика. Предположим, что у внешней команды есть сомнения или вопросы по применению функциональности, созданной другой группой разработчиков. Один из способов решения проблемы  —  обратиться за разъяснениями непосредственно к ее автору. Конечно, это может сработать. Но что если разработчик перешел в другую команду и утратил контекст? В этом случае, выручает SPOC команды, который распределяет вопросы внутри команды. 

Вот такая длинная история… и это еще не все! 

Статья о K8s и приключениях новичка-разработчика подошла к концу. Однако впереди еще много неизведанного и интересного! 

Дополнительные ресурсы 

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Sampriti Mitra: Relating With Docker and Kubernetes As Developers — An Analogue

Предыдущая статьяКак стать разработчиком React в 2022 году?
Следующая статьяPython FastAPI: OpenAPI, CRUD, PostgreSQL в Docker и внедрение зависимостей