服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

云服务器|WEB服务器|FTP服务器|邮件服务器|虚拟主机|服务器安全|DNS服务器|服务器知识|Nginx|IIS|Tomcat|

服务器之家 - 服务器技术 - 服务器知识 - 部署一个 Containerd 容器运行时的 Kubernetes 集群

部署一个 Containerd 容器运行时的 Kubernetes 集群

2021-09-02 22:59k8s技术圈 服务器知识

本篇我们使用 kubeadm 从头搭建一个使用 containerd 作为容器运行时的 Kubernetes 集群,这里我们安装最新的 v1.22.1 版本。

部署一个 Containerd 容器运行时的 Kubernetes 集群

前面我们介绍了 containerd 的基本使用,也了解了如何将现有 docker 容器运行时的 Kubernetes 集群切换成 containerd,接下来我们使用 kubeadm 从头搭建一个使用 containerd 作为容器运行时的 Kubernetes 集群,这里我们安装最新的 v1.22.1 版本。

环境准备

3个节点,都是 Centos 7.6 系统,内核版本:3.10.0-1062.4.1.el7.x86_64,在每个节点上添加 hosts 信息:

  1.  ~ cat /etc/hosts 
  2. 192.168.31.30 master 
  3. 192.168.31.95 node1 
  4. 192.168.31.215 node2 
  • 节点的 hostname 必须使用标准的 DNS 命名,另外千万不用什么默认的 localhost 的 hostname,会导致各种错误出现的。在 Kubernetes 项目里,机器的名字以及一切存储在 Etcd 中的 API 对象,都必须使用标准的 DNS 命名(RFC 1123)。可以使用命令 hostnamectl set-hostname node1 来修改 hostname。

禁用防火墙:

  1.  ~ systemctl stop firewalld 
  2.  ~ systemctl disable firewalld 

禁用 SELINUX:

  1.  ~ setenforce 0 
  2.  ~ cat /etc/selinux/config 
  3. SELINUX=disabled 

由于开启内核 ipv4 转发需要加载 br_netfilter 模块,所以加载下该模块:

  1.  ~ modprobe br_netfilter 

创建/etc/sysctl.d/k8s.conf文件,添加如下内容:

  1. net.bridge.bridge-nf-call-ip6tables = 1 
  2. net.bridge.bridge-nf-call-iptables = 1 
  3. net.ipv4.ip_forward = 1 

bridge-nf 使得 netfilter 可以对 Linux 网桥上的 IPv4/ARP/IPv6 包过滤。比如,设置net.bridge.bridge-nf-call-iptables=1后,二层的网桥在转发包时也会被 iptables的 FORWARD 规则所过滤。常用的选项包括:

  • net.bridge.bridge-nf-call-arptables:是否在 arptables 的 FORWARD 中过滤网桥的 ARP 包
  • net.bridge.bridge-nf-call-ip6tables:是否在 ip6tables 链中过滤 IPv6 包
  • net.bridge.bridge-nf-call-iptables:是否在 iptables 链中过滤 IPv4 包
  • net.bridge.bridge-nf-filter-vlan-tagged:是否在 iptables/arptables 中过滤打了 vlan 标签的包。

执行如下命令使修改生效:

  1.  ~ sysctl -p /etc/sysctl.d/k8s.conf 

安装 ipvs:

  1.  ~ cat > /etc/sysconfig/modules/ipvs.modules <<EOF 
  2. #!/bin/bash 
  3. modprobe -- ip_vs 
  4. modprobe -- ip_vs_rr 
  5. modprobe -- ip_vs_wrr 
  6. modprobe -- ip_vs_sh 
  7. modprobe -- nf_conntrack_ipv4 
  8. EOF 
  9.  ~ chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4 

上面脚本创建了的/etc/sysconfig/modules/ipvs.modules文件,保证在节点重启后能自动加载所需模块。使用lsmod | grep -e ip_vs -e nf_conntrack_ipv4命令查看是否已经正确加载所需的内核模块。

接下来还需要确保各个节点上已经安装了 ipset 软件包:

  1.  ~ yum install ipset 

为了便于查看 ipvs 的代理规则,最好安装一下管理工具 ipvsadm:

  1.  ~ yum install ipvsadm 

同步服务器时间

  1.  ~ yum install chrony -y 
  2.  ~ systemctl enable chronyd 
  3.  ~ systemctl start chronyd 
  4.  ~ chronyc sources 
  5. 210 Number of sources = 4 
  6. MS Name/IP address         Stratum Poll Reach LastRx Last sample 
  7. =============================================================================== 
  8. ^+ sv1.ggsrv.de                  2   6    17    32   -823us[-1128us] +/-   98ms 
  9. ^- montreal.ca.logiplex.net      2   6    17    32    -17ms[  -17ms] +/-  179ms 
  10. ^- ntp6.flashdance.cx            2   6    17    32    -32ms[  -32ms] +/-  161ms 
  11. ^* 119.28.183.184                2   6    33    32   +661us[ +357us] +/-   38ms 
  12.  ~ date 
  13. Tue Aug 31 14:36:14 CST 2021 

