[k8s实践] 超详 | 在虚拟机利用 kubeadm 引导 k8s 集群

2,066 阅读9分钟

准备开始

  • 一台至少有 8G 内存的电脑
  • 已安装虚拟机,比如 VirtualBox
  • 已下载好 Ubuntu 镜像文件,比如可以从清华镜像站下载,版本最好在 16.04 以上

虚拟机安装

虚拟机配置

这里并不赘述如何安装虚拟机,不过请确保给虚拟机分配如下配置

  • 至少 2G 内存,过少会影响运行
  • 至少 2 核 CPU,必须
  • 网络连接选择桥接网卡,界面选择你宿主机当前活跃的网卡


关键信息参考如下
image.png
image.png

安装系统

省略,我这里安装的 Ubuntu 18.04

系统配置

软件源设置国内镜像

两种方式选择其一

image.png

设置一个可用的 DNS 服务器

8.8.8.8114.114.114.114

安装 Docker

安装
参考 yeasy.gitbook.io/docker_prac…
或者 k8s 的文档 kubernetes.io/zh/docs/set…

建议按照 k8s 的文档安装,但是安装时可以按第一个文档替换成国内 GPG 密钥和 apt 源。

做镜像加速
编辑 vim /etc/docker/daemon.json ,添加如下内容

{
  "registry-mirrors":
   [ 
     "https://hub-mirror.c.163.com",
     "https://mirror.baidubce.com" 
   ] 
}

重启 docker 服务

sudo systemctl daemon-reload
sudo systemctl restart docker

安装 ssh 服务

为了能够从宿主机 ssh 访问到虚拟机,我们需要安装 ssh 服务

sudo apt install openssh-server && \
sudo systemctl enable ssh && \
sudo systemctl restart ssh

宿主机从外部访问时可以利用 ssh-copy-id username@ip-your-host 把密钥保存到虚拟机,就不用每次利用密码访问了。具体操作可以参考之前的一篇文章 >>> 。

关闭防火墙

本机的学习环境为了方便可以直接关闭,而生产环境则应该按需打开相应端口。

sudo ufw disable

为安装k8s进行的设定

确保 iptables 工具不使用 nftables 后端

如果您系统的 iptables 工具使用 nftables 后端,则需要把 iptables 工具切换到“旧版”模式来避免这些问题。 默认情况下,至少在 Debian 10 (Buster)、Ubuntu 19.04、Fedora 29 和较新的发行版本中会出现这种问题。RHEL 8 不支持切换到旧版本模式,因此与当前的 kubeadm 软件包不兼容。

update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy

解释说明参考 k8s 官方文档

禁用交换分区

查看是否已禁用交换分区
第一个办法 free -m,看到 swap 一行 都是 0
image.png
第二个办法 swapon -v ,输出空白则已关闭

禁用方法
编辑 vim/etc/fstab 文件,注释掉swap was on /dev/sda5 during installation 下面的配置,即截图中光标所在行
image.png

复制多台虚拟机

现在我们已经把集群的控制面板的机器安装好了环境,下一步看你宿主机的配置,想搭配多少 worker,就多复制几台。我们使用复制功能,也是想减少工作量,因为如果单独配置需要大量手动工作。
复制操作如下

  1. 停止现有虚拟机
  2. 在 VirtualBox 等面板的虚拟机列表中选择刚刚我们配置好的机器,右键 选择 复制

image.png

  1. 设置新的虚拟机,留意 MAC 地址要设定重新生成

image.png

  1. 继续,然后等待就完成了。

虚拟机准备效果

比如,我准备了一个 master,两台 worker 节点
image.png

安装集群前的再检查

确保每个节点上 MAC 地址和 product_uuid 的唯一性

您可以使用命令 ip linkifconfig -a 来获取网络接口的 MAC 地址
可以使用 sudo cat /sys/class/dmi/id/product_uuid 命令对 product_uuid 校验
一般来讲,硬件设备会拥有唯一的地址,但是有些虚拟机的地址可能会重复。Kubernetes 使用这些值来唯一确定集群中的节点。 如果这些值在每个节点上不唯一,可能会导致安装失败。

