Развертывание приложения Micronaut, контейнеризованного с помощью Jib, в Google Kubernetes Engine

1. Обзор

О Micronaut

Micronaut — это современный, основанный на JVM, полнофункциональный фреймворк для создания модульных, легко тестируемых микросервисных и бессерверных приложений. Micronaut стремится обеспечить быстрое время запуска, высокую пропускную способность и минимальное потребление памяти. Разработчики могут создавать приложения с помощью Micronaut на Java, Groovy или Kotlin.

Micronaut предоставляет:

  • Быстрое время запуска и низкое потребление памяти — основанные на рефлексии IoC-фреймворки загружают и кэшируют данные рефлексии для каждого поля, метода и конструктора в вашем коде, тогда как с Micronaut время запуска вашего приложения и потребление памяти не ограничены размером вашей кодовой базы.
  • Декларативный, реактивный HTTP-клиент, реализуемый на этапе компиляции — Декларативный подход к созданию реактивных HTTP-клиентов, которые реализуются на этапе компиляции, что снижает потребление памяти.
  • Неблокирующий HTTP-сервер на базе Netty — Благодаря простоте освоения, HTTP-сервер Micronaut максимально упрощает предоставление API-интерфейсов, доступных для HTTP-клиентов.
  • Быстрое и простое тестирование — легко запускайте серверы и клиенты в модульных тестах и ​​выполняйте их мгновенно.
  • Эффективное внедрение зависимостей на этапе компиляции и аспектно-ориентированное программирование — Micronaut предоставляет простой API аспектно-ориентированного программирования на этапе компиляции, который не использует рефлексию.
  • Создавайте полностью реактивные и неблокирующие приложения — Micronaut поддерживает любой фреймворк, реализующий Reactive Streams, включая RxJava и Reactor.

Для получения более подробной информации посетите веб-сайт Micronaut .

О Kubernetes

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

В этой лабораторной работе вы развернете простой микросервис Micronaut на основе Groovy в Kubernetes , работающем на Kubernetes Engine .

Цель этого практического занятия — запустить ваш микросервис в качестве реплицированного сервиса, работающего на Kubernetes. Вы берете код, разработанный на вашем компьютере, преобразуете его в образ контейнера Docker, а затем запускаете этот образ в Kubernetes Engine.

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

Kubernetes Codelab Diagram 1 (2).png

В рамках этого практического занятия использование управляемой среды, такой как Kubernetes Engine (версия Kubernetes, размещенная Google и работающая на Compute Engine), позволяет вам больше сосредоточиться на изучении Kubernetes, а не на настройке базовой инфраструктуры.

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

О стреле

Jib — это инструмент с открытым исходным кодом, позволяющий создавать образы Docker и OCI для ваших Java-приложений. Он доступен в виде плагинов для Maven и Gradle, а также в виде Java-библиотеки.

Jib aims to be:

  • Быстро — Развертывайте изменения быстро. Jib разделяет ваше приложение на несколько слоев, отделяя зависимости от классов. Теперь вам не нужно ждать, пока Docker пересоберет все ваше Java-приложение — просто разверните те слои, которые изменились.
  • Воспроизводимость — Пересборка образа контейнера с тем же содержимым всегда приводит к созданию одного и того же образа. Больше никогда не будет запускаться ненужное обновление.
  • Daemonless — Сократите зависимость от командной строки. Создавайте образы Docker из Maven или Gradle и отправляйте их в любой выбранный вами реестр. Больше не нужно писать Dockerfile и вызывать команды `docker build`/`push`.

Более подробную информацию о Jib можно найти на странице проекта на Github.

Об этом уроке

В этом руководстве используется пример кода из инструмента Jib для создания контейнеров для Java-приложений.

В качестве примера представлен простой сервис "Hello World" , использующий фреймворк Micronaut и язык программирования Apache Groovy .

Что вы узнаете

  • Как упаковать простое Java-приложение в контейнер Docker с помощью Jib
  • Как создать кластер Kubernetes в Kubernetes Engine.
  • Как развернуть сервис Micronaut в Kubernetes на Kubernetes Engine
  • Как масштабировать сервис и внедрить обновление.
  • Как получить доступ к графической панели управления Kubernetes.

Что вам понадобится

  • Проект Google Cloud Platform
  • Браузер, например Chrome или Firefox.
  • Знание стандартных текстовых редакторов Linux, таких как Vim, EMACs или Nano.

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

