Как стать автором
Обновить

Комментарии 35

Коллеги, перестаньте себе ломать пальцы молотком. Не надо на линукс виртуальных машинах работать через окошко гипервизора. Не надо на windows 10 использовать putty. Есть windows terminal preview и встроенный клиент ssh. Даже просто обычные консоли cmd и ps могут запускать встроенный ssh client, это избавит вас от монтирования общих папок на ВМ и вы просто будете копировать из буфеа обмена команды.
О, отлично, не знал про такую возможность. Спасибо!

Тоже пока чтал статью хотел об этом сказать. Давно пользуюсь Windows Terminal — всё устраивает. Главное ssh по ключу настроить и можно сделать готовый профиль для входа в систему.
Кстати, автор, а вы я надеюсь потом виртуалки в headless режиме запускали?

Да, headless, но я по старинке пользовался мультипутти.
Есть windows terminal preview и встроенный клиент ssh


Спасибо, я лучше с putty поработаю. Не все комбинации клавиш работают, проблемы с копированием ставкой текста… Наверное дело привычки, не зашло.

Мне вот интересно: при наличии hyperv (в pro версии 10), зачем использовать всякие там virtualbox'ы и ломать при этом wsl? При наличии home версии у вас не будет hyperv и отключать его не надо.


У меня есть некоторый опыт развёртывания kubernetes с Windows в качестве рабочих узлов. Интересно ли это кому-нибудь? Могу написать статейку со списком известных проблем и путей их решения.

У меня Home версия с WLS, пришлось отключать hyper-v в итоге, т.к. без этого vb не работал. Вообще я не исключаю, что возможно где-то перемудрил, но всё же цель была заставить это работать. Если можно сделать проще, то я бы с удовольствием почитал, т.к. развернуть k8s по моему опыту — это основной геморрой когда начинаешь его изучать.

Всё дело в том, что Home версия мало подходит для таких экспериментов. Дня нормальной работы IT-специалиста так или иначе понадобится Pro, Enterprise или Education.
И причина в том, что если вы захотите использовать WSL(2), то вы не сможете использовать VirtualBox. В Pro версии 10 он вам просто не понадобится. Виртуальные машины будут работать под Hyper-V. И WSL будет работать и Docker for Desktop будет работать и для Linux и для Windows контейнеров.


Но… Pro стоит денег. Или (шепотом) торрент...


В любом случае это уже оффтопик. За статью спасибо.

При желании личную лицензию на Pro можно купить за смешные деньги — сейчас ~1000 руб. (Я пару лет назад купил за 550)

Я никогда upgrade лицензию не покупал. А с нуля Pro версия стоит около $200.

Про лицензия oem на ebay стоит баксов 10. Т.к. я занимаюсь сборкой компьютера, имею право установить такую лицензию. Собирал брату, отцу и себе, вот уже 5 лет работает всё корректно.
А можно, пожалуйста, подробней? давно хотел себе ноут на прошку перевести
Интересно конечно, напишите пожалуйста.
Не сильный аргумент, но не приятный: vagrant + hyper-v.

Чтобы отключить/подключить свап не нужно систему перегружать. Для этого есть команды: swapoff и swapon. Как ими пользоваться можно посмотреть в man.

Они вроде только до перезагрузки работают

При перезагрузке подключится то, что Вы прописали в файле fstab. Вы же там удалили/закомментировали строку подключения свап.

Думаю автору надо посмотреть Vagrant.
Очень облегчает процесс создание виртуальных боксов.

Вот только хотел спросить у автора, работает ли Вагрант под Windows

Vagrant, как хорошее средство выделить время на кофе, пока все собирается :)

Возможно, кому-то пригодится, моя домашняя сборка. Она довольно затратна по ресурсам и конфиги не очень свежие, но для экспериментов хватает.

Vagrantfile
# encoding: utf-8
# -*- mode: ruby -*-
# vi: set ft=ruby :

