- PVSM.RU - https://www.pvsm.ru -

Немного хардкора: как поднять Kubernetes на двух старых ноутбуках с Gentoo

Хочу рассказать об интересном эксперименте, суть которого заключалась в развертывании и настройке Kubernetes на двух старых ноутбуках — один из них, кроме того, был с процессором на архитектуре i386. В качестве теоретической основы использовалось руководство Kubernetes The Hard Way, которое по ходу дела пришлось немного доработать, а в качестве системы на хостах — Gentoo (да, вам не показалось). Давайте погрузимся в этот увлекательный хардкор!

Немного хардкора: как поднять Kubernetes на двух старых ноутбуках с Gentoo - 1

Наверное, многие слышали про полезный и по-своему легендарный репозиторий Келси Хайтауэра [1]Kubernetes The Hard Way [2], инструкцию по развертыванию кластера K8s без готовых скриптов и утилит. В ней объясняется, как вручную запустить Kubernetes на Google Cloud Platform (GCP). Но даже сам автор утверждает, что стоимость такого кластера будет больше, чем 300 USD, которые даются в подарок за регистрацию на сервисе.

А что, если у вас есть один или несколько старых ноутбуков, которые пылятся на полке, и вы хотите поднять-таки Kubernetes своими руками и бесплатно?

Попробуем!

Важно: эту статью стоит воспринимать лишь как дополнение к оригинальному руководству Келси Хайтауэра, так как практически всё, что им описывается, применимо не только к GCP, но и к любому другому железу или виртуальным машинам, хотя и с некоторыми оговорками.

Исходные данные

Для экспериментов у меня было два ноутбука на базе Gentoo Linux:

  • Dell G3 3590 на базе Intel Core i5-9300H (архитектура AMD64) (далее — просто dell);

  • HP Compaq 6720s на базе Intel Core2 Duo (архитектура i686) (далее — hpcom).

Они стали узлами кластера. Операционная система ставилась по официальной документации для amd64 [3] и x32 [4]. Но ядро собиралось с несколькими дополнительными настройками для IPSet [5] и Docker [6]. Для kube-proxy были включены параметры ядра NETFILTER_XT_MATCH_COMMENT и NETFILTER_XT_MATCH_STATISTIC. Также в процессе установки я столкнулся с парой трудностей, решить которые помог форум сообщества Gentoo. На всякий случай оставлю ссылки: черный экран сразу после GRUB [7] и ошибка с ​​non-PAE kernel [8].

Что еще:

  • самый обычный роутер от провайдера;

  • основной ноутбук, с которого удаленно проводились все работы;

  • сильное желание повозиться с Kubernetes.

Как правильно пользоваться руководством

Выше я отметил, что внес лишь небольшие правки в оригинальное руководство по Kubernetes. Поэтому еще раз подчеркну, что в статье описываю только эти правки, указывая места, где нужно отступить от исходных инструкций. В остальных случаях даю ссылки на оригинальные разделы руководства.

Установка Kubernetes

Prerequisites

В этом разделе [9] ничего не делаем, поэтому его можно со спокойной душой пропустить.

Installing the Client Tools

Здесь никаких изменений: делаем так, как написано [10].

Provisioning Compute Resources

Эту страницу [11] официального руководства можно пропустить, а вместо нее для упрощения дальнейшей работы записать локальные IP-адреса будущих узлов кластера (у меня получилось так: hpcom — 192.168.1.71, dell — 192.168.1.253).

Для удобства запишем эти адреса в файлик node_list.txt:

cat <<EOF | tee node_list.txt
dell 192.168.1.253 # Поменять на свои адреса и имена
hpcom 192.168.1.71
EOF

Для имитации Load Balancer’а на рабочей машине можно установить и развернуть NGINX. Затем добавить в конце конфигурационного файла nginx.conf строку include passthrough.conf (на Linux стандартная директория для конфигов NGINX — /etc/nginx/, а на macOS при установке через brew — /opt/homebrew/etc/).

