angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Нужно ли переносить Docker Swarm на Kubernetes?

Я перевел проект Docker-Compose на Kubernetes и решил перейти на Kubernetes.

15 сентября 2023
post main image
https://www.pexels.com/nl-nl/@fotios-photos

Когда читаешь в Интернете сообщения о том, что 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 год, а из-за того, что эта (тривиальная функция) не работает, по всему миру люди создают свои собственные скрипты, чтобы заставить это работать. Замечательно. Итак, что должен делать скрипт:

  1. Запустить новую оболочку (Bash).
  2. Экспортируйте пары ключ-значение в файл '.env'.
  3. С помощью '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

Оставить комментарий

Комментируйте анонимно или войдите в систему, чтобы прокомментировать.

Комментарии

Оставьте ответ

Ответьте анонимно или войдите в систему, чтобы ответить.