关闭 swap 分区:

  1.  ~ swapoff -a 

修改/etc/fstab文件,注释掉 SWAP 的自动挂载,使用free -m确认 swap 已经关闭。swappiness 参数调整,修改/etc/sysctl.d/k8s.conf添加下面一行:

  1. vm.swappiness=0 

执行 sysctl -p /etc/sysctl.d/k8s.conf 使修改生效。

安装 Containerd

我们已经了解过容器运行时 containerd 的一些基本使用,接下来在各个节点上安装 Containerd。

由于 containerd 需要调用 runc,所以我们也需要先安装 runc,不过 containerd 提供了一个包含相关依赖的压缩包 cri-containerd-cni-${VERSION}.${OS}-${ARCH}.tar.gz,可以直接使用这个包来进行安装。首先从 release 页面下载最新版本的压缩包,当前为 1.5.5 版本:

  1.  ~ wget https://github.com/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz 
  2. # 如果有限制,也可以替换成下面的 URL 加速下载 
  3. # wget https://download.fastgit.org/containerd/containerd/releases/download/v1.5.5/cri-containerd-cni-1.5.5-linux-amd64.tar.gz 

直接将压缩包解压到系统的各个目录中:

  1.  ~ tar -C / -xzf cri-containerd-cni-1.5.5-linux-amd64.tar.gz 

然后要将 /usr/local/bin 和 /usr/local/sbin 追加到 ~/.bashrc 文件的 PATH 环境变量中:

  1. export PATH=$PATH:/usr/local/bin:/usr/local/sbin 

然后执行下面的命令使其立即生效:

  1.  ~ source ~/.bashrc 

containerd 的默认配置文件为 /etc/containerd/config.toml,我们可以通过如下所示的命令生成一个默认的配置:

  1.  ~ mkdir -p /etc/containerd 
  2.  ~ containerd config default > /etc/containerd/config.toml 

对于使用 systemd 作为 init system 的 Linux 的发行版,使用 systemd 作为容器的 cgroup driver 可以确保节点在资源紧张的情况更加稳定,所以推荐将 containerd 的 cgroup driver 配置为 systemd。修改前面生成的配置文件 /etc/containerd/config.toml,在 plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options 配置块下面将 SystemdCgroup 设置为 true:

  1. [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] 
  2.   ... 
  3.   [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] 
  4.     SystemdCgroup = true 
  5.     .... 

