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


После редактирования свойств deployment'а кубер запоминает его состояния (rollouts)
Глубина истории: revisionHistoryLimit (10)

# Внесение изменений в свойства deploy
kubectl set image deployment/app1 appc1=app:2.0 --record
# --record  добавляет детали в history

# Просмотр истории состояний и их конкретные детали
kubectl rollout history deployment dep2
kubectl rollout history deployment dep2 --revision 2
# Откатка в состояние номер ...
kubectl rollout undo deployment dep2 --to-revision 2
# Пересоздать deployment
kubectl rollout restart deployment dep2




# Создать 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-contexts      # посмотреть доступные 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


 В control-plain мастеров кубернетес может быть:
etcd       норма: 3-5, max: 9
apiserver  норма: 3    max: десятки
controller норма: 3 (1 active + 2 standby)
scheduller норма: 3 (1 active + 2 standby)

etcd[*] образуют самостоятельный Raft-кластер (Leader+followers...)
каждый APIserver коннектится ко всем etcd,
    read из разных, write в один, тот реплицирует остальным

controller и scheduler сами в kubelet не ходят, дергают все сквозь api
 (по факту из etcd)
API своей памяти не имеет, все хранит в etcd и из него же дергает данные

controller-manager держит постоянный watch-stream на нужные типы объектов:
 Deployment Controller:  watch /apis/apps/v1/deployments
 ReplicaSet Controller:  watch /apis/apps/v1/replicasets
 Job Controller:         watch /apis/batch/v1/jobs
 В изменения в watch-api проявляются мгновенно и сразу реакция - запускается
task по приведению реального состояния об'екта к желаемому(записанному в etcd)

CONTROLLER watch  --> API=>etcd
SCHEDULLER watch  --> API=>etcd
API push,get,write--> etcd[*]
KUBECTL           --> API
KUBELET    push   --> API :6443 (NodeStatus и PodStatus и node-heartbeats)
API               --> kubelet:10250

Порты:      apiserver:6443   kubelet:10250      etcd:2379,2380
Monitoring/health:           controller:10257 scheduller:10259



kubelet регулярно ~ О(1сек) сканирует директорию /etc/kubernetes/manifests/.
Если в нее поместить yaml pod'а, он автоматически стартует.  Статус  pod'ов,
checkpoint'ы, метаданные - в /var/lib/kubelet/, /var/lib/kubelet/pods/

sudo ls /etc/kubernetes/manifests/
etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml




Установка почти такая же, как в онлайне, но потребуется 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 ############################################################################

Популярность: 80, Last-modified: Tue, 24 Mar 2026 05:18:30 GmT