检查网络

利用 ping 或者其他工具,检查以上各个节点的连通性,如果不通,则应当考虑 网络连接方式、防火墙或者其他。

安装控制面板

注意

集群安装命令,我们均以 root 用户执行

sudo -i

安装

apt-get update && apt-get install -y apt-transport-https curl

curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -

cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

apt-get update

apt-get install -y kubelet kubeadm kubectl # 默认安装最新版本

apt-mark hold kubelet kubeadm kubectl

systemctl daemon-reload

systemctl restart kubelet

如果需要安装指定版本的组件可以指定版本,如
sudo apt-get install -y kubeadm=1.18.8-00 kubelet=1.18.8-00 kubectl=1.18.8-00

确定软件

kubeadm version

能看到类似如下,部分截图
image.png
完整截图
image.png

初始化集群

在初始化集群之前,确定你想安装的的 网络组件,如果不知道选择哪个,我们以 flannel 示例。因为有的 网络组件 要求在初始化的时候需要指定 pod 的 cidr。如 官方文档的说明 >>> v1-17.docs.kubernetes.io/docs/setup/…
补充:后期如果要测试 NetworkPolicy,因为这个功能只有部分网络组件支持,如 Calico Cilium Kube-router Romana Weave,所以请自行选择。
image.png
因为 kubeadm 安装的控制面板的 apiserver 等各个组件都是以静态 pod 的形式运行的,所以在初始化的时候会拉取镜像,然后启动 docker,为了加快初始化的过程,我们可以先把需要的镜像拉取下来,并且一定要指定镜像仓库,因为默认的是谷歌的,是访问不了的。

预先拉取镜像

kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers

image.png

初始化

kubeadm init --pod-network-cidr=10.244.0.0/16 \
--image-repository=registry.aliyuncs.com/google_containers

执行过程如下

root@vb-n1:~# kubeadm init --pod-network-cidr=10.244.0.0/16 \  
> --image-repository=registry.aliyuncs.com/google_containers  
I0924 02:27:10.520223   12818 version.go:252] remote version is much newer: v1.19.2; falling back to: stable-1.18  
W0924 02:27:15.428893   12818 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]  
[init] Using Kubernetes version: v1.18.9  
[preflight] Running pre-flight checks  
[preflight] Pulling images required for setting up a Kubernetes cluster  
[preflight] This might take a minute or two, depending on the speed of your internet connection  
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'  
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"  
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"  
[kubelet-start] Starting the kubelet  
[certs] Using certificateDir folder "/etc/kubernetes/pki"  
[certs] Generating "ca" certificate and key  
[certs] Generating "apiserver" certificate and key  
[certs] apiserver serving cert is signed for DNS names [vb-n1 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.43.72]  
[certs] Generating "apiserver-kubelet-client" certificate and key  
[certs] Generating "front-proxy-ca" certificate and key  
[certs] Generating "front-proxy-client" certificate and key  
[certs] Generating "etcd/ca" certificate and key  
[certs] Generating "etcd/server" certificate and key  
[certs] etcd/server serving cert is signed for DNS names [vb-n1 localhost] and IPs [192.168.43.72 127.0.0.1 ::1]  
[certs] Generating "etcd/peer" certificate and key  
[certs] etcd/peer serving cert is signed for DNS names [vb-n1 localhost] and IPs [192.168.43.72 127.0.0.1 ::1]  
[certs] Generating "etcd/healthcheck-client" certificate and key  
[certs] Generating "apiserver-etcd-client" certificate and key  
[certs] Generating "sa" key and public key  
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"  
[kubeconfig] Writing "admin.conf" kubeconfig file  
[kubeconfig] Writing "kubelet.conf" kubeconfig file  
[kubeconfig] Writing "controller-manager.conf" kubeconfig file  
[kubeconfig] Writing "scheduler.conf" kubeconfig file  
[control-plane] Using manifest folder "/etc/kubernetes/manifests"  
[control-plane] Creating static Pod manifest for "kube-apiserver"  
[control-plane] Creating static Pod manifest for "kube-controller-manager"  
W0924 02:36:50.592219   12818 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"  
[control-plane] Creating static Pod manifest for "kube-scheduler"  
W0924 02:36:50.593625   12818 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"  
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"  
[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  
[apiclient] All control plane components are healthy after 24.504562 seconds  
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace  
[kubelet] Creating a ConfigMap "kubelet-config-1.18" in namespace kube-system with the configuration for the kubelets in the cluster  
[upload-certs] Skipping phase. Please see --upload-certs  
[mark-control-plane] Marking the node vb-n1 as control-plane by adding the label "node-role.kubernetes.io/master=''"  
[mark-control-plane] Marking the node vb-n1 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]  
[bootstrap-token] Using token: 2dsvjn.icq3o9bbenit60kg  
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles  
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes  
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials  
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token  
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster  
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace  
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key  
[addons] Applied essential addon: CoreDNS  
[addons] Applied essential addon: kube-proxy  
Your Kubernetes control-plane has initialized successfully!  
To start using your cluster, you need to run the following as a regular user:  
  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config    
  sudo chown $(id -u):$(id -g) $HOME/.kube/config  
