Самый простой способ по быстрому настроить это хозяйство, это использовать kubespray, но лучше один раз пройти этот квест ручками.
Итого, у меня есть два узла и первым делом необходимо объединить их в VPN-сеть по инструкции Объединение bare-metal и vps серверов в коммутируемую сеть при помощи OpenVPN. После объединения у нас получились два узла srv-prod-sbercloud-01 (10.100.1.1) и srv-prod-sbercloud-02 (10.100.1.2).
Устанавливаем Docker по инструкциям.
- Установка Docker+DockerCompose+KubeCtl+Helm
- Управление внутренними настройками логирования в Docker
- Перенос хранилища образов, томов и т.п. Docker в /opt/
Отключаем Swap
Я все еще не понимаю, почему они так swap не любят. Как везде написано использование swap путает планировщик ресурсов, но есть дополнительная опция, чтобы игнорировать наличие swap.
Будем делать как в инструкции написано и в fstab отключаем использование swap и руками сбрасываем текущий в оперативную память.
# swapoff -a
Подключаем сетевые модули ядра
Загрузка модулей при старте сервера.
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
Подключаем сразу, но временно.
# modprobe overlay
# modprobe br_netfilter
Проверяем, что модули загружены.
# lsmod | egrep "br_netfilter|overlay"
br_netfilter 32768 0
bridge 311296 1 br_netfilter
overlay 151552 1
Еще правил посоветовали если вы UFW используете (в файлике /etc/ufw/sysctl.conf).
net/bridge/bridge-nf-call-ip6tables = 1
net/bridge/bridge-nf-call-iptables = 1
net/bridge/bridge-nf-call-arptables = 1
Перезагрузим один узел и проверим, что модули подхватываются на старте и если все ок, то продолжаем.
Немного правок по параметрам iptables
Мостики и маршрутизация.
cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
Применяем настройки.
# sysctl --system
Так как я закрыт fiewall от cloud.ru можно смело отключить UFW.
# systemctl stop ufw
# systemctl disable ufw
Ну или если вы в дикий интернет напрямую ходите, то откройте порты 6443
, 2379
, 2380
, 10250
, 10259
, 10257
и у меня для этого тоже есть заметка “Работа со штатным Firewall Ubuntu (UFW)“
Аналогично на вкус и цвет еще накручиваем.
# apt-get install ebtables ethtool
Установка Kubernetes
Теоретически, мы на этапе подготовки узла все необходимые манипуляции уже провели, но повторение мать учения и т.п. Лезем смотреть какая у нас актуальная версия на сайт https://kubernetes.io/releases/download/ и сейчас актуальная 1.32
# curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | 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.29/deb/ /' | tee /etc/apt/sources.list.d/kubernetes.list
# apt-get update
# apt -y install kubelet kubeadm kubectl && apt-mark hold kubelet kubeadm kubectl
Инициализируем мастер-node
Я как старовер хотел использовать стандартный движок docker-ce и вот тут начинаются фокусы.
These instructions assume that you are using the
cri-dockerd
adapter to integrate Docker Engine with Kubernetes.
И нам понадобится адаптер для подключения ретро движка к которому на самом деле многие привыкли и не хотят слезать.
Итак, установка.
# wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.2.5/cri-dockerd-0.2.5.amd64.tgz
# tar -xvf cri-dockerd-0.2.5.amd64.tgz
# cd cri-dockerd/
# mkdir -p /usr/local/bin
# install -o root -g root -m 0755 ./cri-dockerd /usr/local/bin/cri-dockerd
Запуск этой прослойки в виде SystemD сервиса.
# tee /etc/systemd/system/cri-docker.service << EOFOF
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket
[Service]
Type=notify
ExecStart=/usr/local/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket
[Service]
Type=notify
ExecStart=/usr/local/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=
ExecReload=/bin/kill -s HUP
TimeoutSec=0
RestartSec=2
Restart=always
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
Delegate=yes
KillMode=process
[Install]
WantedBy=multi-user.target
# tee /etc/systemd/system/cri-docker.socket << EOF
[Unit]
Description=CRI Docker Socket for the API
PartOf=cri-docker.service
[Socket]
ListenStream=%t/cri-dockerd.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
EOF
[Unit]
Description=CRI Docker Socket for the API
PartOf=cri-docker.service
[Socket]
ListenStream=%t/cri-dockerd.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
Запускаем.
# systemctl daemon-reload
# systemctl enable cri-docker.service
# systemctl enable --now cri-docker.socket
# systemctl start cri-docker.service
# systemctl status cri-docker.service
P.S. актуальная версия сейчас 0.3.16
https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.16/cri-dockerd-0.3.16.amd64.tgz
P.P.S. С адаптером свежие версии kubeadm больше не работают, ну или у меня не получилось их подружить и будем использовать стандартный cri-o для работы.
Установка CRI-O
(Вот так не делайте!) Подключаем репозиторий с cri-o.
А у меня блог познавательный, вдруг кому пригодится.
# export CRIO_VERSION=v1.32.2
# curl -fsSL https://download.opensuse.org/repositories/isv:/cri-o:/stable:/$CRIO_VERSION/deb/Release.key |
gpg --dearmor -o /etc/apt/keyrings/cri-o-apt-keyring.gpg
# echo "deb [signed-by=/etc/apt/keyrings/cri-o-apt-keyring.gpg] https://download.opensuse.org/repositories/isv:/cri-o:/stable:/$CRIO_VERSION/deb/ /" |
tee /etc/apt/sources.list.d/cri-o.list
# apt-get update
Если сделали, удаляйте эти репы к чертовой матери.
Давайте руками все сделаем
В принципе (это же блог и я не претендую на первую инстанцию) скачаем https://storage.googleapis.com/cri-o/artifacts/cri-o.amd64.v1.32.2.tar.gz
Распакуем в /tmp/ и запустим install. И получаем вот такую простыню текста.
# ./install
++ DESTDIR=
++ PREFIX=/usr/local
++ ETCDIR=/etc
++ LIBEXECDIR=/usr/libexec
++ LIBEXEC_CRIO_DIR=/usr/libexec/crio
++ ETC_CRIO_DIR=/etc/crio
++ CONTAINERS_DIR=/etc/containers
++ CONTAINERS_REGISTRIES_CONFD_DIR=/etc/containers/registries.conf.d
++ CNIDIR=/etc/cni/net.d
++ BINDIR=/usr/local/bin
++ MANDIR=/usr/local/share/man
++ OCIDIR=/usr/local/share/oci-umount/oci-umount.d
++ BASHINSTALLDIR=/usr/local/share/bash-completion/completions
++ FISHINSTALLDIR=/usr/local/share/fish/completions
++ ZSHINSTALLDIR=/usr/local/share/zsh/site-functions
++ OPT_CNI_BIN_DIR=/opt/cni/bin
++ dpkg -l
++ SYSCONFIGDIR=/etc/default
++ sed -i 's;sysconfig/crio;default/crio;g' etc/crio
++ source /etc/os-release
+++ PRETTY_NAME='Ubuntu 22.04.5 LTS'
+++ NAME=Ubuntu
+++ VERSION_ID=22.04
+++ VERSION='22.04.5 LTS (Jammy Jellyfish)'
+++ VERSION_CODENAME=jammy
+++ ID=ubuntu
+++ ID_LIKE=debian
+++ HOME_URL=https://www.ubuntu.com/
+++ SUPPORT_URL=https://help.ubuntu.com/
+++ BUG_REPORT_URL=https://bugs.launchpad.net/ubuntu/
+++ PRIVACY_POLICY_URL=https://www.ubuntu.com/legal/terms-and-policies/privacy-policy
+++ UBUNTU_CODENAME=jammy
++ [[ ubuntu == \f\e\d\o\r\a ]]
++ [[ ubuntu == \r\h\c\o\s ]]
++ SYSTEMDDIR=/usr/local/lib/systemd/system
++ SELINUX=
++ selinuxenabled
++ ARCH=amd64
++ install -d -m 755 /etc/cni/net.d
++ install -D -m 755 -t /opt/cni/bin cni-plugins/LICENSE cni-plugins/README.md cni-plugins/bandwidth cni-plugins/bridge cni-plugins/dhcp cni-plugins/dummy cni-plugins/firewall cni-plugins/host-device cni-plugins/host-local cni-plugins/ipvlan cni-plugins/loopback cni-plugins/macvlan cni-plugins/portmap cni-plugins/ptp cni-plugins/sbr cni-plugins/static cni-plugins/tap cni-plugins/tuning cni-plugins/vlan cni-plugins/vrf
++ install -D -m 644 -t /etc/cni/net.d contrib/10-crio-bridge.conflist.disabled
++ install -d -m 755 /usr/libexec/crio
++ install -D -m 755 -t /usr/libexec/crio bin/conmon
++ install -D -m 755 -t /usr/libexec/crio bin/conmonrs
++ install -D -m 755 -t /usr/libexec/crio bin/crun
++ install -D -m 755 -t /usr/libexec/crio bin/runc
++ install -d -m 755 /usr/local/share/bash-completion/completions
++ install -d -m 755 /usr/local/share/fish/completions
++ install -d -m 755 /usr/local/share/zsh/site-functions
++ install -d -m 755 /etc/containers/registries.conf.d
++ install -D -m 755 -t /usr/local/bin bin/crio
++ install -D -m 755 -t /usr/local/bin bin/pinns
++ install -D -m 755 -t /usr/local/bin bin/crictl
++ install -D -m 644 -t /etc etc/crictl.yaml
++ install -D -m 644 -t /usr/local/share/oci-umount/oci-umount.d etc/crio-umount.conf
++ install -D -m 644 -t /etc/default etc/crio
++ install -D -m 644 -t /etc/crio contrib/policy.json
++ install -D -m 644 -t /etc/crio/crio.conf.d etc/10-crio.conf
++ install -D -m 644 -t /usr/local/share/man/man5 man/crio.conf.5
++ install -D -m 644 -t /usr/local/share/man/man5 man/crio.conf.d.5
++ install -D -m 644 -t /usr/local/share/man/man8 man/crio.8
++ install -D -m 644 -t /usr/local/share/bash-completion/completions completions/bash/crio
++ install -D -m 644 -t /usr/local/share/fish/completions completions/fish/crio.fish
++ install -D -m 644 -t /usr/local/share/zsh/site-functions completions/zsh/_crio
++ install -D -m 644 -t /usr/local/lib/systemd/system contrib/crio.service
++ install -D -m 644 -t /etc/containers/registries.conf.d contrib/registries.conf
++ sed -i 's;/usr/bin;/usr/local/bin;g' /etc/crio/crio.conf.d/10-crio.conf
++ sed -i 's;/usr/libexec;/usr/libexec;g' /etc/crio/crio.conf.d/10-crio.conf
++ sed -i 's;/etc/crio;/etc/crio;g' /etc/crio/crio.conf.d/10-crio.conf
++ '[' -n '' ']'
Ок, судя по выхлопу у нас есть сервис и даже конфиги.
Ну, шо погнали включаем и смотрим статус.
# systemctl start crio
# systemctl enable crio
# systemctl status crio
● crio.service - Container Runtime Interface for OCI (CRI-O)
Loaded: loaded (/usr/local/lib/systemd/system/crio.service; disabled; vendor preset: enabled)
Active: active (running) since Fri 2025-03-07 04:30:59 UTC; 6s ago
Docs: https://github.com/cri-o/cri-o
Main PID: 439149 (crio)
Tasks: 7
Memory: 10.3M
CPU: 132ms
CGroup: /system.slice/crio.service
└─439149 /usr/local/bin/crio
Итого, работает в чистом виде.
# /usr/local/bin/crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD NAMESPACE
Господь с ним и запихиваем в автозапуск.
# systemctl enable crio
Смертельный номер и мы ребутим хост (на проде таких опытов не делайте!)
Работает cri-o
# /usr/local/bin/crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD NAMESPACE
Работает старый движок.
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Изумительно.
Давайте в кубик играть
Сейчас мы руками MiniKube (Аналог) соберем и даже там что-то странное запустим.
В целом если вам интересно, то реально лучше читать документацию. Например, тут https://kubernetes.io/docs/reference/setup-tools/kubeadm/ там все описано.
# kubeadm init --pod-network-cidr=192.168.0.0/16 --cri-socket unix:///var/run/crio/crio.sock
Коллеги, за 192.168.0.0 тут сорян, мне в голову пришло только это безумие.
Окей, у нас джойн ключ появился.
kubeadm join 10.0.0.7:6443 --token xxxTokenxxx \
--discovery-token-ca-cert-hash sha256:xxxRaznaya-heroboraxxx
Адрес конечно странноватый из внутренней подсети cloud.ru. И мы его не будем использовать (ну не нраятся k8s сети хоть и мостовые).
Смотрим на наш кластер из одного узла.
# kubectl get nodes
E0309 04:46:44.521685 10905 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"http://localhost:8080/api?timeout=32s\": dial tcp 127.0.0.1:8080: connect: connection refused"
Маразм крепчал.
# crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD NAMESPACE
3e7ee50b68d71 f1332858868e1c6a905123b21e2e322ab45a5b99a3532e68ff49a87c2266ebc5 9 minutes ago Running kube-proxy 0 1acd62827bf18 kube-proxy-r9n7c kube-system
ab01eeed44764 85b7a174738baecbc53029b7913cd430a2060e0cbdb5f56c7957d32ff7f241ef 9 minutes ago Running kube-apiserver 0 895cce371d03f kube-apiserver-srv-prod-sbercloud-01 kube-system
5445234427c29 d8e673e7c9983f1f53569a9d2ba786c8abb42e3f744f77dc97a595f3caf9435d 9 minutes ago Running kube-scheduler 0 191b0c4b4886f kube-scheduler-srv-prod-sbercloud-01 kube-system
2f33ebe5f4e25 b6a454c5a800d201daacead6ff195ec6049fe6dc086621b0670bca912efaf389 9 minutes ago Running kube-controller-manager 0 647ac8348c819 kube-controller-manager-srv-prod-sbercloud-01 kube-system
f42907da88b39 a9e7e6b294baf1695fccb862d956c5d3ad8510e1e4ca1535f35dc09f247abbfc 9 minutes ago Running etcd 0 1aa54f8edb256 etcd-srv-prod-sbercloud-01 kube-system
Если в лоб делать, то получится как-то так.
# ls /etc/kubernetes
admin.conf controller-manager.conf kubelet.conf manifests pki scheduler.conf super-admin.conf
Опять всем привет.
# kubectl get nodes --kubeconfig /etc/kubernetes/kubelet.conf
Error from server (Forbidden): nodes is forbidden: User "system:node:srv-prod-sbercloud-01" cannot list resource "nodes" in API group "" at the cluster scope: node 'srv-prod-sbercloud-01' cannot read all nodes, only its own Node object
Ну тут имя надо указывать при создании кластера или свой локальный DNS, но мне лень, погнали на локаль раскидаем и поправим адреса. И это называется дурдом на минималках.