### configuration parameters
# K8S requires minimum 2 CPU cores
VM_GROUP = "Kubernetes Deployment"
VM_BOX_IMAGE = "ubuntu/bionic64"
VM_BOX_VERSION = "20200908.0.0"
VM_PREFIX = "k8s"
VM_CPU = "4"
VM_MEM = "2048"
VM_CPU_MASTER = "2"
VM_MEM_MASTER = "2048"

# Number of nodes in cluster
K8S_NODES = 4
# Master IP address (x.y.z.K8S_MASTER)
K8S_MASTER_IP = 10
K8S_NETWORK = "100.77.42"
K8S_HEAD_IP = "#{K8S_NETWORK}.#{K8S_MASTER_IP}"

Vagrant.configure("2") do |config|
    config.disksize.size = '50GB'

    config.vm.define "#{VM_PREFIX}-head" do |node|
        node.vm.provision "shell", inline: "echo Configuring node: #{VM_PREFIX}-head"

        node.vm.box = VM_BOX_IMAGE
        node.vm.box_version = VM_BOX_VERSION
        node.vm.hostname = "#{VM_PREFIX}-head"
        node.vm.network :private_network, ip: "#{K8S_HEAD_IP}"

        node.vm.provider "virtualbox" do |v|
            v.name = "#{VM_PREFIX}-head"
            v.customize ["modifyvm", :id, "--groups", "/#{VM_GROUP}"]
            v.customize ["modifyvm", :id, "--memory", VM_MEM_MASTER]
            v.customize ["modifyvm", :id, "--cpus", VM_CPU_MASTER]
            # Prevent VirtualBox from interfering with host audio stack
            v.customize ["modifyvm", :id, "--audio", "none"]
        end

        # Install/setup base services on VM
        node.vm.provision :shell, path: "./k8s-base.sh"

        # Install/setup related services on VM
        node.vm.provision :shell, path: "./k8s-head.sh"
    end

    (1..K8S_NODES).each do |i|
        vm_name = "#{VM_PREFIX}-node-#{i}"
        vm_ip = K8S_MASTER_IP + i

        config.vm.define "#{vm_name}" do |node|
            node.vm.provision "shell", inline: "echo Configuring node: #{vm_name}"

            node.vm.box = VM_BOX_IMAGE
            node.vm.box_version = VM_BOX_VERSION
            node.vm.hostname = vm_name
            node.vm.network :private_network, ip: "#{K8S_NETWORK}.#{vm_ip}"

            node.vm.provider "virtualbox" do |v|
                v.name = vm_name
                v.customize ["modifyvm", :id, "--groups", "/#{VM_GROUP}"]
                v.customize ["modifyvm", :id, "--memory", VM_MEM]
                v.customize ["modifyvm", :id, "--cpus", VM_CPU]
                # Prevent VirtualBox from interfering with host audio stack
                v.customize ["modifyvm", :id, "--audio", "none"]

                # see https://www.virtualbox.org/manual/ch08.html#vboxmanage-storageattach
                # Disk 100GB
                disk_name = "data/disk-#{vm_name}.vdb"
                unless File.exist?(disk_name)
                    v.customize ["createhd", "--filename", disk_name, "--size", 102400 ]
                end

                v.customize [ "storageattach", :id, "--storagectl", "SCSI", "--port", 3, "--device", 0, "--type", "hdd", "--medium", disk_name ]
            end

            # Install/setup base services on VM
            node.vm.provision :shell, path: "./k8s-base.sh"

            # Install/setup related services on VM
            node.vm.provision :shell, path: "./k8s-node.sh", env: {"K8S_HEAD_IP" => K8S_HEAD_IP}
        end
    end
end



k8s-base.sh
#!/usr/bin/env bash

apt-get update
apt-get upgrade -y -f
apt-get install -y apt-transport-https ca-certificates curl software-properties-common

# Install docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") $(lsb_release -cs) stable"
apt-get update
apt-cache policy docker-ce
apt-get install -y docker-ce
systemctl enable docker
systemctl status docker

# run docker commands as vagrant user (sudo not required)
usermod -aG docker vagrant

