Рубрики
Без рубрики

Непрерывная разработка с использованием Java и Kubernetes

Непрерывная разработка с использованием Java и Kubernetes с помощью Jib и Scaffold. Помеченный kubernetes, java, jib, scaffold.

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

  • Создание приложения
  • Создание образа docker
  • Перемещение образа контейнера в реестр docker
  • Создание/обновление объектов Kubernetes

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

К счастью, Google недавно анонсировал Jib 1.0.0 , который в сочетании с Scaffold способен решить эту проблему. В этой статье я собираюсь показать вам рабочий процесс с помощью этих инструментов наряду с Spring Boot и Штурвал .

Приложение для весенней загрузки

Сначала нам нужно иметь базовое приложение Spring Boot. Я предлагаю использовать Spring Initializer , который может помочь вам запустить приложение Spring Boot за несколько секунд. В этой статье я использую Spring Boot 2.1.3 с gradle, однако вы также найдете связанные с maven файлы в репозитории .

Просто скачайте сгенерированный проект и давайте создадим RestController

@RestController
public class TestController {

    @GetMapping(value = "/echo/{text}")
    public ResponseEntity test(@NotNull @PathVariable String text) {
        return ResponseEntity.ok(text);
    }

    @GetMapping
    public ResponseEntity hello() {
        return ResponseEntity.ok("HELLO");
    }
}

Во время статьи я хочу продемонстрировать настраиваемость Jib, поэтому давайте изменим номер порта по умолчанию на 55000 . Создайте application.properties и поместите эту строку в файл

server.port=55000

Откройте свою любимую оболочку и запустите ./gradlew Запуск загрузки . Если оба http://localhost:55000 и http://localhost:55000/echo/test кажется, работает, давайте продолжим этап контейнеризации.

Использование кливера для создания образа docker

Jib реализован на Java и запускается как часть вашей сборки Maven или Gradle. Вам не нужно поддерживать Dockerfile, запускать демон Docker. Вам просто нужно открыть свой файл build.gradle , добавить раздел плагинов с помощью id 'com.google.cloud.инструменты.кливер' версия '1.0.0' и добавьте следующий фрагмент кода в конец

jib {
    to {
        image = 'com.github.pozo/spring-boot-jib'
    }
    container {
        ports = ['55000']
    }
}

Следует отметить, что приведенная выше конфигурация не является обязательной. Однако без этих строк Jib создал бы изображение с именем spring-boot-jib:0.0.1-SNAPSHOT , где первая часть представляет собой значение rootProject.name из settings.gradle а второй обеспечивается переменной version из build.gradle . Чтобы создать более продвинутый образ, я предлагаю просмотреть доступные параметры .

Приведенная выше конфигурация’ equal будет выглядеть как this with Dockerfile

FROM gcr.io/distroless/java:latest

COPY dependencyJars /app/libs
COPY snapshotDependencyJars /app/libs
COPY resources /app/resources
COPY classFiles /app/classes

COPY src/main/jib /

ENTRYPOINT ["java", jib.container.jvmFlags, "-cp", "/app/resources:/app/classes:/app/libs/*", jib.container.mainClass]
CMD [jib.container.args]

Jib использует distroless java в качестве базового образа по умолчанию, который, похоже, использует связанные с контейнером флаги JVM по умолчанию . Инструкции множественного копирования используются для разбиения приложения на слои, что позволяет быстрее перестраивать его после небольших изменений.

Если вы хотите указать другое базовое изображение, просто добавьте раздел from

jib {
    from {
        image = 'java:8-jre-alpine'
    }
    to {
        image = 'com.github.pozo/spring-boot-jib'
    }
    container {
        ports = ['55000']
    }
}

Если мы хотим создать образ контейнера, у нас есть два варианта. Используя jib task, который помещает образ контейнера для вашего приложения в реестр контейнеров, или jibDockerBuild , который использует инструмент командной строки docker и требует, чтобы у вас был docker, доступный на вашем ПУТИ, или вы можете установить местоположение исполняемого файла с помощью объекта Dockerclient .

Откройте терминал и выполните

./gradlew jibDockerBuild

Я собираюсь объяснить, почему нам нужно использовать эту задачу вместо jib в следующем абзаце.

Проверьте выходные данные команды docker images . Если вам интересно, почему ваше изображение создано ~ 49 лет назад, это в целях воспроизводимости , Jib устанавливает время создания изображений контейнера равным 0. Для того, чтобы использовать текущее время, просто добавьте используйте текущую временную метку внутри jib.container . Для получения более подробных вопросов ознакомьтесь с Часто задаваемые вопросы о вакансиях .

После этапа сборки мы можем запустить наш образ с

docker run -p 8080:55000 com.github.pozo/spring-boot-jib

Если оба http://localhost:8080 и http://localhost:8080/echo/test кажется, работает, мы можем продолжить работу с нашими объектами Kubernetes.

