本文更新于 2024-12-26,Kubernetes 更新非常快,请注意可能有过时信息

前言

最近公司业务场景要一个高可用的集群节点用于工业环境,而且数据量非常大,刚刚好手上有一台 IDC 淘来的机架服务器,借机复习一下 K8s 的手动部署。

系统资源

虚拟机配置

$ free -h
               total        used        free      shared  buff/cache   available
Mem:            31Gi       901Mi        25Gi       4.0Mi       5.4Gi        30Gi
Swap:             0B          0B          0B
$ cat /proc/cpuinfo | grep -c processor
32

集群的安装

由于只安装一个 Control Panel,我们只需要配置好以下几个组件即可

  • ETCD
  • Kube-ApiServer
  • Kube-Controller-Manager
  • Kube-Scheduler
  • Kube-Proxy
  • Kubelet

基础的配置

安装基础软件

$ sudo apt install bash-completion git net-tools sudo build-essential golang conntrack
$ go version # 这里的 Go 版本需要大于 1.12
go version go1.22.2 linux/amd64

进行组件的编译

$ mkdir k8s && cd k8s
$ git clone https://github.com/kubernetes/kubernetes.git -b release-1.31 --depth 1
$ make all WHAT=cmd/kube-apiserver cmd/kube-controller-manager cmd/kube-scheduler cmd/cloud-controller-manager # 控制面编译,如果电脑性能足够可以直接不带参数编译全部
$ ls -al _output/bin/
total 979468
drwxr-xr-x 2 sxueck sxueck      4096 Oct 24 21:04 .
drwxr-xr-x 3 sxueck sxueck      4096 Oct 24 20:58 ..
-rwxr-xr-x 1 sxueck sxueck  69255320 Oct 24 21:04 apiextensions-apiserver
-rwxr-xr-x 1 sxueck sxueck 117022912 Oct 24 21:04 e2e.test
-rwxr-xr-x 1 sxueck sxueck 110219128 Oct 24 21:04 e2e_node.test
-rwxr-xr-x 1 sxueck sxueck   9351428 Oct 24 21:04 ginkgo
-rwxr-xr-x 1 sxueck sxueck   1896708 Oct 24 21:04 go-runner
-rwxr-xr-x 1 sxueck sxueck  66691224 Oct 24 21:04 kube-aggregator
-rwxr-xr-x 1 sxueck sxueck  90542232 Oct 24 21:04 kube-apiserver
-rwxr-xr-x 1 sxueck sxueck  84742296 Oct 24 21:04 kube-controller-manager
-rwxr-xr-x 1 sxueck sxueck   1683608 Oct 24 21:04 kube-log-runner
-rwxr-xr-x 1 sxueck sxueck  64417944 Oct 24 21:04 kube-proxy
-rwxr-xr-x 1 sxueck sxueck  63725720 Oct 24 21:04 kube-scheduler
-rwxr-xr-x 1 sxueck sxueck  58290328 Oct 24 21:04 kubeadm
-rwxr-xr-x 1 sxueck sxueck  56381592 Oct 24 21:04 kubectl
-rwxr-xr-x 1 sxueck sxueck  55070872 Oct 24 21:04 kubectl-convert
-rwxr-xr-x 1 sxueck sxueck  76902728 Oct 24 21:04 kubelet
-rwxr-xr-x 1 sxueck sxueck  75108504 Oct 24 21:04 kubemark
-rwxr-xr-x 1 sxueck sxueck   1601688 Oct 24 21:04 mounter

设置NTP时间

