Наш эксперт Михаил Сергеев подготовил подробный материал (в двух форматах: статья и видеоурок), в этом уроке:
- Расскажем, что такое K3s
- Рассмотрим отличия Stateful и Stateless;
- Установим K3s на ВМ;
- Сделаем домен, SSL-сертификат и внешний доступ к нашему приложению;
- Установим Stateful приложение — WordРress;
- Установим Mariadb в K3s.
Расскажем, что такое K3s
K3s - это легковесный дистрибутив Kubernetes, разработанный компанией Rancher Labs. K3s был создан для того, чтобы предоставить простой и удобный способ установки, использования и управления Kubernetes.
K3s потребляет меньше оперативной памяти и меньше CPU, чем полноценная установка Kubernetes. Он имеет небольшой размер (устанавливается всего за 30 секунд одной командой и сразу готов к работе) и может быть запущен на различных устройствах, например, Raspberry Pi. K3s можно легко масштабировать на несколько нод (node).
Raspberry Pi — одноплатный компьютер габаритами с банковскую карту, изначально разработанный в качестве бюджетной системы для обучения информатике, но позднее получивший более широкое применение и известность. Разработан британской компанией Raspberry Pi Foundation во главе с Эбеном Аптоном.
K3s поддерживает все основные функции Kubernetes, включая автоматическое масштабирование, хранение данных, сетевую настройку и управление ресурсами.
Рассмотрим отличия Stateful и Stateless
Сначала рассмотрим Stateful и Stateless приложения. Сетевые приложения условно делятся на Stateful (с сохранением состояния) и Stateless (без сохранения состояния).
Stateless приложения не хранят информацию о состоянии клиента и обрабатывают каждый запрос независимо. Вся необходимая информация передается с каждым запросом, часто в виде токена аутентификации.
Stateful приложения сохраняют информацию о состоянии (например, данные сессии, историю запросов, персональные данные и т.д.) на сервере или в базе данных. Большинство Stateful приложений требуют наличия хранилища, доступ к которому должен быть у каждой node (сетевого устройства). Если у вас одна node, то можно использовать локальное хранилище, а если их несколько, то необходимо отдельное сетевое хранилище. Единственный минус сетевых хранилищ - это их медленность.
Stateless подход упрощает масштабирование, так как нет необходимости хранить состояние между запросами.
Со Stateless приложениями всё проще, вы при создании образа весь свой код приложения копируете в этот образ, разворачиваете под (pod) и его масштабируете на множество node, и у вас всё необходимое уже содержится в этом поде. Но в этом уроке мы будем рассматривать однонодовый k3s c локальным хранилищем. А в качестве рассматриваемого приложения выступит WordPress.
Pods (Поды) — базовые строительные блоки Kubernetes. Обычно под подом понимают сущность, состоящую из одного или нескольких контейнеров, размещённых на одном хосте и настроенных на совместное использование ресурсов сетевого стека и других ресурсов наподобие томов.
WordPress — это популярная система управления содержимым (CMS) для создания и управления веб-сайтами. Она предоставляет простой интерфейс и расширяемость с помощью плагинов и тем для настройки функциональности и внешнего вида сайта.
Установим K3s на ВМ
Перейдём на официальный сайт k3s https://k3s.io/ и посмотрим его документацию с описанием установки.
Далее смотрим системные требования и возможные параметры установки. Мы будем выставлять установки по умолчанию (дефолтные). Нам этого будет вполне достаточно.
Устанавливать k3s мы будем в облаке Corpsoft24. Для этого я сделал виртуальную машину на Ubuntu 22.04.2 LTS (Jammy Jellyfish). Это чистая машина с максимальными обновлениями, 12 Гб оперативной памяти, 4 CPU, 100 Гб свободного дискового места и внешним IP-адресом 194.126.162.54.
Необходимые команды:
# установить k3s: curl -sfL https://get.k3s.io | sh - # посмотреть статус k3s: service k3s status
#Используемые в уроке алиасы: echo "alias k='kubectl'" >> ~/.bashrc echo "alias kg='kubectl get'" >> ~/.bashrc echo "alias kgp='kubectl get po'" >> ~/.bashrc echo "alias kd='kubectl delete -f'" >> ~/.bashrc echo "alias ka='kubectl apply -f'" >> ~/.bashrc echo "alias ke='kubectl exec -it'" >> ~/.bashrc echo "alias k1='kubectl describe'" >> ~/.bashrc echo "alias kl='kubectl logs'" >> ~/.bashrc echo "alias kgs='kubectl get svc -A'" >> ~/.bashrc echo "alias kr='kubectl rollout restart deployment'" >> ~/.bashrc echo "alias krs='kubectl rollout restart sts'" >> ~/.bashrc echo "alias krd='kubectl rollout restart ds'" >> ~/.bashrc echo "alias kpa='kubectl get po -A'" >> ~/.bashrc source ~/.bashrc
Также выкладываю ссылку на список Ингрессов — смотреть
Первое, что нам нужно — это хелм (helm). Как показывает практика, по умолчанию его тут нет. Для этого мы идём на официальный сайт https://helm.sh/, скачиваем скрипт, даём ему права на выполнение и устанавливаем.
Helm — это инструмент развертывания Kubernetes для автоматизации создания, упаковки, настройки и развертывания приложений и служб в кластерах Kubernetes.
Установка helm:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Запускаем helm и проводим его настройку.
Теперь установим Nginx с помощью заранее подготовленного скрипта.
####### INSTALL Nginx HELM mkdir /home/ms/helms -p cd /home/ms/helms helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update helm pull ingress-nginx/ingress-nginx tar zxf ingress-nginx-4.6.0.tgz rm ingress-nginx-4.6.0.tgz -f cp ingress-nginx/values.yaml ingress-nginx-values.yaml vi ingress-nginx-values.yaml helm upgrade --install ingress-nginx -f ingress-nginx-values.yaml ingress-nginx/ kubectl patch svc ingress-nginx-controller -p '{"spec":{"externalTrafficPolicy":"Local"}}' k edit cm ingress-nginx-controller data: use-forwarded-headers: 'true' kr ingress-nginx-controller #############################
Затем устанавливаем cert-manager, также с помощью заранее подготовленного скрипта.
####### INSTALL CERTMANAGER HELM mkdir /home/ms/helms -p cd /home/ms/helms helm repo add jetstack https://charts.jetstack.io helm repo update helm pull jetstack/cert-manager tar zxf cert-manager-*.tgz rm cert-manager-*.tgz -f cp cert-manager/values.yaml cert-manager-values.yaml helm upgrade --install cert-manager -f cert-manager-values.yaml cert-manager/ --set installCRDs=true mkdir /home/ms/ci/ -p cd /home/ms/ci cat << \EOF > cert-manager-issuer.yaml --- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: email: mail@msergeev.ru server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-prod solvers: - http01: ingress: class: nginx EOF ka cert-manager-issuer.yaml #############################
Сделаем домен, SSL-сертификат и внешний доступ к нашему приложению
Ещё есть такая вещь, как Portainer — это платформа для управления доставкой контейнерных приложений, которая может использоваться для управления средами Docker, Docker Swarm, Kubernetes и ACI. С помощью неё через веб-интерфейс можно управлять кластером Kubernetes, смотреть логи подов, зайти в консоль. Ему будет необходим Volumes в котором будут храниться его данные.
Volumes — инструмент, отключающий привязку данных к жизненному циклу контейнера, позволяя получить доступ к контейнерным данным в любой момент. Таким образом, сделанные в контейнерах записи остаются доступными после уничтожения содержавшего их контейнера и могут повторно использоваться в других.
####### INSTALL PORTAINER mkdir /data/ -p chmod 777 -R /data/ mkdir -p /data/volumes/portainer chmod 777 /data/volumes/portainer mkdir /home/ms/pvc -p cd /home/ms/pvc cat << \EOF > portainerpv.yml --- kind: PersistentVolume apiVersion: v1 metadata: name: portainer namespace: default labels: type: local spec: storageClassName: local-path capacity: storage: 20Gi accessModes: - ReadWriteOnce hostPath: path: "/data/volumes/portainer" ... EOF ka portainerpv.yml cd /home/ms/pvc cat << \EOF > portainerpvc.yml --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: portainer namespace: default spec: storageClassName: local-path accessModes: - ReadWriteOnce resources: requests: storage: 20Gi ... EOF ka portainerpvc.yml mkdir /home/ms/helms -p cd /home/ms/helms ### portainer helm repo add portainer https://portainer.github.io/k8s/ helm repo update helm pull portainer/portainer tar zxf portainer-* rm portainer-* -f cp portainer/values.yaml portainer-values.yaml vi portainer-values.yaml #### !!!!! Change NodePort to ClusterIP cd /home/ms/helms helm upgrade --install portainer -f portainer-values.yaml portainer/ mkdir /home/ms/ingress/ -p cd /home/ms/ingress cat << \EOF > portainer-ingress.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: portainer-ingress namespace: default annotations: nginx.ingress.kubernetes.io/whitelist-source-range: 78.47.67.129/32 cert-manager.io/cluster-issuer: letsencrypt-prod spec: rules: - host: portainer.194.126.162.54.sslip.io http: paths: - path: / pathType: Prefix backend: service: name: portainer port: number: 9000 ingressClassName: nginx tls: - hosts: - portainer.194.126.162.54.sslip.io secretName: portainer-ssl EOF ka portainer-ingress.yaml url: portainer.194.126.162.54.sslip.io login: ms pass: Cfeg65vd3rDSer3tr34111111111ddf ####################################
Из важных моментов нужно прописать IP-адреса, с которых разрешён вход в наш Portainer. Например, мы разрешаем вход только с IP-адреса 78.47.67.129/32, поскольку защита паролем ещё не гарантирует полную безопасность. Далее создаём SSL-сертификат.
SSL-сертификат – это цифровой сертификат, удостоверяющий подлинность веб-сайта и позволяющий использовать зашифрованное соединение.
Теперь установим POSTGRESQL HELM.
######### POSTGRESQL HELM mkdir -p /data/volumes/postgresql chmod 777 /data/volumes/postgresql mkdir /home/ms/pvc -p cd /home/ms/pvc cat << \EOF > postgresqlpv.yml --- kind: PersistentVolume apiVersion: v1 metadata: name: postgresql namespace: default labels: type: local spec: storageClassName: local-path capacity: storage: 100Gi accessModes: - ReadWriteOnce hostPath: path: "/data/volumes/postgresql" ... EOF ka postgresqlpv.yml cd /home/ms/pvc cat << \EOF > postgresqlpvc.yml --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: postgresql namespace: default spec: storageClassName: local-path accessModes: - ReadWriteOnce resources: requests: storage: 100Gi ... EOF ka postgresqlpvc.yml mkdir /home/ms/helms -p cd /home/ms/helms ### postgresql helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update helm pull bitnami/postgresql tar zxf postgresql-* rm postgresql-* -f cp postgresql/values.yaml postgresql-values.yaml vi postgresql-values.yaml helm upgrade --install postgresql -f postgresql-values.yaml postgresql/ kubectl get secret postgresql -o jsonpath="{.data.postgres-password}" | base64 -d ke postgresql-0 -- bash PGPASSWORD="Hc2w6hIok4" psql --host 127.0.0.1 -U postgres -d postgres -p 5432 CREATE DATABASE wp; CREATE USER wp WITH PASSWORD 'S2IBBRMefi0m2p0new3Q'; GRANT ALL PRIVILEGES ON DATABASE wp to wp; HOST: postgresql DATABASE: wp USER: wp PASSWORD: S2IBBRMefi0m2p0new3Q #######################
Установим Stateful приложение — WordРress
Теперь установим WordPress.
######### WORDPRESS HELM mkdir -p /data/volumes/wordpress /data/volumes/wordpressdb chmod 777 /data/volumes/wordpress /data/volumes/wordpressdb mkdir /home/ms/pvc -p cd /home/ms/pvc cat << \EOF > wordpresspv.yml --- kind: PersistentVolume apiVersion: v1 metadata: name: wordpress namespace: default labels: type: local spec: storageClassName: local-path capacity: storage: 100Gi accessModes: - ReadWriteOnce hostPath: path: "/data/volumes/wordpress" ... EOF cat << \EOF > wordpressdbpv.yml --- kind: PersistentVolume apiVersion: v1 metadata: name: wordpressdb namespace: default labels: type: local spec: storageClassName: local-path capacity: storage: 100Gi accessModes: - ReadWriteOnce hostPath: path: "/data/volumes/wordpressdb" ... EOF ka wordpresspv.yml ka wordpressdbpv.yml cd /home/ms/pvc cat << \EOF > wordpresspvc.yml --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: wordpress namespace: default spec: storageClassName: local-path accessModes: - ReadWriteOnce resources: requests: storage: 100Gi ... EOF cat << \EOF > wordpressdbpvc.yml --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: wordpressdb namespace: default spec: storageClassName: local-path accessModes: - ReadWriteOnce resources: requests: storage: 100Gi ... EOF ka wordpresspvc.yml ka wordpressdbpvc.yml mkdir /home/ms/helms -p cd /home/ms/helms helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update helm pull bitnami/wordpress tar zxf wordpress-* rm wordpress-* -f cp wordpress/values.yaml wordpress-values.yaml vi wordpress-values.yaml # Loadbalancer to ClusterIP helm upgrade --install wordpress -f wordpress-values.yaml wordpress/ mkdir /home/ms/ingress/ -p cd /home/ms/ingress cat << \EOF > wordpress-ingress.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: wordpress-ingress namespace: default annotations: nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0 cert-manager.io/cluster-issuer: letsencrypt-prod spec: rules: - host: wordpress.194.126.162.54.sslip.io http: paths: - path: / pathType: Prefix backend: service: name: wordpress port: number: 80 ingressClassName: nginx tls: - hosts: - wordpress.194.126.162.54.sslip.io secretName: wordpress-ssl EOF ka wordpress-ingress.yaml user kubectl get secret --namespace default wordpress -o jsonpath="{.data.wordpress-password}" | base64 -d VxHGG7WQcW # Удалить k3s /usr/local/bin/k3s-uninstall.sh
Установим Mariadb в K3s
Она устанавливается автоматически совместно с WordPress из одного хелма (helm). Почитать её описание можно на официальном сайте https://mariadb.org/.
В конце урока мы удаляем все следы своих экспериментов. Это обычно требуется для поддержания дискового пространства в чистоте, чтобы не засорять его файлами, оставшимися от прошлых проектов.