Add kubeadm example (#4)

* Add kubeadm example

* Fix dns

---------

Co-authored-by: Fedor Batonogov <f.batonogov@yandex.ru>
This commit is contained in:
github-actions[bot]
2024-04-25 19:37:15 +03:00
committed by GitHub
parent 346360f820
commit 07fb0c68bf
22 changed files with 1322 additions and 1 deletions

10
.gitignore vendored
View File

@@ -39,5 +39,15 @@ terraform.rc
# End of https://www.toptal.com/developers/gitignore/api/terraform
# Created by https://www.toptal.com/developers/gitignore/api/ansible
# Edit at https://www.toptal.com/developers/gitignore?templates=ansible
### Ansible ###
*.retry
# End of https://www.toptal.com/developers/gitignore/api/ansible
# Other
.vscode
.DS_Store
ansible/secrets

View File

@@ -1 +1,13 @@
# learn-devops
## Мы стремимся подходу **Инфраструктура как код**
Основная идея **Infrastructure as Code (IaC)** в том, чтобы **описать инфраструктуру кодом** и сделать её доступной для понимания. IaC работает со всеми компонентами инфраструктуры так, будто это просто данные. Такое стало возможно благодаря умению платформ виртуализации и облачных провайдеров разделять инфраструктуру и оборудование, а для управления серверами, хранилищами и сетевыми устройствами предоставлять специальное API.
## Структура проекта
0. [kubeadm](./kubeadm/) - это инструмент для простого и быстрого развёртывания кластера Kubernetes.
1. [OpenTofu](./opnetofu) — программное обеспечение с **открытым исходным кодом**, используемое для **управления внешними ресурсами** (например, в рамках модели **инфраструктура как код**). Проект Linux Foundation. Пользователи определяют и предоставляют инфраструктуру центра обработки данных с помощью **декларативного языка конфигурации**, известного как HashiCorp Configuration Language (HCL) или JSON.
2. [Ansible](./ansible) — система управления конфигурациями, написанная на языке программирования **Python**, с использованием **декларативного языка разметки** для **описания конфигураций**. Применяется для **автоматизации настройки и развёртывания программного обеспечения**.

8
ansible/ansible.cfg Normal file
View File

@@ -0,0 +1,8 @@
[defaults]
timeout=60
roles_path=./roles
inventory=./inventory.yml
forks=100
serial=10
host_key_checking=False
callbacks_enabled=ansible.posix.profile_tasks

21
ansible/inventory.yml Normal file
View File

@@ -0,0 +1,21 @@
kubeadm:
children:
kubeadm_control_plane:
hosts:
kubeadm-cp-01:
ansible_host: 10.0.70.70
kubeadm-cp-02:
ansible_host: 10.0.70.78
kubeadm-cp-03:
ansible_host: 10.0.70.79
kubeadm_nodes:
hosts:
kubeadm-node-01:
ansible_host: 10.0.70.71
kubeadm-node-02:
ansible_host: 10.0.70.77
kubeadm-node-03:
ansible_host: 10.0.70.74
vars:
ansible_user: infra
ansible_port: 22

101
ansible/kubeadm.yml Normal file
View File

@@ -0,0 +1,101 @@
# Запустите сервисы как статические подсистемы
# https://github.com/kubernetes/kubeadm/blob/main/docs/ha-considerations.md#option-2-run-the-services-as-static-pods
- name: Настраиваю keepalived + haproxy
become: true
hosts:
- kubeadm_control_plane
roles:
- haproxy_static_pods
- name: Разворачиваю kubernetes кластер
become: true
hosts:
- kubeadm
handlers:
- name: Перезагружаю виртуальные машины
ansible.builtin.reboot:
tasks:
- name: Добавляю модули br_netfilter и overlay
community.general.modprobe:
name: '{{ item }}'
state: present
with_items:
- br_netfilter
- overlay
# notify:
# - Перезагружаю виртуальные машины
- name: Добавляю модули br_netfilter и overlay в /etc/modules
ansible.builtin.lineinfile:
path: /etc/modules
line: '{{ item }}'
create: true
with_items:
- br_netfilter
- overlay
# notify:
# - Перезагружаю виртуальные машины
- name: Включаю маршрутизацию IP и iptables для моста
ansible.posix.sysctl:
name: '{{ item }}'
value: 1
state: present
with_items:
- net.ipv4.ip_forward
- net.bridge.bridge-nf-call-iptables
- name: Устанавливаю пакеты
ansible.builtin.apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gpg
- software-properties-common
update_cache: true
- name: Добавляю gpg ключ для репозиториев Kubernetes и cri-o
ansible.builtin.apt_key:
url: '{{ item["url"] }}'
state: present
keyring: '{{ item["keyring"] }}'
with_items:
- {url: "https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key", keyring: "/etc/apt/keyrings/kubernetes-apt-keyring.gpg"}
- {url: "https://pkgs.k8s.io/addons:/cri-o:/prerelease:/main/deb/Release.key", keyring: "/etc/apt/keyrings/cri-o-apt-keyring.gpg"}
- name: Добавляю репозитории Kubernetes и cri-o
ansible.builtin.apt_repository:
repo: '{{ item }}'
state: present
with_items:
- deb [signed-by=/etc/apt/keyrings/cri-o-apt-keyring.gpg] https://pkgs.k8s.io/addons:/cri-o:/prerelease:/main/deb/ /
- deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /
- name: Устанавливаю пакеты kubelet, kubeadm, kubectl и cri-o
ansible.builtin.apt:
name:
- kubelet
- kubeadm
- kubectl
- cri-o
state: present
update_cache: true
- name: Предотвращаю обновление kubelet, kubeadm и kubectl
ansible.builtin.dpkg_selections:
name: '{{ item }}'
selection: hold
with_items:
- kubelet
- kubeadm
- kubectl
- name: Включаю и запускаю службы kubelet и cri-o
ansible.builtin.systemd:
name: '{{ item }}'
enabled: true
state: started
with_items:
- kubelet
- crio

View File

@@ -0,0 +1,11 @@
#!/bin/sh
errorExit() {
echo "*** $*" 1>&2
exit 1
}
curl --silent --max-time 2 --insecure https://localhost:7443/ -o /dev/null || errorExit "Error GET https://localhost:7443/"
if ip addr | grep -q 10.0.70.85; then
curl --silent --max-time 2 --insecure https://10.0.70.85:7443/ -o /dev/null || errorExit "Error GET https://10.0.70.85:7443/"
fi

View File

@@ -0,0 +1,52 @@
# /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
log /dev/log local0
log /dev/log local1 notice
daemon
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 1
timeout http-request 10s
timeout queue 20s
timeout connect 5s
timeout client 20s
timeout server 20s
timeout http-keep-alive 10s
timeout check 10s
#---------------------------------------------------------------------
# apiserver frontend which proxys to the control plane nodes
#---------------------------------------------------------------------
frontend apiserver
bind *:7443
mode tcp
option tcplog
default_backend apiserverbackend
#---------------------------------------------------------------------
# round robin balancing for apiserver
#---------------------------------------------------------------------
backend apiserverbackend
option httpchk GET /healthz
http-check expect status 200
mode tcp
option ssl-hello-chk
balance roundrobin
server 10.0.70.70 10.0.70.70:6443 check
server 10.0.70.78 10.0.70.78:6443 check
server 10.0.70.79 10.0.70.79:6443 check
# [...]

View File

@@ -0,0 +1,27 @@
apiVersion: v1
kind: Pod
metadata:
name: haproxy
namespace: kube-system
spec:
containers:
- image: haproxy:2.9.7
name: haproxy
livenessProbe:
failureThreshold: 8
httpGet:
host: localhost
path: /healthz
port: 7443
scheme: HTTPS
volumeMounts:
- mountPath: /usr/local/etc/haproxy/haproxy.cfg
name: haproxyconf
readOnly: true
hostNetwork: true
volumes:
- hostPath:
path: /etc/haproxy/haproxy.cfg
type: FileOrCreate
name: haproxyconf
status: {}

View File

@@ -0,0 +1,31 @@
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: keepalived
namespace: kube-system
spec:
containers:
- image: osixia/keepalived:2.0.20
name: keepalived
resources: {}
securityContext:
capabilities:
add:
- NET_ADMIN
- NET_BROADCAST
- NET_RAW
volumeMounts:
- mountPath: /usr/local/etc/keepalived/keepalived.conf
name: config
- mountPath: /etc/keepalived/check_apiserver.sh
name: check
hostNetwork: true
volumes:
- hostPath:
path: /etc/keepalived/keepalived.conf
name: config
- hostPath:
path: /etc/keepalived/check_apiserver.sh
name: check
status: {}

View File

@@ -0,0 +1,40 @@
# tasks file for haproxy_static_pods
- name: Создать директории /etc/kubernetes/manifests и /etc/keepalived
ansible.builtin.file:
path: '{{ item }}'
state: directory
mode: '755'
with_items:
- /etc/kubernetes/manifests
- /etc/keepalived
- /etc/haproxy
- name: Наливаю конфигурацию keepalived
ansible.builtin.template:
src: keepalived.conf.j2
dest: /etc/keepalived/keepalived.conf
mode: "644"
- name: Наливаю check_apiserver.sh
ansible.builtin.copy:
src: check_apiserver.sh
dest: /etc/keepalived/check_apiserver.sh
mode: '644'
- name: Наливаю haproxy.cfg
ansible.builtin.copy:
src: haproxy.cfg
dest: /etc/haproxy/haproxy.cfg
mode: '644'
- name: Наливаю keepalived static pods manifest
ansible.builtin.copy:
src: keepalived.yaml
dest: /etc/kubernetes/manifests/keepalived.yaml
mode: '644'
- name: Наливаю haproxy static pods manifest
ansible.builtin.copy:
src: haproxy.yaml
dest: /etc/kubernetes/manifests/haproxy.yaml
mode: '644'

View File

@@ -0,0 +1,29 @@
! /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
interval 3
weight -2
fall 10
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 101
authentication {
auth_type PASS
auth_pass {{ lookup('password', 'secrets/kubeadm/keepalived/auth_pass length=64') }}
}
virtual_ipaddress {
10.0.70.85/24
}
track_script {
check_apiserver
}
}