# kubelet requires swap off
swapoff -a

# keep swap off after reboot
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

# Install kubeadm
# https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubeadm kubelet kubectl
apt-mark hold kubelet kubeadm kubectl

# set node-ip
IP_ADDR=`hostname -I | cut -d' ' -f2`
echo "Environment=\"KUBELET_EXTRA_ARGS=--node-ip=$IP_ADDR\"" | sudo tee -a /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

# Setup daemon.
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

systemctl daemon-reload
systemctl restart kubelet
systemctl restart docker



k8s-head.sh
#!/usr/bin/env bash

echo "> Init k8s admin (kubeadm)"
IP_ADDR=`hostname -I | cut -d' ' -f2`
HOST_NAME=$(hostname -s)
echo "> Init k8s admin (kubeadm): ${HOST_NAME} => ${IP_ADDR}"
kubeadm init --apiserver-advertise-address=$IP_ADDR --apiserver-cert-extra-sans=$IP_ADDR  --node-name $HOST_NAME --pod-network-cidr=172.16.0.0/16

echo "> Set credentials to regular user (vagrant)"
sudo --user=vagrant mkdir -p /home/vagrant/.kube
cp -i /etc/kubernetes/admin.conf /home/vagrant/.kube/config
chown $(id -u vagrant):$(id -g vagrant) /home/vagrant/.kube/config

echo "> Switch 'cgroup-driver' to 'systemd' (cover case when init command resets env flags)"
export KUBECONFIG=/etc/kubernetes/admin.conf
sed -i "s/cgroup-driver=cgroupfs/cgroup-driver=systemd/g" /var/lib/kubelet/kubeadm-flags.env

# echo "> Use Calico pod network add-on". Use your own network provider
# kubectl apply -f ./network-calico.yaml

echo "> Create k8s join token"
kubeadm token create --print-join-command >> /etc/kubeadm_join_cmd.sh
chmod +x /etc/kubeadm_join_cmd.sh

echo "> Remove password for ssh between guest VMs"
sed -i "/^[^#]*PasswordAuthentication[[:space:]]no/c\PasswordAuthentication yes" /etc/ssh/sshd_config
service sshd restart

echo "> Install Helm"
curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

echo "> Restarting services"
systemctl daemon-reload
systemctl restart kubelet
systemctl restart docker

echo "> kubectrl autocompetition"
kubectl completion bash > /etc/bash_completion.d/kubectl



k8s-node.sh
#!/usr/bin/env bash

echo "> Install sshpass"
add-apt-repository universe
apt-get update
apt-get install -y sshpass

echo "> Join to cluster"
sshpass -p "vagrant" scp -o StrictHostKeyChecking=no vagrant@${K8S_HEAD_IP}:/etc/kubeadm_join_cmd.sh .
sh ./kubeadm_join_cmd.sh

echo "> Restarting services"
systemctl daemon-reload
systemctl restart kubelet
systemctl restart docker



Доступ к CLI каждой машны:

vagrant ssh <name>


Ordos Посмотрите в сторону Vagrant: удобно и меньше ручной работы.
Спасибо, да, вагрант я планировал посмотреть. Просто им хорошо пользоваться, когда уже понимаешь, что именно надо настраивать. Изначально у меня была немного другая задача — в принципе разобраться, как выполняются настройки. Т.к. когда я начал смотреть мануалы из интернета, то полноценно запустить кубер на виртуалках у меня не получилось. Постоянно косяки возникали какие-то.

Можно в вагранте запустить дистрибутив PKE — CNCF сертифицированный дистриб k8s.
https://github.com/banzaicloud/pke
На поиграться — вполне. Из плюшек — можно многонодовый кластер, можно модные сетевые плагины вроде cilium


VolCh