You should now deploy a pod network to the cluster.  
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:  
 https://kubernetes.io/docs/concepts/cluster-administration/addons/  
Then you can join any number of worker nodes by running the following on each as root:  
kubeadm join 192.168.43.72:6443 --token 2dsvjn.icq3o9bbenit60kg \  
    --discovery-token-ca-cert-hash sha256:43a6c576e9efe1f581369ca443bba0a271b9a898a5a94a52730c4e03d617d88d

上面的输出提示,重要信息有两块

1 是集群的相关配置文件要让你将管理集群的用户能够访问到

# 对于非 root 用户管理集群,需要
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
 
# 对于 root 用户
export KUBECONFIG=/etc/kubernetes/admin.conf

2 指明了其他节点加入集群的方法
因为要验证身份,token 参数是有有效期的,一般是 23 小时,不过过期了也没关系,官方文档也给出了重新生成的方法。

不需要执行,只做示例
kubeadm join 192.168.43.72:6443 --token 2dsvjn.icq3o9bbenit60kg \
--discovery-token-ca-cert-hash sha256:43a6c576e9efe1f581369ca443bba0a271b9a898a5a94a52730c4e03d617d88d

确定集群状态

# 可以用如下命令确定集群安装情况,可以看到我们的第一个节点是 Ready 的状态
kubectl get nodes

kubectl cluster-info

image.png

安装工作节点

注意

以下安装步骤操作都是以 root 用户

sudo -i

安装

apt-get update && apt-get install -y apt-transport-https curl

curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -

cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

apt-get update

apt-get install -y kubelet kubeadm # 默认安装最新版本

apt-mark hold kubelet kubeadm

systemctl daemon-reload

systemctl restart kubelet

加入集群

kubeadm join 192.168.43.72:6443 --token 2dsvjn.icq3o9bbenit60kg \
    --discovery-token-ca-cert-hash sha256:43a6c576e9efe1f581369ca443bba0a271b9a898a5a94a52730c4e03d617d88d

最后会有如下输出提示
image.png

查看已加入的节点和整个集群状态

在控制面板节点执行如下

kubectl get nodes

image.png
列表中可以看到刚刚已经加入的工作节点

安装网络组件

现在工作节点已经在集群中注册成功了,但是工作节点和集群还不能进行正常连通。需要安装一款网络组件,刚刚我们在初始化集群指定了一个 pod cidr,我们选择的是 flannel ,需要在 master 控制面板中执行如下

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.12.0/Documentation/kube-flannel.yml

image.png

大功告成

这时我们再来执行,就会发现工作节点已经准备就绪了

kubectl get nodes

image.png

小试牛刀

我们现在来创建一个 pod 试试,我们看到几秒钟就创建好了这个 pod

kubectl run nginx --image=nginx --port=80

image.png
你也可以尝试 kubectl describe pod nginx | grep IP 找到这个 pod 在集群中的 IP,然后尝试 curl 访问
image.png

参考文档