Kubernetes. Часть 2. Hello World with Minikube
PREREQUISITES
В статье предполагаются базовые знания:
- Docker
- Spring Boot
Также предполагается наличие инструментария:
- Docker
- Инструменты для Java разработки: Java, Maven
ЦЕЛЬ
- Установить и настроить Minikube;
- Создать два простейших Spring Boot приложения;
- Упаковать их в Docker;
- Развернуть их в Minikube.
ЧТО ТАКОЕ MINIKUBE
Для локального развёртывания кластера Kubernetes мы будем использовать Minikube - инструмент, позволяющий легко запускать Kubernetes на локальной машине. Кластер, таким образом, будет состоять по факту из одной локальной ноды.
По большому счету, при обучении работе с Kubernetes, не важно сколько именно узлов присутствует в кластере, так как Kubernetes все равно позволяет абстрагироваться от этих деталей.
УСТАНОВКА MINIKUBE И СВЯЗАННОГО ИНСТРУМЕНТАРИЯ
Подготовка
sudo apt-get update -y
sudo apt-get upgrade -y
Устанавка virtualbox
sudo apt install virtualbox virtualbox-ext-pack
На консоли появится лицензионное соглашение. Нажмем Tab и Enter.
В следующем окне выберем "Да":
Установка Minikube
wget https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo cp minikube-linux-amd64 /usr/local/bin/minikube
sudo chmod 755 /usr/local/bin/minikube
minikube version
Установка Kubectl
curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
kubectl version -o json
Запуск Minikube
minikube start
Осталось сконфигурировать Minikube на работу с VirtualBox:
minikube config set vm-driver virtualbox
А также kubectl на работу с Minikube:
kubectl config use-context minikube
Теперь запросим информацию о нашем кластере через kubectl:
kubectl cluster-info
и увидим примерно следующий вывод:
Поздравляем! Процесс установки и настройки Minikube прошел успешно.
Мы даже можем открыть Kubernetes dashboard в браузере. Для этого надо исполнить:
minikube dashboard
и вы увидите в браузере следующую страничку:
СОЗДАНИЕ ПРИЛОЖЕНИЙ ДЛЯ РАЗВЕРТЫВАНИЯ
Теперь создадим два простых Spring Boot приложения, которые условно назовем
- mk-backend
- mk-frontend
mk-backend будет предоставлять REST-ендпоинт на 8085 порту, возвращающий текст "Hello Kubernetes!".
mk-frontend будет доступен на 8081 порту. Всё, что он будет делать - он будет обращаться к mk-backend и возвращать результат.
(1) Создание mk-backend
С помощью Spring Initializr создадим проект:
Добавим в него контроллер:
package com.example.mkbackend.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping
public class BackendController {
@GetMapping(value = "/")
public String hello() {
return "Hello Kubernetes!";
}
}
Отредактируем application.properties:
server.port=8085
Соберем проект maven-ом:
./mvnw clean install
Создадим Dockerfile:
FROM openjdk:11
VOLUME /tmp
COPY target/mk-backend-0.0.1-SNAPSHOT.jar app.jar
ENV JAVA_OPTS=""
ENTRYPOINT exec java -jar /app.jar --debug
(2) Создание mk-frontend
С помощью Spring Initializr создадим проект:
Добавим в него контроллер:
package com.example.mkfrontend.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping
public class FrontendController {
private static final String BACKEND_URL = "http://mk-backend:8085";
@GetMapping(value = "/")
public String hello() {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.getForEntity(BACKEND_URL, String.class);
return ":" + response.getBody();
}
}
Отредактируем application.properties:
server.port=8081
Соберем проект maven-ом:
./mvnw clean install
Создадим Dockerfile:
FROM openjdk:11
VOLUME /tmp
COPY target/mk-frontend-0.0.1-SNAPSHOT.jar app.jar
ENV JAVA_OPTS=""
ENTRYPOINT exec java -jar /app.jar
СОЗДАНИЕ DOCKER-ОБРАЗОВ
Docker-образы мы будем создавать именно в виртуальной машине с Minikube - это важно. Для этого нам нужно перекинуть наши исходники на виртуалку с Minikube.
Воспользуемся для этих целей обычным scp. Однако тут есть нюанс. Сначала нужно узнать логин/пароль этой машины.
# Подключаемся к виртуальной машине с Minikube:
minikube ssh
# Меняем пароль пользователя docker:
sudo passwd docker
# Запоминаем пароль
# Выходим из виртуальной машины:
exit
Далее переходим в папку с проектами и копируем mk-backend на машину с Minikube:
scp -r mk-backend docker@192.168.59.100:/home/docker/mk-backend
Аналогично копируем mk-frontend:
scp -r mk-frontend docker@192.168.59.100:/home/docker/mk-frontend
Теперь снова заходим в Minikube:
minikube ssh
и собираем Docker-образы:
cd mk-backend
docker build --file=Dockerfile --tag=mk-backend:latest --rm=true .
cd ..
cd mk-frontend
docker build --file=Dockerfile --tag=mk-frontend:latest --rm=true .
Убедимся, что образы действительно созданы:
docker images
Итак, мы создали docker-образы наших проектов на виртуальной машине с Minikube.
Теперь выходим из виртуальной машины:
exit
Все дальнейшие шаги будут выполняться через утилиту kubectl и инструменты командной строки Minikube.
СПОСОБЫ РАЗВЕРТЫВАНИЯ В KUBERNETES
Чтобы развернуть контейнеры в инфраструктуре Kubernetes, можно пойти двумя путями:
- Разворачивать поды вручную, поочередно вводя команды Kubectl;
- Разворачивать поды, используя конфигурационные файлы.
Мы будем разворачивать более стационарным способом - с использованием конфигурационных файлов.
СОЗДАНИЕ КОНФИГУРАЦИЙ KUBERNETES
Создадим конфигурацию kubernetes.yml для развертывания mk-backend:
kind: Service
apiVersion: v1
metadata:
name: mk-backend
spec:
selector:
app: mk-backend
ports:
- protocol: TCP
port: 8085
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mk-backend
spec:
selector:
matchLabels:
app: mk-backend
replicas: 3
template:
metadata:
labels:
app: mk-backend
spec:
containers:
- name: mk-backend
image: mk-backend:latest
imagePullPolicy: Never
ports:
- containerPort: 8085
Данным файлом мы описываем две вещи:
- Сервис
- Deployment
Рассмотрим каждый элемент отдельно.
Сервис
Сервисы Kubernetes играют роль точек доступа к наборам подов. В случае mk-backend сервис имеет тип ClusterIP. Сервис такого типа предоставляет доступ через внутренний IP кластера. Таким образом – сервис будет доступен только внутри самого класетра.
Мы назвали сервис mk-backend.
С помощью блока spec мы проинструктировали Kubernetes перенаправлять все TCP-запросы к порту 8085 на любой POD, помеченный лейблом mk-backend.
Сервис ClusterIP также осуществляет балансировку нагрузки на POD-ы.
Deployment
Deployment — это абстракция Kubernetes, которая позволяют нам задавать правила развертывания приложений.
Блок template определяет POD:
- Помечаем создаваемый POD лейблом в блоке labels (в данном случае mk-backend)
- В блоке containers определяем перечень контейнеров, входящих в POD (в данном случае это будет один контейнер mk-backend)
Блок spec:selector определяет какие POD-ы нужно развернуть. В данном случае мы просто передаем объявленный POD mk-backend.
Наконец, Kubernetes легко позволяет создать несколько реплик одного POD-а с помощью тега replicas.
Аналогичным образом определяем конфигурацию Kubernetes для проекта mk-frontend:
kind: Service
apiVersion: v1
metadata:
name: mk-frontend
spec:
selector:
app: mk-frontend
ports:
- protocol: TCP
port: 8081
nodePort: 30001
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mk-frontend
spec:
selector:
matchLabels:
app: mk-frontend
replicas: 3
template:
metadata:
labels:
app: mk-frontend
spec:
containers:
- name: mk-frontend
image: mk-frontend:latest
imagePullPolicy: Never
ports:
- containerPort: 8081
Эта конфигурация очень похожа на предыдущую. Отличия её лишь в номере порта и типе сервиса. Тип сервиса - это в данном случае NodePort, поскольку ClusterIP предоставляет доступ лишь внутри Kubernetes кластера, а NodePort дает доступ извне, что и нужно в случае приложения mk-frontend.
РАЗВЕРТЫВАНИЕ
Итак, приложения созданы, docker-образы уже на виртуальной машине Minikube, конфигурации Kubernetes написаны. Приступаем к развертыванию Kubernetes кластера.
Переходим в директорию mk-backend и запускаем развертывание:
kubectl create -f kubernetes.yml
Перечень существующих развертываний мы теперь можем посмотреть с помощью следующей команды:
kubectl get deployments
Аналогичным образом взглянем на список сервисов:
kubectl get services
Если процесс развертывания прошел правильно, мы увидим на консоли следующее:
Теперь аналогичным образом разворачиваем mk-frontend. Переходим в директорию mk-frontend и выполняем:
kubectl create -f kubernetes.yml
РЕЗУЛЬТАТ
Поздравления! Мы сконфигурировали и запустили кластер. Следующая команда
minikube service mk-frontend
запустит браузер на нашем хосте, где мы сможем увидеть результат:
ПОВТОРНЫЙ ВХОД
После перезапуска рабочего PC необходимо запустить Minikube и развернуть все заново:
minikube start --driver=virtualbox
cd Projects/mk-backend
kubectl create -f kubernetes.yml
cd ..
cd mk-frontend
kubectl create -f kubernetes.yml
minikube service mk-frontend
TROUBLESHOOTING
Проверить доступность сервисов можно следующим образом:
# Приконнектиться к Minikube
minikube ssh
# Получить список развернутых Docker-контейнеров:
docker ps -a
# Войти в любой из контейнеров:
docker exec -it 5832775209d3 /bin/bash
# Ипользовать curl, чтобы протестировать endpoint:
curl 127.0.0.1:8081
ОБНОВЛЕНИЕ DOCKER-ОБРАЗОВ
Disclaimer: В данном примере обновление будет выполняться неоптимальным образом. Тем не менее:
1) Удалить сервисы и deployment-ы:
kubectl delete service mk-frontend
kubectl delete deployment mk-frontend
kubectl delete service mk-backend
kubectl delete deployment mk-backend
2) Пересобрать проекты maven-ом
3) Залить заново проекты в Minikube:
scp -r mk-backend docker@192.168.59.100:/home/docker/mk-backend
scp -r mk-frontend docker@192.168.59.100:/home/docker/mk-frontend
4) Собрать новые образы:
minikube ssh
cd mk-backend
docker build --file=Dockerfile --tag=mk-backend:latest --rm=true .
cd..
cd mk-frontend
docker build --file=Dockerfile --tag=mk-frontend:latest --rm=true .
exit
cd mk-backend
kubectl create -f kubernetes.yml
cd ..
cd mk-frontend
kubectl create -f kubernetes.yml
minikube service mk-frontend
СПРАВОЧНЫЕ КОМАНДЫ
# Запустить minikube:
minikube start --driver=virtualbox
# Отобразить сервисы:
kubectl get services
# Отобразить список POD-ов:
kubectl get pods --all-namespaces
# Отобразить логи по POD-у "mk-frontend-c8d7bd787-sxr6v":
kubectl logs mk-frontend-c8d7bd787-sxr6v
# Удалить сервисы и deployment-ы:
kubectl delete service mk-frontend
kubectl delete deployment mk-frontend
kubectl delete service mk-backend
kubectl delete deployment mk-backend
# Удалить POD c8d7bd787:
kubectl delete pod c8d7bd787
ССЫЛКИ НА ЛИТЕРАТУРУ
baeldung.com/spring-boot-minikube