Хотелось бы ещё почитать про установку и настройку кластера k8s не с Docker, а с rootless контейнерами использующими cgroups v2.
Такого нет пока, вроде. Да и проблемы рутлес мы на работе огребаем пока. Ключевая порты ниже 1024.
Спасибо, а то я потратил несколько вечеров пытаясь, в качестве экспериментов, завести k8s под Fedora, где без дополнительных настроек Docker не работает больше и не получилось, думал, что я криворукий :)
Не, это докер криворукие. У меня работает докер и подман на Федоре. Кубер я с cri-o запускал, работает на Федоре. Но с докером кубер я на Федоре тоже думаю за часик подниму.
Обычно изучение Kubernetes стоит начинать с minikube — консольной утилиты, которая умеет быстро создавать кластер из одного узла с использованием VirtualBox. Это самый лучший вариант для быстрого старта.

TL;DR А почему не Docker Desktop? Ставится на виндовс и на мак, Кубер внутри есть.
Хочешь опеншифт? Не вопрос! Можно через CRC установить

У k8s, который идет вместе с Docker Desktop, есть один нюанс — фиксированная версия, которая привязана к релизу Docker. (Последний релиз идет с версией 1.19.3). Этого вполне хватает для изучения k8s, но не для разработки и отладки.
На тестовых или боевых кластерах зачастую бегают совершенно другие версии, а хочется работать именно с ними.

А почему не взять kind, например?
Хороший простой вариант, быстро запускает кластер, даже обновляет kubectl конфиг, «запустил и забыл».
Сам сидел на самодельной связке VirtualBox + Vagrant + microk8s.io одно время, пока не подсказали kind, сейчас только его и использую.
Единственная его зависимость — это Docker Desktop, который сейчас можно установить даже на Windows Home с WSL2.

Есть еще похожая альтернатива, также работающая поверх Docker, k3d, но пока kind хватает за глаза.
systemctrl edit kubelet.service

И пишешь свою кастомную строку запуска
ExecStart=/usr/bin/kubelet <тут много всяких параметров>

Потом делаешь релоад демону
systemctl daemon-reload

Он перечитает конфиги
Что получилось можно посмотреть

systemctrl cat kubelet.service

Плюсанул бы, да не могу
Если честно выглядит… хардкорно. Можно просто поставить Docker Desktop и включить Kubernetes в настройках. Затем скачать плагин в IDE. У меня VSCode, думаю в других IDE тоже есть что-то подобное. И… всё! Все поды, сервисы, ингрес и т.д. как на ладони. Можно деплоить, смотреть логи, лезть в контейнеры, короче, отрываться по полной. А если захочется Миникуб, докеровский Куб отключается одним чек-боксом. Ну реально через IDE, гораздо комфортнее со всем этим делом работать.
Есть путь проще, Docker Desktop и в настройках ставите галочку использовать k8s. Нативная поддержка jetbrains ide, сам обновляется, минимум геморроя.

Спасибо за статью. Могу отметить пару моментов (может, кому пригодится):
1) на Windows в трех виртуальных машинах этот "кластер" постоянно теряет связь. Не знаю, что тому виной. Пробовал менять тип сети на "внутреннюю сеть" virtualbox. Ничего не поменялось. На мастере регулярно теряется список нод. Настроенный кластер на KVM, тоже на трех виртуальных машинах, работает стабильно.
2) Рекомендую, в тестовых средах в том числе, использовать не IP-адреса, а в файлах hosts на узлах указывать все hostname узлов. Например, kubeadm init --control-plane-endpoint=kuber-master-node, где kuber-master-node - прописанное в hosts на всех узлах.

Спасибо за коммент)) Приятно, что даже спустя почти три года это кому-то пригодилось))

На самом деле позже я сделал тоже самое через vagrant и это работает сильно лучше, исходники есть тут, можно глянуть: https://github.com/Chakrygin/vagrant-kubernetes

Проблему с потерей связи я точно решил в этих скриптах, если я ничего не путаю, проблема была в том, что при установке flannel нужно там заменить IP и указать сетевой интерфейс, который надо использовать, как-то так: https://github.com/Chakrygin/vagrant-kubernetes/blob/main/provision.sh#L127-L131

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации