Setup Kubernetes Cluster Using Kubeadm: Difference between revisions

From wiki.baghirzade.pro
Jump to navigation Jump to search
No edit summary
No edit summary
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Kubeadm Setup Prerequisites ==
На каждую VM:
Following are the prerequisites for '''Kubeadm Kubernetes cluster setup'''.


# Minimum two '''Ubuntu nodes''' [One master and one worker node]. You can have more worker nodes as per your requirement.
* CPU: '''2+ vCPU''' (control-plane лучше 2–4)
# The master node should have a minimum of '''2 vCPU and 2GB RAM'''.
* RAM: '''min 2GB''', лучше '''4GB''' (control-plane 4–8GB)
# For the worker nodes, a minimum of 1vCPU and 2 GB RAM is recommended.
* Disk: '''20GB+'''
# '''10.X.X.X/X''' network range with static IPs for master and worker nodes. We will be using the '''192.x.x.x''' series as the pod network range that will be used by the Calico network plugin. Make sure the Node IP range and pod IP range don't overlap.
* Сеть: все VM '''в одной L2 сети''', чтобы они пинговались по <code>172.16.221.0/24</code>.
Важно для клонов VM:


Set static IP:<pre>
* у каждой ноды должны быть '''уникальные hostname, MAC и product_uuid''' (kubeadm ругается если одинаковые). Проверка:
network:
<syntaxhighlight lang="bash">
  version: 2
hostname
  renderer: networkd
ip link | grep link/
  ethernets:
sudo cat /sys/class/dmi/id/product_uuid
    enp3s0:
      dhcp4: no
      addresses:
        - 10.10.0.50/24
      gateway4: 10.10.0.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 1.1.1.1
</pre>


On cp1:<pre>
</syntaxhighlight>(уникальность прямо указана в kubeadm prerequisites
sudo hostnamectl set-hostname cp1
</pre>On worker1:<pre>
sudo hostnamectl set-hostname w1
</pre>On worker2:<pre>sudo hostnamectl set-hostname w2</pre>Add entries to /etc/hosts on all nodes:<pre>
sudo nano /etc/hosts
</pre>Add the following to the end of the file, replacing with your IP addresses:<pre>
10.0.0.10  cp1
10.0.0.11  w1
10.0.0.12  w2
</pre>This allows nodes to address each other by name rather than by IP address.


'''1. General system preparation (all nodes)'''
== 1) Присвой имена и пропиши hosts (на ВСЕХ нодах) ==
На каждой ноде задай hostname:


'''1.1. Updating packages'''<pre>
'''cp1:'''<syntaxhighlight lang="bash">
sudo apt update
sudo hostnamectl set-hostname cp1
sudo apt upgrade -y
</syntaxhighlight>'''worker1:'''<syntaxhighlight lang="bash">
</pre>We are simply updating the system to avoid bugs caused by old packages.
sudo hostnamectl set-hostname worker1
</syntaxhighlight>'''worker2:'''<syntaxhighlight lang="bash">
sudo hostnamectl set-hostname worker2
</syntaxhighlight>'''worker3:'''<syntaxhighlight lang="bash">
sudo hostnamectl set-hostname worker3
</syntaxhighlight>На '''всех''' нодах добавь в <code>/etc/hosts</code>:<syntaxhighlight lang="bash">
sudo tee -a /etc/hosts >/dev/null <<'EOF'
172.16.221.10 cp1
172.16.221.11 worker1
172.16.221.12 worker2
172.16.221.13 worker3
EOF
</syntaxhighlight>2) Базовая подготовка ОС (на ВСЕХ нодах)


'''1.2. Disable swap (required for kubeadm)'''
2.1 Отключи swap (обязательно)<syntaxhighlight lang="bash">
sudo swapoff -a
sudo sed -i '/\sswap\s/s/^/#/' /etc/fstab
</syntaxhighlight>2.2 Включи нужные модули + sysctl<syntaxhighlight lang="bash">
sudo modprobe overlay
sudo modprobe br_netfilter