然后再为镜像仓库配置一个加速器,需要在 cri 配置块下面的 registry 配置块下面进行配置 registry.mirrors:

  1. [plugins."io.containerd.grpc.v1.cri"
  2.   ... 
  3.   # sandbox_image = "k8s.gcr.io/pause:3.5" 
  4.   sandbox_image = "registry.aliyuncs.com/k8sxio/pause:3.5" 
  5.   ... 
  6.   [plugins."io.containerd.grpc.v1.cri".registry] 
  7.     [plugins."io.containerd.grpc.v1.cri".registry.mirrors] 
  8.       [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"
  9.         endpoint = ["https://bqr1dr1n.mirror.aliyuncs.com"
  10.       [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"
  11.         endpoint = ["https://registry.aliyuncs.com/k8sxio"

由于上面我们下载的 containerd 压缩包中包含一个 etc/systemd/system/containerd.service 的文件,这样我们就可以通过 systemd 来配置 containerd 作为守护进程运行了,现在我们就可以启动 containerd 了,直接执行下面的命令即可:

  1.  ~ systemctl daemon-reload 
  2.  ~ systemctl enable containerd --now 

启动完成后就可以使用 containerd 的本地 CLI 工具 ctr 和 crictl 了,比如查看版本:

  1.  ~ ctr version 
  2. Client: 
  3.   Version:  v1.5.5 
  4.   Revision: 72cec4be58a9eb6b2910f5d10f1c01ca47d231c0 
  5.   Go version: go1.16.6 
  6.  
  7. Server: 
  8.   Version:  v1.5.5 
  9.   Revision: 72cec4be58a9eb6b2910f5d10f1c01ca47d231c0 
  10.   UUID: cd2894ad-fd71-4ef7-a09f-5795c7eb4c3b 
  11.  ~ crictl version 
  12. Version:  0.1.0 
  13. RuntimeName:  containerd 
  14. RuntimeVersion:  v1.5.5 
  15. RuntimeApiVersion:  v1alpha2 

使用 kubeadm 部署 Kubernetes

上面的相关环境配置也完成了,现在我们就可以来安装 Kubeadm 了,我们这里是通过指定yum 源的方式来进行安装的:

  1.  ~ cat <<EOF > /etc/yum.repos.d/kubernetes.repo 
  2. [kubernetes] 
  3. name=Kubernetes 
  4. baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 
  5. enabled=1 
  6. gpgcheck=1 
  7. repo_gpgcheck=1 
  8. gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg 
  9.         https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg 
  10. EOF 

当然了,上面的 yum 源是需要科学上网的,如果不能科学上网的话,我们可以使用阿里云的源进行安装:

  1.  ~ cat <<EOF > /etc/yum.repos.d/kubernetes.repo 
  2. [kubernetes] 
  3. name=Kubernetes 
  4. baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 
  5. enabled=1 
  6. gpgcheck=0 
  7. repo_gpgcheck=0 
  8. gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg 
  9.         http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg 
  10. EOF 

然后安装 kubeadm、kubelet、kubectl:

  1. --disableexcludes 禁掉除了kubernetes之外的别的仓库 
  2.  ~ yum makecache fast 
  3.  ~ yum install -y kubelet-1.22.1 kubeadm-1.22.1 kubectl-1.22.1 --disableexcludes=kubernetes 
  4.  ~ kubeadm version 
  5. kubeadm version: &version.Info{Major:"1", Minor:"22", GitVersion:"v1.22.1", GitCommit:"632ed300f2c34f6d6d15ca4cef3d3c7073412212", GitTreeState:"clean", BuildDate:"2021-08-19T15:44:22Z", GoVersion:"go1.16.7", Compiler:"gc", Platform:"linux/amd64"

可以看到我们这里安装的是 v1.22.1 版本,然后将 master 节点的 kubelet 设置成开机启动:

  1.  ~ systemctl enable --now kubelet 

到这里为止上面所有的操作都需要在所有节点执行配置。

初始化集群

当我们执行 kubelet --help 命令的时候可以看到原来大部分命令行参数都被 DEPRECATED了,这是因为官方推荐我们使用 --config 来指定配置文件,在配置文件中指定原来这些参数的配置,可以通过官方文档 Set Kubelet parameters via a config file 了解更多相关信息,这样 Kubernetes 就可以支持动态 Kubelet 配置(Dynamic Kubelet Configuration)了,参考 Reconfigure a Node’s Kubelet in a Live Cluster。

然后我们可以通过下面的命令在 master 节点上输出集群初始化默认使用的配置:

  1.  ~ kubeadm config print init-defaults --component-configs KubeletConfiguration > kubeadm.yaml 

然后根据我们自己的需求修改配置,比如修改 imageRepository 指定集群初始化时拉取 Kubernetes 所需镜像的地址,kube-proxy 的模式为 ipvs,另外需要注意的是我们这里是准备安装 flannel 网络插件的,需要将 networking.podSubnet 设置为10.244.0.0/16:

  1. # kubeadm.yaml 
  2. apiVersion: kubeadm.k8s.io/v1beta3 
  3. bootstrapTokens: 
  4. - groups: 
  5.   - system:bootstrappers:kubeadm:default-node-token 
  6.   token: abcdef.0123456789abcdef 
  7.   ttl: 24h0m0s 
  8.   usages: 
  9.   - signing 
  10.   - authentication 
  11. kind: InitConfiguration 
  12. localAPIEndpoint: 
  13.   advertiseAddress: 192.168.31.30  # 指定master节点内网IP 
  14.   bindPort: 6443 
  15. nodeRegistration: 
  16.   criSocket: /run/containerd/containerd.sock  # 使用 containerd的Unix socket 地址 
  17.   imagePullPolicy: IfNotPresent 
  18.   name: master 
  19.   taints:  # 给master添加污点,master节点不能调度应用 
  20.   - effect: "NoSchedule" 
  21.     key"node-role.kubernetes.io/master" 
  22.  
  23. --- 
  24. apiVersion: kubeproxy.config.k8s.io/v1alpha1 
  25. kind: KubeProxyConfiguration 
  26. mode: ipvs  # kube-proxy 模式 
  27.  
  28. --- 
  29. apiServer: 
  30.   timeoutForControlPlane: 4m0s 
  31. apiVersion: kubeadm.k8s.io/v1beta3 
  32. certificatesDir: /etc/kubernetes/pki 
  33. clusterName: kubernetes 
  34. controllerManager: {} 
  35. dns: {} 
  36. etcd: 
  37.   local
  38.     dataDir: /var/lib/etcd 
  39. imageRepository: registry.aliyuncs.com/k8sxio 
  40. kind: ClusterConfiguration 
  41. kubernetesVersion: 1.22.1 
  42. networking: 
  43.   dnsDomain: cluster.local 
  44.   serviceSubnet: 10.96.0.0/12 
  45.   podSubnet: 10.244.0.0/16  # 指定 pod 子网 
  46. scheduler: {} 
  47.  
  48. --- 
  49. apiVersion: kubelet.config.k8s.io/v1beta1 
  50. authentication: 
  51.   anonymous: 
  52.     enabled: false 
  53.   webhook: 
  54.     cacheTTL: 0s 
  55.     enabled: true 
  56.   x509: 
  57.     clientCAFile: /etc/kubernetes/pki/ca.crt 
  58. authorization
  59.   mode: Webhook 
  60.   webhook: 
  61.     cacheAuthorizedTTL: 0s 
  62.     cacheUnauthorizedTTL: 0s 
  63. clusterDNS: 
  64. - 10.96.0.10 
  65. clusterDomain: cluster.local 
  66. cpuManagerReconcilePeriod: 0s 
  67. evictionPressureTransitionPeriod: 0s 
  68. fileCheckFrequency: 0s 
  69. healthzBindAddress: 127.0.0.1 
  70. healthzPort: 10248 
  71. httpCheckFrequency: 0s 
  72. imageMinimumGCAge: 0s 
  73. kind: KubeletConfiguration 
  74. cgroupDriver: systemd  # 配置 cgroup driver 
  75. logging: {} 
  76. memorySwap: {} 
  77. nodeStatusReportFrequency: 0s 
  78. nodeStatusUpdateFrequency: 0s 
  79. rotateCertificates: true 
  80. runtimeRequestTimeout: 0s 
  81. shutdownGracePeriod: 0s 
  82. shutdownGracePeriodCriticalPods: 0s 
  83. staticPodPath: /etc/kubernetes/manifests 
  84. streamingConnectionIdleTimeout: 0s 
  85. syncFrequency: 0s 
  86. volumeStatsAggPeriod: 0s 

对于上面的资源清单的文档比较杂,要想完整了解上面的资源对象对应的属性,可以查看对应的 godoc 文档,地址: https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3。

”在开始初始化集群之前可以使用kubeadm config images pull --config kubeadm.yaml预先在各个服务器节点上拉取所k8s需要的容器镜像。

配置文件准备好过后,可以使用如下命令先将相关镜像 pull 下面:

  1.  ~ kubeadm config images pull --config kubeadm.yaml 
  2. [config/images] Pulled registry.aliyuncs.com/k8sxio/kube-apiserver:v1.22.1 
  3. [config/images] Pulled registry.aliyuncs.com/k8sxio/kube-controller-manager:v1.22.1 
  4. [config/images] Pulled registry.aliyuncs.com/k8sxio/kube-scheduler:v1.22.1 
  5. [config/images] Pulled registry.aliyuncs.com/k8sxio/kube-proxy:v1.22.1 
  6. [config/images] Pulled registry.aliyuncs.com/k8sxio/pause:3.5 
  7. [config/images] Pulled registry.aliyuncs.com/k8sxio/etcd:3.5.0-0 
  8. failed to pull image "registry.aliyuncs.com/k8sxio/coredns:v1.8.4"outputtime="2021-08-31T15:09:13+08:00" level=fatal msg="pulling image: rpc error: code = NotFound desc = failed to pull and unpack image \"registry.aliyuncs.com/k8sxio/coredns:v1.8.4\": failed to resolve reference \"registry.aliyuncs.com/k8sxio/coredns:v1.8.4\": registry.aliyuncs.com/k8sxio/coredns:v1.8.4: not found" 
  9. , error: exit status 1 
  10. To see the stack trace of this error execute with --v=5 or higher 

上面在拉取 coredns 镜像的时候出错了,没有找到这个镜像,我们可以手动 pull 该镜像,然后重新 tag 下镜像地址即可:

  1.  ~ ctr -n k8s.io i pull docker.io/coredns/coredns:1.8.4 
  2. docker.io/coredns/coredns:1.8.4:                                                  resolved       |++++++++++++++++++++++++++++++++++++++| 
  3. index-sha256:6e5a02c21641597998b4be7cb5eb1e7b02c0d8d23cce4dd09f4682d463798890:    done           |++++++++++++++++++++++++++++++++++++++| 
  4. manifest-sha256:10683d82b024a58cc248c468c2632f9d1b260500f7cd9bb8e73f751048d7d6d4: done           |++++++++++++++++++++++++++++++++++++++| 
  5. layer-sha256:bc38a22c706b427217bcbd1a7ac7c8873e75efdd0e59d6b9f069b4b243db4b4b:    done           |++++++++++++++++++++++++++++++++++++++| 
  6. config-sha256:8d147537fb7d1ac8895da4d55a5e53621949981e2e6460976dae812f83d84a44:   done           |++++++++++++++++++++++++++++++++++++++| 
  7. layer-sha256:c6568d217a0023041ef9f729e8836b19f863bcdb612bb3a329ebc165539f5a80:    exists         |++++++++++++++++++++++++++++++++++++++| 
  8. elapsed: 12.4s                                                                    total:  12.0 M (991.3 KiB/s) 
  9. unpacking linux/amd64 sha256:6e5a02c21641597998b4be7cb5eb1e7b02c0d8d23cce4dd09f4682d463798890... 
  10. done: 410.185888ms 
  11.  ~ ctr -n k8s.io i tag docker.io/coredns/coredns:1.8.4 registry.aliyuncs.com/k8sxio/coredns:v1.8.4 

然后就可以使用上面的配置文件在 master 节点上进行初始化:

  1.  ~ kubeadm init --config kubeadm.yaml 
  2. [init] Using Kubernetes version: v1.22.1 
  3. [preflight] Running pre-flight checks 
  4. [preflight] Pulling images required for setting up a Kubernetes cluster 
  5. [preflight] This might take a minute or two, depending on the speed of your internet connection 
  6. [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' 
  7. [certs] Using certificateDir folder "/etc/kubernetes/pki" 
  8. [certs] Generating "ca" certificate and key 
  9. [certs] Generating "apiserver" certificate and key 
  10. [certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local master] and IPs [10.96.0.1 192.168.31.30] 
  11. [certs] Generating "apiserver-kubelet-client" certificate and key 
  12. [certs] Generating "front-proxy-ca" certificate and key 
  13. [certs] Generating "front-proxy-client" certificate and key 
  14. [certs] Generating "etcd/ca" certificate and key 
  15. [certs] Generating "etcd/server" certificate and key 
  16. [certs] etcd/server serving cert is signed for DNS names [localhost master] and IPs [192.168.31.30 127.0.0.1 ::1] 
  17. [certs] Generating "etcd/peer" certificate and key 
  18. [certs] etcd/peer serving cert is signed for DNS names [localhost master] and IPs [192.168.31.30 127.0.0.1 ::1] 
  19. [certs] Generating "etcd/healthcheck-client" certificate and key 
  20. [certs] Generating "apiserver-etcd-client" certificate and key 
  21. [certs] Generating "sa" key and public key 
  22. [kubeconfig] Using kubeconfig folder "/etc/kubernetes" 
  23. [kubeconfig] Writing "admin.conf" kubeconfig file 
  24. [kubeconfig] Writing "kubelet.conf" kubeconfig file 
  25. [kubeconfig] Writing "controller-manager.conf" kubeconfig file 
  26. [kubeconfig] Writing "scheduler.conf" kubeconfig file 
  27. [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" 
  28. [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" 
  29. [kubelet-start] Starting the kubelet 
  30. [control-plane] Using manifest folder "/etc/kubernetes/manifests" 
  31. [control-plane] Creating static Pod manifest for "kube-apiserver" 
  32. [control-plane] Creating static Pod manifest for "kube-controller-manager" 
  33. [control-plane] Creating static Pod manifest for "kube-scheduler" 
  34. [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" 
  35. [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s 
  36. [apiclient] All control plane components are healthy after 12.501933 seconds 
  37. [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace 
  38. [kubelet] Creating a ConfigMap "kubelet-config-1.22" in namespace kube-system with the configuration for the kubelets in the cluster 
  39. [upload-certs] Skipping phase. Please see --upload-certs 
  40. [mark-control-plane] Marking the node master as control-plane by adding the labels: [node-role.kubernetes.io/master(deprecated) node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers] 
  41. [mark-control-plane] Marking the node master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] 
  42. [bootstrap-token] Using token: abcdef.0123456789abcdef 
  43. [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles 
  44. [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes 
  45. [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials 
  46. [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token 
  47. [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster 
  48. [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace 
  49. [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key 
  50. [addons] Applied essential addon: CoreDNS 
  51. [addons] Applied essential addon: kube-proxy 
  52.  
  53. Your Kubernetes control-plane has initialized successfully! 
  54.  
  55. To start using your cluster, you need to run the following as a regular user
  56.  
  57.   mkdir -p $HOME/.kube 
  58.   sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 
  59.   sudo chown $(id -u):$(id -g) $HOME/.kube/config 
  60.  
  61. Alternatively, if you are the root user, you can run: 
  62.  
  63.   export KUBECONFIG=/etc/kubernetes/admin.conf 
  64.  
  65. You should now deploy a pod network to the cluster. 
  66. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at
  67.   https://kubernetes.io/docs/concepts/cluster-administration/addons/ 
  68.  
  69. Then you can join any number of worker nodes by running the following on each as root: 
  70.  
  71. kubeadm join 192.168.31.30:6443 --token abcdef.0123456789abcdef \ 
  72.  --discovery-token-ca-cert-hash sha256:8c1f43da860b0e7bd9f290fe057f08cf7650b89e650ff316ce4a9cad3834475c 

根据安装提示拷贝 kubeconfig 文件:

  1.  ~ mkdir -p $HOME/.kube 
  2.  ~ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 
  3.  ~ sudo chown $(id -u):$(id -g) $HOME/.kube/config 

然后可以使用 kubectl 命令查看 master 节点已经初始化成功了:

  1.  ~ kubectl get nodes 
  2. NAME     STATUS   ROLES                  AGE     VERSION 
  3. master   Ready    control-plane,master   2m10s   v1.22.1 

添加节点

记住初始化集群上面的配置和操作要提前做好,将 master 节点上面的 $HOME/.kube/config 文件拷贝到 node 节点对应的文件中,安装 kubeadm、kubelet、kubectl(可选),然后执行上面初始化完成后提示的 join 命令即可:

  1.  ~ kubeadm join 192.168.31.30:6443 --token abcdef.0123456789abcdef \ 
  2. --discovery-token-ca-cert-hash sha256:8c1f43da860b0e7bd9f290fe057f08cf7650b89e650ff316ce4a9cad3834475c 
  3. [preflight] Running pre-flight checks 
  4. [preflight] WARNING: Couldn't create the interface used for talking to the container runtime: docker is required for container runtime: exec"docker": executable file not found in $PATH 
  5. [preflight] Reading configuration from the cluster... 
  6. [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' 
  7. [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" 
  8. [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" 
  9. [kubelet-start] Starting the kubelet 
  10. [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... 
  11.  
  12. This node has joined the cluster: 
  13. * Certificate signing request was sent to apiserver and a response was received. 
  14. * The Kubelet was informed of the new secure connection details. 
  15.  
  16. Run 'kubectl get nodes' on the control-plane to see this node join the cluster. 
  • 如果忘记了上面的 join 命令可以使用命令 kubeadm token create --print-join-command 重新获取。

执行成功后运行 get nodes 命令:

  1.  ~ kubectl get nodes 
  2. NAME     STATUS     ROLES                  AGE   VERSION 
  3. master   Ready      control-plane,master   47m   v1.22.1 
  4. node2    NotReady   <none>                 46s   v1.22.1 

可以看到是 NotReady 状态,这是因为还没有安装网络插件,接下来安装网络插件,可以在文档 https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/ 中选择我们自己的网络插件,这里我们安装 flannel:

  1.  ~ wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml 
  2. # 如果有节点是多网卡,则需要在资源清单文件中指定内网网卡 
  3. # 搜索到名为 kube-flannel-ds 的 DaemonSet,在kube-flannel容器下面 
  4.  ~ vi kube-flannel.yml 
  5. ...... 
  6. containers: 
  7. name: kube-flannel 
  8.   image: quay.io/coreos/flannel:v0.14.0 
  9.   command: 
  10.   - /opt/bin/flanneld 
  11.   args: 
  12.   - --ip-masq 
  13.   - --kube-subnet-mgr 
  14.   - --iface=eth0  # 如果是多网卡的话,指定内网网卡的名称 
  15. ...... 
  16.  ~ kubectl apply -f kube-flannel.yml  # 安装 flannel 网络插件 

隔一会儿查看 Pod 运行状态:

  1.  ~ kubectl get pods -n kube-system 
  2. NAME                             READY   STATUS    RESTARTS   AGE 
  3. coredns-7568f67dbd-5mg59         1/1     Running   0          8m32s 
  4. coredns-7568f67dbd-b685t         1/1     Running   0          8m31s 
  5. etcd-master                      1/1     Running   0          66m 
  6. kube-apiserver-master            1/1     Running   0          66m 
  7. kube-controller-manager-master   1/1     Running   0          66m 
  8. kube-flannel-ds-dsbt6            1/1     Running   0          11m 
  9. kube-flannel-ds-zwlm6            1/1     Running   0          11m 
  10. kube-proxy-jq84n                 1/1     Running   0          66m 
  11. kube-proxy-x4hbv                 1/1     Running   0          19m 
  12. kube-scheduler-master            1/1     Running   0          66m 
  • 当我们部署完网络插件后执行 ifconfig 命令,正常会看到新增的 cni0 与 flannel1 这两个虚拟设备,但是如果没有看到 cni0 这个设备也不用太担心,我们可以观察 /var/lib/cni 目录是否存在,如果不存在并不是说部署有问题,而是该节点上暂时还没有应用运行,我们只需要在该节点上运行一个 Pod 就可以看到该目录会被创建,并且 cni0 设备也会被创建出来。

网络插件运行成功了,node 状态也正常了:

  1.  ~ kubectl get nodes 
  2. NAME     STATUS   ROLES                  AGE    VERSION 
  3. master   Ready    control-plane,master   111m   v1.22.1 
  4. node2    Ready    <none>                 64m    v1.22.1 

用同样的方法添加另外一个节点即可。

Dashboard

v1.22.1 版本的集群需要安装最新的 2.0+ 版本的 Dashboard:

  1. # 推荐使用下面这种方式 
  2.  ~ wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml 
  3.  ~ vi recommended.yaml 
  4. # 修改Service为NodePort类型 
  5. ...... 
  6. kind: Service 
  7. apiVersion: v1 
  8. metadata: 
  9.   labels: 
  10.     k8s-app: kubernetes-dashboard 
  11.   name: kubernetes-dashboard 
  12.   namespace: kubernetes-dashboard 
  13. spec: 
  14.   ports: 
  15.     - port: 443 
  16.       targetPort: 8443 
  17.   selector: 
  18.     k8s-app: kubernetes-dashboard 
  19.   type: NodePort  # 加上type=NodePort变成NodePort类型的服务 
  20. ...... 

直接创建:

  1.  ~ kubectl apply -f recommended.yaml 

新版本的 Dashboard 会被默认安装在 kubernetes-dashboard 这个命名空间下面:

  1.  ~ kubectl get pods -n kubernetes-dashboard -o wide 
  2. NAME                                         READY   STATUS    RESTARTS   AGE   IP          NODE     NOMINATED NODE   READINESS GATES 
  3. dashboard-metrics-scraper-856586f554-pllvt   1/1     Running   0          24m   10.88.0.7   master   <none>           <none> 
  4. kubernetes-dashboard-76597d7df5-82998        1/1     Running   0          21m   10.88.0.2   node2    <none>           <none> 

我们仔细看可以发现上面的 Pod 分配的 IP 段是 10.88.xx.xx,包括前面自动安装的 CoreDNS 也是如此,我们前面不是配置的 podSubnet 为 10.244.0.0/16 吗?我们先去查看下 CNI 的配置文件:

  1.  ~ ls -la /etc/cni/net.d/ 
  2. total 8 
  3. drwxr-xr-x  2 1001 docker  67 Aug 31 16:45 . 
  4. drwxr-xr-x. 3 1001 docker  19 Jul 30 01:13 .. 
  5. -rw-r--r--  1 1001 docker 604 Jul 30 01:13 10-containerd-net.conflist 
  6. -rw-r--r--  1 root root   292 Aug 31 16:45 10-flannel.conflist 

可以看到里面包含两个配置,一个是 10-containerd-net.conflist,另外一个是我们上面创建的 Flannel 网络插件生成的配置,我们的需求肯定是想使用 Flannel 的这个配置,我们可以查看下 containerd 这个自带的 cni 插件配置:

  1.  ~ cat /etc/cni/net.d/10-containerd-net.conflist 
  2.   "cniVersion""0.4.0"
  3.   "name""containerd-net"
  4.   "plugins": [ 
  5.     { 
  6.       "type""bridge"
  7.       "bridge""cni0"
  8.       "isGateway"true
  9.       "ipMasq"true
  10.       "promiscMode"true
  11.       "ipam": { 
  12.         "type""host-local"
  13.         "ranges": [ 
  14.           [{ 
  15.             "subnet""10.88.0.0/16" 
  16.           }], 
  17.           [{ 
  18.             "subnet""2001:4860:4860::/64" 
  19.           }] 
  20.         ], 
  21.         "routes": [ 
  22.           { "dst""0.0.0.0/0" }, 
  23.           { "dst""::/0" } 
  24.         ] 
  25.       } 
  26.     }, 
  27.     { 
  28.       "type""portmap"
  29.       "capabilities": {"portMappings"true
  30.     } 
  31.   ] 

可以看到上面的 IP 段恰好就是 10.88.0.0/16,但是这个 cni 插件类型是 bridge 网络,网桥的名称为 cni0:

  1.  ~ ip a 
  2. ... 
  3. 6: cni0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 
  4.     link/ether 9a:e7:eb:40:e8:66 brd ff:ff:ff:ff:ff:ff 
  5.     inet 10.88.0.1/16 brd 10.88.255.255 scope global cni0 
  6.        valid_lft forever preferred_lft forever 
  7.     inet6 2001:4860:4860::1/64 scope global 
  8.        valid_lft forever preferred_lft forever 
  9.     inet6 fe80::98e7:ebff:fe40:e866/64 scope link 
  10.        valid_lft forever preferred_lft forever 
  11. ... 

但是使用 bridge 网络的容器无法跨多个宿主机进行通信,跨主机通信需要借助其他的 cni 插件,比如上面我们安装的 Flannel,或者 Calico 等等,由于我们这里有两个 cni 配置,所以我们需要将 10-containerd-net.conflist 这个配置删除,因为如果这个目录中有多个 cni 配置文件,kubelet 将会使用按文件名的字典顺序排列的第一个作为配置文件,所以前面默认选择使用的是 containerd-net 这个插件。

  1.  ~ mv /etc/cni/net.d/10-containerd-net.conflist /etc/cni/net.d/10-containerd-net.conflist.bak 
  2.  ~ ifconfig cni0 down && ip link delete cni0 
  3.  ~ systemctl daemon-reload 
  4.  ~ systemctl restart containerd kubelet 

然后记得重建 coredns 和 dashboard 的 Pod,重建后 Pod 的 IP 地址就正常了:

  1.  ~ kubectl get pods -n kubernetes-dashboard -o wide 
  2. NAME                                         READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES 
  3. dashboard-metrics-scraper-856586f554-tp8m5   1/1     Running   0          42s   10.244.1.6   node2   <none>           <none> 
  4. kubernetes-dashboard-76597d7df5-9rmbx        1/1     Running   0          66s   10.244.1.5   node2   <none>           <none> 
  5.  ~ kubectl get pods -n kube-system -o wide -l k8s-app=kube-dns 
  6. NAME                       READY   STATUS    RESTARTS   AGE     IP           NODE    NOMINATED NODE   READINESS GATES 
  7. coredns-7568f67dbd-n7bfx   1/1     Running   0          5m40s   10.244.1.2   node2   <none>           <none> 
  8. coredns-7568f67dbd-plrv8   1/1     Running   0          3m47s   10.244.1.4   node2   <none>           <none> 

查看 Dashboard 的 NodePort 端口:

  1.  ~ kubectl get svc -n kubernetes-dashboard 
  2. NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE 
  3. dashboard-metrics-scraper   ClusterIP   10.99.37.172    <none>        8000/TCP        25m 
  4. kubernetes-dashboard        NodePort    10.103.102.27   <none>        443:31050/TCP   25m 

然后可以通过上面的 31050 端口去访问 Dashboard,要记住使用 https,Chrome 不生效可以使用Firefox 测试,如果没有 Firefox 下面打不开页面,可以点击下页面中的信任证书即可:

部署一个 Containerd 容器运行时的 Kubernetes 集群

信任证书

信任后就可以访问到 Dashboard 的登录页面了:

部署一个 Containerd 容器运行时的 Kubernetes 集群

然后创建一个具有全局所有权限的用户来登录 Dashboard:(admin.yaml)

  1. kind: ClusterRoleBinding 
  2. apiVersion: rbac.authorization.k8s.io/v1 
  3. metadata: 
  4.   name: admin 
  5. roleRef: 
  6.   kind: ClusterRole 
  7.   name: cluster-admin 
  8.   apiGroup: rbac.authorization.k8s.io 
  9. subjects: 
  10. - kind: ServiceAccount 
  11.   name: admin 
  12.   namespace: kubernetes-dashboard 
  13. --- 
  14. apiVersion: v1 
  15. kind: ServiceAccount 
  16. metadata: 
  17.   name: admin 
  18.   namespace: kubernetes-dashboard 

直接创建:

  1.  ~ kubectl apply -f admin.yaml 
  2.  ~ kubectl get secret -n kubernetes-dashboard|grep admin-token 
  3. admin-token-lwmmx                  kubernetes.io/service-account-token   3         1d 
  4.  ~ kubectl get secret admin-token-lwmmx -o jsonpath={.data.token} -n kubernetes-dashboard |base64 -d 
  5. # 会生成一串很长的base64后的字符串 

然后用上面的 base64 解码后的字符串作为 token 登录 Dashboard 即可,新版本还新增了一个暗黑模式:

部署一个 Containerd 容器运行时的 Kubernetes 集群

最终我们就完成了使用 kubeadm 搭建 v1.22.1 版本的 kubernetes 集群、coredns、ipvs、flannel、containerd。

  1.  ~ kubectl get nodes -o wide 
  2. NAME     STATUS   ROLES                  AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION                CONTAINER-RUNTIME 
  3. master   Ready    control-plane,master   36m   v1.22.1   192.168.31.30    <none>        CentOS Linux 7 (Core)   3.10.0-1160.25.1.el7.x86_64   containerd://1.5.5 
  4. node2    Ready    <none>                 27m   v1.22.1   192.168.31.215   <none>        CentOS Linux 7 (Core)   3.10.0-1160.25.1.el7.x86_64   containerd://1.5.5 

清理

如果你的集群安装过程中遇到了其他问题,我们可以使用下面的命令来进行重置:

  1.  ~ kubeadm reset 
  2.  ~ ifconfig cni0 down && ip link delete cni0 
  3.  ~ ifconfig flannel.1 down && ip link delete flannel.1 
  4.  ~ rm -rf /var/lib/cni/ 

原文链接:https://mp.weixin.qq.com/s/auSU3F1XA4091aA0sw4GRA

延伸 · 阅读

精彩推荐