EvenChan's Ops.

K8S 部署流程

字数统计: 4.6k阅读时长: 20 min
2020/10/26

本地 Kubernetes 集群安装

0. 网络环境的准备

Kubernetes 用到的很多镜像都在 gcr.io 上,在国内访问会有困难。

这里提供两个手段:

  • 在家庭路由器上整个科学代理,实现全局科学上网。

  • 使用

    liangyuanpeng

    大佬在评论区提供的 gcr 国内镜像地址,这需要进行如下替换:

    • k8s.gcr.io—> lank8s.cn
    • gcr.io—> gcr.lank8s.cn

1. 节点的环境准备

首先准备三台 Linux 虚拟机,系统按需选择,然后调整这三台机器的设置:

  • 节点配置:

    • master:不低于 2c/3g,硬盘 20G
      • 主节点性能也受集群 Pods 个数的影响,上述配置应该可以支撑到每个 Worker 节点跑 100 个 Pod.
    • worker:看需求,建议不低于 2c/4g,硬盘不小于 20G,资源充分的话建议 40G 以上。
  • 处于同一网络内并可互通(通常是同一局域网)

  • 各主机的 hostname 和 mac/ip 地址以及

    1
    /sys/class/dmi/id/product_uuid

    ,都必须唯一

    • 这里新手最容易遇到的问题,是 hostname 冲突
  • 必须关闭 swap 交换内存,kubelet 才能正常工作

方便起见,我直接使用 ryan4yin/pulumi-libvirt 自动创建了五个 opensuse leap 15.3 虚拟机,并设置好了 ip/hostname.

1.1 iptables 设置

目前 kubernetes 的容器网络,默认使用的是 bridge 模式,这种模式下,需要使 iptables 能够接管 bridge 上的流量。

配置如下:

| 1 2 3 4 5 6 7 8 9 10 | sudo modprobe br_netfilter cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf br_netfilter EOF cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sudo sysctl --system |
| ———————— | ———————————————————— |
| | |

1.2 开放节点端口

局域网环境的话,建议直接关闭防火墙。这样所有端口都可用,方便快捷。

通常我们的云上集群,也是关闭防火墙的,只是会通过云服务提供的「安全组」来限制客户端 ip

Control-plane 节点,也就是 master,需要开放如下端口:

Protocol Direction Port Range Purpose Used By
TCP Inbound 6443* Kubernetes API server All
TCP Inbound 2379-2380 etcd server client API kube-apiserver, etcd
TCP Inbound 10250 kubelet API Self, Control plane
TCP Inbound 10251 kube-scheduler Self
TCP Inbound 10252 kube-controller-manager Self

Worker 节点需要开发如下端口:

Protocol Direction Port Range Purpose Used By
TCP Inbound 10250 kubelet API Self, Control plane
TCP Inbound 30000-32767 NodePort Services† All

另外通常我们本地测试的时候,可能更想直接在 80 443 8080 等端口上使用 NodePort, 就需要修改 kube-apiserver 的 --service-node-port-range 参数来自定义 NodePort 的端口范围,相应的 Worker 节点也得开放这些端口。

2. 安装 containerd

首先是环境配置:

| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf overlay br_netfilter nf_conntrack EOF sudo modprobe overlay sudo modprobe br_netfilter sudo modprobe nf_conntrack # Setup required sysctl params, these persist across reboots. cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 EOF # Apply sysctl params without reboot sudo sysctl --system |
| ————————————————— | ———————————————————— |
| | |

安装 containerd+nerdctl:

1 2 3 4 5 6 7 8 wget https://github.com/containerd/nerdctl/releases/download/v0.11.1/nerdctl-full-0.11.1-linux-amd64.tar.gz tar -axvf nerdctl-full-0.11.1-linux-amd64.tar.gz # 这里简单起见,rootless 相关的东西也一起装进去了,测试嘛就无所谓了... mv bin/* /usr/local/bin/ mv lib/systemd/system/containerd.service /usr/lib/systemd/system/ systemctl enable containerd systemctl start containerd

nerdctl 是一个 containerd 的命令行工具,但是它的容器、镜像与 Kubernetes 的容器、镜像是完全隔离的,不能互通!

目前只能通过 crictl 来查看、拉取 Kubernetes 的容器、镜像,下一节会介绍 crictl 的安装。

3. 安装 kubelet/kubeadm/kubectl

试用 crictl:

1 2 3 4 5 6 export CONTAINER_RUNTIME_ENDPOINT='unix:///var/run/containerd/containerd.sock' # 列出所有 pods,现在应该啥也没 crictl pods # 列出所有镜像 crictl images

4. 为 master 的 kube-apiserver 创建负载均衡实现高可用

根据 kubeadm 官方文档 Kubeadm Docs - High Availability Considerations 介绍,要实现 kube-apiserver 的高可用,目前最知名的负载均衡方式是 keepalived+haproxy,另外也可以考虑使用 kube-vip 等更简单的工具。

简单起见,我们直接用 kube-vip 吧,参考了 kube-vip 的官方文档:Kube-vip as a Static Pod with Kubelet.

P.S. 我也见过有的安装工具会直接抛弃 keepalived,直接在每个节点上跑一个 nginx 做负载均衡,配置里写死了所有 master 的地址…

首先使用如下命令生成 kube-vip 的配置文件,以 ARP 为例(生产环境建议换成 BGP):

| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | cat <<EOF | sudo tee add-kube-vip.sh # 你的虚拟机网卡,opensuse/centos 等都是 eth0,但是 ubuntu 可能是 ens3 export INTERFACE=eth0 # 用于实现高可用的 vip,需要和前面的网络接口在同一网段内,否则就无法路由了。 export VIP=192.168.122.200 # 生成 static-pod 的配置文件 mkdir -p /etc/kubernetes/manifests nerdctl run --rm --network=host --entrypoint=/kube-vip ghcr.io/kube-vip/kube-vip:v0.3.8 \ manifest pod \ --interface $INTERFACE \ --vip $VIP \ --controlplane \ --services \ --arp \ --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml EOF bash add-kube-vip.sh |
| —————————————————— | ———————————————————— |
| | |

三个 master 节点都需要跑下上面的命令(worker 不需要),创建好 kube-vip 的 static-pod 配置文件。 在完成 kubeadm 初始化后,kubelet 会自动把它们拉起为 static pod.

5. 使用 kubeadm 创建集群

其实需要运行的就是这条命令:

kubeadm 应该会报错,提示你有些依赖不存在,下面先安装好依赖项。

1 sudo zypper in -y socat ebtables conntrack-tools

再重新运行前面的 kubeadm 命令,应该就能正常执行了,它做的操作有:

  • 拉取控制面的容器镜像
  • 生成 ca 根证书
  • 使用根证书为 etcd/apiserver 等一票工具生成 tls 证书
  • 为控制面的各个组件生成 kubeconfig 配置
  • 生成 static pod 配置,kubelet 会根据这些配置自动拉起 kube-proxy 以及其他所有的 k8s master 组件

运行完会给出三部分命令:

  • kubeconfig 放到 $HOME/.kube/config 下,kubectl 需要使用该配置文件连接 kube-apiserver

  • control-plane 节点加入集群的命令:

    • 这里由于我们提前添加了 kube-vip 的 static-pod 配置,这里的 preflight-check 会报错,需要添加此参数忽略该报错 - --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests
    1 2 3 4 kubeadm join 192.168.122.200:6443 --token <token> \ --discovery-token-ca-cert-hash sha256:<hash> \ --control-plane --certificate-key <key> \ --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests
  • worker 节点加入集群的命令:

    1 2 kubeadm join 192.168.122.200:6443 --token <token> \ --discovery-token-ca-cert-hash sha256:<hash>

跑完第一部分 kubeconfig 的处理命令后,就可以使用 kubectl 查看集群状况了:

1 2 3 4 5 6 7 8 9 10 11 12 k8s-master-0:~/kubeadm # kubectl get no NAME STATUS ROLES AGE VERSION k8s-master-0 NotReady control-plane,master 79s v1.22.1 k8s-master-0:~/kubeadm # kubectl get po --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-78fcd69978-6tlnw 0/1 Pending 0 83s kube-system coredns-78fcd69978-hxtvs 0/1 Pending 0 83s kube-system etcd-k8s-master-0 1/1 Running 6 90s kube-system kube-apiserver-k8s-master-0 1/1 Running 4 90s kube-system kube-controller-manager-k8s-master-0 1/1 Running 4 90s kube-system kube-proxy-6w2bx 1/1 Running 0 83s kube-system kube-scheduler-k8s-master-0 1/1 Running 7 97s

现在在其他节点运行前面打印出的加入集群的命令,就可以搭建好一个高可用的集群了。

所有节点都加入集群后,通过 kubectl 查看,应该是三个控制面 master,两个 worker:

1 2 3 4 5 6 7 k8s-master-0:~/kubeadm # kubectl get node NAME STATUS ROLES AGE VERSION k8s-master-0 NotReady control-plane,master 26m v1.22.1 k8s-master-1 NotReady control-plane,master 7m2s v1.22.1 k8s-master-2 NotReady control-plane,master 2m10s v1.22.1 k8s-worker-0 NotReady <none> 97s v1.22.1 k8s-worker-1 NotReady <none> 86s v1.22.1

现在它们都还处于 NotReady 状态,需要等到我们把网络插件安装好,才会 Ready.

现在再看下集群的证书签发状态:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 ❯ kubectl get csr --sort-by='{.spec.username}' NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION csr-95hll 6m58s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:q8ivnz <none> Approved,Issued csr-tklnr 7m5s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:q8ivnz <none> Approved,Issued csr-w92jv 9m15s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:q8ivnz <none> Approved,Issued csr-rv7sj 8m11s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:q8ivnz <none> Approved,Issued csr-nxkgx 10m kubernetes.io/kube-apiserver-client-kubelet system:node:k8s-master-0 <none> Approved,Issued csr-cd22c 10m kubernetes.io/kubelet-serving system:node:k8s-master-0 <none> Pending csr-wjrnr 9m53s kubernetes.io/kubelet-serving system:node:k8s-master-0 <none> Pending csr-sjq42 9m8s kubernetes.io/kubelet-serving system:node:k8s-master-1 <none> Pending csr-xtv8f 8m56s kubernetes.io/kubelet-serving system:node:k8s-master-1 <none> Pending csr-f2dsf 8m3s kubernetes.io/kubelet-serving system:node:k8s-master-2 <none> Pending csr-xl8dg 6m58s kubernetes.io/kubelet-serving system:node:k8s-worker-0 <none> Pending csr-p9g24 6m52s kubernetes.io/kubelet-serving system:node:k8s-worker-1 <none> Pending

能看到有好几个 kubernetes.io/kubelet-serving 的证书还处于 pending 状态, 这是因为我们在 kubeadm 配置文件中,设置了 serverTLSBootstrap: true,让 Kubelet 从集群中申请 CA 签名证书,而不是自签名导致的。

设置这个参数的主要目的,是为了让 metrics-server 等组件能使用 https 协议与 kubelet 通信,避免为 metrics-server 添加参数 --kubelet-insecure-tls.

目前 kubeadm 不支持自动批准 kubelet 申请的证书,需要我们手动批准一下:

1 2 # 批准 Kubelet 申请的所有证书 kubectl certificate approve csr-cd22c csr-wjrnr csr-sjq42 csr-xtv8f csr-f2dsf csr-xl8dg csr-p9g24

在未批准这些证书之前,所有需要调用 kubelet api 的功能都将无法使用,比如:

  • 查看 pod 日志
  • 获取节点 metrics
  • 等等

5.1 常见问题

5.1.1 使用国内镜像源

如果你没有科学环境,kubeadm 默认的镜像仓库在国内是拉不了的。 如果对可靠性要求高,最好是自建私有镜像仓库,把镜像推送到私有仓库。

可以通过如下命令列出所有需要用到的镜像地址:

1 2 3 4 5 6 7 8 ❯ kubeadm config images list --kubernetes-version v1.22.1 k8s.gcr.io/kube-apiserver:v1.22.1 k8s.gcr.io/kube-controller-manager:v1.22.1 k8s.gcr.io/kube-scheduler:v1.22.1 k8s.gcr.io/kube-proxy:v1.22.1 k8s.gcr.io/pause:3.5 k8s.gcr.io/etcd:3.5.0-0 k8s.gcr.io/coredns/coredns:v1.8.4

使用 skopeo 等工具或脚本将上述镜像拷贝到你的私有仓库,或者图方便(测试环境)也可以考虑网上找找别人同步好的镜像地址。将镜像地址添加到 kubeadm-config.yaml 中再部署。

5.1.2 重置集群配置

创建集群的过程中出现任何问题,都可以通过在所有节点上运行 kubeadm reset 来还原配置,然后重新走 kubeadm 的集群创建流程。

但是要注意几点:

  • kubeadm reset 会清除包含 kube-vip 配置在内的所有 static-pod 配置文件,所以 master 节点需要重新跑下前面给的 kube-vip 命令,生成下 kube-vip 配置。
  • kubeadm reset 不会重置网络接口的配置,master 节点需要手动清理下 kube-vip 添加的 vip: ip addr del 192.168.122.200/32 dev eth0.
  • 如果你在安装了网络插件之后希望重装集群,顺序如下:
    • 通过 kubectl delete -f xxx.yaml/helm uninstall 删除所有除网络之外的其他应用配置
    • 删除网络插件
    • 先重启一遍所有节点,或者手动重置所有节点的网络配置
      • 建议重启,因为我不知道该怎么手动重置… 试了 systemctl restart network 并不会清理所有虚拟网络接口。

如此操作后,再重新执行集群安装,应该就没啥毛病了。

6. 验证集群的高可用性

虽然网络插件还没装导致集群所有节点都还没 ready,但是我们已经可以通过 kubectl 命令来简单验证集群的高可用性了。

首先,我们将前面放置在 k8s-master-0 的认证文件 $HOME/.kube/config 以及 kunbectl 安装在另一台机器上,比如我直接放我的宿主机。

然后在宿主机上跑 kubectl get node 命令验证集群的高可用性:

  • 三个主节点都正常运行时,kubectl 命令也正常
  • pause 或者 stop 其中一个 master,kubectl 命令仍然能正常运行
  • 再 pause 第二个 master,kubectl 命令应该就会卡住,并且超时,无法使用了
  • resume 恢复停掉的两个 master 之一,会发现 kubectl 命令又能正常运行了

到这里 kubeadm 的工作就完成了,接下来再安装网络插件,集群就可用了。

7. 安装网络插件

社区有很多种网络插件可选,比较知名且性能也不错的,应该是 Calico 和 Cilium,其中 Cilium 主打基于 eBPF 的高性能与高可观测性。

下面分别介绍这两个插件的安装方法。(注意只能安装其中一个网络插件,不能重复安装。)

需要提前在本机安装好 helm,我这里使用宿主机,因此只需要在宿主机安装:

| 1 2 3 4 5 | # 一行命令安装,也可以自己手动下载安装包,都行 curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash # 或者 opensuse 直接用包管理器安装 sudo zypper in helm |
| ———— | ———————————————————— |
| | |

7.1 安装 Cilium

官方文档:https://docs.cilium.io/en/v1.10/gettingstarted/k8s-install-kubeadm/

cilium 通过 eBPF 提供了高性能与高可观测的 k8s 集群网络, 另外 cilium 还提供了比 kube-proxy 更高效的实现,可以完全替代 kube-proxy.

这里我们还是先使用 kube-proxy 模式,先熟悉下 cilium 的使用:

| 1 2 3 4 | helm repo add cilium https://helm.cilium.io/ helm search repo cilium/cilium -l | head helm install cilium cilium/cilium --version 1.10.4 --namespace kube-system |
| ———- | ———————————————————— |
| | |

可以通过 kubectl get pod -A 查看 cilium 的安装进度,当所有 pod 都 ready 后,集群就 ready 了~

cilium 也提供了专用的客户端:

1 2 3 4 curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz{,.sha256sum} sha256sum --check cilium-linux-amd64.tar.gz.sha256sum sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin rm cilium-linux-amd64.tar.gz{,.sha256sum}

然后使用 cilium 客户端检查网络插件的状态:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ cilium status --wait /¯¯\ /¯¯\__/¯¯\ Cilium: OK \__/¯¯\__/ Operator: OK /¯¯\__/¯¯\ Hubble: disabled \__/¯¯\__/ ClusterMesh: disabled \__/ DaemonSet cilium Desired: 5, Ready: 5/5, Available: 5/5 Deployment cilium-operator Desired: 2, Ready: 2/2, Available: 2/2 Containers: cilium Running: 5 cilium-operator Running: 2 Cluster Pods: 2/2 managed by Cilium Image versions cilium quay.io/cilium/cilium:v1.10.4@sha256:7d354052ccf2a7445101d78cebd14444c7c40129ce7889f2f04b89374dbf8a1d: 5 cilium-operator quay.io/cilium/operator-generic:v1.10.4@sha256:c49a14e34634ff1a494c84b718641f27267fb3a0291ce3d74352b44f8a8d2f93: 2