$ sudo apt install chrony
$ sudo systemctl status chrony
● chrony.service - chrony, an NTP client/server
   Loaded: loaded (/lib/systemd/system/chrony.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2021-06-27 03:07:41 AKDT; 55s ago
     Docs: man:chronyd(8)
           man:chronyc(1)
           man:chrony.conf(5)
 Main PID: 2028 (chronyd)
    Tasks: 2 (limit: 4915)
   Memory: 1.6M
   CGroup: /system.slice/chrony.service
           ├─2028 /usr/sbin/chronyd -F -1
           └─2029 /usr/sbin/chronyd -F -1

Jun 27 03:07:41 sxueck systemd[1]: Starting chrony, an NTP client/server...
Jun 27 03:07:41 sxueck chronyd[2028]: chronyd version 3.4 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +SECHASJun 27 03:07:41 sxueck chronyd[2028]: Initial frequency 6.947 ppm
Jun 27 03:07:41 sxueck chronyd[2028]: Loaded seccomp filter
Jun 27 03:07:41 sxueck systemd[1]: Started chrony, an NTP client/server.
Jun 27 03:07:48 sxueck chronyd[2028]: Selected source 183.177.72.201
Jun 27 03:07:49 sxueck chronyd[2028]: Selected source 60.248.114.17
$ chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
^- tock.ntp.infomaniak.ch        1  10   337   841   +491us[ +491us] +/-  110ms
^- time.cloudflare.com           3  10   377    72  -5089us[-5089us] +/-  121ms
^* 139.199.215.251               2  10   377  1017  -2594us[-3319us] +/-   40ms
^- makaki.miuku.net              2  10   333   24m    +78ms[  +77ms] +/-  106ms
$ sudo timedatectl set-timezone Asia/Shanghai

修改一些必要的内核参数以供 CNI 插件能正常使用

$ sudo /sbin/modprobe br_netfilter
$ cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
$ sudo sysctl -p /etc/sysctl.d/k8s.conf

至此,我们可以开始安装集群依赖组件

证书的生成

CA 根证书

K8s 的许多组件都需要依赖证书进行操作,例如 Kube-ApiServer 的认证等,我们这里通过一个自签 CA 证书进行整个集群的签名,但是请注意千万保管好这个证书

在 Kubernetes 集群中,各个组件间通过 TLS 进行通信。组件的证书可以代表其唯一性( Common Name )。搭建 PKI 可以自由签发证书给需要的组件。

生成自签名的 CA 证书和私钥

$ sudo mkdir -p /etc/kubernetes/pki
$ sudo openssl genrsa -out /etc/kubernetes/pki/ca.key 2048
$ sudo openssl req -x509 -new -nodes -key /etc/kubernetes/pki/ca.key -subj "/CN=kubernetes-ca" -days 3650 -out /etc/kubernetes/pki/ca.crt

如果是以前的话,还需要使用 cf-ssl 工具,并且同时需要编写大量的证书 CSR,现在归功于大量的文档和 AI 搜索引擎,直接找到简易签发我们需要的证书方法了

生成其他组件的证书

kube-apiserver

$ sudo openssl genrsa -out /etc/kubernetes/pki/apiserver.key 2048
$ sudo openssl req -new -key /etc/kubernetes/pki/apiserver.key -subj "/CN=kube-apiserver" -out /etc/kubernetes/pki/apiserver.csr
$ sudo openssl x509 -req -in /etc/kubernetes/pki/apiserver.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/apiserver.crt -days 365
Certificate request self-signature ok
subject=CN = kube-apiserver

kubelet

$ sudo openssl genrsa -out /etc/kubernetes/pki/kubelet-client.key 2048
$ sudo openssl req -new -key /etc/kubernetes/pki/kubelet-client.key -subj "/CN=kubelet-client" -out /etc/kubernetes/pki/kubelet-client.csr
$ sudo openssl x509 -req -in /etc/kubernetes/pki/kubelet-client.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/kubelet-client.crt -days 365
Certificate request self-signature ok
subject=CN = kubelet-client

kube-controller-manager

$ sudo openssl genrsa -out /etc/kubernetes/pki/controller-manager.key 2048
$ sudo openssl req -new -key /etc/kubernetes/pki/controller-manager.key -subj "/CN=system:kube-controller-manager" -out /etc/kubernetes/pki/controller-manager.csr
$ sudo openssl x509 -req -in /etc/kubernetes/pki/controller-manager.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/controller-manager.crt -days 365
Certificate request self-signature ok
subject=CN = system:kube-controller-manager

kube-scheduler

$ sudo openssl genrsa -out /etc/kubernetes/pki/scheduler.key 2048
$ sudo openssl req -new -key /etc/kubernetes/pki/scheduler.key -subj "/CN=system:kube-scheduler" -out /etc/kubernetes/pki/scheduler.csr
$ sudo openssl x509 -req -in /etc/kubernetes/pki/scheduler.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out /etc/kubernetes/pki/scheduler.crt -days 365
Certificate request self-signature ok
subject=CN = system:kube-scheduler

最后让我们来看一下具体签发和配置的证书文件

$ ls /etc/kubernetes/pki/ -al
total 68
drwxr-xr-x 2 root root 4096 Oct 24 21:36 .
drwxr-xr-x 3 root root 4096 Oct 24 21:20 ..
-rw-r--r-- 1 root root 1005 Oct 24 21:24 apiserver.crt
-rw-r--r-- 1 root root  899 Oct 24 21:24 apiserver.csr
-rw------- 1 root root 1704 Oct 24 21:23 apiserver.key
-rw-r--r-- 1 root root 1123 Oct 24 21:22 ca.crt
-rw------- 1 root root 1704 Oct 24 21:22 ca.key
-rw-r--r-- 1 root root   41 Oct 24 21:36 ca.srl
-rw-r--r-- 1 root root 1025 Oct 24 21:32 controller-manager.crt
-rw-r--r-- 1 root root  920 Oct 24 21:31 controller-manager.csr
-rw------- 1 root root 1704 Oct 24 21:31 controller-manager.key
-rw-r--r-- 1 root root 1005 Oct 24 21:31 kubelet-client.crt
-rw-r--r-- 1 root root  899 Oct 24 21:28 kubelet-client.csr
-rw------- 1 root root 1704 Oct 24 21:25 kubelet-client.key
-rw-r--r-- 1 root root 1013 Oct 24 21:36 scheduler.crt
-rw-r--r-- 1 root root  907 Oct 24 21:35 scheduler.csr
-rw------- 1 root root 1704 Oct 24 21:35 scheduler.key

组件的配置和启动

我们先将编译构建的二进制文件放到对应的目录中

$ sudo mkdir -p /etc/kubernetes/manifests /var/lib/kubelet /var/log/kubernetes
$ sudo cp _output/bin/kube-apiserver /usr/local/bin/
$ sudo cp _output/bin/kube-controller-manager /usr/local/bin/
$ sudo cp _output/bin/kube-scheduler /usr/local/bin/
$ sudo cp _output/bin/kubelet /usr/local/bin/
$ sudo cp _output/bin/kubectl /usr/local/bin/

在主节点上创建 /etc/systemd/system/kube-apiserver.service 文件

[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=network.target

[Service]
ExecStart=/usr/local/bin/kube-apiserver \
  --advertise-address=192.168.0.100 \  # 替换为你的主节点 IP
  --allow-privileged=true \
  --authorization-mode=Node,RBAC \
  --client-ca-file=/etc/kubernetes/pki/ca.crt \
  --enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
  --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt \
  --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt \
  --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key \
  --etcd-servers=https://127.0.0.1:2379 \
  --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt \
  --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key \
  --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname \
  --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt \
  --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key \
  --requestheader-allowed-names=front-proxy-client \
  --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt \
  --requestheader-extra-headers-prefix=X-Remote-Extra- \
  --requestheader-group-headers=X-Remote-Group \
  --requestheader-username-headers=X-Remote-User \
  --secure-port=6443 \
  --service-account-key-file=/etc/kubernetes/pki/sa.pub \
  --service-cluster-ip-range=10.96.0.0/12 \
  --tls-cert-file=/etc/kubernetes/pki/apiserver.crt \
  --tls-private-key-file=/etc/kubernetes/pki/apiserver.key

Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

注意,--advertise-address 参数在 kube-apiserver 中非常重要,它指定了该组件向集群中的其他组件和客户端广播的 IP 地址。这个 IP 地址是其他组件(如 kubelet、kube-controller-manager、kube-scheduler 等)和外部客户端(如 kubectl)用来与 API Server 通信的地址,因此需要考虑一下选择一个和 Worker 节点共同的 IP 进行填写。

$ sudo systemctl daemon-reload
$ sudo systemctl start kube-apiserver
$ sudo systemctl enable kube-apiserver
$ sudo systemctl status kube-apiserver.service
● kube-apiserver.service - Kubernetes API Server
     Loaded: loaded (/etc/systemd/system/kube-apiserver.service; enabled; preset: enabled)
     Active: active (running) since Thu 2024-10-24 21:54:45 CST; 594us ago
       Docs: https://github.com/kubernetes/kubernetes
   Main PID: 68130 (9)
      Tasks: 0 (limit: 28726)
     Memory: 0B ()
     CGroup: /system.slice/kube-apiserver.service
             └─68130 /usr/lib/systemd/systemd-executor --deserialize 53 --log-level info --log-target journal

Oct 24 21:54:45 snival-pc systemd[1]: kube-apiserver.service: Scheduled restart job, restart counter is at 16.
Oct 24 21:54:45 snival-pc systemd[1]: Started kube-apiserver.service - Kubernetes API Server.