Если вы разрабатываете несколько приложений одновременно для 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
‘scontainer.ports
с
- name: debug containerPort: 5005 protocol: TCP
- Создайте удаленную конфигурацию для отладчика
Затем запустите конвейер. Scaffold автоматически перенаправит все перечисленные порты, однако будьте осторожны, после изменения Scaffold может выбрать случайный порт, если запрошенный порт недоступен . Установите точку останова и запустите ранее созданную удаленную конфигурацию, вызовите соответствующую конечную точку и вуаля.
Я надеюсь, вам понравилось читать эту статью так же, как мне понравилось ее писать. Я не опытный писатель, поэтому, если у вас есть комментарий, пожалуйста, не стесняйтесь поделиться им в разделе комментариев. Исходный код этой статьи доступен на GitHub .
Я хочу поблагодарить Перго Слэба и Даниэля Сабо за всю помощь.
Если вас интересует эта тема, я предлагаю также ознакомиться с этими статьями
- Закрепите Приложение Spring Boot С Помощью Стрелы
- Докеризация Java-приложений с помощью Jib
- Непрерывная разработка для Kubernetes (Слайды)
- Представляем Jib — улучшенную сборку изображений Java Docker
- awesome-kubernetes – Кураторский список потрясающих источников kubernetes
- Управление Kubernetes: Почему Это Имеет Значение
- Проект против Github против Helm против Ksonnet против Metaparticle против Skaffold
Оригинал: “https://dev.to/pozo/continuous-development-with-java-and-kubernetes-3d08”