On all nodes:<pre>
sudo tee /etc/modules-load.d/k8s.conf >/dev/null <<'EOF'
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
</pre>Verification:<pre>
free -h
</pre>'''1.3. Kernel modules and sysctl (for the grid)↵↵On each node:'''<pre>
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
overlay
br_netfilter
br_netfilter
EOF
EOF
 
</syntaxhighlight>Sysctl:<syntaxhighlight lang="bash">
sudo modprobe overlay
sudo tee /etc/sysctl.d/k8s.conf >/dev/null <<'EOF'
sudo modprobe br_netfilter
net.ipv4.ip_forward = 1
</pre>Now sysctl:<pre>
net.bridge.bridge-nf-call-iptables = 1
cat <<EOF | sudo tee /etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                = 1
EOF
EOF


sudo sysctl --system
sudo sysctl --system
</pre>This includes correct traffic handling through the Linux bridge and forwarding — mandatory for CNI (Calico).
</syntaxhighlight>Проверка (ip_forward должен быть 1) <syntaxhighlight lang="bash">
sysctl net.ipv4.ip_forward
</syntaxhighlight>3) Установка containerd (на ВСЕХ нодах)


'''1.4. (For lab) Disable UFW'''
3.1 Поставь containerd<syntaxhighlight lang="bash">
sudo apt-get update
sudo apt-get install -y containerd
</syntaxhighlight>3.2 Сгенерируй конфиг и включи SystemdCgroup<syntaxhighlight lang="bash">
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
</syntaxhighlight>Открой файл:<syntaxhighlight lang="bash">
sudo nano /etc/containerd/config.toml
</syntaxhighlight>Найди секцию runc options и поставь:


If UFW is enabled and this is a clean lab:<pre>
* для containerd '''1.x''':
sudo ufw disable
<syntaxhighlight lang="bash">
</pre>In Prod, of course, it is better to open the necessary ports, but for the first build it is easier without a firewall.
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true
</syntaxhighlight>


'''2. Install containerd (all nodes)'''
* для containerd 2'''.x''':
<syntaxhighlight lang="bash">
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
  SystemdCgroup = true
</syntaxhighlight>(это требование и примеры прямо в доках Kubernetes


At each node:<pre>
Также убедись, что '''CRI не отключен''': в <code>disabled_plugins</code> не должно быть <code>"cri"</code>
sudo apt install -y containerd
 
</pre>Generate default configuration:<pre>
Перезапусти:<syntaxhighlight lang="bash">
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
</pre>Restart and switch on:<pre>
sudo systemctl restart containerd
sudo systemctl restart containerd
sudo systemctl enable containerd
sudo systemctl enable containerd
sudo systemctl status containerd
</syntaxhighlight>Проверка сокета:<syntaxhighlight lang="bash">
</pre>SystemdCgroup = true → kubelet and containerd use the same cgroup driver (systemd). This is now considered best practice.
ls -l /run/containerd/containerd.sock
</syntaxhighlight>4) Установка kubeadm/kubelet/kubectl (на ВСЕХ нодах)


'''3. Install kubeadm/kubelet/kubectl 1.34 (all nodes)'''
Ставим '''Kubernetes v1.35 (актуальная ветка в доке)''' из '''pkgs.k8s.io'''<syntaxhighlight lang="bash">
 
According to the official documentation for v1.34:
 
'''3.1. Repo packages'''
 
At each node:<pre>
sudo apt-get update
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
</pre>'''3.2. GPG key and pkgs.k8s.io repository (v1.34)↵↵Ubuntu 22.04 already has /etc/apt/keyrings, but if it doesn't:'''
</syntaxhighlight>Ключ:<syntaxhighlight lang="bash">
 
sudo mkdir -p -m 755 /etc/apt/keyrings
Repository key:
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
 
</syntaxhighlight>Репо:<syntaxhighlight lang="bash">
<syntaxhighlight lang="shell">
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo mkdir -p /etc/apt/keyrings
</syntaxhighlight>Установка и “hold”:<syntaxhighlight lang="bash">
 
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key \
  | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
 
</syntaxhighlight>Add repo specifically for Kubernetes 1.34:<pre>
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /" \
  | sudo tee /etc/apt/sources.list.d/kubernetes.list
</pre>'''3.3. Installing kubeadm/kubelet/kubectl'''<pre>
sudo apt-get update
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
</pre><blockquote>Repository v1.34 ensures that branch 1.34.x is installed. apt-mark hold will prevent accidental updates to other minor versions during apt upgrade.</blockquote>(Not required, but you can enable kubelet immediately; it will run and wait for kubeadm init / join):<pre>
</syntaxhighlight>Включи kubelet:<syntaxhighlight lang="bash">
sudo systemctl enable --now kubelet
sudo systemctl enable --now kubelet
</pre>'''5. Control-plane initialisation (cp1 only)'''
</syntaxhighlight>(эти команды и repo-URL — из официальной страницы установки kubeadm


Now we create a cluster on <code>cp1</code>.
5) Инициализация control-plane (ТОЛЬКО на cp1 = 172.16.221.10)


'''5.1. kubeadm init with pod-CIDR for Calico'''
5.1 kubeadm init


Calico uses 192.168.0.0/16 by default. For convenience, we will use the same:
Я использую pod CIDR '''192.168.0.0/16''' (дефолт под Calico). Calico это любит, а документация Calico для kubeadm прямо его упоминает


On <code>cp1</code>:<pre>
На '''cp1''':<syntaxhighlight lang="bash">
sudo kubeadm init \
sudo kubeadm init \
   --apiserver-advertise-address=10.0.0.10 \
   --apiserver-advertise-address=172.16.221.10 \
   --pod-network-cidr=192.168.0.0/16
   --pod-network-cidr=192.168.0.0/16
</pre>
</syntaxhighlight>После успеха kubeadm покажет '''kubeadm join ...''' — '''сохрани его''' (для worker-нод).


* <code>--apiserver-advertise-address</code> — IP cp1, which everyone will use to access the API.
5.2 Настрой kubectl для твоего пользователя
* <code>--pod-network-cidr</code> — The IP range for pods that Calico will use.


At the end, kubeadm will output:
На cp1 (под обычным юзером, не root):<syntaxhighlight lang="bash">
 
* message about successful initialisation;
* The command kubeadm join ... — be sure to copy it somewhere (we will use it on the workers).
 
'''5.2. Configuring kubectl for the sadmin user (cp1)'''
 
Currently, kubeconfig is located in /etc/kubernetes/admin.conf and belongs to root.
 
On cp1 under sadmin:<pre>
mkdir -p $HOME/.kube
mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
</pre>Verification:<pre>
</syntaxhighlight>Проверка:<syntaxhighlight lang="bash">
kubectl get nodes
</pre>Until the network is up, the node may be NotReady — this is normal.
 
'''6. Install Calico 3.31 (cp1 only)'''
 
We take the latest Calico 3.31.1 from the official on-prem instructions.
 
'''6.1. Tigera Operator + CRD'''
 
On <code>cp1</code>:<pre>
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.31.1/manifests/operator-crds.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.31.1/manifests/tigera-operator.yaml
</pre><blockquote>This sets the Calico operator, which then rolls out the necessary components across the nodes itself.</blockquote>'''6.2. Calico configuration (custom-resources)'''
 
By default, we use iptables-dataplane (without eBPF, so as not to complicate things for now).
 
On <code>cp1</code>:<pre>
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.31.1/manifests/custom-resources.yaml
kubectl create -f custom-resources.yaml
</pre>(If you want eBPF in the future, there is also ''custom-resources-bpf.yaml.'')
 
'''6.3. Verify that Calico has started'''
 
