Нужно ли переносить Docker Swarm на Kubernetes?
Я перевел проект Docker-Compose на Kubernetes и решил перейти на Kubernetes.
Когда читаешь в Интернете сообщения о том, что Docker Swarm умер, становится страшно. У меня работает Docker Swarm и мне это нравится, это просто, когда ты уже используешь Docker.
Какие есть альтернативы? Мы все время читали, что есть только один выход - перейти на Kubernetes и забыть обо всем остальном.
Я был на полпути миграции с Docker на Docker Swarm и хотел узнать, стоит ли мне продолжать или переключиться на Kubernetes.
Возможно, наиболее логичным следующим шагом было бы использование Docker Desktop , поскольку он включает Kubernetes. Однако я не использую Docker Desktop, я использую Docker Swarm также на моей машине для разработки, и он прекрасно работает.
Вернемся к Kubernetes. Все мои приложения работают на Ubuntu и Debian , и после дополнительного чтения Microk8s показался хорошим выбором, его можно использовать и для разработки, и для производства. Итак, предположим, что мы переходим на Microk8s, тогда что нужно сделать для миграции? Я использовал один из своих текущих проектов Docker-Compose, чтобы выяснить это.
В этой заметке я рассказываю в основном о том, что мне пришлось сделать, чтобы достичь результата, я не показываю все detail проекта Docker-Compose.
Как всегда, я работаю на Ubuntu 22.04.
Мое приложение
Мое приложение состоит из нескольких блоков. Каждый блок состоит из одного или нескольких проектов Docker-Compose. В настоящее время только Task Runners управляется с помощью Docker Swarm. Они подключаются к Backend с помощью оверлейной сети Ingress .
+----------+ +---------+ +-------------+
--| Frontend |---| Backend |----+----| Task Runner |
+----------+ +---------+ | +-------------+
|
| +-------------+
Ingress -> +----| Task Runner |
overlay | +-------------+
network //
| +-------------+
+----| Task Runner |
+-------------+
manage with manage with
|<--- Docker-Compose --->|<---- Docker Swarm ---->|
v
migrate
v
manage with
|<----- Kubernetes ---->|
Task Runner - это проект Docker-Compose с пятью сервисами:
rabbitmq
task
local-web
unbound-cloudflare
unbound-quad9
'local-web' - слегка модифицированный образ Nginx , возвращающий настроенную веб-страницу.
+-------------+
| local-web |
+-------------+
^
|
+----------+ +-----------------+
| | | |-+
| |------>| | |-+
<-->| rabbitmq | | task | | |
| |<------| | | |
| | | | | |
+----------+ +-----------------+ | |
| | ------+ |
| | --------+
+--------------------+ | |
| unbound-cloudflare |<--+ |
+--------------------+ |
|
+--------------------+ |
| unbound-quad9 |<--------+
+--------------------+
rabbitmq-service соединяется с Backend. С помощью Docker Swarm я создаю реплики task-service.
Здесь представлена урезанная версия файла проекта Docker-Compose:
# docker-compose.yml
services:
rabbitmq:
...
networks:
task-runner-network
task:
...
local-web:
...
unboud-cloudflare:
...
networks:
task-runner-network:
external: true
Только rabbitmq подключен к внешней сети. В этом посте я собираюсь запустить Task Runner на Kubernetes, с реплицированным сервисом 'task'.
Вопросы и ответы
Перед началом работ я составил список вопросов и попытался получить на них ответы. Вот они:
Является ли Pod тем же самым, что и Docker Container?
Нет, это не так. Из документации: Pod - это наименьшая развертываемая вычислительная единица, которую можно создавать и которой можно управлять в Kubernetes. В Pod может быть несколько контейнеров. Pod предоставляет контейнерам среду для работы и совместного использования ресурсов, хранилища, сети и межпроцессного взаимодействия. Они используют одно и то же сетевое пространство имен и могут взаимодействовать друг с другом с помощью localhost.
Подводя итог, можно сказать, что если вы не делаете ничего особенного, то на один контейнер следует использовать один Pod .
Pods взаимодействует с помощью служб
Контейнер в Pod взаимодействует с другим Pod , используя свой IP address. Но это не совсем верный путь. В общем случае мы создаем Сервис для каждого Pod, и обращаемся к Pod через его Сервис. Мы обращаемся к сервису по его имени, здесь же мы можем сопоставлять порты.
Если у нас есть Pod с реплицированными контейнерами, то Сервис будет dist распределять запросы между этими контейнерами. В этом случае служба также выступает в роли балансировщика нагрузки. Это очень похоже на Docker Swarm.
Когда использовать Deployments?
Deployment используется для управления Pod. С помощью Deployment можно задавать реплики Pod , размещение Pod на узлах, порядок выпуска новых обновлений. Это означает, что для Pod (почти) всегда нужен Deployment . Поскольку мы можем указать Pod внутри Deployment, нам не нужны отдельные файлы YAML для Pods!
Как выполнить протоколирование Pods ?
Pods не ведет протоколирование. Журналы генерируют контейнеры. Это не отличается от протоколирования в Docker . В моей системе лог-файлы находятся в:
/var/log/pods
Можем ли мы назначить каталог на хосте для Pod , например Docker Volumes?
Да, для этого мы можем использовать директиву 'hostPath'.
Директива Kubernetes предназначена только для производства или ее можно использовать и для разработки?
Microk8s можно использовать и в разработке, и в производстве. Но для производства мы можем использовать и что-то другое, например, вариант Kubernetes от облачного провайдера. На своей машине разработки я использую Microk8s наряду с Docker без проблем.
В Docker Swarm у нас есть Task.Slot, а что является эквивалентом в Kubernetes?
Не совсем то же самое, но сопоставимо - это Kubernetes 'StatefulSet'. Этого я пока не пробовал.
Можно ли подключить сеть Docker Swarm к Kubernetes Pod (контейнер)?
Причина, по которой я хотел бы этого, - миграция. Конечно, мы всегда можем создать свой собственный балансировщик нагрузки proxy, но есть ли простой / стандартный способ сделать это? На данный момент я создаю службу 'nodePort'. Это сопоставляет порт службы внутри Kubernetes с портом на хосте.
Перед преобразованием проверьте и исправьте имена объектов
В файлах Docker-Compose у меня были все эти красивые имена, в которых использовались символы подчеркивания ('_'). В Kubernetes имена объектов должны соответствовать RFC 1123, что означает:
- Не более 63 символов.
- Должны начинаться и заканчиваться строчной буквой или цифрой.
- Содержать строчные буквы, цифры и дефисы.
Прежде чем что-то делать, я изменил это в проекте Docker-Compose.
Kompose: Преобразование файла проекта Docker-Compose
Теперь попробуем преобразовать файлы Task Runner Docker-Compose в нечто Kubernetes, используя Kompose. Kompose - это инструмент для преобразования Docker Compose в Kubernetes. И мы сразу же сталкиваемся с проблемами. Оказалось, что Kompose не умеет работать с файлом '.env', который является весьма существенным. Также (как следствие?) не был сгенерирован файл ConfigMap . По этому поводу есть сообщение о проблеме.
Я проверю наличие новой версии в одну из ближайших недель, а пока подставляем переменные окружения сами, используя Docker-Compose 'config':
> docker-compose -f docker_compose_shared_file.yml -f docker_compose_deployment_file.yml config > docker-compose-config.yml
И затем запускаем Kompose. Здесь мы используем опцию hostPath , так как я использую тома с использованием локальных системных каталогов:
> kompose -v convert -f docker-compose-config.yml --volumes hostPath
Kompose создал следующие файлы:
local-web-pod.yaml
rabbitmq-pod.yaml
rabbitmq-service.yaml
task-pod.yaml
unbound-cloudflare-pod.yaml
unbound-quad9-pod.yaml
Для каждого сервиса Docker-Compose создается файл '-pod.yaml', и только для одного - файл '-service.yaml'. Также я встречал примеры, когда Kompose генерировал Deployments вместо Pods. Почему? Для меня результаты Kompose - это только отправная точка, я должен создать Deployment YAML из файлов Pod YAML , а также добавить файлы Service YAML . Вероятно, можно добиться лучших результатов от Kompose (добавив инструкции в файл 'docker-compose.yml'), но у меня сейчас нет времени на эксперименты.
Установка Microk8s
Теперь давайте поработаем руками. Я использую Ubuntu 22.04, так что это легко, мы используем Microk8s , чтобы получить последний стабильный релиз:
> sudo snap install microk8s --classic
Посмотрим, что включено:
> microk8s status
Результат:
microk8s is running
high-availability: no
datastore master nodes: 127.0.0.1:19001
datastore standby nodes: none
addons:
enabled:
dns # (core) CoreDNS
ha-cluster # (core) Configure high availability on the current node
helm # (core) Helm - the package manager for Kubernetes
helm3 # (core) Helm 3 - the package manager for Kubernetes
disabled:
cert-manager # (core) Cloud native certificate management
community # (core) The community addons repository
dashboard # (core) The Kubernetes dashboard
gpu # (core) Automatic enablement of Nvidia CUDA
host-access # (core) Allow Pods connecting to Host services smoothly
hostpath-storage # (core) Storage class; allocates storage from host directory
ingress # (core) Ingress controller for external access
kube-ovn # (core) An advanced network fabric for Kubernetes
mayastor # (core) OpenEBS MayaStor
metallb # (core) Loadbalancer for your Kubernetes cluster
metrics-server # (core) K8s Metrics Server for API access to service metrics
minio # (core) MinIO object storage
observability # (core) A lightweight observability stack for logs, traces and metrics
prometheus # (core) Prometheus operator for monitoring and logging
rbac # (core) Role-Based Access Control for authorisation
registry # (core) Private image registry exposed on localhost:32000
storage # (core) Alias to hostpath-storage add-on, deprecated
Включить hostpath-storage
Некоторые сервисы в моем файле docker-compose.yml используют постоянные данные в каталогах на localhost. Включите/включите сервисы хранения данных в Microk8s:
> microk8s.enable hostpath-storage
Панель управления Kubernetes
Microk8s включает в себя приборную панель Kubernetes . Сначала включите ее:
> microk8s enable dashboard
Существует несколько вариантов ее включения, этот вариант прост:
> microk8s dashboard-proxy
Затем в браузере перейдите по адресу:
https://127.0.0.1:10443
Примите самоподписанный сертификат, скопируйте-вставьте токен из терминала и вы в деле.
Остановка и запуск
Для остановки и запуска Microk8s:
> microk8s stop
> microk8s start
Использование kubectl
Kubectl - это инструмент командной строки, используемый для выполнения команд управления кластерами Kubernetes .
Чтобы использовать 'kubectl' вместо 'microk8s kubectl':
> alias kubectl='microk8s kubectl'
Чтобы сделать это постоянным, добавьте это в файл 'bashrc':
> echo "alias kubectl='microk8s kubectl'" >> ~/.bashrc
Делайте много псевдонимов, иначе ваши пальцы устанут!
Получение справки, например, о портах контейнера в Pod:
> kubectl explain pod.spec.containers.ports
Для создания и обновления объектов Kubernetes мы можем использовать как декларативный синтаксис ('apply'), так и императивный ('create').
Вот некоторые команды:
> kubectl get nodes
> kubectl apply -f <manifest file>
> kubectl get pods -o wide
> kubectl get deployments
> kubectl get services
> kubectl delete pods local-web
> kubectl describe pods local-web
> kubectl logs local-web
Чтобы получить последние события:
> kubectl get events
И, чтобы получить все:
> kubectl get all -A
Помните, что Deployment содержит спецификацию ReplicaSet и Pod , то есть если вы создадите Deployment, то получите одну или несколько Pods в зависимости от указанных вами реплик.
Развертывание Pod
Можем ли мы развернуть один из Pods , созданный Kompose? Kompose создал для нас следующий файл:
local-web-pod.yaml
Не редактируя этот файл, мы пытаемся развернуть этот Pod:
> kubectl apply -f local-web-pod.yaml
Результат:
pod/local-web created
Pod существует?
> kubectl get pods
Результат:
NAME READY STATUS RESTARTS AGE
local-web 0/1 Pending 0 119s
Есть, но статус 'Pending'. Давайте проверим журналы:
> kubectl logs --timestamps local-web
Журналов нет, ничего не возвращается. Проверим события:
> kubectl get events
Результат:
LAST SEEN TYPE REASON OBJECT MESSAGE
9m31s Warning FailedScheduling pod/local-web 0/1 nodes are available: persistentvolumeclaim "local-web-claim0" not found. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod..
101s Warning FailedScheduling pod/local-web 0/1 nodes are available: 1 node(s) didn't match Pod's node affinity/selector. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling..
Оказалось, что 'nodeAffinity' имеет значение файла Docker-Compose 'deploy - node.hostname'. Пришлось, конечно, изменить его на имя хоста, который я использую в данный момент... :-(
Добавьте частный (образный) реестр
Удалите Pod, снова подайте заявку и получите статус:
> kubectl delete pod local-web
> kubectl apply -f local-web-pod.yaml
> kubectl get pods
Результат:
NAME READY STATUS RESTARTS AGE
local-web 0/1 ErrImagePull 0 76s
Я уже использую частный реестр для Docker . Чтобы использовать его в Kubernetes, необходимо добавить аутентификацию для этого реестра.
Проверьте наличие элемента registry-credential :
> kubectl get secret registry-credential --output=yaml
Результат:
Error from server (NotFound): secrets "registry-credential" not found
Здесь я использую информацию, уже имеющуюся в Docker. Создайте элемент registry-credential:
> kubectl create secret generic registry-credential \
--from-file=.dockerconfigjson=/home/peter/.docker/config.json \
--type=kubernetes.io/dockerconfigjson
Результат:
secret/registry-credential created
Для проверки:
> kubectl get secret registry-credential --output=yaml
Сначала мы переносим образ в реестр. Затем редактируем файлы Pod и добавляем ссылку на учетные данные в реестре:
imagePullSecrets:
- name: registry-credential
Теперь удаляем Pod и применяем снова:
> kubectl get pods
Результат:
NAME READY STATUS RESTARTS AGE
local-web 1/1 Running 0 9s
Наконец-то все работает!
Войдите в контейнер Pod
Войдите в контейнер 'local-web':
> kubectl exec -it local-web -- /bin/bash
Теперь мы можем проверить переменные окружения, монтирования и т.д.
Возможно, вы захотите войти в контейнер с правами root. Мой Microk8s использует 'runc' (Open Container Initiative runtime) для доступа к контейнерам. Получите идентификатор контейнера:
> kubectl describe pod <your pod> | grep containerd
Получится что-то вроде:
Container ID: containerd://6a060ba8436f575b86b4f3fe10a373125aaf7c125af835180d792f5382836355
Затем выполните команду exec от имени root в контейнере:
> sudo runc --root /run/containerd/runc/k8s.io/ exec -t -u 0 6a060ba8436f575b86b4f3fe10a373125aaf7c125af835180d792f5382836355 sh
Доступ к Pod через службу
После остановки и запуска Pod на IP address может быть назначен новый Pod. Поэтому для доступа к Pod мы используем сервис и имя сервиса.
Создав сервис для Pod , мы можем обращаться к Pod , используя его имя, а не IP address. Для этого нам необходим DNS кластера Kubernetes , он должен быть включен:
> kubectl get services kube-dns --namespace=kube-system
Результат:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.152.183.10 <none> 53/UDP,53/TCP,9153/TCP 3d5h
Создать службу для local-web Pod
В файле local-web-pod.yaml не было записи о портах, поэтому я добавил containerPort:
ports:
- containerPort: 80
Поскольку файл local-web-service.yaml не был создан Kompose, я создал его сам. Важно: здесь я добавляю порт, который дает доступ к Pod. В Docker-Compose этот порт нам не понадобился, так как сервис находится во внутренней сети.
apiVersion: v1
kind: Service
metadata:
name: local-web
namespace: default
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
io.kompose.service: local-web
Порт 'selector' должен совпадать с портом 'label' из Pod.
После этого запускаем службу:
> kubectl apply -f local-web-service.yaml
Теперь мы должны иметь возможность доступа к сервису local-web из другого контейнера Pod .
Запустим контейнер Busybox . Существуют проблемы с последними версиями Busybox images и Kubernetes, поэтому используем версию 1.28.
> kubectl run -i --tty --image busybox:128 test --restart=Never --rm /bin/sh
Затем внутрь контейнера:
# wget local-web-service:80
Результат:
Connecting to local-web-service:80 (10.152.183.30:80)
saving to 'index.html'
index.html 100% |**********************************************************************************************************************************| 400 0:00:00 ETA
'index.html' saved
Отлично.
Создание Deployments и сервисов
Как уже было сказано выше, мы создаем не файлы Pod YAML , а файлы Deployment YAML . И мы также добавляем Сервис для каждого Deployment , у которого есть порты.
В Kubernetes имена сервисов глобальные, в Docker-Compose сервисы во внутренней сети локальны для проекта Docker-Compose. Это означает, что в Kubernetes мы должны задать пространство имен для наших сервисов.
Мы можем сделать это двумя способами:
- Добавить пространство имен для этого проекта Docker-Compose
- Добавить prefix к имени сервиса.
На данный момент я считаю, что добавление prefix является наилучшим вариантом:
task-runner-
Таким образом, мы получаем имена Deployment и Service:
task-runner-rabbitmq-deployment
task-runner-local-web-deployment
task-runner-task-deployment
task-runner-unbound-cloudflare-deployment
task-runner-unbound-quad9-deployment
task-runner-rabbitmq-service
task-runner-local-web-service
task-runner-task-service
task-runner-unbound-cloudflare-service
task-runner-unbound-quad9-service
И имена файлов:
task-runner-rabbitmq-deployment.yaml
task-runner-local-web-deployment.yaml
task-runner-task-deployment.yaml
task-runner-unbound-cloudflare-deployment.yaml
task-runner-unbound-quad9-deployment.yaml
task-runner-rabbitmq-service.yaml
task-runner-local-web-service.yaml
task-runner-task-service.yaml
task-runner-unbound-cloudflare-service.yaml
task-runner-unbound-quad9-service.yaml
В Deployment я начинаю с 1 реплики. Вот первая часть файла Deployment :
# task-runner-local-web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
# metadata name must not contain dots
name: task-runner-local-web-deployment
namespace: default
spec:
# number of copies of each pod we want
replicas: 1
strategy:
type: Recreate
# pods managed by this deployment
selector:
# match the labels we set on the pod, see below
matchLabels:
task-runner.local-web.deployment: task-runner-local-web-deployment
# template field is a regular pod configuration nested inside the deployment spec
template:
metadata:
# set labels on the pod, used in the deployment selector, see above
labels:
task-runner.local-web.deployment: task-runner-local-web-deployment
spec:
...
Сделать файл '.env' доступным при запуске контейнеров
У меня много пар ключ-значение в файле '.env', используемом Docker-Compose. В Kubernetes мы можем использовать ConfigMap для импорта их в наши файлы Deployment YAML .
Сначала мы создадим ConfigMap. ConfigMap создается в пространстве имен "по умолчанию", его можно изменить, добавив флаг и значение пространства имен:
> kubectl create configmap task-runner-env-configmap --from-env-file=.env
List the ConfigMaps:
> kubectl get configmaps
Результат:
NAME DATA AGE
...
task-runner-env-configmap 51 19m
Мы можем просмотреть результат в формате yaml:
> kubectl get configmaps task-runner-env-configmap -o yaml
Затем в файлах Deployment YAML удалим секцию 'env' и добавим секцию 'envFrom'.
From:
spec:
containers:
- env:
- name: ENV_VAR1
value: "1"
...
image: ...
To:
spec:
containers:
- envFrom:
- configMapRef:
name: task-runner-env-configmap
env:
- name: VAR_C = $(VAR_A)/$(VAR_B)
image: ...
Здесь мы также создаем новую переменную окружения VAR_C из двух переменных окружения, присутствующих в файле ConfigMap.
Мы можем обновить ConfigMap следующим образом:
> kubectl create configmap task-runner-env-configmap --from-env-file=.env -o yaml --dry-run | kubectl apply -f -
Мы создали ConfigMap для передачи контейнерам пар ключ-значение из файла '.env'. Но здесь возникает большая проблема. Мы не можем использовать переменные окружения в других частях наших манифестов. Например, предположим, что вы хотите иметь возможность переключать хранилище с помощью переменной окружения IMAGE_REGISTRY:
spec:
containers:
- envFrom:
- configMapRef:
name: task-runner-env-configmap
env:
- name: VAR_C = $(VAR_A)/$(VAR_B)
image: $(IMAGE_REGISTRY)...
Это не сработает! На дворе 2023 год, а из-за того, что эта (тривиальная функция) не работает, по всему миру люди создают свои собственные скрипты, чтобы заставить это работать. Замечательно. Итак, что должен делать скрипт:
- Запустить новую оболочку (Bash).
- Экспортируйте пары ключ-значение в файл '.env'.
- С помощью 'envsubst' заменить переменные в нашем манифесте.
Сначала создадим новую оболочку, чтобы не нарушать текущее окружение dist. В новом окружении мы создаем переменные окружения, используя файл '.env'. Наконец, мы заменяем переменные:
> envsubst < mydeploy.yaml | kubectl apply -f -
PersistentVolumes и VolumeClaims
Kompose создал для меня секцию VolumeMounts и секцию Volumes в файлах Pods YAML , используя hostPath. Это означает, что фактические каталоги localhost жестко закодированы в файлах Deployment . Очевидно, что это не то, что нам нужно.
Поэтому я создал несколько манифестов PersistentVolume и PersistentVolumeClaim и использовал их в файлах Deployment .
Создание сервисов для Deployments
Здесь я покажу только службу local-web .
# task-runner-local-web-service.yaml
apiVersion: v1
kind: Service
metadata:
# metadata name must not contain dots
name: task-runner-local-web-service
namespace: default
spec:
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
selector:
task-runner.local-web.deployment: task-runner-local-web-deployment
Запустите службу:
> kubectl apply -f task-runner-local-web-service.yaml
Изменения в коде приложения
Мне потребовались лишь небольшие изменения в коде приложения. Как уже упоминалось выше, я prefix дополнил начальные имена служб символом 'task-runner-'. Для сохранения совместимости с Docker-Compose я теперь использую переменные окружения для имен Сервисов и портов, задаваемые в виде пар ключ-значение в файле '.env'.
Хотя порты теперь задаются во всех Сервисах, менять ничего не нужно, поскольку порты привязаны к Сервисам, а каждый Сервис имеет свой собственный IP address.
Чтобы проверить, где запущен экземпляр Pod , я сохраняю переменную окружения HOSTNAME вместе с результатом выполнения задачи. Для Docker Swarm я использовал .Node.Hostname. В логах мы можем проверить это поле.
Использование nodePort для выставления сервиса rabbitmq на Back End
Сервис Task Runner запущен и работает, но связь с внешним миром отсутствует. Существует несколько способов открыть службу rabbitmq , и здесь я использую nodePort. Мы просто создаем дополнительную службу с типом nodePort и указываем номер порта:
# task-runner-rabbitmq-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
# metadata name must not contain dots
name: task-runner-rabbitmq-nodeport
namespace: default
spec:
type: NodePort
# The range of valid ports is 30000-32767
ports:
- name: amqp
port: 10763
targetPort: 5672
nodePort: 31763
- name: http
port: 20763
targetPort: 15672
nodePort: 32763
selector:
task-runner.rabbitmq.deployment: task-runner-rabbitmq-deployment
Затем мы можем обратиться к этому сервису Kubernetes на хосте следующим образом: localhost:<port>.
Для подключения контейнера Backend Docker к этому порту мы добавляем несколько строк в файл 'docker-compose.yaml':
extra_hosts:
- "host.docker.internal:host-gateway"
И затем обращаемся к сервису как к сервису:
host.docker.internal:<port>
Добавление рабочего узла, DNS не работает
Конечно, мне захотелось добавить новый узел и запустить на нем Pods . С помощью VitualBox на моей машине для разработки я создал VM с сервером Ubuntu 22.04. Затем добавил Microk8s и подключился к новому узлу.
Проблемы ... Kubernetes DNS не работал на новом узле. На странице Microk8s Github упоминается множество проблем с DNS. Возможно, это связано с iptables ...
Мне удалось получить нормально работающий кластер Kubernetes из двух машин VirtualBox . В настоящее время я занимаюсь расследованием этого вопроса.
Разработка и устранение неполадок на Kubernetes
Одна из машин Pods не работала. В журнале было видно, что не так, но мы не хотим зацикливаться:
--+-> make changes ---> build image ---> test --+--->
^ |
| v
+--------------------<------------------------+
Поэтому я смонтировал код внешнего проекта обратно в контейнер, что вернуло меня в среду разработки, и смог решить проблему очень быстро.
Инструменты
Во время миграции я использовал только один дополнительный инструмент: yamllint для проверки манифестов (файлы YAML ).
> sudo apt-get install yamllint
А затем запустить для примера:
> yamllint task-runner-local-web-deployment.yaml
Резюме
Начнем с того, что я провел с Kubernetes всего две недели (не стреляйте в пианиста). Возможно, я сделал неправильный выбор, но часть моего приложения теперь работает и управляется Kubernetes.
Docker Swarm - это легкий выбор, когда речь идет об оркестровке проектов Docker-Compose. Он просто работает, без серьезных ограничений. Для моего приложения, состоящего из нескольких проектов Docker-Compose, мне не нужны тысячи реплик. При использовании Docker Swarm вы запускаете новый узел, добавляете несколько директив развертывания в файлы docker-compose.yml, и все готово. Сеть Docker - одна из лучших возможностей Docker. С помощью Docker Swarm достаточно превратить сеть в зашифрованную оверлейную сеть Ingress для обмена данными между узлами.
Переход на Kubernetes обеспечивает большую гибкость развертывания, но главная причина, по которой Kubernetes стал первым выбором, заключается в том, что он очень широко распространен и многие инструменты интегрированы с ним. Именно в этом Docker Swarm отстает. На момент написания этой заметки разработка Docker Swarm , похоже, более или менее застопорилась (считается ли она полностью завершенной?). Очень жаль, потому что это отличное решение очень сложной проблемы.
В идеальном мире среда разработки идентична производственной среде. Если она работает в разработке, то она работает и в производстве. Docker Swarm очень близок к этому, не требуя особых сложностей. Использование Kubernetes, с другой стороны, создает разрыв. Это похоже на то, что "Ок, разработчик, ты сделал свою работу, теперь предоставь ее DevOps для внедрения в производство". Если разработчик вносит изменения в проекты Docker-Compose, то DevOps также должен работать над ними.
Если вы используете Kubernetes для производства, то, думаю, неизбежно, что в среде разработки также работает Kubernetes. А во многих случаях и Docker Swarm . Это облегчает или усложняет разработку и производство по сравнению с использованием только Docker Swarm? Microk8s очень легко использовать в среде разработки, но это только начало. Создавать файлы проекта Docker-Compose очень просто. Обычно у вас есть два yaml-файла и файл '.env'. После конвертации мой проект Kubernetes уже имел 14 yaml-файлов Kubernetes и более.
Было бы очень хорошо, если бы в Kubernetes были добавлены расширения для файлов YAML , позволяющие импортировать/добавлять другие файлы (например, Nginx) и данные окружения. Пока нам приходится писать собственные скрипты или использовать что-то вроде Helm... еще много чего предстоит узнать.
В общем, в этой заметке я попытался выяснить, что потребуется для переноса части моего приложения с Docker Swarm на Kubernetes. На основании полученных результатов я решил перейти на Kubernetes, я не буду продолжать использовать Docker Swarm для производства. И я также буду использовать Kubernetes для разработки.
Начинать работу с Kubernetes не очень сложно, но иногда очень запутанно. Через несколько дней вы поймете большинство концепций и получите нечто работающее. Дальше можно совершенствовать и расширять. Могут возникнуть (очень) серьезные и трудоемкие проблемы, например, не работает DNS. Я не хочу становиться специалистом по iptables, но другого пути нет.
Количество изменений, которые мне пришлось внести в свое приложение, очень ограничено:
- Изменение имен на RFC1123.
- Префиксация имен служб с использованием переменных окружения.
- Хранение других переменных окружения в результатах.
Вернемся к кодированию ...
Ссылки / кредиты
Configure a Pod to Use a ConfigMap
https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap
Connecting Kubernetes and Docker
https://developers.redhat.com/blog/2017/09/22/connecting-kubernetes-docker
Helm - The package manager for Kubernetes
https://helm.sh
How to go from Docker to Kubernetes the right way
https://www.opensourcerers.org/2021/02/01/how-to-go-from-docker-to-kubernetes-the-right-way
How To Migrate a Docker Compose Workflow to Kubernetes
https://www.digitalocean.com/community/tutorials/how-to-migrate-a-docker-compose-workflow-to-kubernetes
Kompose
https://github.com/kubernetes/kompose
Kubernetes - Documentation - Concepts
https://kubernetes.io/docs/concepts
Kubernetes - Documentation - kubectl Cheat Sheet
https://kubernetes.io/docs/reference/kubectl/cheatsheet
Kustomize - Kubernetes native configuration management
https://kustomize.io
MicroK8s documentation - home
https://microk8s.io/docs
Running Kubernetes locally on Linux with Microk8s
https://kubernetes.io/blog/2019/11/26/running-kubernetes-locally-on-linux-with-microk8s
Using private docker registry inside kubernetes
https://sam-thomas.medium.com/using-private-docker-registry-inside-kubernetes-46a3cede7cb1
When should I use envFrom for configmaps?
https://stackoverflow.com/questions/66352023/when-should-i-use-envfrom-for-configmaps
Подробнее
Docker Swarm Kubernetes
Недавний
- Скрытие первичных ключей базы данных UUID вашего веб-приложения
- Don't Repeat Yourself (DRY) с Jinja2
- SQLAlchemy, PostgreSQL, максимальное количество строк для user
- Показать значения в динамических фильтрах SQLAlchemy
- Безопасная передача данных с помощью шифрования Public Key и pyNaCl
- rqlite: альтернатива dist с высокой степенью готовности и SQLite
Большинство просмотренных
- Используя Python pyOpenSSL для проверки SSL-сертификатов, загруженных с хоста
- Использование UUID вместо Integer Autoincrement Primary Keys с SQLAlchemy и MariaDb
- Подключение к службе на хосте Docker из контейнера Docker
- Использование PyInstaller и Cython для создания исполняемого файла Python
- SQLAlchemy: Использование Cascade Deletes для удаления связанных объектов
- Flask Удовлетворительный запрос API проверка параметров запроса с помощью схем Маршмэллоу