Прочитайте только от начала до конца. Прочитайте текст и выполните упражнения.

Как бы вы оценили свой опыт разработки веб-приложений на HTML/CSS?

Новичок Средний Профессионал

Как бы вы оценили свой опыт использования сервисов Google Cloud Platform?

Новичок Средний Профессионал

2. Настройка и требования

Настройка среды для самостоятельного обучения

  1. Войдите в Cloud Console и создайте новый проект или используйте существующий. (Если у вас еще нет учетной записи Gmail или G Suite, вам необходимо ее создать .)

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

Запомните идентификатор проекта (Project ID) — уникальное имя для всех проектов Google Cloud (указанное выше имя уже занято и вам не подойдёт, извините!). В дальнейшем в этом практическом занятии оно будет обозначаться как PROJECT_ID .

  1. Далее вам потребуется включить оплату в Cloud Console, чтобы использовать ресурсы Google Cloud.

Выполнение этого практического задания не должно стоить дорого, если вообще что-либо. Обязательно следуйте инструкциям в разделе «Очистка», где указано, как отключить ресурсы, чтобы избежать дополнительных расходов после завершения этого урока. Новые пользователи Google Cloud имеют право на бесплатную пробную версию стоимостью 300 долларов США .

3. Получите исходный код примера Micronaut.

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

$ git clone https://github.com/GoogleContainerTools/jib.git
$ cd jib/examples/micronaut/

4. Краткий обзор кода

Наш простой сервис в Micronaut состоит из контроллера, который выводит печально известное сообщение "Hello World":

@Controller("/hello")
class HelloController {
    @Get("/")
    String index() {
        "Hello World"
    }
}

Контроллер HelloController отвечает на запросы по пути /hello , а метод index() принимает HTTP GET-запросы.

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

class HelloControllerSpec extends Specification {
    @Shared
    @AutoCleanup
    EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer)

    @Shared
    @AutoCleanup
    RxHttpClient client = embeddedServer.applicationContext.createBean(RxHttpClient, embeddedServer.getURL()) 

    void "test hello world response"() {
        when:
        HttpRequest request = HttpRequest.GET('/hello')
        String rsp  = client.toBlocking().retrieve(request)

        then:
        rsp == "Hello World"
    }
}

Этот тест — не просто модульный тест, он фактически запускает тот же серверный стек Micronaut (на основе фреймворка Netty ), который используется в производственной среде. Поэтому поведение вашего кода в продукте будет точно таким же, как и в тестах.

Для запуска тестов вы можете выполнить следующую команду, чтобы убедиться, что все в порядке:

./gradlew test

5. Запустите приложение локально.

Запустить службу Micronaut можно обычным способом с помощью следующей команды Gradle:

$ ./gradlew run

После запуска приложения вы можете открыть дополнительный экземпляр Cloud Shell, нажав на значок "+", а затем проверить с помощью команды curl, получаете ли вы ожидаемый результат:

$ curl localhost:8080/hello

И вы должны увидеть простое сообщение "Hello World".

6. Упакуйте приложение в контейнер Docker с помощью Jib.

Далее подготовьте ваше приложение к работе в Kubernetes. Для этого мы воспользуемся Jib, который выполнит всю сложную работу за нас, поскольку нам не придётся самостоятельно редактировать Dockerfile !

Давайте выполним команду для создания нашего контейнера:

$ ./gradlew jibDockerBuild

Вот результат, который вы должны увидеть:

Tagging image with generated image reference micronaut-jib:0.1. If you'd like to specify a different tag, you can set the jib.to.image parameter in your build.gradle, or use the --im
age=<MY IMAGE> commandline flag.

Containerizing application to Docker daemon as micronaut-jib:0.1...
warning: Base image 'gcr.io/distroless/java' does not use a specific image digest - build may not be reproducible
Getting base image gcr.io/distroless/java...
Building dependencies layer...
Building resources layer...
Building classes layer...
Finalizing...

Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, example.micronaut.Application]
Loading to Docker daemon...

Built image to Docker daemon as micronaut-jib:0.1

Теперь, когда наш образ создан, давайте проверим, видим ли мы наше дружелюбное приветственное сообщение, запустив наш образ Docker на первой вкладке Cloud Shell:

$ docker run -it -p 8080:8080 micronaut-jib:0.1
16:57:20.255 [main] INFO  i.m.context.env.DefaultEnvironment - Established active environments: [cloud, gcp]
16:57:23.203 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 2926ms. Server Running: http://97b7d76ccf3f:8080