On <code>cp1</code>:<pre>
watch kubectl get tigerastatus
</pre>We are waiting until everything is ''AVAILABLE=True:''<pre>
NAME              AVAILABLE  PROGRESSING  DEGRADED  SINCE
calico            True        False        False      ...
ippools          True        False        False      ...
...
</pre>And let's look at the pods:<pre>
kubectl get pods -n calico-system
kubectl get pods -n kube-system
kubectl get nodes
kubectl get nodes
</pre><code>cp1</code> should transition to Ready status.
</syntaxhighlight>На этом этапе cp1 будет <code>NotReady</code> — это нормально, пока не поставим CNI (Calico).
 
'''7. Make the control plane "clean" (without workload pods)'''
 
By default, in 1.34, the control plane can accept normal pods (taint is not set automatically).


You don't need this, so let's set taint right away:
6) Установка Calico (на cp1)


On <code>cp1</code>:<pre>
Чтобы '''не ловить проблемы с operator-crds/annotations''', я даю '''manifest-вариант''' (самый прямой и обычно “без сюрпризов” для учебных кластеров).
kubectl taint nodes cp1 node-role.kubernetes.io/control-plane=:NoSchedule
</pre>Verification:<pre>
kubectl describe node cp1 | grep -i Taint
</pre>It should be something like:<pre>
Taints: node-role.kubernetes.io/control-plane:NoSchedule
</pre><blockquote>Now the scheduler will NOT place regular pods on cp1. Only system components will remain there (kube-apiserver, etcd, kube-controller-manager, scheduler, Calico DaemonSet, etc.).</blockquote>'''8. Connect worker1 and worker2'''


'''8.1. Obtain the join command (if lost)'''
На '''cp1''':<syntaxhighlight lang="bash">
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.31.2/manifests/calico.yaml
kubectl apply -f calico.yaml
</syntaxhighlight>(официальная дока Calico для on-prem/kubeadm: скачать <code>calico.yaml</code> и применить


If you did not save the output of kubeadm init, on cp1:<pre>
Подожди, пока поднимется:<syntaxhighlight lang="bash">
sudo kubeadm token create --print-join-command
kubectl get pods -n kube-system -w
</pre>Example:<pre>
</syntaxhighlight>Проверка, что ноды стали Ready:<syntaxhighlight lang="bash">
kubeadm join 10.0.0.10:6443 --token abcdef.0123456789abcdef \
kubectl get nodes -o wide
  --discovery-token-ca-cert-hash sha256:xxxxxxxx...
</syntaxhighlight>7) Подключение worker-нод (на worker1/2/3)
</pre>8.2. Perform a join on worker1 / worker2↵↵On worker1:<pre>
sudo kubeadm join 10.0.0.10:6443 --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:xxxxxxxx...
</pre>On <code>worker2</code>:<pre>
sudo kubeadm join 10.0.0.10:6443 --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:xxxxxxxx...
</pre><blockquote>Here, a token and CA hash are used to enable workers to securely join the cluster.</blockquote>After that, on <code>cp1</code>:<pre>
kubectl get nodes
</pre>Expected result:<pre>
NAME      STATUS  ROLES          AGE  VERSION
cp1      Ready    control-plane  20m  v1.34.x
worker1   Ready    <none>          5m    v1.34.x
worker2  Ready    <none>          3m    v1.34.x
</pre>If workers are NotReady for some time, wait until kube-proxy + Calico catch up and start.


'''9. Verification: only on worker nodes'''
На '''каждой''' worker-ноде выполни команду, которую показал <code>kubeadm init</code> на cp1, вида:<syntaxhighlight lang="bash">
sudo kubeadm join 172.16.221.10:6443 --token <TOKEN> \
  --discovery-token-ca-cert-hash sha256:<HASH>
</syntaxhighlight>После подключения всех:<syntaxhighlight lang="bash">
kubectl get nodes -o wide
</syntaxhighlight>8) Быстрые проверки “всё ок”