cilium 还提供了命令,自动创建 pod 进行集群网络的连接性测试:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ❯ cilium connectivity test ℹ️ Monitor aggregation detected, will skip some flow validation steps ✨ [kubernetes] Creating namespace for connectivity check... ✨ [kubernetes] Deploying echo-same-node service... ✨ [kubernetes] Deploying same-node deployment... ✨ [kubernetes] Deploying client deployment... ✨ [kubernetes] Deploying client2 deployment... ✨ [kubernetes] Deploying echo-other-node service... ✨ [kubernetes] Deploying other-node deployment... ... ℹ️ Expose Relay locally with: cilium hubble enable cilium status --wait cilium hubble port-forward& 🏃 Running tests... ... --------------------------------------------------------------------------------------------------------------------- ✅ All 11 tests (134 actions) successful, 0 tests skipped, 0 scenarios skipped.

通过 kubectl get po -A 能观察到,这个测试命令会自动创建一个 cilium-test 名字空间,并在启动创建若干 pod 进行详细的测试。

整个测试流程大概会持续 5 分多钟,测试完成后,相关 Pod 不会自动删除,使用如下命令手动删除:

1 kubectl delete namespace cilium-test

7.2 安装 Calico

官方文档:https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises

也就两三行命令。安装确实特别简单,懒得介绍了,看官方文档吧。

但是实际上 calico 的细节还蛮多的,建议通读下它的官方文档,了解下 calico 的架构。

8. 查看集群状态

官方的 dashboard 个人感觉不太好用,建议直接在本地装个 k9s 用,特别爽。

1 sudo zypper in k9s

然后就可以愉快地玩耍了。

9. 安装 metrics-server

这一步可能遇到的问题:Enabling signed kubelet serving certificates

如果需要使用 HPA 以及简单的集群监控,那么 metrics-server 是必须安装的,现在我们安装一下它。

首先,跑 kubectl 的监控命令应该会报错:

1 2 ❯ kubectl top node error: Metrics API not available

k9s 里面应该也看不到任何监控指标。

现在通过 helm 安装它:

| 1 2 3 4 | helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ helm search repo metrics-server/metrics-server -l | head helm upgrade --install metrics-server metrics-server/metrics-server --version 3.5.0 --namespace kube-system |
| ———- | ———————————————————— |
| | |

metrics-server 默认只会部署一个实例,如果希望高可用,请参考官方配置:metrics-server - high-availability manifests

等 metrics-server 启动好后,就可以使用 kubectl top 命令啦:

10. 为 etcd 添加定期备份能力

请移步 [etcd 的备份与恢复](https://github.com/ryan4yin/knowledge/blob/master/datastore/etcd/etcd 的备份与恢复.md)

11. 安装 Volume Provisioner

在我们学习使用 Prometheus/MinIO/Tekton 等有状态应用时,它们默认情况下会通过 PVC 声明需要的数据卷。

为了支持这个能力,我们需要在集群中部署一个 Volume Provisioner.

对于云上环境,直接接入云服务商提供的 Volume Provisioner 就 OK 了,方便省事而且足够可靠。

而对于 bare-metal 环境,比较有名的应该是 rook-ceph,但是这个玩意部署复杂,维护难度又高,不适合用来测试学习,也不适合生产环境。

对于开发、测试环境,或者个人集群,建议使用:

CATALOG
  1. 1. 本地 Kubernetes 集群安装
  2. 2. 0. 网络环境的准备
  3. 3. 1. 节点的环境准备
    1. 3.1. 1.1 iptables 设置
    2. 3.2. 1.2 开放节点端口
  4. 4. 2. 安装 containerd
  5. 5. 3. 安装 kubelet/kubeadm/kubectl
  6. 6. 4. 为 master 的 kube-apiserver 创建负载均衡实现高可用
  7. 7. 5. 使用 kubeadm 创建集群
    1. 7.1. 5.1 常见问题
      1. 7.1.1. 5.1.1 使用国内镜像源
      2. 7.1.2. 5.1.2 重置集群配置
  8. 8. 6. 验证集群的高可用性
  9. 9. 7. 安装网络插件
    1. 9.1. 7.1 安装 Cilium
    2. 9.2. 7.2 安装 Calico
  10. 10. 8. 查看集群状态
  11. 11. 9. 安装 metrics-server
  12. 12. 10. 为 etcd 添加定期备份能力
  13. 13. 11. 安装 Volume Provisioner