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 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. Настройка и требования
Настройка среды для самостоятельного обучения
- Войдите в Cloud Console и создайте новый проект или используйте существующий. (Если у вас еще нет учетной записи Gmail или G Suite, вам необходимо ее создать .)
Запомните идентификатор проекта (Project ID) — уникальное имя для всех проектов Google Cloud (указанное выше имя уже занято и вам не подойдёт, извините!). В дальнейшем в этом практическом занятии оно будет обозначаться как PROJECT_ID .
- Далее вам потребуется включить оплату в 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 реестра контейнеров », чтобы включить его:

После того как реестр будет готов, для отправки образа в реестр выполните следующие команды:
$ 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 сможет получить доступ и управлять им, как вы увидите через несколько минут.

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

Кластер состоит из главного 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:

Теперь пришло время развернуть ваше собственное контейнеризированное приложение в кластере 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.

Перейдите в папку /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.
Узнать больше
- Документация и примеры Jib: https://github.com/GoogleContainerTools/jib/
- Веб-сайт Micronaut: http://micronaut.io/
- Java на платформе Google Cloud: https://cloud.google.com/java/
- Примеры на Java: https://cloud.google.com/java/samples
- Более подробное и полное руководство по Kubernetes можно найти по ссылке bit.ly/k8s-lab, где описан процесс развертывания полнофункционального приложения.
Лицензия
Данная работа распространяется под лицензией Creative Commons Attribution 2.0 Generic.