Let's create a test deployment:
8.1 Системные поды<syntaxhighlight lang="bash">
kubectl -n kube-system get pods -o wide
</syntaxhighlight>8.2 CoreDNS должен быть Running<syntaxhighlight lang="bash">
kubectl -n kube-system get deploy coredns
</syntaxhighlight>9) Частые проблемы и как чинить (коротко)


On <code>cp1</code>:<pre>
1) Node NotReady после Calico
kubectl create deployment nginx --image=nginx --replicas=3
kubectl expose deployment nginx --port=80 --type=NodePort
</pre>Let's see:<pre>
kubectl get pods -o wide
</pre>All nginx pods should be on worker1 and worker2, but not on cp1.↵↵If you see a pod on cp1, it means that taint did not apply → once again:<pre>
kubectl taint nodes cp1 node-role.kubernetes.io/control-plane=:NoSchedule --overwrite
kubectl rollout restart deploy nginx
</pre>✅ 1. How to delete these pods (Deployment + Service)


You created:
смотри:<syntaxhighlight lang="bash">
kubectl -n kube-system get pods -o wide
kubectl -n kube-system describe pod <calico-node-...>
</syntaxhighlight>проверь sysctl/модули (<code>br_netfilter</code>, <code>ip_forward=1</code>)
2) kubelet ругается на cgroup


* Deployment: '''nginx'''
* 99%: не включил <code>SystemdCgroup = true</code> в containerd или CRI отключен Kubernetes
* Service: '''nginx'''
* после правки:
<syntaxhighlight lang="bash">
sudo systemctl restart containerd kubelet
</syntaxhighlight>3) Token протух


To remove:<pre>
На cp1 сгенерь новый join:<syntaxhighlight lang="bash">
kubectl delete service nginx
kubeadm token create --print-join-command
</pre>Remove Deployment:<pre>
</syntaxhighlight>
kubectl delete deployment nginx
</pre>Let's check:<pre>
kubectl get pods
kubectl get svc
</pre>📌 If you want to remove EVERYTHING related to nginx with a single command:<pre>
kubectl delete deploy,svc nginx
</pre>Установить пакет bash-completion (если ещё нет)<pre>
sudo apt install bash-completion -y
</pre>Активировать автодополнение в текущей сессии:<pre>
source /etc/bash_completion
</pre>Включить autocomplete для kubectl<pre>
echo "source <(kubectl completion bash)" >> ~/.bashrc
source ~/.bashrc
</pre>

Latest revision as of 13:51, 7 January 2026

На каждую VM:

  • CPU: 2+ vCPU (control-plane лучше 2–4)
  • RAM: min 2GB, лучше 4GB (control-plane 4–8GB)
  • Disk: 20GB+
  • Сеть: все VM в одной L2 сети, чтобы они пинговались по 172.16.221.0/24.

Важно для клонов VM:

  • у каждой ноды должны быть уникальные hostname, MAC и product_uuid (kubeadm ругается если одинаковые). Проверка:
hostname
ip link | grep link/
sudo cat /sys/class/dmi/id/product_uuid

(уникальность прямо указана в kubeadm prerequisites

1) Присвой имена и пропиши hosts (на ВСЕХ нодах)

На каждой ноде задай hostname:

cp1:

sudo hostnamectl set-hostname cp1

worker1:

sudo hostnamectl set-hostname worker1

worker2:

sudo hostnamectl set-hostname worker2

worker3:

sudo hostnamectl set-hostname worker3

На всех нодах добавь в /etc/hosts:

sudo tee -a /etc/hosts >/dev/null <<'EOF'
172.16.221.10 cp1
172.16.221.11 worker1
172.16.221.12 worker2
172.16.221.13 worker3
EOF

2) Базовая подготовка ОС (на ВСЕХ нодах) 2.1 Отключи swap (обязательно)

sudo swapoff -a
sudo sed -i '/\sswap\s/s/^/#/' /etc/fstab

