Установка 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
#########################################





# Создать 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



  Можно прописать запрет, добавив ключ для игнорирования запрета
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



    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



Установка почти такая же, как в онлайне, но потребуется 3 дополнительных шага:



# Поднимаем локальный 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



На _всех_ нодах 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
#############################################################################



# Перед установкой имеет смысл закачать 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



######## Устанавливаем кубелет и 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