Далее рядом создаем файл passthrough.conf. Сделать это можно такой командой (не забудьте поменять путь до NGINX-директории и путь до файла с хостами на ваши):

cat <<EOF | tee /opt/homebrew/etc/nginx/passthrough.conf
stream {
    upstream kube {
$(cat node_list.txt | cut -d" " -f2 | xargs -I{} echo "$(printf '%8s')server {}:6443;")
    }

    server {
        listen       443;
        proxy_pass kube;
        proxy_next_upstream on;
    }
}

EOF

Это поможет нам создать простейшую имитацию High-Availability-кластера (HA). Для обучения большего и не нужно.

Provisioning a CA and Generating TLS Certificates

В этом разделе [12] выполняем все в точности до пункта The Kubelet Client Certificates. Теперь нам пригодятся записанные ранее IP-адреса узлов будущего кластера:

for instance in $(cat node_list.txt | cut -d" " -f1); do
cat > ${instance}-csr.json <<EOF
{
  "CN": "system:node:${instance}",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "system:nodes",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

INTERNAL_IP=$(cat node_list.txt | grep $instance | cut -d" " -f2)

cfssl gencert 
  -ca=ca.pem 
  -ca-key=ca-key.pem 
  -config=ca-config.json 
  -hostname=${instance},${INTERNAL_IP},127.0.0.1 
  -profile=kubernetes 
  ${instance}-csr.json | cfssljson -bare ${instance}
done

Далее идем по исходной инструкции вплоть до пункта The Kubernetes API Server Certificate. Здесь меняем вводимые строки на такие:

{

KUBERNETES_HOSTNAMES=kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster,kubernetes.svc.cluster.local

cat > kubernetes-csr.json <<EOF
{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "Kubernetes",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

cfssl gencert 
  -ca=ca.pem 
  -ca-key=ca-key.pem 
  -config=ca-config.json 
  -hostname=$(cut -d" " -f2 node_list.txt| tr 'n' ',')127.0.0.1,${KUBERNETES_HOSTNAMES} 
  -profile=kubernetes 
  kubernetes-csr.json | cfssljson -bare kubernetes

}

В следующем разделе, The Service Account Key Pair, выполняем все по инструкции, а в Distribute the Client and Server Certificates просто разносим все нужное по узлам с помощью scp. Чтобы это заработало, на рабочей машине создаем файл ~/.ssh/config с помощью команды:

cat node_list.txt | xargs -n2 bash -c 'echo -e "Host $0ntHostname $1ntUser <Ваш пользователь на узлах>"' | tee ~/.ssh/config

Копируем файлы на узлы:

{
for instance in $(cut -d" " -f1 node_list.txt); do
  scp node_list.txt ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem service-account-key.pem service-account.pem ca.pem ${instance}-key.pem ${instance}.pem node_list.txt  # Также переносим файл с IP-адресами на все узлы для дальнейшей работы.
${instance}:~/
done
}

В моем случае оба ноутбука будут выступать в качестве master’а и рабочего узла одновременно, поэтому я скопировал на них не только сертификаты для control plane, но и для рабочих узлов.

Generating Kubernetes Configuration Files for Authentication

Здесь [13] пропускаем пункт про Kubernetes Public IP Address, а в The kubelet Kubernetes Configuration File вместо исходной команды выполняем:

for instance in $(cat node_list.txt | cut -d" " -f1); do
  kubectl config set-cluster kubernetes-the-hard-way 
    --certificate-authority=ca.pem 
    --embed-certs=true 
    --server=https://127.0.0.1:443 
    --kubeconfig=${instance}.kubeconfig

  kubectl config set-credentials system:node:${instance} 
    --client-certificate=${instance}.pem 
    --client-key=${instance}-key.pem 
    --embed-certs=true 
    --kubeconfig=${instance}.kubeconfig

  kubectl config set-context default 
    --cluster=kubernetes-the-hard-way 
    --user=system:node:${instance} 
    --kubeconfig=${instance}.kubeconfig

  kubectl config use-context default --kubeconfig=${instance}.kubeconfig
done

И аналогично для The kube-proxy Kubernetes Configuration File:

 kubectl config set-cluster kubernetes-the-hard-way 
    --certificate-authority=ca.pem 
    --embed-certs=true 
    --server=https://127.0.0.1:443 
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config set-credentials system:kube-proxy 
    --client-certificate=kube-proxy.pem 
    --client-key=kube-proxy-key.pem 
    --embed-certs=true 
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config set-context default 
    --cluster=kubernetes-the-hard-way 
    --user=system:kube-proxy 
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

Далее следуем инструкции до момента копирования файлов на узлы. Вместо этого делаем так:

{
for instance in $(cat node_list.txt | cut -d" " -f1); do
  scp ${instance}.kubeconfig kube-proxy.kubeconfig admin.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig ${instance}:~/
done
}

Generating the Data Encryption Config and Key

В этом разделе [14] выполняем всё по инструкции, за исключением копирования файлов по узлам. Копируем так:

{
for instance in $(cat node_list.txt | cut -d" " -f1); do
  scp encryption-config.yaml ${instance}:~/
done
}

Bootstrapping the etcd Cluster

Вместо оригинальной инструкции [15] вначале заходим на узел (выполнять для каждого узла):

ssh hpcom

Устанавливаем следующие необходимые утилиты:

sudo emerge --sync && emerge --ask dev-vcs/git sys-devel/make net-misc/wget net-misc/curl dev-lang/go app-shells/bash-completion

Скачиваем и собираем etcd:

git clone https://github.com/etcd-io/etcd.git
cd etcd
git checkout v3.4.15
go mod vendor
./build
sudo mv bin/etcd* /usr/local/bin/

Конфигурируем собранный etcd. Устанавливаем сертификаты:

{
  sudo mkdir -p /etc/etcd /var/lib/etcd
  sudo chmod 700 /var/lib/etcd
  sudo cp ca.pem kubernetes-key.pem kubernetes.pem /etc/etcd/
}

Получаем IP-адрес и имя узла:

INTERNAL_IP=$(grep $(hostname -s) node_list.txt | cut -d' ' -f2)
ETCD_NAME=$(hostname -s)

И формируем Unit для systemd:

cat <<EOF | sudo tee /etc/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.com/etcd-io/etcd

[Service]
Type=notify
Environment="ETCD_UNSUPPORTED_ARCH=386" # Только для архитектуры i386, для amd64 не нужно указывать.
ExecStart=/usr/local/bin/etcd \
  --name ${ETCD_NAME} \
  --cert-file=/etc/etcd/kubernetes.pem \
  --key-file=/etc/etcd/kubernetes-key.pem \
  --peer-cert-file=/etc/etcd/kubernetes.pem \
  --peer-key-file=/etc/etcd/kubernetes-key.pem \
  --trusted-ca-file=/etc/etcd/ca.pem \
  --peer-trusted-ca-file=/etc/etcd/ca.pem \
  --peer-client-cert-auth \
  --client-cert-auth \
  --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \
  --listen-peer-urls https://${INTERNAL_IP}:2380 \
  --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://${INTERNAL_IP}:2379 \
  --initial-cluster-token etcd-cluster-0 \
  --initial-cluster $(cat node_list.txt | sed 's# #=https://#g' | tr 'n' ',' | sed 's#,#:2380,#g' | sed 's#,$##g') \
  --initial-cluster-state new \
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Теперь возвращаемся к исходной инструкции и выполняем все, что идет после пункта Start the etcd Server включительно.

Bootstrapping the Kubernetes Control Plane

Вначале заходим на узел (выполнять для каждого узла):

ssh hpcom

Создаем каталог для конфигурации:

sudo mkdir -p /etc/kubernetes/config

Скачиваем исходники Kubernetes и собираем control plane:

git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes && git checkout v1.21.0
make kube-scheduler kube-apiserver kube-controller-manager kubectl
cd _output/bin
chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/

Переносим сертификаты:

{
sudo mkdir -p /var/lib/kubernetes/
cd && sudo mv ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem 
    service-account-key.pem service-account.pem 
    encryption-config.yaml /var/lib/kubernetes/
}

Для имитирования HA ставим NGINX (перед этим создав файл для USE-флагов дополнительных модулей Gentoo):

cat <<EOF | sudo tee /etc/portage/package.use/nginx
www-servers/nginx NGINX_MODULES_HTTP: access gzip gzip_static gunzip proxy push_stream stub_status upstream_check upstream_hash upstream_ip_hash upstream_keepalive upstream_least_conn upstream_zone
www-servers/nginx NGINX_MODULES_STREAM: access geo limit_conn map return split_clients upstream_hash upstream_least_conn upstream_zone geoip realip ssl_preread geoip2 javascript
EOF

sudo emerge --ask www-servers/nginx

В nginx.conf в блок http добавляем проверку работы сервера:

server {
		listen 127.0.0.1:80;
		server_name localhost;

		access_log /var/log/nginx/localhost.access_log main;
		error_log /var/log/nginx/localhost.error_log info;

		location /nginx_status {
	        	stub_status on;

        		access_log off;
        		allow 127.0.0.1;
        		deny all;
	}

И также в конец файла дописываем строку с include по аналогии с Provisioning Compute Resources выше:

echo include passthrough.conf; | sudo tee -a /etc/nginx/nginx.conf

Затем, как на рабочей машине, создаем рядом файл passthrough.conf:

cat <<EOF | sudo tee /etc/nginx/passthrough.conf
stream {
    upstream kube {
$(cat node_list.txt | cut -d" " -f2 | xargs -I{} echo "$(printf '%8s')server {}:6443;")
    }

    server {
        listen       443;
        proxy_pass kube;
        proxy_next_upstream on;
    }
}
EOF

Конфигурируем API-сервер. Получаем нужные IP-адреса:

INTERNAL_IP=$(grep $(hostname -s) node_list.txt | cut -d' ' -f2)
KUBERNETES_PUBLIC_ADDRESS=127.0.0.1

Создаем Unit для systemd:

cat <<EOF | sudo tee /etc/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \
  --advertise-address=${INTERNAL_IP} \
  --allow-privileged=true \
  --apiserver-count=$(cat node_list.txt | wc -l) \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-path=/var/log/audit.log \
  --authorization-mode=Node,RBAC \
  --bind-address=0.0.0.0 \
  --client-ca-file=/var/lib/kubernetes/ca.pem \
  --enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
  --etcd-cafile=/var/lib/kubernetes/ca.pem \
  --etcd-certfile=/var/lib/kubernetes/kubernetes.pem \
  --etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \
  --etcd-servers=$(cut -d' ' -f2 node_list.txt | sed 's#^#https://#g' | sed 's#$#:2379#g' | xargs | tr ' ' ',') \
  --event-ttl=1h \
  --encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \
  --kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \
  --kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \
  --runtime-config='api/all=true' \
  --service-account-key-file=/var/lib/kubernetes/service-account.pem \
  --service-account-signing-key-file=/var/lib/kubernetes/service-account-key.pem \
  --service-account-issuer=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
  --service-cluster-ip-range=10.32.0.0/24 \
  --service-node-port-range=30000-32767 \
  --tls-cert-file=/var/lib/kubernetes/kubernetes.pem \
  --tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Далее выполняем всё из оригинальной инструкции [16] до пункта The Kubernetes Frontend Load Balancer. Устанавливать и настраивать balancer не требуется, хотя при желании можно развернуть MetalLB после окончательной настройки кластера. Блок Verification также можно пропустить, так как мы уже развернули NGINX.

Проверить работоспособность API-сервера можно так:

curl --cacert /var/lib/kubernetes/ca.pem  https://127.0.0.1:443/healthz

Bootstrapping the Kubernetes Worker Nodes

Заходим на каждый узел и устанавливаем необходимые пакеты:

ssh hpcom
sudo emerge --ask net-misc/socat net-firewall/conntrack-tools net-firewall/ipset sys-fs/btrfs-progs

Создаем нужные каталоги, скачиваем и собираем нужные бинарники:

sudo mkdir -p 
  /etc/cni/net.d 
  /opt/cni/bin 
  /var/lib/kubelet 
  /var/lib/kube-proxy 
  /var/lib/kubernetes 
  /var/run/kubernetes

crictl для i386:

wget -q --show-progress --https-only --timestamping https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.21.0/crictl-v1.21.0-linux-386.tar.gz
tar -xvf crictl-v1.21.0-linux-386.tar.gz && sudo mv crictl /usr/local/bin/

И для  amd64:

https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.21.0/crictl-v1.21.0-linux-amd64.tar.gz
tar -xvf crictl-v1.21.0-linux-amd64.tar.gz && sudo mv crictl /usr/local/bin/

runc:

cd && git clone git@github.com:opencontainers/runc.git && cd runc && git checkout v1.0.0-rc93
make
sudo make install

CNI plugins:

cd && git clone git@github.com:containernetworking/plugins.git && cd plugins && git checkout v0.9.1
./build_linux.sh
sudo mv bin/* /opt/cni/bin/

containerd requirements для i386:

cd && wget -c https://github.com/google/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_32.zip
sudo unzip protoc-3.11.4-linux-x86_32.zip -d /usr/local

И для amd64:

cd && wget -c 
https://github.com/google/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip
sudo unzip protoc-3.11.4-linux-x86_64.zip -d /usr/local

containerd:

cd && git clone git@github.com:containerd/containerd.git && cd containerd 
git clone git@github.com:containerd/containerd.git && cd containerd/
make 
sudo make install

K8s:

cd ~/kubernetes && git checkout v1.21.0
make kubelet kube-proxy
cd _output/bin
chmod +x kubelet kube-proxy
sudo mv kubelet kube-proxy /usr/local/bin/

Конфигурируем CNI-плагин:

POD_CIDR=10.200.$(grep -n $(hostname -s) node_list.txt | cut -d':' -f1).0/24
cat <<EOF | sudo tee /etc/cni/net.d/10-bridge.conf
{
    "cniVersion": "0.4.0",
    "name": "bridge",
    "type": "bridge",
    "bridge": "cnio0",
    "isGateway": true,
    "ipMasq": true,
    "ipam": {
        "type": "host-local",
        "ranges": [
          [{"subnet": "${POD_CIDR}"}]
        ],
        "routes": [{"dst": "0.0.0.0/0"}]
    }
}
EOF

cat <<EOF | sudo tee /etc/cni/net.d/99-loopback.conf
{
    "cniVersion": "0.4.0",
    "name": "lo",
    "type": "loopback"
}
EOF

Конфигурируем containerd (используется другая версия конфига, в отличие от оригинального репозитория):

sudo mkdir -p /etc/containerd/

cat << EOF | sudo tee /etc/containerd/config.toml
version = 2
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "docker.io/alexeymakhonin/pause:i386" # k8s.gcr.io/pause:3.7 для amd64

  [plugins."io.containerd.grpc.v1.cri".containerd]
    snapshotter = "overlayfs"
    [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/sbin/runc"
      runtime_root = ""
EOF

Контейнер pause (он же sandbox_image в конфиге containerd) от K8s не собирается для i386-архитектуры. Поэтому его можно собрать самостоятельно или воспользоваться готовым образом из моего Docker Hub’а: docker.io/alexeymakhonin/pause:i386 [17].

Если вы решили пойти первым путем, на узле с i386-архитектурой нужно собрать бинарник:

cd ~/kubernetes/build/pause && mkdir bin
gcc -Os -Wall -Werror -static -DVERSION=v3.6-bbc2dbb9801 -o bin/pause-linux-i386 linux/pause.c

Полученный бинарник и всю директорию следует скопировать на рабочий ноутбук с Docker Buildx [18], на котором будет собираться образ:

scp -r hpcom:~/kubernetes/build/pause ./ && cd pause
docker buildx build --pull --output=type=docker --platform linux/i386                 -t docker.io/<DockerHub username>/pause:i386 --build-arg BASE=scratch --build-arg ARCH=i386 .
docker push docker.io/<DockerHub username>/pause:i386

Затем в конфигурационном файле containerd нужно поменять sandbox_image на собранный образ.

Теперь создаем Unit containerd для systemd:

cat <<EOF | sudo tee /etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
EOF

Сконфигурировать kubelet и kube-proxy можно по оригинальной инструкции [19]. Однако стоит помнить, что ca.pem уже скопирован в /var/lib/kubernetes, поэтому команда mv упадет с ошибкой.

Проверить работоспособность узла можно так:

kubectl get node --kubeconfig ~/admin.kubeconfig

Configuring kubectl for Remote Access

Из этого раздела [20] нас интересует только самое начало — пункт The Admin Kubernetes Configuration File. Выполняем его:

{
  KUBERNETES_PUBLIC_ADDRESS=127.0.0.1

  kubectl config set-cluster kubernetes-the-hard-way 
    --certificate-authority=ca.pem 
    --embed-certs=true 
    --server=https://${KUBERNETES_PUBLIC_ADDRESS}:443

  kubectl config set-credentials admin 
    --client-certificate=admin.pem 
    --client-key=admin-key.pem

  kubectl config set-context kubernetes-the-hard-way 
    --cluster=kubernetes-the-hard-way 
    --user=admin

  kubectl config use-context kubernetes-the-hard-way
}

Provisioning Pod Network Routes

Эти инструкции [21] можно пропустить.

Deploying the DNS Cluster Add-on

Здесь инструкции [22] придется разделить на две части. Для машины с архитектурой amd64 выполняем всё, как в оригинале, а вот для i386 придется пойти другим путем. Обусловлено это тем, что официального образа coredns для i386 не существует, поэтому его придется собирать самим (или взять уже собранный мной [23]). Чтобы собрать образ самостоятельно, на машине с Docker Buildx [18] выполняем команды:

git clone git@github.com:coredns/coredns.git && cd coredns && git checkout v1.8.3
make CGO_ENABLED=0 GOOS=linux GOARCH=386
docker buildx build --pull --output=type=docker --platform linux/i386 -t docker.io/<DockerHub username>/coredns:i386 .
docker push docker.io/<DockerHub username>/coredns:i386

Затем берем конфиг с заменой образа на наш и деплоим его:

curl -L https://storage.googleapis.com/kubernetes-the-hard-way/coredns-1.8.yaml --silent -o - | sed 's#image: coredns/coredns:1.8.3#image: docker.io/<DockerHub username>/coredns:i386#g' | kubectl apply -f -

Теперь остается только наложить патч на созданный ресурс, заменив значение аннотации на i386 или amd64 в зависимости от того, на какой узел вы хотите назначить coredns по архитектуре:

cat <<EOF | yq -ojson  | tee patch.json
spec:
  template:
    spec:
      nodeSelector:
        kubernetes.io/arch: "386"
    
EOF

kubectl patch -n kube-system deployments.apps coredns --patch-file patch.json

Теперь можно проверить, что все работает, выполнив команды из оригинальной инструкции. 

На этом этапе может возникнуть ошибка: Pod’ы будут зависать в состоянии ContainerCreating с ошибкой:

cgroups: cgroup mountpoint does not exist: unknown.

Если это произошло, починить можно так:

sudo mkdir /sys/fs/cgroup/systemd
sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd

Smoke Test

Делаем всё по инструкции [24], за исключением двух пунктов.

Команда проверки шифрования:

ssh hpcom
sudo ETCDCTL_API=3 etcdctl get 
  --endpoints=https://127.0.0.1:2379 
  --cacert=/etc/etcd/ca.pem 
  --cert=/etc/etcd/kubernetes.pem 
  --key=/etc/etcd/kubernetes-key.pem
  /registry/secrets/default/kubernetes-the-hard-way | hexdump -C

Для NODE_PORT-сервиса:

curl -I  http://$(grep hpcom node_list.txt | cut -d' ' -f2):${NODE_PORT}

Cleaning up

На этом этапе [25] можно просто снести систему :)

Заключение

Мы рассмотрели, как можно с интересом провести время и не дать пропасть старому железу, которое, например, давно отложено в кладовку, а выбросить руки не поднимаются. Также мы научились разворачивать Kubernetes на физическом оборудовании, используя готовые инструкции из Kubernetes The Hard Way с небольшими доработками.

Особенно интересным и полезным может быть опыт самостоятельной сборки недостающих образов для архитектуры i386: хотя она уже давно выходит из обращения, иногда все-таки встречается.

Надеюсь, статья поможет тем, кто хочет поглубже влезть в Kubernetes и его настройку.

P.S.

Читайте также в нашем блоге:

Автор: Махонин Алексей

Источник [29]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/gentoo/379154

Ссылки в тексте:

[1] Келси Хайтауэра: https://github.com/kelseyhightower

[2] Kubernetes The Hard Way: https://github.com/kelseyhightower/kubernetes-the-hard-way

[3] amd64: https://wiki.gentoo.org/wiki/Handbook:AMD64

[4] x32: https://wiki.gentoo.org/wiki/Handbook:X86/Full/Installation

[5] IPSet: https://wiki.gentoo.org/wiki/IPSet

[6] Docker: https://wiki.gentoo.org/wiki/Docker

[7] черный экран сразу после GRUB: https://forums.gentoo.org/viewtopic-t-1083076-start-0.html

[8] ошибка с ​​non-PAE kernel: https://forums.gentoo.org/viewtopic-t-1051792-start-0.html

[9] В этом разделе: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/01-prerequisites.md

[10] как написано: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/02-client-tools.md

[11] Эту страницу: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/03-compute-resources.md

[12] В этом разделе: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/04-certificate-authority.md

[13] Здесь: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/05-kubernetes-configuration-files.md

[14] В этом разделе: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/06-data-encryption-keys.md

[15] оригинальной инструкции: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/07-bootstrapping-etcd.md

[16] из оригинальной инструкции: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/08-bootstrapping-kubernetes-controllers.md

[17] docker.io/alexeymakhonin/pause:i386: http://docker.io/alexeymakhonin/pause:i386

[18] Docker Buildx: https://docs.docker.com/buildx/working-with-buildx/

[19] по оригинальной инструкции: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/09-bootstrapping-kubernetes-workers.md

[20] Из этого раздела: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/10-configuring-kubectl.md

[21] Эти инструкции: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/11-pod-network-routes.md

[22] инструкции: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/12-dns-addon.md

[23] собранный мной: http://docker.io/alexeymakhonin/coredns:i386

[24] по инструкции: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/13-smoke-test.md

[25] На этом этапе: https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/14-cleanup.md

[26] «Kubernetes в миниатюре для локального запуска: k0s, MicroK8s, kind, k3s и Minikube»: https://habr.com/ru/company/flant/blog/572188/

[27] «Внутреннее устройство Kubernetes-кластера простым языком»: https://habr.com/ru/company/flant/blog/583660/

[28] «Kubernetes — это как океанариум»: https://habr.com/ru/company/flant/blog/544306/

[29] Источник: https://habr.com/ru/post/685616/?utm_source=habrahabr&utm_medium=rss&utm_campaign=685616