2.2 Включи нужные модули + sysctl

sudo modprobe overlay
sudo modprobe br_netfilter

sudo tee /etc/modules-load.d/k8s.conf >/dev/null <<'EOF'
overlay
br_netfilter
EOF

Sysctl:

sudo tee /etc/sysctl.d/k8s.conf >/dev/null <<'EOF'
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sudo sysctl --system

Проверка (ip_forward должен быть 1)

sysctl net.ipv4.ip_forward

3) Установка containerd (на ВСЕХ нодах) 3.1 Поставь containerd

sudo apt-get update
sudo apt-get install -y containerd

3.2 Сгенерируй конфиг и включи SystemdCgroup

sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml >/dev/null

Открой файл:

sudo nano /etc/containerd/config.toml

Найди секцию runc options и поставь:

  • для containerd 1.x:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true
  • для containerd 2.x:
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
  SystemdCgroup = true

(это требование и примеры прямо в доках Kubernetes

Также убедись, что CRI не отключен: в disabled_plugins не должно быть "cri"

Перезапусти:

sudo systemctl restart containerd
sudo systemctl enable containerd

Проверка сокета:

ls -l /run/containerd/containerd.sock

4) Установка kubeadm/kubelet/kubectl (на ВСЕХ нодах) Ставим Kubernetes v1.35 (актуальная ветка в доке) из pkgs.k8s.io

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

Ключ:

sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

Репо:

echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

Установка и “hold”:

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

Включи kubelet:

sudo systemctl enable --now kubelet

(эти команды и repo-URL — из официальной страницы установки kubeadm

5) Инициализация control-plane (ТОЛЬКО на cp1 = 172.16.221.10)

5.1 kubeadm init

Я использую pod CIDR 192.168.0.0/16 (дефолт под Calico). Calico это любит, а документация Calico для kubeadm прямо его упоминает

На cp1:

sudo kubeadm init \
  --apiserver-advertise-address=172.16.221.10 \
  --pod-network-cidr=192.168.0.0/16

После успеха kubeadm покажет kubeadm join ...сохрани его (для worker-нод).

5.2 Настрой kubectl для твоего пользователя

На cp1 (под обычным юзером, не root):

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Проверка:

kubectl get nodes

На этом этапе cp1 будет NotReady — это нормально, пока не поставим CNI (Calico).

6) Установка Calico (на cp1)

Чтобы не ловить проблемы с operator-crds/annotations, я даю manifest-вариант (самый прямой и обычно “без сюрпризов” для учебных кластеров).

На cp1:

curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.31.2/manifests/calico.yaml
kubectl apply -f calico.yaml

(официальная дока Calico для on-prem/kubeadm: скачать calico.yaml и применить Подожди, пока поднимется:

kubectl get pods -n kube-system -w

Проверка, что ноды стали Ready:

kubectl get nodes -o wide

7) Подключение worker-нод (на worker1/2/3) На каждой worker-ноде выполни команду, которую показал kubeadm init на cp1, вида:

sudo kubeadm join 172.16.221.10:6443 --token <TOKEN> \
  --discovery-token-ca-cert-hash sha256:<HASH>

После подключения всех:

kubectl get nodes -o wide

8) Быстрые проверки “всё ок” 8.1 Системные поды

kubectl -n kube-system get pods -o wide

8.2 CoreDNS должен быть Running

kubectl -n kube-system get deploy coredns

9) Частые проблемы и как чинить (коротко)

1) Node NotReady после Calico

смотри:

kubectl -n kube-system get pods -o wide
kubectl -n kube-system describe pod <calico-node-...>

проверь sysctl/модули (br_netfilter, ip_forward=1)

2) kubelet ругается на cgroup

  • 99%: не включил SystemdCgroup = true в containerd или CRI отключен Kubernetes
  • после правки:
sudo systemctl restart containerd kubelet

3) Token протух На cp1 сгенерь новый join:

kubeadm token create --print-join-command