Установка kubernetes в Redos 8
... с локальным registry в Redos 8
Шпаргалка по kubectl kubectl/cheatsheet/
kubectl run --image mirror.gcr.io/alpine al2 --restart=Always -- sleep 600 # "демонический" запуск
kubectl run --image server1:5000/alpine al2 --rm -ti --restart=Never -- sh # интерактивный одноразовый запуск
kubectl run ng1 --image=nginx --dry-run -o yaml > ng1.yaml # записать спецификацию pod'а в файл pod.yaml , не создавая pod'а
kubectl run ng2 --image=nginx --port 80 --restart=Never -n mynamespace # Запустить pod' nginx в заданном namespace
kubectl get pods -o wide -A # список всех pod'ов
kubectl get pods pod_name -o jsonpath='{.spec.initContainers[*].name}' # список контейнеров pod'а
kubectl debug --image server1:5000/busybox -ti -c al4-busybox pod/al4 -- sh # добавить в pod временный контейнер al4-busybox и войти в его shell
kubectl exec -ti -c al4-busybox pod/al4 -- sh # запустить интерактивную команду в контейнере al4-busybox pod'a al4
kubectl logs my-pod # логи pod'а (в stdout)
kubectl logs -l name=myLabel # логи pod'а с меткой myLabel (в stdout)
kubectl logs my-pod --previous # логи pod'а (в stdout) по предыдущему экземп ляру контейнера
kubectl logs my-pod -c my-container # логи контейнера pod'а (в stdout)
kubectl logs -f my-pod # логи pod'а в режиме реального времени (в stdout)
kubectl logs -f my-pod -c my-container # логи контейнера pod'а в режиме реального времени (в stdout)
kubectl logs -f -l name=myLabel --all-containers # логи всех pod'ов с меткой myLabel (в stdout)
kubectl attach my-pod -i # Прикрепить терминал к запущенному контейнеру
kubectl port-forward my-pod 5000:80 # Переадресовать порт localhost:5000 клиентской машины на pod/my-pod:80
kubectl exec my-pod -- ls / # Выполнить команду в первом контейнере pod'а
kubectl exec my-pod -ti -c my-container -- sh # Интерактивная команду в конкретном контейнере pod'а
kubectl top pod POD_NAME --containers # Показать метрики по заданному pod'у вместе с его контейнерами
# Создать deplojment вместе с сервисом для него:
kubectl create deployment myapp --image=nginx
kubectl expose deployment myapp --port=80 --target-port=80 --type=ClusterIP
kubectl create deploy qqqq --image=nginx:latest --replicas=2
# label/selector будут сгенерены автоматически: app=deployname
# selector деплоймент'а обязан соответствовать label pod''а
# к селектору автоматически добавляется проверка на совпадение
# авто-метки pod-template-hash
# Как посмотреть pod'ы входящие в deploy. Одной командой -o yaml, по человечески - никак
# Универсально: Сперва смотрим что есть, распечатываем метки, затем grep -
kubectl get -A deploy,po -o wide --show-labels
# состав deploy/coredns - ловим grep по имени, либо по selector label
kubectl get pods -A -o custom-columns=:metadata.name --no-headers | grep '^coredns-'
kubectl get pods -l k8s-app=kube-dns -n kube-system -o custom-columns=:metadata.name --no-headers
kubectl apply -f qqqq.yaml
kubectl get deploy,po -o wide --show-labels
# Работа с метками pod'а в Deploy и ReplicaSet(RS создается только манифестом)
kubectl get pod --show-labels # посмотреть
kubectl label pod ng5-abcd app- # удалить метку app=ng5
kubectl label pod ng5-abcd app=ng4 # прописать метку app=ng4
# Если у pod'а удалить селекторный label, он покинет RS и Deploy
# вместо него сразу создается новый pod
# Если подменить селекторный label, pod "заедет" в указанный RS
# а лишний pod в RS будет удален
# Чтоб pod "заехал" в указанный deployment, необходимо подменять
# две метки: селекторную "app=deployname" и pod-template-hash
# т.к. RS входящему в Deploy генерится двойной selector: app и hash
#### qqqq.yaml #####################################
apiVersion: apps/v1
kind: Deployment
metadata:
name: qqqq
spec:
replicas: 2
selector:
matchLabels:
app: qqqq
template:
metadata:
labels:
app: qqqq
spec:
containers:
- image: nginx:latest
name: nginx
#########################################
Создание сервисов, команда expose
# Создать pod+service одной командой
kubectl run ng2 --image=nginx:alpine --port=80 --expose
kubectl create service ... servicename # создает сервис с селектором по имени сервиса app=servicename
kubectl expose deploy # создает сервис для деплоя взяв селектор из из деплоя app=deployname
kubectl expose pod # создает сервис для под'а с селектором из pod run=podname
kubectl expose deployment/pod/rc/rs {name}
[--port=port] [--protocol=TCP|UDP|SCTP] [--target-port=number-or-name]
[--type=ClusterIP|NodePort|LoadBalancer]
# Если deployment создан с --port, то в expose порт указывать не обязательно
kubectl create service clusterip {service-name} \
--tcp={port:targetPort} [--udp={port:targetPort}]
kubectl create service nodeport {service-name} \
--tcp={port:targetPort} [--udp={port:targetPort}]
kubectl create service loadbalancer {service-name} \
--tcp={port:targetPort}
# Просто добавляет в kubedns CN запись на желаемое имя домена
kubectl create service externalname {service-name} \
--external-name={external-dns-name}
# Создание HeadLess сервиса для deploy (тип ClusterIP но с clusterIP:None)
# тогда адреса pod'ов доступны через dns и kubectl get endpoints
kubectl expose deployment ng4 --overrides='{"spec":{"clusterIP": "None"}}'
nslookup ng4.default.svc.cluster.local 10.96.0.10
Name: ng4.default.svc.cluster.local
Address: 10.244.0.63
Name: ng4.default.svc.cluster.local
Address: 10.244.0.65
kubectl get endpoints ng4
ng4 10.244.0.62:80,10.244.0.63:80,10.244.0.64:80 + 1 more... 3m26s
kubectl get endpoints ng4 -o yaml | egrep 'ip|name:'
Каждый сервис автоматически регистрируется в kube-dns с хостнеймом вида
servicename.namespace.svc.cluster.local Например:
kubectl run --image nginx ng1 # создали pod ng1 с nginx
kubectl run --image nginx ng2 # создали pod ng1 с nginx
kubectl create deploy --image nginx --port 80 --replicas 2 ng3 # создали deploy ng3
kubectl create service clusterip --tcp 80 ng1 # создали для него service селектирующий метку сервиса ng1
kubectl expose --type clusterip --port 80 ng1 # создали для него service селектирующий все метки pod'а ng2
kubectl expose --type nodeport ng3 # создали для deploy/ng3 service селектирующий все метки deploy/ng3
kubectl get endpoints -A # Посмотреть оконечные порты сервисов
kubectl get service -A # Посмотреть IP-адреса dns-сервиса и сервиса для ng1
. . .
default ng1 ClusterIP 10.100.107.211 {none} 80/TCP 5m22s
kube-system kube-dns ClusterIP 10.96.0.10 {none} 53/UDP,53/TCP,9153/TCP 69m
nslookup kube-dns.kube-system.svc.cluster.local 10.96.0.10
Server: 10.96.0.10
Name: kube-dns.kube-system.svc.cluster.local
Address: 10.96.0.10
nslookup ng1.default.svc.cluster.local 10.96.0.10
Server: 10.96.0.10
Name: ng1.default.svc.cluster.local
Address: 10.100.107.211
# В контейнере kube-dns задан в /etc/resolv.conf, текущий namespace-домен добавлен в search
kubectl run --image busybox --restart Never --rm -ti alp2 cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
ingress-контроллер: Веб-точка входа с reverce-proxy, переруливает запросы на
внутренние сервисы кубера. Кого-куда узнает через Ingress-API
# загрузка ингресс-контроллера NGINX IngressClass:nginx
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.14.3/deploy/static/provider/baremetal/deploy.yaml
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
kubectl get ingressclass
kubectl get all -n ingress-nginx
# удаление ingress-nginx
kubectl delete all --all -n ingress-nginx
kubectl delete ns ingress-nginx
kubectl delete ingressclass nginx
kubectl delete ValidatingWebhookConfiguration ingress-nginx-admission
kubectl delete MutatingWebhookConfiguration ingress-nginx-admission
Создаем ingress с правилом переадресации, и атрибутом spec.ingressClassName
(или annotations: kubernetes.io/ingress.class: "nginx")
Все ingress-контроллеры читают все Ingress из API, но реагирует только на
"свой" IngressClass
Обращаться к ингрессам через NodePort контроллера, добавив требуемые host-
names в dns или /etc/hosts
Если несколько ingress-controller, ingress с незаданным class достаются
ровно одному IngressClass с аннотацией
ingressclass.kubernetes.io/is-default-class: "true"
Если дефолтного контроллера нет, то ингресс остануться "ничьими"
kubectl describe ingressclass nginx | grep default
# Назчначить default ingressclass
kubectl patch ingressclass nginx -p '{"metadata": {"annotations":{"ingressclass.kubernetes.io/is-default-class":"true"}}}'
# Либо можно ходить на cluster-IP сервиса ingress-nginx-controller
# и использовать 80, 443 порты
# Чтоб ингресс-контроллер сидел не на NodePort'ах а на 80 и 443 хостов
# прописать ему в манифест hostPort # не сработает, нужно root для nginx
kubectl edit -n ingress-nginx deployments.apps ingress-nginx-controller
- containerPort: 80
hostPort: 80
- containerPort: 443
hostPort: 443
#######################################################################
# переадресовка домена ng2.local в сервис ng2
echo `hostname -I |cut -f1 -d' '` ng2.local >> /etc/hosts
kubectl create ingress ng2-ing --class=nginx --rule=ng2.local/=ng2:80
curl ng2.local:30694 # 30694 -- nodeport ingress-контроллера "nginx"
Можно указывать несколько --rule в одной команде
# По умолчанию --rule создает редиректы с бесполезным pathType: Exact
# они работают только при точном совпадении url. А нам нужны pathType: Prefix
# Все web-запросы реадресовать на ng2
kubectl create ingress ng2-catchall --class=nginx --rule="/=ng2:80"
kubectl create ingress ng2-catchall --class=nginx --default-backend="ng2:80"
# Запустить pod nginx с маркированным index.html и авто-сервисом на 80
kubectl run ng1 --port 80 --expose --image=nginx -- \
sh -c 'echo "Pod: $(hostname)" > /usr/share/nginx/html/index.html && nginx -g "daemon off;"'
# Запустить deploy nginx сервис для него на 80
kubectl create deploy dep2 --replicas 3 --image=nginx -- \
sh -c 'echo "Pod: $(hostname)" > /usr/share/nginx/html/index.html && nginx -g "daemon off;"'
kubectl create service nodeport dep2 --tcp 80
# redirect по hostname
kubectl create ingress dep2 --rule="dep2.local/=dep2:80" --dry-run -o yaml |\
sed 's/pathType:.*/pathType: Prefix/' | kubectl apply -f -
# redirect по local-url
kubectl create ingress ng8 --class=nginx --rule=ng2.local/ng8=ng2:80
kubectl edit ingress ng8
#### добавить аннотацию ##### и изменить pathType на Prefix ###
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
...
path: /ng9
pathType: Prefix
################################
kubectl create ingress ng9 \
--class=nginx \
--rule="ng2.local/ng9(/|\$)(.*)=ng9:80" \
--annotation="nginx.ingress.kubernetes.io/rewrite-target=/\$2"
kubectl create ingress ng9 --class=nginx --rule="/ng9=ng9:80"
# NB! по факту будет редиректить http://ng9.local/ng9 в сервис:ng9/ng9
# префикс /ng9 останется в url передаваемом в сервисный pod
Taints - запрет запуска pod'ов на ноде
Можно прописать запрет, добавив ключ для игнорирования запрета
PreferNoSchedule # запускать нежелательно
NoSchedule # нельзя запускать
NoExecute # нельзя запускать, убить запущенные
# установить запрет
kubectl taint node stationX node-role.kubernetes.io/control-plane:NoSchedule
# посмотреть taints (запреты) для ноды
kubectl describe node worker1001 | egrep -i -A3 taints
kubectl get node station2.example.com -o yaml | egrep -i -A3 taints
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane:NoSchedule
# снять запрет (- в конце)
kubectl taint node stationX node-role.kubernetes.io/control-plane:NoSchedule-
# Чтобы pod' игнорировал запрет, добавить в манифест pod_toleration_example.yaml
# tolerationSeconds - сколько времени игнорировать
spec
tolerations
- key: "node.kubernetes.io/network-unavailable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 300
Context для доступа к kubernetes master
Config для доступа задается:
0. kubectl --cluster --user --context
1. kubectl --kubeconfig=configfile ...
2. KUBECONFIG=configfile[:file_path21:file_path31:file_path41:...]
3. ~/.kube/config
4. http://localhost:8080 # если остальные варианты не заданы
Создание составного конфига с несколькими context
# склейка конфигов с автопереименованием совпадающих атрибутов
export KUBECONFIG=~/k1:~/k8 # NB! автопереименование НЕ СРАБАТЫВАЕТ!
kubectl config view --merge --flatten > ~/merged-config
# Поэтому колхозим ручной режим.
# Посмотреть кластера, пользователей и контексты в config
for get in get-clusters get-users get-contexts;do kubectl config $get --kubeconfig k8;done
kubectl config rename-context kubernetes-admin@kubernetes kubernetes8-admin@kubernetes8 --kubeconfig k8
vi k8 # user и cluster в k8 правим руками
sed -i -e "s/kubernetes/kubernetes8/g" k8 # или sed
# Валидирование config-файла --minify=только текущий контекст, --flatten log-формат
for get in get-clusters get-users get-contexts;do kubectl config $get --kubeconfig k7;done|grep -v NAME
for get in get-clusters get-users get-contexts;do kubectl config $get --kubeconfig k8;done|grep -v NAME
kubectl config view --kubeconfig=k7
kubectl config view --kubeconfig=k8
# Склейка модифицированных конфигов
KUBECONFIG=~/k7:~/k8 kubectl config view --merge --flatten > ~/merged-config
kubectl config view # просмотр конфигов
Работа с несколькими контекстами
kubectl config current-context # узнать current
kubectl config get-context # посмотреть доступные context ( current помечен "*" )
kubectl config get-context use-context kubernetes-admin@kubernetes # назначить current
kubectl config set-context --namespace default --current # в [текущем] контексте переназначить namespace
kubectl config set-context --namespace kube-system kubernetes8-admin@kubernetes8
kubectl get nodes # коннект в current и не-current context
kubectl get nodes --context kubernetes8-admin@kubernetes8
# Скопировать все об'екты одного кубера namespace:default в другой
kubectl get all -n default -o yaml --context kubernetes-admin@kubernetes |\
kubectl apply -f - --context kubernetes13-admin@kubernetes13
Пересоздание /etc/kubernetes/admin.conf с сохранением самого кластера
kubeadm init phase kubeconfig admin --kubeconfig-dir /etc/kubernetes
kubeadm init phase kubeconfig admin --kubeconfig-dir /etc/kubernetes \
--control-plane-endpoint "IP_MASTER:6443"
ё NB! без --kubeconfig-dir /etc/kubernetes он перегенерит ~root/.kube/config
Создание конфига с нуля
kubectl config set-cluster prod \
--server=https://api.prod.example.com --certificate-authority=$(base64 -i prodCA.crt)
kubectl config set-credentials admin \
--client-certificate=client.crt --client-key=client.key
User "admin" set.
# создание контекста prod_admin (контекст = api-url+user + namespace )
kubectl config set-context prod_admin --cluster=prod --user=admin --namespace=kube-system
# назначение дефолтного namespace для контекста
kubectl config set-context --current --namespace=namespace
Создание пользовательского контекста s1 с правами на namespace s1
[master]# kubectl create namespace s1
[master]# kubectl create -f http://server1/limitRange.yaml -n s1
[master]# kubectl create -f http://server1/resourceQuota.yaml -n s1
[master]# kubectl create rolebinding s1-admin --clusterrole=admin --user=s1 -n s1
rolebinding.rbac.authorization.k8s.io/s1-admin created
[master]# kubeadm alpha kubeconfig user --config=kubeadm-config.yaml --client-name=s1 --org=gurus > s1.kubeconfig
[master]# kubectl --kubeconfig=s1.kubeconfig config set-context --namespace=s1 --current
# kubectl config get-contexts
# kubectl config set-context kubernetes-admin@kubernetes --namespace=kube-system
# kubectl config get-contexts
* УСТАНОВКА KUBERNETES с внутренним(оффлайновым) registry *
Установка почти такая же, как в онлайне, но потребуется 3 дополнительных шага:
1) Делаем свой локальный http registry, закачиваем в него все необходимые образы
# Поднимаем локальный http registry на адрес server:5000
server1$ docker run -d -p 5000:5000 -v /var/lib/registry:/var/lib/registry \
--restart always --name registry registry:2
# Список обязательных kuber-образов получим командой:
kubeadm config images list # версия может быть .12 или .15
registry.k8s.io/kube-apiserver:v1.28.15
registry.k8s.io/kube-controller-manager:v1.28.15
registry.k8s.io/kube-scheduler:v1.28.15
registry.k8s.io/kube-proxy:v1.28.15
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.15-0
registry.k8s.io/coredns/coredns:v1.10.1
registry.red-soft.ru/k8s8/flannel-cni-plugin-flannel:latest
registry.red-soft.ru/k8s8/flannel-flanneld:latest
for image in ` kubeadm config images list | cut -f2-3 -d/ ` ; do
docker pull registry.k8s.io/$image
docker tag registry.k8s.io/$image server1:5000/$image
docker push server1:5000/$image
done
docker image tag server1:5000/coredns/coredns:v1.10.1 server1:5000/coredns:v1.10.1
docker image push server1:5000/coredns:v1.10.1 # tak nado
# Дополнительно загружаем images для боевой работы:
for image in busybox alpine nginx redis ubuntu fedora httpd mysql ; do
docker pull $image ; docker tag $image server1:5000/$image ; docker push server1:5000/$image
done
# Если наш локальный doker не может качать из registry.k8s.ie то качаем "у друга",
# Сейвим имаджи в TAR, и импортируем их у себя
external$ for image in {список необходимых образов} ; do
docker image save $f > kuber/$image.tar ; done
internal$ scp -r external.site:kuber/ .
internal$ for file in kuber/*.tar; do docker image load -i kuber/$file ; done
2) На _всех_ нодах правим /etc/containerd/config.toml
На _всех_ нодах containerd указываем альтернативный registry и отмену для него https
И назначаем свой local registry в качестве default registry
#############################################################################
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."server1:5000".tls]
insecure_skip_verify = true
. . . .
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."server1:5000"]
endpoint = ["http://server1:5000"]
. . . .
sandbox_image = "server1:5000/pause:3.9"
. . . .
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
####### а тут команда которая все это проделает "in place" #################
sed -i\
-e '/\[plugins."io.containerd.grpc.v1.cri".registry.mirrors\]/a\
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."server1:5000"]\
endpoint = ["http://server1:5000"]' \
-e '/\[plugins."io.containerd.grpc.v1.cri".registry.configs\]/a\
[plugins."io.containerd.grpc.v1.cri".registry.configs."server1:5000".tls]\
insecure_skip_verify = true' \
-e '/sandbox_image/ s%registry.k8s.io/pause:3.8%server1:5000/pause:3.9%' \
-e '/^\s*\[plugins."io.containerd.grpc.v1.cri".registry\]/,+1s/config_path = ""/config_path = "\/etc\/containerd\/certs.d"/' \
/etc/containerd/config.toml
#################################################################3
# Дефолтным registry изначально является docker.io. Перемапливаем его:
# в /etc/containerd/config.toml указываем каталог настроек registry и в нем
# создаем /etc/containerd/certs.d/docker.io/hosts.yaml "фиктивного" docker.io
mkdir -p /etc/containerd/certs.d/docker.io
cat > /etc/containerd/certs.d/docker.io/hosts.toml << EOF;
server = "https://docker.io"
[host."http://server1:5000"]
capabilities = ["pull", "resolve"]
EOF
systemctl restart containerd kubelet
#############################################################################
3) Инсталлятору добавить ключ --image-repository=server1:5000
# Перед установкой имеет смысл закачать kuber-images заранее:
kubeadm config images list
kubeadm config images pull --image-repository=server1:5000
# А теперь собственно установка master'а
kubeadm reset # ресетим старый конфиг и новый init
kubeadm init --image-repository=server1:5000 \
--pod-network-cidr=10.244.0.0/16 \
--kubernetes-version=$(kubeadm version -o=short)
# возможные дополнительные параметры:
# --apiserver-advertise-address=0.0.0.0
# --service-cidr=10.96.0.0/16
* УСТАНОВКА KUBERNETES ИСПОЛЬЗУЯ ВНЕШНИЙ registry.k8s.io *
######## Устанавливаем кубелет и containerd на master-ноде и на всех worker-нодах #######
echo ==== Отключаем swap
swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
echo ==== Проверяем правильность hostname
hostname && hostname -I
echo ==== Обязательные модули ядра
cat > /etc/modules-load.d/containerd.conf << EOF;
overlay
br_netfilter
EOF
modprobe overlay ; modprobe br_netfilter
lsmod | grep -E "br_netfilter|overlay"
echo ==== sysctl-переменные необходимые kubernetes-сетям - ip-forwarding, nf-iptables
cat > /etc/sysctl.d/99-kubernetes-cri.conf << EOF;
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sysctl --system
echo ==== отключить использование stub-resolv в systemd-resolved
sed -i 's|#DNSStubListener=yes|DNSStubListener=no|g' /etc/systemd/resolved.conf
systemctl daemon-reload
systemctl restart systemd-resolved.service
echo ==== УСТАНОВКА KUBERNETES
dnf install -y kubernetes kubernetes-kubeadm containerd iproute-tc
iptables -P FORWARD ACCEPT
containerd config default | tee /etc/containerd/config.toml
sed -i 's|bin_dir = "/opt/cni/bin"|bin_dir = "/usr/libexec/cni"|g' /etc/containerd/config.toml
sed -i 's|SystemdCgroup = false|SystemdCgroup = true|g' /etc/containerd/config.toml
systemctl daemon-reload
systemctl restart containerd
systemctl enable --now containerd
systemctl enable kubelet.service
echo ==== Чтоб устанавливаемая потом CNI flannele находила свой исполнимый файл
ln -s /opt/cni/bin/flannel /usr/libexec/cni/flannel
echo ==== Обеспечиваем себе возможность командовать containerd командой sudo crictl
crictl config --set runtime-endpoint=unix:///run/containerd/containerd.sock \
--set image-endpoint=unix:///run/containerd/containerd.sock
crictl completion bash > /etc/bash_completion.d/crictl
##############################################################################################
##### в случае использования локального registry server1:5000 ################################
# в этом месте можно запустить подготовку kubelet к локальному registry
# а затем активировать МАСТЕР'а командой
# kubeadm init --pod-network-cidr=10.244.0.0/16 \
# --image-repository=server1:5000 \
# --kubernetes-version=$(kubeadm version -o=short)
#
# NB! без CNI pod-network задана в /etc/cni/net.d/100-crio-bridge.conflist и там 10.85.0.0/16
######################################
################### АКТИВАЦИЯ MASTER'А С ИСПОЛЬЗОВАНИЕМ ВНЕШНЕГО registry.k8s.io ############
echo ==== Смотрим версию kubernetes
kubeadm version -o=short # или
kubeadm version -o=yaml
echo ==== Настройка Master-ноды
kubeadm init --pod-network-cidr=10.244.0.0/16 --kubernetes-version=$(kubeadm version -o=short)
##############################################################################################
###### НАСТРОЙКА КОНФИГОВ КЛИЕНТА kubectl для root и обычного польователя #####
echo ==== Для управления кластером от имени непривилегированного пользователя
for user in root student $USER ; do
KUBEDIR=`eval echo ~$user/.kube` ;
mkdir $KUBERDIR 2> /dev/null
cp /etc/kubernetes/admin.conf $KUBERDIR/config
chown -R $user $KUBERDIR
done
# echo ==== Для управления кластером от имени root
# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> /root/.bashrc
# source /root/.bashrc
# export KUBECONFIG=/etc/kubernetes/admin.conf
###############################################################################
##### ПОДКЛЮЧЕНИЕ worker ИСПОЛНЯЕТСЯ НА КАЖДОЙ worker-ноде ##################
echo `$(ssh root@master kubeadm token create --print-join-command) `
echo Нажми CTRL-C если передумал подключаться в kubernetes-кластер
sleep 15
`$(ssh root@master kubeadm token create --print-join-command) `
# Альтернатива: запустить циклом с master'a
# for worker in {список worker-нод} ; do
# kubeadm token create --print-join-command | ssh root@$worker sh ; done
#############################################################################
#### Конфигурирование CNI flannele исполняется на МАСТЕР'е после подключения worker-нод ###
#### впрочем, потом, на вновь добавляемых нодах pod'ы с flannele запустятся автоматически
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
ln -s /opt/cni/bin/flannel /usr/libexec/cni/flannel
echo ==== coredns, запущенные до flannel - на неправильных ClusterIP. Delete for correct restart
for pod in `kubectl get pods -l k8s-app=kube-dns -n kube-system -o custom-columns=:metadata.name --no-headers`
do kubectl delete -n kube-system pod/$pod ; done
sleep 15 ; kubectl get pods -A -o wide ; sleep 15 ; kubectl get pods -A -o wide
kubectl get nodes -o wide
# Если kubectl describe pod/kube-flannele... -n kube-flannel # показывает "cni0 flannel error"
##### то удалить бридж cni0 и поды pod/coredns-* и рестартануть kubelet
# ip link delete cni0 type bridge
# kubectl delete -n kube-sytem pod/coredns-...
##### то удалить бриджи cni0 и flannel.1
# ip link set cni0 down ; ip link set flannel.1 down
# ip link delete cni0 ; ip link delete flannel.1
## или ip link delete cni0 type bridge # или # brctl delbr cni0
# systemctl restart containerd kubelet
#############################################################################
############################################################################
echo Отменить taint на однонодном кластере
kubectl taint node stationX node-role.kubernetes.io/control-plane:NoSchedule
############################################################################
Популярность: 30, Last-modified: Sat, 21 Feb 2026 13:10:31 GmT