Наша служба запущена, поэтому теперь мы можем запустить команду curl во второй вкладке Cloud Shell, чтобы проверить, работает ли она должным образом:

$ curl localhost:8080/hello
Hello World

Остановить контейнер можно, нажав Ctrl+C в Cloud Shell.

7. Загрузка нашего контейнеризированного сервиса в реестр.

Теперь, когда образ работает как положено, вы можете загрузить его в Google Container Registry — частный репозиторий для ваших образов Docker, доступный из любого проекта Google Cloud (а также и извне Google Cloud Platform).

Прежде чем отправлять изменения в реестр, убедитесь, что реестр контейнеров включен для вашего проекта, перейдя в меню Инструменты > Реестр контейнеров . Если он не включен, вы увидите следующее диалоговое окно; затем нажмите « Включить API реестра контейнеров », чтобы включить его:

ac812e6260ac7dfb.png

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

$ gcloud auth configure-docker
$ docker tag micronaut-jib:0.1 \
         gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1
$ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1

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

Если все пройдет успешно, через некоторое время вы должны увидеть образ контейнера в консоли: Инструменты > Реестр контейнеров . На этом этапе у вас будет доступен образ Docker для всего проекта, к которому Kubernetes сможет получить доступ и управлять им, как вы увидите через несколько минут.

12224c4e42183b4e.png

8. Создайте свой кластер

Итак, теперь вы готовы создать свой кластер Kubernetes Engine, но перед этим перейдите в раздел Google Kubernetes Engine в веб-консоли и дождитесь инициализации системы (это займет всего несколько секунд).

20c0587c0108b8ba.png

Кластер состоит из главного API-сервера Kubernetes, управляемого Google, и набора рабочих узлов. Рабочие узлы — это виртуальные машины Compute Engine. Давайте воспользуемся CLI gcloud из вашей сессии CloudShell, чтобы создать кластер с двумя узлами n1-standard-1 (это займет несколько минут):

$ gcloud container clusters create hello-cluster \
  --num-nodes 2 \
  --machine-type n1-standard-1 \
  --zone us-central1-c

В итоге вы должны увидеть созданный кластер.

Creating cluster hello-cluster in us-central1-c...done.
Created [https://container.googleapis.com/v1/projects/mn-gke-test/zones/us-central1-c/clusters/hello-cluster].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-c/hello-cluster?project=mn-gke-test
kubeconfig entry generated for hello-cluster.
NAME           LOCATION       MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
hello-cluster  us-central1-c  1.9.7-gke.7     35.239.224.115  n1-standard-1  1.9.7-gke.7   2          RUNNING

Теперь у вас должен быть полностью функционирующий кластер Kubernetes на базе Google Kubernetes Engine:

d9e1e314769753e7.png

Теперь пришло время развернуть ваше собственное контейнеризированное приложение в кластере Kubernetes! С этого момента вы будете использовать командную строку kubectl (уже настроенную в вашей среде Cloud Shell). Для выполнения остальной части этого практического задания требуется, чтобы версия клиента и сервера Kubernetes была 1.2 или выше. kubectl version покажет вам текущую версию команды.

9. Разверните ваше приложение в Kubernetes.

Развертывание в Kubernetes позволяет создавать, управлять и масштабировать несколько экземпляров вашего приложения, используя только что созданный образ контейнера. Давайте создадим развертывание вашего приложения в Kubernetes с помощью команды kubectl create deployment :

$ kubectl create deployment hello-micronaut \
  --image=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1

Чтобы просмотреть созданное вами развертывание, просто выполните следующую команду:

$ kubectl get deployments
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-micronaut   1         1         1            1           5m

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

$ kubectl get pods
NAME                               READY     STATUS    RESTARTS   AGE
hello-micronaut-5647fb98c5-lh5h7   1/1       Running   0          5m

На этом этапе ваш контейнер должен работать под управлением Kubernetes, но вам все еще необходимо обеспечить к нему доступ извне.

10. Разрешить внешний трафик

По умолчанию доступ к поду внутри кластера возможен только по его внутреннему IP-адресу. Чтобы контейнер hello-micronaut был доступен извне виртуальной сети Kubernetes, необходимо сделать под доступным в качестве сервиса Kubernetes.

Из Cloud Shell вы можете сделать под доступным из публичного интернета с помощью команды kubectl expose в сочетании с флагом --type=LoadBalancer . Этот флаг необходим для создания внешнего IP-адреса:

$ kubectl expose deployment hello-micronaut --type=LoadBalancer --port=8080

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

Главный узел Kubernetes создает балансировщик нагрузки и связанные с ним правила переадресации Compute Engine, целевые пулы и правила брандмауэра, чтобы обеспечить полную доступность сервиса извне платформы Google Cloud Platform.

Чтобы узнать общедоступный IP-адрес службы, просто запросите у kubectl вывод списка всех служб кластера:

$ kubectl get services
NAME              TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
hello-micronaut   LoadBalancer   10.39.243.251   aaa.bbb.ccc.ddd 8080:30354/TCP   1m
kubernetes        ClusterIP      10.39.240.1     <none>          443/TCP          31m

Обратите внимание, что для вашей службы указаны 2 IP-адреса, оба обслуживают порт 8080 Один из них — внутренний IP-адрес, видимый только внутри вашей виртуальной сети в облаке; другой — внешний IP-адрес с балансировкой нагрузки. В этом примере внешний IP-адрес — aaa.bbb.ccc.ddd .

Теперь вы сможете получить доступ к сервису, перейдя в браузере по следующему адресу: http://<EXTERNAL_IP> :8080 /hello

11. Расширьте масштабы своих услуг.

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

$ kubectl scale deployment hello-micronaut --replicas=3
deployment.extensions "hello-micronaut" scaled

$ kubectl get deployment
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-micronaut   3         3         3            3           16m

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

12. Внедрите обновление для вашей услуги.

В какой-то момент развернутому вами в продакшене приложению потребуется исправление ошибок или добавление новых функций. Kubernetes поможет вам развернуть новую версию в продакшене без ущерба для пользователей.

Для начала давайте изменим приложение. Откройте редактор кода в Cloud Shell.

5aee8f3d1e003571.png

Перейдите в папку /jib/examples/micronaut/src/main/groovy/example/micronaut/HelloController.groovy и обновите значение ответа:

@Controller("/hello")
class HelloController {
    @Get("/")
    String index() {
        "Hello Kubernetes World"
    }
}

В файле /jib/examples/micronaut/build.gradle мы обновим версию нашего образа с 0.1 до 0.2, изменив следующую строку:

version '0.2'

Затем пересоберите и упакуйте приложение с учетом последних изменений:

$ ./gradlew jibDockerBuild

А затем пометить и загрузить образ в реестр образов контейнеров:

$ docker tag micronaut-jib:0.2 \
         gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2
$ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2

Теперь вы готовы к тому, чтобы Kubernetes плавно обновил ваш контроллер репликации до новой версии приложения. Чтобы изменить метку образа для запущенного контейнера, вам необходимо отредактировать существующее hello-micronaut deployment и изменить образ с gcr.io/PROJECT_ID/micronaut-jib:0.1 на gcr.io/PROJECT_ID/micronaut-jib:0.2 .

С помощью команды kubectl set image вы можете попросить Kubernetes развернуть новую версию вашего приложения по всему кластеру, по одному экземпляру за раз, с использованием скользящего обновления:

$ kubectl set image deployment/hello-micronaut \
          micronaut-jib=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2

deployment.apps "hello-micronaut" image updated

Проверьте еще раз адрес http://EXTERNAL_IP:8080, чтобы убедиться, что он возвращает новый ответ.

13. Откат назад

Ой — вы допустили ошибку в новой версии приложения? Возможно, в новой версии обнаружилась ошибка, и вам нужно быстро откатить изменения. В Kubernetes это можно сделать легко. Давайте откатим приложение, выполнив команду:

$ kubectl rollout undo deployment/hello-micronaut

Если вы посмотрите на вывод сервиса, мы вернемся к нашему первоначальному сообщению "Hello World".

14. Резюме

На этом этапе вы настроили простой сервис Micronaut "hello world" на основе Apache Groovy и запустили его непосредственно из Cloud Shell, упаковали его в контейнер с помощью Jib и развернули в Google Kubernetes Engine.

15. Поздравляем!

Вы научились создавать и развертывать новый веб-микросервис на основе Apache Groovy / Micronaut в Kubernetes на платформе Google Kubernetes Engine.

Узнать больше

Лицензия

Данная работа распространяется под лицензией Creative Commons Attribution 2.0 Generic.