Доступ по портам (но только для своего адреса) придется все же выдать (специфика такая в cloud.ru). Пока ему печально и похоже надо в логи лезть.
Пока все грустно и медленно, но плюс-минус пойдет.
# kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-668d6bf9bc-cxrlz 0/1 Pending 0 41m
kube-system coredns-668d6bf9bc-wf5zf 0/1 Pending 0 41m
kube-system etcd-srv-prod-sbercloud-01 1/1 Running 0 41m
kube-system kube-apiserver-srv-prod-sbercloud-01 1/1 Running 0 41m
kube-system kube-controller-manager-srv-prod-sbercloud-01 1/1 Running 0 41m
kube-system kube-proxy-r9n7c 1/1 Running 0 41m
kube-system kube-scheduler-srv-prod-sbercloud-01 1/1 Running 0 41m
Итого у нас CoreDNS в состоянии не стояния.
# kubectl get pods --namespace=kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
coredns-668d6bf9bc-cxrlz 0/1 Pending 0 58m
coredns-668d6bf9bc-wf5zf 0/1 Pending 0 58m
Разрешим запуск подов на мастер-узле, ну и будет такой мини-куб. Сейчас так.
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
srv-prod-sbercloud-01 NotReady control-plane 68m v1.32.2
Примерно так делаем (хоть так и не стоит делать).
# kubectl taint node srv-prod-sbercloud-01 node-role.kubernetes.io/control-plane:NoSchedule-
# kubectl patch node srv-prod-sbercloud-01 -p "{\"spec\":{\"unschedulable\":false}}"
# kubectl label nodes srv-prod-sbercloud-01 kubernetes.io/role=master
Проверим, что за чертовщину мы наделали.
# kubectl describe pod coredns-668d6bf9bc-cxrlz
Name: coredns-668d6bf9bc-cxrlz
Namespace: kube-system
Priority: 2000000000
Priority Class Name: system-cluster-critical
Service Account: coredns
Node: <none>
Labels: k8s-app=kube-dns
pod-template-hash=668d6bf9bc
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Controlled By: ReplicaSet/coredns-668d6bf9bc
Containers:
coredns:
Image: registry.k8s.io/coredns/coredns:v1.11.3
Ports: 53/UDP, 53/TCP, 9153/TCP
Host Ports: 0/UDP, 0/TCP, 0/TCP
Args:
-conf
/etc/coredns/Corefile
Limits:
memory: 170Mi
Requests:
cpu: 100m
memory: 70Mi
Liveness: http-get http://:8080/health delay=60s timeout=5s period=10s #success=1 #failure=5
Readiness: http-get http://:8181/ready delay=0s timeout=1s period=10s #success=1 #failure=3
Environment: <none>
Mounts:
/etc/coredns from config-volume (ro)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-qppjv (ro)
Conditions:
Type Status
PodScheduled False
Volumes:
config-volume:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: coredns
Optional: false
kube-api-access-qppjv:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: Burstable
Node-Selectors: kubernetes.io/os=linux
Tolerations: CriticalAddonsOnly op=Exists
node-role.kubernetes.io/control-plane:NoSchedule
node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m33s (x18 over 88m) default-scheduler 0/1 nodes are available: 1 node(s) had untolerated taint {node.kubernetes.io/not-ready: }. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.
Еще смертельный номер.
# kubectl label nodes srv-prod-sbercloud-01 ingress-ready=true
# kubectl taint nodes srv-prod-sbercloud-01 dedicated=special-user:NoSchedule
Добавим еще один рабочий узел
Подготовка хоста аналогичная мастер-узлу, все так-же с cri-o. И потом инициализируем инфраструктуру.
# kubeadm join 10.100.1.1:6443 --token olo9fy.bbnalvyeygtak7z4 \
--discovery-token-ca-cert-hash sha256:3030XXXXtokenXXXX --cri-socket unix:///var/run/crio/crio.sock
Тут мы словили ошибку.
error execution phase preflight: couldn't validate the identity of the API Server: failed to request the cluster-info ConfigMap: Get "https://10.100.1.1:6443/api/v1/namespaces/kube-public/configmaps/cluster-info?timeout=10s": tls: failed to verify certificate: x509: certificate is valid for 10.96.0.1, 10.0.0.7, not 10.100.1.1
Слишком много интерфейсов наплодили, тут и cloud.ru свои внутренние сети понамешал и я еще добавил, а так-как блог у нас образовательный сносим мастер ноду к черту.
# kubeadm reset --cri-socket unix:///var/run/crio/crio.sock
И пересоздаем по инструкции выше, но теперь я настроил еще и доступ с локальной машины до этой сети и можем использовать VsCode для управления кластером. И уберем этот 192.168.0.0/16 оно реально бесит где встречаю.
И вот это недоразумение автоматизации то и призналось, что нам надо еще и имя на интерфейс в hosts записать.
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local srv-prod-sbercloud-01] and IPs [10.96.0.1 10.0.0.7]
Блин, я забыл про этот пень и с мульти-интерфейсами и теперь заклинание получилось гораздо интереснее.
# kubeadm init --pod-network-cidr=10.20.0.0/16 --apiserver-advertise-address=10.100.1.1 --cri-socket unix:///var/run/crio/crio.sock
Вот теперь у нас двуногий кластер.
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
Чем дальше в лес тем страшнее. Сносим CoreDNS.
# kubectl delete deployment coredns -n kube-system
Хотя похоже дело в том, что calico забанило РФ и пойдем другим путем.
# kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml
Идиотия на марше (никогда не повторяйте описанное в этой заметке)
Итого, Weave справилась задачей, а вот штатный сетевой оркестратор говорит, что из РФ нельзя и это уже начинает бесить.

