Собираю единомышленников в телеграм канале. Там же отвечаю на вопросы.
Присоединяйся

Гайд по онлайн установке здесь
В корпоративных средах безопасность имеет первостепенное значение.
Одной из распространенных мер безопасности является изоляция критической инфраструктуры от интернета.
Это создает проблемы при развертывании сложных распределенных систем, таких как Kubernetes, для установки которых обычно требуется загрузка многочисленных пакетов и образов контейнеров.
Если вы когда-либо пытались настроить Kubernetes в изолированной от интернета среде, вы знаете, насколько это сложно.
Стандартные процедуры установки предполагают наличие подключения к интернету, поэтому вам нет необходимости вручную собирать и переносить десятки зависимостей.
В этом гайде представлен мощный подход с использованием Kubespray настроенным на offline развертывание Kubernetes в закрытых средах без доступа к сети.
Этот метод не только решает проблему безопасности, но и обеспечивает более быструю установку благодаря предварительной загрузке необходимых компонентов, что делает его идеальным для развертывания с помощью скриптов и автоматизации рабочих задач.
Гайд составлялся на протяжении недели, с дебагом кучи ошибок и зависимостей. Не скупитесь тапнуть палец вверх внизу заметки, если она была полезной. Поехали!
Шаг 1. Вводные
Требуемые ресурсы
| Role | CPU | RAM | SSD | OS | IP | Req |
|---|
| pc-inet | 2 | 4 | 20 | Ubuntu 24.04 | 192.168.1.99 | INET |
| harbor | 2 | 4 | 50 | Ubuntu 24.04 | 192.168.1.100 | TLS |
| master-1-k8s | 2 | 4 | 50 | Ubuntu 24.04 | 192.168.1.101 | ansible, python3 |
| master-2-k8s | 2 | 4 | 50 | Ubuntu 24.04 | 192.168.1.102 | |
| master-3-k8s | 2 | 4 | 50 | Ubuntu 24.04 | 192.168.1.103 | |
| node-1-k8s | 4 | 8 | 100 | Ubuntu 24.04 | 192.168.1.104 | |
| node-2-k8s | 4 | 8 | 100 | Ubuntu 24.04 | 192.168.1.105 | |
| MetallB | - | - | - | - | 192.168.1.200 | |
- pc-inet с доступом в интернет (чтобы скачать пакеты)
- 3 Мастер узла
- 2 Воркера
- Доступ ssh с мастера к воркерам по sudo
- Сервер Harbor настроенный на https
- Свободный IP адрес или пул в той же сети, для MetallB
- Пользователь с root правами, в моём примере admin
Что будет установлено
| Component | Version |
|---|
| Kubespray | v2.29.1 |
| Kubernetes | v1.34.3 |
| Cilium | v.1.18.5 |
| MetalLB | v0.13.9 |
| Ingress-nginx | v1.13.3 |
Шаг 2. Подготовка виртуальных серверов
В отличии от гайда, который я составлял ранее по online установке kubespray, в этом, настройку VM для кубера я переложу на ansible-плейбук.
Предполагается установка ОС Ubuntu 24.04 на все хосты.
Сервер с инетом pc-inet.
Клонируем репозиторий:
1
| git clone https://github.com/ZM56/k8s-ans-bootstrap.git
|
Переносим на сервер: master-1-k8s
На master-1-k8s создаём SSH-ключ для подключения к другим машинам:
И копируем его на все сервера:
1
2
3
4
| ssh-copy-id admin@192.168.1.102
ssh-copy-id admin@192.168.1.103
ssh-copy-id admin@192.168.1.104
ssh-copy-id admin@192.168.1.105
|
Переходим:
Меняем в inventory на свои адреса, имена и переменные в group_vars.
Устанавливаем ansible:
1
| sudo apt install ansible-core -y
|
Запускаем
1
| ansible-playbook -i inventory.ini play.yml -u admin
|
Машины готовы.
Шаг 3. Подготовка образов.
На машине с интернетом pc-inet
Готовим окружение
Мы не сможем поставить все зависимости питона на хосты без инета.
Здесь два варианта:
- Использовать докер образ kubespray и собирать с помощью него.
- Создать окружение на машине с выходом в инет и затем скопировать на целевые хосты.
Я выбрал второе, так как в докер образе kubespray Trivy увидел high critical CVE, такое СБ не пропустят, а морочиться с пересборкой образа не наша основная задача.
1
2
3
4
5
| mkdir /opt/kuber_off && cd /opt/kuber_off
apt update -y
apt install python3.12-venv -y
python3.12 -m venv venv
source venv/bin/activate
|
Клонируем репозиторий:
1
| git clone --branch v2.29.1 --single-branch https://github.com/kubernetes-sigs/kubespray.git
|
Переходим в директорию:
Проверяем версию:
Должно быть: v2.29.1
Готовим инвентори:
1
2
| cp -r /opt/kuber_off/kubespray/inventory/sample /opt/kuber_off/kubespray/inventory/offline_cluster
nano /opt/kuber_off/kubespray/inventory/offline_cluster/inventory.ini
|
Удаляем всё и добавляем pc-inet хост:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| [all]
pc-inet ansible_host=192.168.1.99 ip=192.168.1.99
[kube_control_plane]
pc-inet
[etcd]
pc-inet
[kube_node]
pc-inet
[k8s_cluster:children]
kube_control_plane
kube_node
|
Добавляем переменные:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/k8s_cluster/addons.yml
|
Включаем установку HELM, Ingress Nginx и MetalLB:
1
2
3
4
5
6
7
8
| # Helm deployment
helm_enabled: true
# Включаем ingress-nginx
ingress_nginx_enabled: true
# MetalLB deployment
metallb_enabled: true
|
Контейнерный движок я выбрал containerd.
Почему не cri-o?
Containerd плюсы:
- default в Kubespray
- меньше сюрпризов в оффлайн-режиме
- лучше тестируется в CI Kubespray
- меньше зависимостей ОС
Минусы: - чуть больше “общего” функционала
Cri-o плюсы:
- tight-интеграция с Kubernetes
- любят в OpenShift-мире
Минусы: - в Kubespray требует больше ручных правок
Добавляем переменные и даём название кластеру:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/k8s_cluster/k8s-cluster.yml
|
Устанавливаем cilium плагин, поэтому выставляем соответствующие настройки.
Указанные поддерживаемые версии я брал отсюда: https://github.com/kubernetes-sigs/kubespray
Раздел: Supported components
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| kube_owner: root
# Этой строчки нет, вписываем ручками
kube_proxy_remove: true
kube_network_plugin: cilium
# Этой строчки тоже нет, добавляем
cilium_version: "1.18.5"
kube_proxy_strict_arp: true
# Доменное имя вашего будущего кластера
cluster_name: k8s.domain.local
## Default: containerd
container_manager: containerd
|
Открываем файл etcd:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/all/etcd.yml
|
Меняем (сверяем) параметр:
1
| etcd_deployment_type: host
|
Открываем конфиг cilium:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/k8s_cluster/k8s-net-cilium.yml
|
Укажем что proxy теперь cilium, а не kube-proxy и mtu 1450:
1
2
3
| cilium_mtu: "1450"
cilium_kube_proxy_replacement: true
cilium_tunnel_mode: geneve
|
Включаем Hubble
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Hubble
### Enable Hubble without install
cilium_enable_hubble: true
### Enable Hubble-ui
### Installed by default when hubble is enabled. To disable set to false
cilium_enable_hubble_ui: "{{ cilium_enable_hubble }}"
### Enable Hubble Metrics
cilium_enable_hubble_metrics: true
### if cilium_enable_hubble_metrics: true
cilium_hubble_metrics:
- dns
- drop
- tcp
- flow
- icmp
- http
|
Открываем файл offline установки:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/all/offline.yml
|
И добавляем в самое начало файла параметры загрузки:
1
2
3
4
5
6
| ---
download_run_once: true
download_localhost: true
download_keep_remote_cache: true
download_force_cache: true
download_cache_dir: /opt/kubespray-cache
|
Запускаем загрузку
Устанавливаем зависимости питона:
1
| pip install -r requirements.txt
|
Создадим директории и на всякий установим containerd:
1
2
3
| apt install containerd -y
mkdir -p /opt/kubespray-cache/images/
mkdir /opt/kubespray-releases/
|
Если в инет ходишь через прокси, то укажи здесь
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/all/all.yml
|
Заполни и расскоментируй:
1
2
| # http_proxy: ""
# https_proxy: ""
|
По умолчанию некоторые файлы скачиваются в /tmp/releases, с помощью переменной local_release_dir изменяем путь на /opt/kubespray-releases
Запускаемся:
1
2
3
4
5
| /opt/kuber_off/venv/bin/ansible-playbook -i inventory/offline_cluster/inventory.ini cluster.yml \
-e local_release_dir=/opt/kubespray-releases \
--tags download \
--skip-tags upload,upgrade -b \
-u admin
|
Получаем ошибку
1
2
3
| TASK [download : Download_container | Download image if required]
task path: /opt/kuber_off/kubespray/roles/download/tasks/download_container.yml:57
fatal: [pc-inet -> localhost]: FAILED! => {"attempts": 4, "changed": false, "cmd": "/usr/local/bin/nerdctl -n k8s.io pull --quiet quay.io/cilium/cilium:v1.18.5", "msg": "[Errno 2] No such file or directory: b'/usr/local/bin/nerdctl'", >
|
Идём исправлять:
1
| cp /opt/kubespray-releases/nerdctl /opt/kubespray-releases/crictl /usr/local/bin
|
Делаем линк:
1
| sudo ln -sf /usr/bin/ctr /usr/local/bin/ctr
|
И проверить:
1
| /usr/local/bin/nerdctl --version
|
Перезапускаем:
1
2
3
4
5
| /opt/kuber_off/venv/bin/ansible-playbook -i inventory/offline_cluster/inventory.ini cluster.yml \
-e local_release_dir=/opt/kubespray-releases \
--tags download \
--skip-tags upload,upgrade -b \
-u admin
|
Должно завершиться успешно, без ошибок.
Некоторых важных образов нет, они не скачиваются по умолчанию.
Поэтому получаем список контейнеров и с помощью скрипта и докачиваем:
1
2
| cd /opt/
nano download_k8s_images.sh
|
Вставляем:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| #!/bin/bash
# На машине с ИНТЕРНЕТОМ
set -e
echo "Получаю список образов от kubeadm..."
# Ваш путь к kubeadm
KUBEADM_PATH="/opt/kubespray-cache/kubeadm-*-amd64"
# Получаем список образов
IMAGES=$($KUBEADM_PATH config images list 2>/dev/null | grep -v "WARN" || $KUBEADM_PATH config images list)
echo "Найдено образов: $(echo "$IMAGES" | wc -l)"
echo "$IMAGES"
echo ""
# Идём в директорию с images
DOWNLOAD_DIR="/opt/kubespray-cache/images"
cd "$DOWNLOAD_DIR"
echo "Начинаю скачивание в: $DOWNLOAD_DIR"
echo "=========================================="
# Скачиваем каждый образ
for IMAGE in $IMAGES; do
echo ""
echo "Обрабатываю: $IMAGE"
# Скачиваем
echo " Pulling..."
nerdctl pull "$IMAGE"
# Генерируем имя файла
FILENAME=$(echo "$IMAGE" | sed 's|/|_|g; s|:|_|g').tar
echo " Saving to: $FILENAME"
# Сохраняем
nerdctl save "$IMAGE" -o "$FILENAME"
# Удаляем образ из локального nerdctl
echo " Removing from local nerdctl..."
nerdctl rmi "$IMAGE"
# Информация о файле
SIZE=$(du -h "$FILENAME" | cut -f1)
echo "Сохранено: $FILENAME ($SIZE)"
done
echo ""
echo "=========================================="
echo "Все образы скачаны!"
echo "Итого файлов: $(ls -1 *.tar | wc -l)"
|
Запускаемся:
1
2
3
| chmod +x /opt/kubespray-cache/kube*
chmod +x download_k8s_images.sh
./download_k8s_images.sh
|
И ещё докачиваем образ:
1
2
| nerdctl pull quay.io/cilium/operator-generic:v1.18.5
nerdctl save -o /opt/kubespray-cache/images/quay.io_cilium_operator-generic_v1.18.5.tar quay.io/cilium/operator-generic:v1.18.5
|
Далее скачаем Helm чарт для Cilium
Копируем helm бинарник:
1
| cp /opt/kubespray-releases/helm-3.18.4/linux-amd64/helm /usr/local/bin/
|
Проверяем:
Закачиваем:
1
2
3
4
5
| helm repo add cilium https://helm.cilium.io
helm repo update
helm pull cilium/cilium --version 1.18.5
# появится файл cilium-1.18.5.tgz
mv cilium-1.18.5.tgz /opt/cilium-1.18.5.tgz
|
Упаковать:
1
2
| tar -C /opt -czf kubespray-code.tar.gz kuber_off
tar -C /opt -czf kubespray-offline-bundle.tar.gz kubespray-cache kubespray-releases cilium-1.18.5.tgz
|
Далее: Перетаскиваем файлы на закрытый контур без инета (хост master-1-k8s).
Шаг 4. Подготовка окружения оффлайн установки
Заливаем образы в Harbor
Ставим докер (Предполагается что он есть в ваших закрытых репозиториях Убунты):
1
2
| sudi apt install docker.io -y
systemctl enable docker --now
|
Хост: master-1-k8s
1
2
| tar -xzf /home/admin/kubespray-code.tar.gz -C /opt/
tar -xzf /home/admin/kubespray-offline-bundle.tar.gz -C /opt
|
Копируем бинари:
1
| cp /opt/kubespray-releases/crictl /opt/kubespray-releases/nerdctl /usr/local/bin
|
И проверить:
1
2
| /usr/local/bin/nerdctl --version
/usr/local/bin/crictl --version
|
Предполагается, что Harbor также находится в закрытой зоне сети, поэтому первым шагом мы зальём образы в репо.
Идём в Harbor создаём новый проект с названием k8s и другой с названием helm.
Репозиторий k8s измените с приватного на публичный. Это связано с тем, что containerd роль не считывает логин и пароль от репо из файла.
Решения у разрабов kubespray не нашел.
Helm репозиторий можно оставить приватным.

Делаем переменные окружения:
1
2
3
4
5
6
| # Имя репозитория harbor
export HARBOR="harbor.domain.local"
# Проект в Harbor
export PROJECT="k8s"
# Где лежат *.tar
export IMG_DIR="/opt/kubespray-cache/images"
|
Логинимся
1
2
3
| docker login $HARBOR
# Если x509, то проблема с сертами на Harbor. Гуглите.
cd $IMG_DIR
|
Грузим все образы в локальный докер
1
2
3
4
| for f in *.tar; do
echo "Loading $f"
docker load -i "$f"
done
|
Тегируем:
1
2
3
4
5
6
7
8
9
10
11
12
| docker images --format '{{.Repository}}:{{.Tag}}' \
| grep -E '^(quay\.io|registry\.k8s\.io|docker\.io|gcr\.io)/|^nginx:' \
| while read img; do
if [[ "$img" == nginx:* ]]; then
img="docker.io/library/${img}"
fi
new="${HARBOR}/${PROJECT}/${img}"
echo "TAG $img -> $new"
docker tag "$img" "$new"
echo "PUSH $new"
docker push "$new"
done
|
Пушим все образы в локальный репозиторий:
1
2
3
4
5
6
| docker images --format '{{.Repository}}:{{.Tag}}' \
| grep -E "^${HARBOR}/${PROJECT}/(quay\.io|registry\.k8s\.io|docker\.io|gcr\.io)/" \
| while read img; do
echo "PUSH $img"
docker push "$img"
done
|
У меня получился 21 образ в Harbor
Готовим конфиги
Открываем файл:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/all/offline.yml
|
Изменяем конфигурацию kubespray чтобы смотрел в локальный репо:
1
2
3
4
5
6
7
8
9
| # Репозиторий СВОЙ указываем
registry_host: "harbor.domain.local"
kube_image_repo: "{{ registry_host }}/k8s/registry.k8s.io"
gcr_image_repo: "{{ registry_host }}/k8s/gcr.io"
docker_image_repo: "{{ registry_host }}/k8s/docker.io"
quay_image_repo: "{{ registry_host }}/k8s/quay.io"
#Строки нет, добавить:
cilium_install_extra_flags: "--repository oci://{{registry_host}}/helm/cilium"
|
Здесь тоже поменяем, но на момент написания мануала это не работало, именно поэтому мы сделали репозиторий k8s в Harbor открытым.
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/all/containerd.yml
|
Вставить в самый низ:
1
2
3
4
5
| containerd_registry_auth:
- registry: harbor.domain.local
prefix: harbor.domain.local
username: admin
password: password_ot_harbor
|
При загрузке в репозиторий Harbor SHA у образов изменяется, поэтому отключим их сопоставление:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/k8s_cluster/k8s-net-cilium.yml
|
В самый низ файла:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| cilium_extra_values:
image:
useDigest: false
digest: ""
operator:
image:
useDigest: false
digest: ""
envoy:
image:
useDigest: false
digest: ""
hubble:
relay:
image:
useDigest: false
digest: ""
ui:
backend:
image:
useDigest: false
digest: ""
frontend:
image:
useDigest: false
digest: ""
|
Добавляем образы в helm-репо
Копируем helm бинарник:
1
| cp /opt/kubespray-releases/helm-3.18.4/linux-amd64/helm /usr/local/bin/
|
Проверяем:
Авторизовываемся:
1
| helm registry login $HARBOR
|
И пушим наш образ для Cilium:
1
| helm push /opt/cilium-1.18.5.tgz oci://$HARBOR/helm
|
Подготовка нод.
Открываем файл с хостами:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/inventory.ini
|
Переписываем inventory на наши хосты:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| [all]
master-1-k8s ansible_host=192.168.1.101
master-2-k8s ansible_host=192.168.1.102
master-3-k8s ansible_host=192.168.1.103
node-1-k8s ansible_host=192.168.1.104
node-2-k8s ansible_host=192.168.1.105
[kube_control_plane]
master-1-k8s
master-2-k8s
master-3-k8s
[kube_node]
node-1-k8s
node-2-k8s
[etcd]
master-1-k8s
[k8s_cluster:children]
kube_control_plane
kube_node
|
Шаг 5. Установка оффлайн кластера Kubespray
Доустанавливаем на master-1-k8s пакеты:
1
| apt install docker.io -y
|
Если указывался прокси
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/all/all.yml
|
Тогда нужно удалить здесь:
1
2
| # http_proxy: ""
# https_proxy: ""
|
И запускаем установку:
1
2
3
4
| cd /opt/kuber_off/
source venv/bin/activate
cd kubespray/
ansible-playbook -i inventory/offline_cluster/inventory.ini cluster.yml -b -u admin
|
После установки проверяем кластер:

Для вебки нужно раскатать конфиг MetalLB, для этого выбираем свободный пул адресов (я использую 1 адрес) из той же подсети где и кубер.
1
2
3
| mkdir kube-manifests
cd kube-manifests
nano metallb.yml
|
Вставляем:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: ingress-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.200/32
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: ingress-l2
namespace: metallb-system
spec:
ipAddressPools:
- ingress-pool
|
Также создаём deployment ingress контроллера и адрес по которому будет открываться вебка Hubble
1
| nano ingress-hubble-ui.yml
|
Вставляем:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hubble-ui
namespace: kube-system
spec:
ingressClassName: nginx
rules:
- host: hubble.k8s.domail.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hubble-ui
port:
number: 80
|
Применить:
Настрой DNS (или временно C:\Windows\System32\drivers\etc\hosts)
Тебе нужно, чтобы hubble.k8s.domain.local резолвился в 192.168.1.200.
Ingress будет слушать IP адрес MetalLB контроллера.
Всё готово!
Проблемы и решения
- Есть проблемы с авторизацией по containerd, поэтому репозиторий k8s делаем открытым.
- Проблема с образом cilium
Failed to pull image “harbor.domain.local/k8s/quay.io/cilium/cilium:v1.18.5@sha256:2c92fb05962a346eaf0ce11b912ba434dc10bd54b9989e970416681f4a069628”: > rpc error: code = NotFound desc = failed to pull and unpack image “harbor.domain.local”
В файле
1
| inventory/offline_cluster/group_vars/k8s_cluster/k8s-net-cilium.yml
|
Не находит образ с sha. Отключаем.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| cilium_extra_values:
image:
useDigest: false
digest: ""
operator:
image:
useDigest: false
digest: ""
envoy:
image:
useDigest: false
digest: ""
hubble:
relay:
image:
useDigest: false
digest: ""
ui:
backend:
image:
useDigest: false
digest: ""
frontend:
image:
useDigest: false
digest: ""
|
- Ошибка с image Cilium-operator
image operator-generic не закачивается автоматом. Выкачать и закинуть в наш репозиторий.
Failed to pull image “harbor.domain.local/k8s/quay.io/cilium/operator-generic:v1.18.5”: rpc error: code = NotFound desc = failed to pull an>
1
2
3
4
| docker pull quay.io/cilium/operator-generic:v1.18.5
docker tag quay.io/cilium/operator-generic:v1.18.5 harbor.domain.local/k8s/quay.io/cilium/operator-generic:v1.18.5
docker push harbor.domain.local/k8s/quay.io/cilium/operator-generic:v1.18.5
kubectl delete po -n kube-system -l name=cilium-operator
|
Возможно потребуется перепулить image, поэтому меняем политику на Always, пулим и возвращаем на Default
1
2
3
4
| kubectl -n kube-system get deploy cilium-operator -o jsonpath='{.spec.template.spec.containers[0].imagePullPolicy}{"\n"}'
kubectl -n kube-system patch deploy cilium-operator --type='json' -p='[{"op":"replace","path":"/spec/template/spec/containers/0/imagePullPolicy","value":"Always"}]'
kubectl delete po -n kube-system -l name=cilium-operator
kubectl -n kube-system patch deploy cilium-operator --type='json' -p='[{"op":"replace","path":"/spec/template/spec/containers/0/imagePullPolicy","value":"IfNotPresent"}]'
|
- Не поднимается hubble-relay (Не резолвит DNS)
A record lookup error: lookup hubble-peer.kube-system.svc.k8s.domain.local. on 169.254.25.10:53: read udp 10.233.67.64:56328->169.254.25.10:53: i/o timeout" connectionTimeout=30s
Добавить в k8s-net-cilium.yml значение true, перезапустить плейбук с сетевыми тегами и удалить под, чтобы он пересоздался:
1
2
3
| cilium_kube_proxy_replacement: true
ansible-playbook -i inventory/offline_cluster/inventory.ini cluster.yml -b --tags "cilium,network,kubernetes-apps" -v
kubectl delete po -l k8s-app=hubble-relay -n kube-system
|
- Проблема:
cp: cannot create regular file ‘/hostbin/cilium-mount’: Permission denied
В файле
1
| opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/k8s_cluster/k8s-cluster.yaml
|
Доюавить root
1
2
3
| # This is the user that owns the cluster installation.
# Note: cilium needs to set kube_owner to root https://kubespray.io/#/docs/CNI/cilium?id=unprivileged-agent-configuration
kube_owner: root
|
- Ошибка. Не все ноды Cilium поднимаются.
Раскопал, что VMware неочень дружит с Cilium на дефолтном порту. Вывод смена порта или tunnel_mode. Я выбрал второе.
Про это написано здесь
Статус:
1
| kubectl -n kube-system exec -it ds/cilium -- cilium status | egrep -i 'KubeProxyReplacement|Cluster health'
|
Вывод:
1
2
| KubeProxyReplacement: True [ens33 192.168.0.104 (Direct Routing)]
Cluster health: 1/5 reachable (2026-01-30T09:34:21Z) (Probe interval: 2m23.873716367s)
|
Файл:
1
| nano /opt/kuber_off/kubespray/inventory/offline_cluster/group_vars/k8s_cluster/k8s-net-cilium.yml
|
Параметры:
1
2
3
4
| # Overlay Network Mode
cilium_tunnel_mode: geneve
cilium_mtu: "1450"
#tunnelPort: 8223 # Это не сработало для vxlan, поэтому выбрал geneve
|
Запуск повторно:
1
2
3
4
| ansible-playbook -i inventory/offline_cluster/inventory.ini cluster.yml -b --tags "cilium,network" -v
kubectl -n kube-system rollout restart ds/cilium
kubectl -n kube-system rollout status ds/cilium
kubectl -n kube-system exec -it ds/cilium -- cilium status | grep "Cluster health"
|
Post Install
Как управлять всем этим?
Управление самим Kubernetes (нодами, сетью, ПО)
Через Kubespray:
| Задача | Как делать |
|---|
| Добавить ноду | добавить в inventory + scale.yml |
| Обновить k8s версию | поменять kube_version + upgrade-cluster.yml |
| Изменить сеть Cilium | править group_vars/k8s_cluster/k8s-network-cilium.yml + –tags cilium |
- Kubespray = железо кластера.
- Управление Cilium (сеть и безопасность)
| Что | Как управлять |
|---|
| Политики сети | CRD CiliumNetworkPolicy |
| Диагностика сети | cilium status, cilium health, hubble observe |