Запуск образа приложения внутри Kubernetes

Если вы не знакомы с Kubernetes, я рекомендую начать с официальной документации .

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

Другой вариант – Docker для настольных Kubernetes . Он запускает одноузловой кластер локально внутри вашего экземпляра Docker. Я считаю, что это самый удобный способ взлома с помощью Kubernetes, поэтому я предлагаю использовать этот.

Нам также нужен kubectl , который представляет собой интерфейс командной строки для выполнения команд против кластеров Kubernetes.

Если вы решили использовать Миникуб, то запустите кластер с

minikube start

Эта команда создает и настраивает виртуальную машину, которая запускает одноузловой кластер. Эта команда также настраивает вашу установку kubectl для взаимодействия с этим кластером. Вам также нужно запустить

eval $(minikube docker-env)

Команда minicube docker-env возвращает набор экспортируемых переменных среды Bash для настройки локальной среды для повторного использования демона Docker внутри экземпляра Minikube. (источник)

Это означает, что вам не нужно создавать на своем хост-компьютере и помещать образ в реестр docker, вы можете просто создавать внутри того же демона docker, что и Minikube. Так после

./gradlew jibDockerBuild

Мини-куб сможет дотянуться до изображения com.github.pozo/пружинный загрузочный кливер . Не забудьте запустить eval $(minicube docker-env) каждый раз, когда вы запрашиваете новый терминал.

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

Чтобы запустить наш образ в кластере, нам нужно сначала определить Deployment . Развертывание представляет собой набор из нескольких идентичных модулей без уникальных идентификаторов. При развертывании выполняется несколько копий вашего приложения и автоматически заменяются все экземпляры, которые выходят из строя или перестают отвечать на запросы. Кроме того, нам нужен внешний/| Сервис , с помощью которого мы можем получить доступ к нашему приложению из-за пределов кластера. Вот схема того, чего мы хотим достичь

Давайте создадим каталог kubernetes в корневом каталоге проекта и создадим файл spring-boot-jib.yaml со следующим содержимым в недавно созданном каталоге

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-boot-jib
  template:
    metadata:
      labels:
        app: spring-boot-jib
    spec:
      containers:
        - name: spring-boot-jib-pod
          image: com.github.pozo/spring-boot-jib
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 55000
--------
apiVersion: v1
kind: Service
metadata:
  name: spring-boot-jib-service
spec:
  type: LoadBalancer
  ports:
    - port: 8080
      targetPort: 55000
      protocol: TCP
      name: http
  selector:
    app: spring-boot-jib

Здесь следует упомянуть несколько важных вещей.

  • Значение Deployment spec.selector.match Labels.app должно совпадать со значением spec.template.metadata.labels.app
  • Значение службы spec.selector.app должно совпадать со значением развертывания спецификация.селектор.сопоставление меток.приложение значение. Таким образом, служба может найти наш модуль и передавать ему каждый запрос.
  • Значение службы spec.ports.port должно быть тем, что мы хотим предоставить внешнему миру, в нашем случае 8080
  • Порт службы spec.ports.target/| должен совпадать с портом развертывания Порт службы spec.ports.target/| должен совпадать с портом развертывания таким образом, служба перенаправит все на номер порта контейнера 55000
  • . Наконец, модуль spec.containers.imagePullPolicy должно быть если не присутствует или Никогда . Значение по умолчанию Всегда выдаст ошибку, так как такого репозитория

Как мы ранее использовали jibDockerBuild построить у нас есть наш образ локально, и поскольку кластер Docker for Desktop использует экземпляр docker нашего хоста, он сможет получить доступ к образу по умолчанию. В случае Mini kube, благодаря eval $(mini cube docker-env) образ, созданный демоном docker Minikube, также сможет получить доступ к изображению.

Откройте терминал и запустите

kubectl create -f kubernetes/

Команда create выполняет итерацию по каталогу kubernetes и создает ресурсы Kubernetes из его содержимого.

Откройте браузер и попытайтесь добраться до http://localhost:8080 и http://localhost:8080/echo/test снова. В случае мини-куба выполните список служб мини-куба , чтобы узнать адрес развернутой службы. Если мы получаем код статуса 200 затем мы проделали отличную работу, и у нас есть запущенное приложение в нашем кластере.

Соедините все вместе с помощью строительных лесов

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

Строительные леса помогут нам избавиться от этой ручной работы. Перейти к их веб-сайт и следуйте инструкциям по установке. Если все установлено, создайте scaffold.yaml в корневой каталог проекта со следующим содержимым

apiVersion: skaffold/v1beta4
kind: Config
build:
  local:
    push: false
  artifacts:
    - image: com.github.pozo/spring-boot-jib
      jibGradle: {}