506
kubeadm/README.md Normal file
View File

@@ -0,0 +1,506 @@
# Настройка kubernetes кластера после чистой установки при помощи **kubeadm**
## Подготовка ВМ
Тестирование проводилось на **Ubuntu 22.04**
Подготавливаем ВМ при помощи [плейбука](../ansible/kubeadm.yml)
Плейбук настроит все что нудно для работы **Kubernetes**.
Добавит необходимые **модули ядра**, установит **kubelet**, **kubeadm**, **kubectl**, **cri-o**... и перезапустит машинки если это необходимо.
Запускаем плейбук
```sh
ansible-playbook kubeadm.yml
```
Результат работы плейбука
```output
PLAY RECAP *******************************************************************************************************
kubeadm-cp-01 : ok=19 changed=16 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
kubeadm-cp-02 : ok=19 changed=16 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
kubeadm-cp-03 : ok=19 changed=16 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
kubeadm-node-01 : ok=12 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
kubeadm-node-02 : ok=12 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
kubeadm-node-03 : ok=12 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
вторник 23 апреля 2024 09:29:22 +0300 (0:00:41.104) 0:02:19.111 ********
===============================================================================
Устанавливаю пакеты kubelet, kubeadm, kubectl и cri-o ---------------------------------------------------- 51.97s
Перезагружаю виртуальные машины -------------------------------------------------------------------------- 41.10s
Добавляю репозитории Kubernetes и cri-o ------------------------------------------------------------------ 12.58s
Устанавливаю пакеты --------------------------------------------------------------------------------------- 6.54s
upgrade_packages : Обновляю все пакеты до актуальных версий ----------------------------------------------- 3.54s
Добавляю gpg ключ для репозиториев Kubernetes и cri-o ----------------------------------------------------- 2.61s
Gathering Facts ------------------------------------------------------------------------------------------- 2.53s
Gathering Facts ------------------------------------------------------------------------------------------- 2.53s
Включаю маршрутизацию IP и iptables для моста ------------------------------------------------------------- 2.19s
Включаю и запускаю службы kubelet и cri-o ----------------------------------------------------------------- 2.09s
Предотвращаю обновление kubelet, kubeadm и kubectl -------------------------------------------------------- 1.87s
haproxy_static_pods : Создать директории /etc/kubernetes/manifests и /etc/keepalived ---------------------- 1.64s
Добавляю модули br_netfilter и overlay -------------------------------------------------------------------- 1.21s
Добавляю модули br_netfilter и overlay в /etc/modules ----------------------------------------------------- 1.20s
haproxy_static_pods : Наливаю keepalived.conf ------------------------------------------------------------- 1.19s
haproxy_static_pods : Наливаю haproxy.cfg ----------------------------------------------------------------- 1.11s
haproxy_static_pods : Наливаю haproxy static pods manifest ------------------------------------------------ 1.09s
haproxy_static_pods : Наливаю check_apiserver.sh ---------------------------------------------------------- 1.07s
haproxy_static_pods : Наливаю keepalived static pods manifest --------------------------------------------- 1.03s
```
## Инициализация кластера
Первый вариант подходит для тестирования, или создания не отказоустоичивого кластера,
Второй вариант создаст отказоустойчивый кластер готовый для прода.
### Non HA (Подходит для тестирования, не рекомендуется для прода)
Для инициализации кластера запускаем на **control-plane** машинке команду
```sh
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
```
Команда инициализирует кластер Kubernetes с указанием диапазона подсети для сети плагина CNI (Container Network Interface).
В результате выполнения вы увидите лог выполнения и получите краткую инструкцию по дальнейшей работе.
В результате мы должны получить что-то подобное
```sh
kubectl get nodes -o wide
```
```output
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
kubeadm-cp-01 Ready control-plane 2m9s v1.30.0 10.0.70.70 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
kubeadm-node-01 Ready <none> 27s v1.30.0 10.0.70.71 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
kubeadm-node-02 Ready <none> 13s v1.30.0 10.0.70.77 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
```
### HA (Production Ready решение, рекомендуется)
Мы разместим **haproxy** и **keepalived** на **control-plane** узлах. Конфигурации налиты при помощи Ansible на этапе подготовки.
Наш виртуальный IP: **10.0.70.85:7443** для взаимодействия с **Kube Api Server**
```sh
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint=10.0.70.85:7443 --upload-certs
```
При успешном выполнении мы увидим примерно следующее
```output
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join 10.0.70.85:7443 --token r120zn.za3vq0au6kzgoepu \
--discovery-token-ca-cert-hash sha256:cacb3c674f63d7f261c4fed403f59ce6e7d4c869c3748e301c98b2b9f17f7786 \
--control-plane --certificate-key 31ba08487b6899c2ebe43dd3857e168840a98d1077a7998c79f6f4838b4c08f7
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 10.0.70.85:7443 --token r120zn.za3vq0au6kzgoepu \
--discovery-token-ca-cert-hash sha256:cacb3c674f63d7f261c4fed403f59ce6e7d4c869c3748e301c98b2b9f17f7786
```
Добавляем узлы и проверяем.
В результате мы должны получить что-то подобное
```sh
kubectl get nodes -o wide
```
```output
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
kubeadm-cp-01 Ready control-plane 2m26s v1.30.0 10.0.70.70 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
kubeadm-cp-02 Ready control-plane 68s v1.30.0 10.0.70.78 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
kubeadm-cp-03 Ready control-plane 64s v1.30.0 10.0.70.79 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
kubeadm-node-01 Ready <none> 53s v1.30.0 10.0.70.71 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
kubeadm-node-02 Ready <none> 27s v1.30.0 10.0.70.77 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
kubeadm-node-03 Ready <none> 37s v1.30.0 10.0.70.74 <none> Ubuntu 22.04.4 LTS 5.15.0-105-generic cri-o://1.30.0
```
## Настройка CNI
**CNI (Container Network Interface)** - это спецификация, которая определяет, как контейнеры в сети взаимодействуют друг с другом и с внешним миром.
Она позволяет плагинам сети в Kubernetes управлять сетевыми настройками контейнеров.
Мы установим простой плагин **Flannel**
**Flannel** - это один из плагинов сети для Kubernetes, который обеспечивает сетевую подсистему для контейнеров.
Он позволяет контейнерам в кластере общаться друг с другом и с внешним миром, обеспечивая сетевую изоляцию и маршрутизацию.
Настраиваем **Flannel**:
```sh
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
```
Проверяем
```sh
kubectl get pods -o wide -n kube-flannel
```
Должны увидеть, что-то подобное
```output
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel-ds-6hm2g 1/1 Running 0 26s 10.0.70.71 kubeadm-node-01 <none> <none>
kube-flannel-ds-8fzzw 1/1 Running 0 26s 10.0.70.74 kubeadm-node-03 <none> <none>
kube-flannel-ds-9hrcj 1/1 Running 0 26s 10.0.70.78 kubeadm-cp-02 <none> <none>
kube-flannel-ds-gm24r 1/1 Running 0 26s 10.0.70.70 kubeadm-cp-01 <none> <none>
kube-flannel-ds-rd7jr 1/1 Running 0 26s 10.0.70.77 kubeadm-node-02 <none> <none>
kube-flannel-ds-rjsl9 1/1 Running 0 26s 10.0.70.79 kubeadm-cp-03 <none> <none>
```
## Установка тестового приложения
Для проверки работоспособности кластера установим **kube-prometheus-stack** при помощи **helm**
```sh
helm upgrade \
--install \
--namespace monitoring \
--create-namespace \
kube-prometheus-stack \
prometheus-community/kube-prometheus-stack \
--version 58.2.2
```
Проверяем, что все запустилось
```sh
kubectl get pods -o wide -n monitoring
```
Должны увидеть
```output
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
alertmanager-kube-prometheus-stack-alertmanager-0 2/2 Running 0 34s 10.244.2.5 kubeadm-node-02 <none> <none>
kube-prometheus-stack-grafana-67997d8bd4-7s2fq 3/3 Running 0 50s 10.244.1.2 kubeadm-node-01 <none> <none>
kube-prometheus-stack-kube-state-metrics-6fb5dddbdb-48l45 1/1 Running 0 50s 10.244.2.3 kubeadm-node-02 <none> <none>
kube-prometheus-stack-operator-775b5fb784-gpn94 1/1 Running 0 50s 10.244.1.3 kubeadm-node-01 <none> <none>
kube-prometheus-stack-prometheus-node-exporter-9d6ks 1/1 Running 0 50s 10.0.70.71 kubeadm-node-01 <none> <none>
kube-prometheus-stack-prometheus-node-exporter-d74z8 1/1 Running 0 50s 10.0.70.77 kubeadm-node-02 <none> <none>
kube-prometheus-stack-prometheus-node-exporter-fzgq2 1/1 Running 0 50s 10.0.70.70 kubeadm-cp-01 <none> <none>
prometheus-kube-prometheus-stack-prometheus-0 2/2 Running 0 34s 10.244.2.6 kubeadm-node-02 <none> <none>
```
Зайдем на веб интерфейс графаны
```sh
kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 8000:80
```
Заходим на [localhost:8000](http://localhost:8000/login) и вводим
```grafana
Логин: admin
Пароль: prom-operator
```
## Настройка CSI
**CSI (Container Storage Interface)** - это спецификация, которая позволяет контейнерам в **Kubernetes** взаимодействовать с различными хранилищами данных,
такими как блочные и файловые системы, через стандартизированный интерфейс. Это позволяет управлять хранилищем данных более гибко и эффективно в среде контейнеров.
Для организации системы хранения в кластере, мы будем использовать **[Longhorn](https://longhorn.io/)**.
**Longhorn** - это легкая, надежная и мощная система хранения распределенных блоков для **Kubernetes**.
**Longhorn** реализует распределенное блочное хранилище с помощью **контейнеров** и **микросервисов**.
**Longhorn** создает выделенный контроллер хранения для каждого тома блочного устройства и синхронно реплицирует том на несколько реплик,
хранящихся на нескольких узлах. Контроллер хранилища и реплики сами оркеструются с помощью **Kubernetes**.
### Характеристики
- **Распределенное блочное хранилище** корпоративного класса без единой точки отказа
- **Инкрементный снимок** блочного хранилища
- Резервное копирование на вторичное хранилище (**NFS** или **S3-совместимое** объектное хранилище), основанное на эффективном обнаружении блоков изменений
- **Повторяющиеся снимки** и **резервное копирование**
- **Автоматизированное обновление без сбоев**. Вы можете обновить весь стек программного обеспечения **Longhorn**, не нарушая работу томов хранения.
- Интуитивно понятная приборная панель с **графическим интерфейсом**
### Пререквизиты
- Кластер Kubernetes: Убедитесь, что каждый узел соответствует требованиям к установке.
- Ваша рабочая станция: Установите Helm версии 3.0 или более поздней.
### Установка Longhorn
Примечание:
- Начальные настройки для **Longhorn** можно найти в пользовательских опциях **Helm** или отредактировав файл конфигурации развертывания.
- Для **Kubernetes** < v1.25, если в вашем кластере все еще используется контроллер допуска Pod Security Policy, установите значение helm enablePSP в true,
чтобы установить ресурс longhorn-psp PodSecurityPolicy, который позволит запускать привилегированные поды **Longhorn**.
### Требования к установке
Каждый узел в кластере **Kubernetes**, на котором установлен **Longhorn**, должен отвечать следующим требованиям:
- Контейнерная среда выполнения, совместимая с Kubernetes (Docker v1.13+, containerd v1.3.7+ и т. д.)
- Kubernetes >= v1.21
- Установлен open-iscsi, и на всех узлах запущен демон iscsid.
Это необходимо, поскольку Longhorn полагается на iscsiadm на узле для предоставления постоянных томов Kubernetes. Помощь в установке open-iscsi см. в этом разделе.
- Поддержка RWX требует, чтобы на каждом узле был установлен клиент NFSv4.
Об установке клиента NFSv4 читайте в этом разделе.
- Файловая система узла поддерживает функцию расширения файлов для хранения данных. В настоящее время мы поддерживаем:
ext4
XFS
- Должны быть установлены bash, curl, findmnt, grep, awk, blkid, lsblk.
- Распространение монтирования должно быть включено.
Рабочие нагрузки Longhorn должны иметь возможность запускаться от имени root, чтобы Longhorn был развернут и работал должным образом.
Этот сценарий можно использовать для проверки среды Longhorn на наличие потенциальных проблем.
Минимальное рекомендуемое аппаратное обеспечение см. в руководстве по передовому опыту.
1. Добавьте репозиторий Longhorn Helm:
```sh
helm repo add longhorn https://charts.longhorn.io
```
2. Получите список последних чартов из репозитория:
```sh
helm repo update
```
3. Установите Longhorn в пространстве имен longhorn-system.
```sh
helm upgrade \
--install \
longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--version 1.6.1
```
4. Чтобы убедиться, что развертывание прошло успешно, выполните команду:
```sh
kubectl -n longhorn-system get pod
```
Результат должен выглядеть следующим образом:
```output
NAME READY STATUS RESTARTS AGE
csi-attacher-799967d9c-nx4f9 1/1 Running 0 3m10s
csi-attacher-799967d9c-vsz7g 1/1 Running 0 3m10s
csi-attacher-799967d9c-zh6vq 1/1 Running 0 3m10s
csi-provisioner-58f97759c-676jf 1/1 Running 0 3m10s
csi-provisioner-58f97759c-fxsb5 1/1 Running 0 3m10s
csi-provisioner-58f97759c-krfs2 1/1 Running 0 3m10s
csi-resizer-6c9b8598f4-dzxwp 1/1 Running 0 3m10s
csi-resizer-6c9b8598f4-kkfn4 1/1 Running 0 3m10s
csi-resizer-6c9b8598f4-wq47f 1/1 Running 0 3m10s
csi-snapshotter-5c5f9b754d-4pdbg 1/1 Running 0 3m10s
csi-snapshotter-5c5f9b754d-7n7wf 1/1 Running 0 3m10s
csi-snapshotter-5c5f9b754d-q4rzx 1/1 Running 0 3m10s
engine-image-ei-5cefaf2b-8j4j9 1/1 Running 0 3m14s
engine-image-ei-5cefaf2b-94g2f 1/1 Running 0 3m14s
engine-image-ei-5cefaf2b-g5bg5 1/1 Running 0 3m14s
instance-manager-3af1ba7167264c2020df4d36d77d3905 1/1 Running 0 3m14s
instance-manager-8452580cb8e2bc9ad134bb6a1c2806cc 1/1 Running 0 3m12s
instance-manager-a006e8fdef719ff0b5aee753abbe1dd8 1/1 Running 0 3m14s
longhorn-csi-plugin-bswvc 3/3 Running 0 3m10s
longhorn-csi-plugin-fmlrd 3/3 Running 0 3m10s
longhorn-csi-plugin-tpnqm 3/3 Running 0 3m10s
longhorn-driver-deployer-68b5879955-7tkrs 1/1 Running 0 3m31s
longhorn-manager-5psrc 1/1 Running 0 3m31s
longhorn-manager-5qjbd 1/1 Running 0 3m31s
longhorn-manager-rwzbb 1/1 Running 0 3m31s
longhorn-ui-9ccf5c989-bxdv2 1/1 Running 0 3m31s
longhorn-ui-9ccf5c989-dsvz6 1/1 Running 0 3m31s
```
5. Чтобы включить доступ к пользовательскому интерфейсу Longhorn, необходимо настроить контроллер Ingress.
По умолчанию аутентификация в пользовательском интерфейсе Longhorn не включена.
Информацию о создании контроллера NGINX Ingress с базовой аутентификацией см. в [этом разделе](https://longhorn.io/docs/1.6.1/deploy/accessing-the-ui/longhorn-ingress).
6. Войдите в пользовательский интерфейс Longhorn, выполнив [следующие действия](https://longhorn.io/docs/1.6.1/deploy/accessing-the-ui).
Посмотреть на веб интерфейс можно так:
```sh
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8000:80
```
## Ingress Controller
Ingress Controller - это компонент в Kubernetes, который управляет входящими HTTP и HTTPS запросами в кластер.
Он обеспечивает балансировку нагрузки, маршрутизацию трафика и обеспечивает доступ к службам внутри кластера извне.
Ingress Controller работает на уровне приложения и использует информацию из объекта Ingress, который определяет правила маршрутизации для входящего трафика.
Это позволяет настраивать маршрутизацию трафика без изменения конфигурации службы или приложения.
### Установка при помощи helm
Добавьте репозиторий Traefik Labs в Helm:
```sh
helm repo add traefik https://traefik.github.io/charts
```
Вы можете обновить хранилище, выполнив команду:
```sh
helm repo update
```
И установите его с помощью командной строки Helm:
```sh
helm upgrade \
--install \
--namespace traefik \
--create-namespace \
traefik traefik/traefik
```
### Проброс дашборда Traefik
```sh
kubectl port-forward -n traefik $(kubectl get pods -n traefik --selector "app.kubernetes.io/name=traefik" --output=name) 9000:9000
```
Его ним можно увидеть по адресу: [127.0.0.1:9000/dashboard/](http://127.0.0.1:9000/dashboard/)
## Удаляем узел из кластера
В Kubernetes, для удаления узла (node) из кластера, вы можете использовать следующую команду kubectl
```sh
kubectl get nodes -o wide
```
Эти команды выполняют следующие действия:
- kubectl drain - этот шаг убеждается, что все поды, которые могут быть перезапущены в другом месте, были перезапущены.
Он также удаляет все пустые директории, которые были созданы подами на узле,
и удаляет все поды, которые не могут быть перезапущены в другом месте (например, поды, которые имеют локальные данные).
```sh
kubectl drain kubeadm-node-01 --delete-local-data --force --ignore-daemonsets
```
- kubectl delete node - этот шаг удаляет узел из кластера.
Обратите внимание, что эти команды могут привести к потере данных,
поэтому убедитесь, что вы понимаете, что делаете, и что у вас есть резервное копирование данных, если это необходимо.
```sh
kubectl delete node kubeadm-node-01
```
## Просмотр списка join ссылок в Kubernetes
Для просмотра списка join ссылок в Kubernetes, вы можете использовать команду kubeadm token list.
Эта команда отобразит список всех активных join токенов, которые могут быть использованы для присоединения новых узлов к кластеру.
Вот пример использования:
```sh
kubeadm token list
```
Для получения join ссылки в Kubernetes, вы можете использовать команду kubeadm token create --print-join-command.
Эта команда создаст новый join токен и напечатает команду, которую вы можете использовать для присоединения новых узлов к кластеру.
Вот пример использования:
```sh
kubeadm token create --print-join-command
```
## Тестирование кластера
Отчет **sonobuoy**
```txt
Plugin: e2e
Status: failed
Total: 7201
Passed: 384
Failed: 20
Skipped: 6797
Failed tests:
[sig-network] DNS should provide DNS for pods for Subdomain [Conformance]
[sig-network] Services should be able to change the type from ExternalName to ClusterIP [Conformance]
[sig-network] Services should be able to switch session affinity for service with type clusterIP [LinuxOnly] [Conformance]
[sig-cli] Kubectl client Guestbook application should create and stop a working application [Conformance]
[sig-network] Services should be able to switch session affinity for NodePort service [LinuxOnly] [Conformance]
[sig-network] Services should serve multiport endpoints from pods [Conformance]
[sig-network] Services should have session affinity work for NodePort service [LinuxOnly] [Conformance]
[sig-architecture] Conformance Tests should have at least two untainted nodes [Conformance]
[sig-network] DNS should provide DNS for services [Conformance]
[sig-network] Services should be able to change the type from NodePort to ExternalName [Conformance]
[sig-network] DNS should resolve DNS of partial qualified names for services [LinuxOnly] [Conformance]
[sig-network] Services should be able to change the type from ExternalName to NodePort [Conformance]
[sig-network] Services should serve a basic endpoint from pods [Conformance]
[sig-apps] Daemon set [Serial] should rollback without unnecessary restarts [Conformance]
[sig-network] DNS should provide DNS for ExternalName services [Conformance]
[sig-network] DNS should provide DNS for the cluster [Conformance]
[sig-network] Services should be able to create a functioning NodePort service [Conformance]
[sig-network] Services should be able to change the type from ClusterIP to ExternalName [Conformance]
[sig-auth] ServiceAccounts ServiceAccountIssuerDiscovery should support OIDC discovery of service account issuer [Conformance]
[sig-network] Services should have session affinity work for service with type clusterIP [LinuxOnly] [Conformance]
Plugin: systemd-logs
Status: passed
Total: 2
Passed: 2
Failed: 0
Skipped: 0
Run Details:
API Server version: v1.30.0
Node health: 2/2 (100%)
Pods health: 13/14 (92%)
Details for failed pods:
sonobuoy/sonobuoy-e2e-job-c23b74c9b2004efd Ready:False: :
Errors detected in files:
Warnings:
754 podlogs/kube-system/kube-controller-manager-kubeadm-cp-01/logs/kube-controller-manager.txt
90 podlogs/kube-system/kube-apiserver-kubeadm-cp-01/logs/kube-apiserver.txt
29 podlogs/kube-system/kube-scheduler-kubeadm-cp-01/logs/kube-scheduler.txt
7 podlogs/sonobuoy/sonobuoy-e2e-job-c23b74c9b2004efd/logs/e2e.txt
3 podlogs/kube-system/etcd-kubeadm-cp-01/logs/etcd.txt
1 podlogs/sonobuoy/sonobuoy/logs/kube-sonobuoy.txt
Errors:
6268 podlogs/sonobuoy/sonobuoy-e2e-job-c23b74c9b2004efd/logs/e2e.txt
1742 podlogs/kube-system/kube-controller-manager-kubeadm-cp-01/logs/kube-controller-manager.txt
350 podlogs/kube-system/kube-apiserver-kubeadm-cp-01/logs/kube-apiserver.txt
63 podlogs/kube-system/kube-scheduler-kubeadm-cp-01/logs/kube-scheduler.txt
9 podlogs/kube-system/coredns-7db6d8ff4d-lkwk9/logs/coredns.txt
9 podlogs/kube-system/coredns-7db6d8ff4d-bdvht/logs/coredns.txt
8 podlogs/kube-system/kube-proxy-4g6fl/logs/kube-proxy.txt
8 podlogs/kube-system/kube-proxy-p5vr5/logs/kube-proxy.txt
```

25
opentofu/kubeadm/.terraform.lock.hcl generated Normal file
View File

@@ -0,0 +1,25 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/bpg/proxmox" {
version = "0.54.0"
constraints = ">= 0.51.0"
hashes = [
"h1:xgDrDol/cYu93YOPTL0UVpURchPzdxPXaHjcoieoXXI=",
"zh:4521f8893b4645c93e75ffc3545ea59d3f31aed7cea4c26dcd0fbd7c0cce6ca8",
"zh:520e56abd10d888935047ef07a7577c2a1cce5bc54e25b03a0dbdc4356997ca9",
"zh:53469dd058ef8b2ea29577f69a2681f8ffb9f79494b8c1d1594dd42ad314d7bd",
"zh:6948adb6e088fe652b7273906a5c11032528f84eb5a5ca797534ab3b6076a8c6",
"zh:72655e9765b7791e3e37508c70a847172561bff348c7d5f916794e5823a84efe",
"zh:7faa281319d90026ad9b2dce00ac059896f451cb9305ed11bb90fcfda7c5d143",
"zh:8fe20fa893e9545aa30672392f76948ed56a93a2decb1d3bd8693c5e1d2dd85a",
"zh:b175411aa820c1a47473ef691c743670eeb900999576c6cdcb113d14a7c499aa",
"zh:b59205ad7981f263ff287d3eb0a93296f8cd6b166a01ddd3b16606fc39d456ec",
"zh:f26e0763dbe6a6b2195c94b44696f2110f7f55433dc142839be16b9697fa5597",
"zh:f3524bc67d995e98ad9d7e17f3be91f7a975608180fad6b227fc42087b5facc1",
"zh:f4bf087717e1b0f5f3ee7d3b6b47fb66e5f821097f15ec0cf6714a39c7d80959",
"zh:fc14a29b1aef50872d60f338af89f7cbbac307c630f973c07a7951bdde8be2a5",
"zh:fc72da3d651bf0f0e20a0860e9217a94797b4c1d5cae1742f1b8e15d28f8ceeb",
"zh:fff2299a427e1590775611bf186220686795af966772e61e44234f0df44b6c22",
]
}

View File

@@ -0,0 +1,70 @@
# Машинка
resource "proxmox_virtual_environment_vm" "kubeadm-cp-01" {
name = "kubeadm-cp-01"
migrate = true
description = "Managed by OpenTofu"
tags = ["kubeadm", "test"]
on_boot = true
# Указываем целевой узел, на котором будет запущена ВМ
node_name = "pve-01"
# Шоблон из которого будет создавать ВМ
clone {
vm_id = "2204"
node_name = "pve-01"
retries = 2
}
# Активируем QEMU для этов ВМ
agent {
enabled = true
}
operating_system {
type = "l26"
}
cpu {
cores = 4
type = "host"
numa = true
}
memory {
dedicated = 4096
}
disk {
size = "50"
interface = "virtio0"
datastore_id = "k8s-data-01"
file_format = "raw"
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
datastore_id = "k8s-data-01"
ip_config {
ipv4 {
address = "10.0.70.70/24"
gateway = "10.0.70.101"
}
}
dns {
servers = [
"77.88.8.8"
]
}
user_account {
username = "infra"
keys = [
"ssh-rsa..."
]
}
}
}

View File

@@ -0,0 +1,70 @@
# Машинка
resource "proxmox_virtual_environment_vm" "kubeadm-cp-02" {
name = "kubeadm-cp-02"
migrate = true
description = "Managed by OpenTofu"
tags = ["kubeadm", "test"]
on_boot = true
# Указываем целевой узел, на котором будет запущена ВМ
node_name = "pve-02"
# Шоблон из которого будет создавать ВМ
clone {
vm_id = "2204"
node_name = "pve-01"
retries = 2
}
# Активируем QEMU для этов ВМ
agent {
enabled = true
}
operating_system {
type = "l26"
}
cpu {
cores = 4
type = "host"
numa = true
}
memory {
dedicated = 4096
}
disk {
size = "50"
interface = "virtio0"
datastore_id = "k8s-data-01"
file_format = "raw"
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
datastore_id = "k8s-data-01"
ip_config {
ipv4 {
address = "10.0.70.78/24"
gateway = "10.0.70.101"
}
}
dns {
servers = [
"77.88.8.8"
]
}
user_account {
username = "infra"
keys = [
"ssh-rsa..."
]
}
}
}

View File

@@ -0,0 +1,70 @@
# Машинка
resource "proxmox_virtual_environment_vm" "kubeadm-cp-03" {
name = "kubeadm-cp-03"
migrate = true
description = "Managed by OpenTofu"
tags = ["kubeadm", "test"]
on_boot = true
# Указываем целевой узел, на котором будет запущена ВМ
node_name = "pve-03"
# Шоблон из которого будет создавать ВМ
clone {
vm_id = "2204"
node_name = "pve-01"
retries = 2
}
# Активируем QEMU для этов ВМ
agent {
enabled = true
}
operating_system {
type = "l26"
}
cpu {
cores = 4
type = "host"
numa = true
}
memory {
dedicated = 4096
}
disk {
size = "50"
interface = "virtio0"
datastore_id = "k8s-data-01"
file_format = "raw"
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
datastore_id = "k8s-data-01"
ip_config {
ipv4 {
address = "10.0.70.79/24"
gateway = "10.0.70.101"
}
}
dns {
servers = [
"77.88.8.8"
]
}
user_account {
username = "infra"
keys = [
"ssh-rsa..."
]
}
}
}

View File

@@ -0,0 +1,70 @@
# Машинка
resource "proxmox_virtual_environment_vm" "kubeadm-node-01" {
name = "kubeadm-node-01"
migrate = true
description = "Managed by OpenTofu"
tags = ["kubeadm", "test"]
on_boot = true
# Указываем целевой узел, на котором будет запущена ВМ
node_name = "pve-01"
# Шоблон из которого будет создавать ВМ
clone {
vm_id = "2204"
node_name = "pve-01"
retries = 2
}
# Активируем QEMU для этов ВМ
agent {
enabled = true
}
operating_system {
type = "l26"
}
cpu {
cores = 4
type = "host"
numa = true
}
memory {
dedicated = 32768
}
disk {
size = "500"
interface = "virtio0"
datastore_id = "k8s-data-01"
file_format = "raw"
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
datastore_id = "k8s-data-01"
ip_config {
ipv4 {
address = "10.0.70.71/24"
gateway = "10.0.70.101"
}
}
dns {
servers = [
"77.88.8.8"
]
}
user_account {
username = "infra"
keys = [
"ssh-rsa..."
]
}
}
}

View File

@@ -0,0 +1,70 @@
# Машинка
resource "proxmox_virtual_environment_vm" "kubeadm-node-02" {
name = "kubeadm-node-02"
migrate = true
description = "Managed by OpenTofu"
tags = ["kubeadm", "test"]
on_boot = true
# Указываем целевой узел, на котором будет запущена ВМ
node_name = "pve-02"
# Шоблон из которого будет создавать ВМ
clone {
vm_id = "2204"
node_name = "pve-01"
retries = 2
}
# Активируем QEMU для этов ВМ
agent {
enabled = true
}
operating_system {
type = "l26"
}
cpu {
cores = 4
type = "host"
numa = true
}
memory {
dedicated = 32768
}
disk {
size = "500"
interface = "virtio0"
datastore_id = "k8s-data-01"
file_format = "raw"
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
datastore_id = "k8s-data-01"
ip_config {
ipv4 {
address = "10.0.70.77/24"
gateway = "10.0.70.101"
}
}
dns {
servers = [
"77.88.8.8"
]
}
user_account {
username = "infra"
keys = [
"ssh-rsa..."
]
}
}
}

View File

@@ -0,0 +1,70 @@
# Машинка
resource "proxmox_virtual_environment_vm" "kubeadm-node-03" {
name = "kubeadm-node-03"
migrate = true
description = "Managed by OpenTofu"
tags = ["kubeadm", "test"]
on_boot = true
# Указываем целевой узел, на котором будет запущена ВМ
node_name = "pve-03"
# Шоблон из которого будет создавать ВМ
clone {
vm_id = "2204"
node_name = "pve-01"
retries = 2
}
# Активируем QEMU для этов ВМ
agent {
enabled = true
}
operating_system {
type = "l26"
}
cpu {
cores = 4
type = "host"
numa = true
}
memory {
dedicated = 32768
}
disk {
size = "500"
interface = "virtio0"
datastore_id = "k8s-data-01"
file_format = "raw"
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
datastore_id = "k8s-data-01"
ip_config {
ipv4 {
address = "10.0.70.74/24"
gateway = "10.0.70.101"
}
}
dns {
servers = [
"77.88.8.8"
]
}
user_account {
username = "infra"
keys = [
"ssh-rsa..."
]
}
}
}

View File

@@ -0,0 +1,17 @@
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = ">= 0.51.0"
}
}
}
provider "proxmox" {
endpoint = var.virtual_environment_endpoint
api_token = var.virtual_environment_api_token
insecure = true
ssh {
agent = false
}
}

View File

@@ -0,0 +1,2 @@
virtual_environment_api_token = "root@pam!for-terraform-provider=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
virtual_environment_endpoint = "https://10.0.70.116:8006/"

View File

@@ -0,0 +1,9 @@
variable "virtual_environment_endpoint" {
type = string
description = "The endpoint for the Proxmox Virtual Environment API (example: https://host:port)"
}
variable "virtual_environment_api_token" {
type = string
description = "The api roken the Proxmox Virtual Environment API (example: root@pam!for-terraform-provider=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)"
}