Ну, теперь допустим, что сеть у нас есть и теперь надо CoreDNS и Ingress вернуть и мы молодцы.
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
srv-prod-sbercloud-01 Ready control-plane 65m v1.32.2
srv-prod-sbercloud-02 Ready <none> 56m v1.32.2
А зачем нам CoreDNS когда есть более современные игрушки. Хотя пофиг потом посмотрим потом.
# helm --namespace=kube-system install coredns coredns/coredns
# kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
Дальше наши любимые ошибочки.
If you don't see a command prompt, try pressing enter.
warning: couldn't attach to pod/dnstools, falling back to streaming logs: Internal error occurred: error sending request: Post "https://213.171.26.110:10250/attach/default/dnstools/dnstools?input=1&output=1&tty=1": dial tcp 213.171.26.110:10250: i/o timeout
pod "dnstools" deleted
Error from server: Get "https://213.171.26.110:10250/containerLogs/default/dnstools/dnstools": dial tcp 213.171.26.110:10250: i/o timeout
Полный абзац, дальше мне еще правила рисовать между хостами. Ну спасибо Cloud.ru там сейчас сам черт ногу сломает где что и куда ходит.
Для тестирования внутреннего DNS подходит образ dnstools.
# kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
Как показывает практика на внешнем интерфейсе мастер-ноды все же придется открыть порты 6443, 2379, 2380, 10250, 10259, 10257.
Добавим еще Ingress и в первом приближении плюс-минус что-то готово.
# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
# helm install ingress-nginx/ingress-nginx --generate-name
Проверяем, что под появился и статус.

В первом приближении что-то собрал. Опыт конечно интересный, но специфичный.