deploy:
  kubectl:
    manifests:
      - kubernetes/*.yaml

Это наш совершенно новый файл конвейера Scaffold/| .

  • В build.local.push: false принудительно использует Scaffold для использования jibDockerBuild .
  • build.artifacts – это список реальных изображений, которые мы собираемся создать.
  • Параметр build.artifacts.jibGradle настраивает Skaffold на использование Jib на этапе создания изображения.
  • Значение deploy.kubectl.manifests задает имя папки, в которой у нас уже есть файлы манифеста kubernetes. Если мы пропустим это, то имя каталога по умолчанию будет k8s .

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

Откройте терминал и запустите

skaffold dev --trigger notify

Эта команда запускает наш файл конвейера в режиме разработки, что означает, что каждое изменение в нашей кодовой базе приведет к тому, что Skaffold вызовет Jib для создания образа и kubectl для его развертывания. Звучит круто, правда?

Измените возвращаемое значение Test Controller ‘s привет способ "ДО СВИДАНИЯ" и посмотрите, что происходит в терминале. Обновите браузер через несколько секунд, и вы увидите "ДО СВИДАНИЯ" вместо "ПРИВЕТ" .

Использование руля

Если вы не знакомы с helm, я предлагаю сначала взглянуть на официальное краткое руководство для начинающих .

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

Создайте диаграмму управления для нашего приложения с

helm create spring-boot-jib

Команда helm create создаст структуру каталогов с несколькими файлами. Чтобы сделать его более чистым, что у нас есть в этой папке, переименуйте его в helm . Наиболее важные файлы находятся в каталоге templates и values.yaml сам по себе.

Измените сгенерированный service.yaml s spec.ports.target порт на

targetPort: {{ .Values.service.containerPort }}

Развертывание .yaml ‘s spec.template.spec.containers.image значение к

image: "{{ .Values.image.repository }}{{ if .Values.image.tag }}:{{ .Values.image.tag }}{{ end }}"

И развертывание .yaml ‘s спецификация.шаблон.спецификация.контейнеры.порты значение к

ports:
  {{- toYaml .Values.container.ports | nindent 12 }}

Все, что находится между {{ }} , взято из значений .yaml или _helper.tpl файлы. На самом деле мы используем Перейдите к шаблону . И измените значения .yaml файл, подобный этому

replicaCount: 1

image:
  repository: com.github.pozo/spring-boot-jib
  tag: latest
  pullPolicy: IfNotPresent

nameOverride: ""
fullnameOverride: "spring-boot-jib"

service:
  type: LoadBalancer
  port: 8080
  containerPort: 55000

container:
  ports:
    - name: http
      containerPort: 55000
      protocol: TCP

Поскольку мы хотим использовать Helm вместо kubectl, нам нужно соответствующим образом настроить конвейер Scaffold

apiVersion: skaffold/v1beta4
kind: Config
build:
  local:
    push: false
  artifacts:
    - image: com.github.pozo/spring-boot-jib
      jibGradle: {}
deploy:
  helm:
    releases:
      - name: spring-boot-jib
        chartPath: helm
        values:
          image.repository: com.github.pozo/spring-boot-jib
        setValues:
          image.tag: ""

Мы должны настроить путь к диаграмме ,/| image.repository , и мы должны установить image.tag значение пустой строки для Helm, поэтому Scaffold сможет управлять пользовательскими тегами при развертывании.

Если все настроено, запускайте

skaffold dev --trigger notify

Если мы используем Minicube, нам больше не нужно выполнять eval $(mini kube docker-env) , так как Skaffold позаботится об этом. Если вы хотите посмотреть, что происходит под капотом, просто добавьте переключатель -v debug .

skaffold dev --trigger notify -v debug

Жить отладка

Во время разработки естественным требованием является установка точки останова и проверка состояния приложения во время его запуска. Локально это очень простой процесс, но что, если у нас есть все в кластере? На самом деле все проще, как вы могли бы подумать, нам нужно скорректировать всего несколько вещей.

  • Добавить 5005 к списку портов в конфигурации кливера в Добавить
  • 5005 к списку портов в конфигурации кливера в Добавьте соответствующую конфигурацию agentlib
jib {
    to {
        image = 'com.github.pozo/spring-boot-jib'
    }
    container {
        useCurrentTimestamp = true
        ports = ['55000', '5005']
        jvmFlags = [ '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005' ]
    }
}
  • Расширить значения.yaml ‘s container.ports с
- name: debug
  containerPort: 5005
  protocol: TCP

Затем запустите конвейер. Scaffold автоматически перенаправит все перечисленные порты, однако будьте осторожны, после изменения Scaffold может выбрать случайный порт, если запрошенный порт недоступен . Установите точку останова и запустите ранее созданную удаленную конфигурацию, вызовите соответствующую конечную точку и вуаля.

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

Я хочу поблагодарить Перго Слэба и Даниэля Сабо за всю помощь.

Если вас интересует эта тема, я предлагаю также ознакомиться с этими статьями

Оригинал: “https://dev.to/pozo/continuous-development-with-java-and-kubernetes-3d08”