主机环境预设

本示例中的安装部署Kubernetes集群将基于以下环境进行。

  • OS: Ubuntu 20.04.2 LTS (GNU/Linux 5.11.0-25-generic x86_64)
  • Kubernetes:v1.22
  • Container Runtime:  Docker version 20.10.8

测试环境说明

测试使用的Kubernetes集群可由一个master主机及一个以上(建议至少两个)node主机组成,这些主机可以是物理服务器,也可以运行于vmware、virtualbox或kvm等虚拟化平台上的虚拟机,甚至是公有云上的VPS主机。

本测试环境将由master、node、work三个独立的主机组成,它们分别拥有2核心的CPU及4G的内存资源,操作系统环境均为最小化部署的Ubuntu Server 20.04.2 LTS,启用了SSH服务,域名为10691.cn。此外,各主机需要预设的系统环境如下:

(1)借助于chronyd服务(程序包名称chrony)设定各节点时间精确同步;

(2)通过DNS完成各节点的主机名称解析;

(3)各节点禁用所有的Swap设备;

(4)各节点禁用默认配置的iptables防火墙服务;

注意:为了便于操作,后面将在各节点直接以系统管理员root用户进行操作。若用户使用了普通用户,建议将如下各命令以sudo方式运行。

设定时钟同步  

若节点可直接访问互联网,安装chrony程序包后,可直接启动chronyd系统服务,并设定其随系统引导而启动。随后,chronyd服务即能够从默认的时间服务器同步时间。

  ~]# apt install chrony

  ~]# systemctl start chronyd.service  

不过,建议用户配置使用本地的的时间服务器,在节点数量众多时尤其如此。存在可用的本地时间服务器时,修改节点的/etc/chrony/chrony.conf配置文件,并将时间服务器指向相应的主机即可,配置格式如下: 

server CHRONY-SERVER-NAME-OR-IP iburst

主机名称解析

出于简化配置步骤的目的,本测试环境使用hosts文件进行各节点名称解析,文件内容如下所示:

# kubeapi主机名作为API Server的专用接入名称,也为控制平面的高可用配置留下便于配置的余地;
10.100.1.1 master.10691.cn master kubeapi.10691.cn kubeapi
10.100.21.24    master.10691.cn master
10.100.21.25    node.10691.cn   node
10.100.21.26    work.10691.cn   work

hostnamectl set-hostname master
hostnamectl set-hostname node
hostnamectl set-hostname work

禁用Swap设备

部署集群时,kubeadm默认会预先检查当前主机是否禁用了Swap设备,并在未禁用时强制终止部署过程。因此,在主机内存资源充裕的条件下,需要禁用所有的Swap设备,否则,就需要在后文的kubeadm init及kubeadm join命令执行时额外使用相关的选项忽略检查错误。

关闭Swap设备,需要分两步完成。首先是关闭当前已启用的所有Swap设备: 

~]# swapoff -a

而后编辑/etc/fstab配置文件,注释用于挂载Swap设备的所有行。

另外,若确需在节点上使用Swap设备,也可选择让kubeam忽略Swap设备的相关设定。我们编辑kubelet的配置文件/etc/default/kubelet,设置其忽略Swap启用的状态错误即可,文件内容如下: 

KUBELET_EXTRA_ARGS="--fail-swap-on=false"

禁用默认的防火墙服务

Ubuntu和Debian等Linux发行版默认使用ufw(Uncomplicated FireWall)作为前端来简化 iptables的使用,处于启用状态时,它默认会生成一些规则以加强系统安全。出于降低配置复杂度之目的,本文选择直接将其禁用。

~]# ufw disable

~]# ufw status

安装部署Kubernetes集群

安装程序包

提示:以下操作需要在本示例中的所有四台主机上分别进行。

安装并启动docker

首先,生成docker-ce相关程序包的仓库,这里以阿里云的镜像服务器为例进行说明:

apt -y install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
apt update

接着,安装相关的程序包,Ubuntu 20.04上要使用的程序包名称为docker-ce:

  ~]# apt install docker-ce

kubelet需要让docker容器引擎使用systemd作为CGroup的驱动,其默认值为cgroupfs,因而,我们还需要编辑docker的配置文件/etc/docker/daemon.json,添加如下内容,其中的registry-mirrors用于指明使用的镜像加速服务。   

{
"registry-mirrors": [
  "https://docker.mirrors.ustc.edu.cn/",
  "https://hub-mirror.c.163.com",
  "https://reg-mirror.qiniu.com",
  "https://registry.docker-cn.com"
],
"exec-opts": ["native.cgroupdriver=systemd"]
}

配置完成后即可启动docker服务,并将其设置为随系统启动而自动引导:

 ~]# systemctl daemon-reload

 ~]# systemctl start docker.service

 ~]# systemctl enable docker.service

为Docker设定使用的代理服务

Kubeadm部署Kubernetes集群的过程中,默认使用Google的Registry服务k8s.gcr.io上的镜像,例如k8s.grc.io/kube-apiserver等,但国内部分公司可能无法访问到该服务。必要时,可自行设置合适的代理来获取相关镜像,或者从Dockerhub上下载镜像至本地后自行对打镜像标签。

这里简单说明一下设置代理服务的方法。编辑/lib/systemd/system/docker.service文件,在[Service]配置段中添加类似如下内容,其中的PROXY_SERVER_IP和PROXY_PORT要按照实际情况修改。

Environment="HTTP_PROXY=http://$PROXY_SERVER_IP:$PROXY_PORT" Environment="HTTPS_PROXY=https://$PROXY_SERVER_IP:$PROXY_PORT"
Environment="NO_PROXY=127.0.0.0/8,172.17.0.0/16"

配置完成后需要重载systemd,并重新启动docker服务:

 ~]# systemctl daemon-reload

 ~]# systemctl restart docker.service

安装配置kubelet和kubeadm

首先,在各主机上生成kubelet和kubeadm等相关程序包的仓库,这里以阿里云的镜像服务为例:



apt update && apt install -y apt-transport-https curl
curl -fsSL 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 update

接着,在各主机安装kubelet、kubeadm和kubectl等程序包,并将其设置为随系统启动而自动引导:

apt install -y kubelet kubeadm kubectl
systemctl enable kubelet

安装完成后,要确保kubeadm等程序文件的版本,这将也是后面初始化Kubernetes集群时需要明确指定的版本号。

初始化第一个主节点

该步骤开始尝试构建Kubernetes集群的master节点,配置完成后,各worker节点直接加入到集群中的即可。需要特别说明的是,由kubeadm部署的Kubernetes集群上,集群核心组件kube-apiserver、kube-controller-manager、kube-scheduler和etcd等均会以静态Pod的形式运行,它们所依赖的镜像文件默认来自于k8s.gcr.io这一Registry服务之上。但我们无法直接访问该服务,常用的解决办法有如下两种,本示例将选择使用更易于使用的前一种方式。

  • 使用能够到达该服务的代理服务;
  • 使用国内的镜像服务器上的服务,例如gcr.azk8s.cn/google_containers和registry.aliyuncs.com/google_containers等 。

初始化master节点(在master01上完成如下操作)

在运行初始化命令之前先运行如下命令单独获取相关的镜像文件,而后再运行后面的kubeadm init命令,以便于观察到镜像文件的下载过程。

~]# kubeadm config images list

k8s.gcr.io/kube-apiserver:v1.22.0
k8s.gcr.io/kube-controller-manager:v1.22.0
k8s.gcr.io/kube-scheduler:v1.22.0
k8s.gcr.io/kube-proxy:v1.22.0
k8s.gcr.io/pause:3.5
k8s.gcr.io/etcd:3.5.0-0
k8s.gcr.io/coredns/coredns:v1.8.4

~]# kubeadm config images pull

[config/images] Pulled k8s.gcr.io/kube-apiserver:v1.22.0

[config/images] Pulled k8s.gcr.io/kube-controller-manager:v1.22.0

[config/images] Pulled k8s.gcr.io/kube-scheduler:v1.22.0

[config/images] Pulled k8s.gcr.io/kube-proxy:v1.22.0

[config/images] Pulled k8s.gcr.io/pause:3.5

[config/images] Pulled k8s.gcr.io/etcd:3.5.0-0

[config/images] Pulled k8s.gcr.io/coredns/coredns:v1.8.4

而后即可进行master节点初始化。kubeadm init命令支持两种初始化方式,一是通过命令行选项传递关键的部署设定,另一个是基于yaml格式的专用配置文件,后一种允许用户自定义各个部署参数。下面分别给出了两种实现方式的配置步骤,建议读者采用第二种方式进行。

安装部署Kubernetes集群-初始化方式一

运行如下命令完成master01节点的初始化:

kubeadm init --apiserver-advertise-address=10.100.21.24 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version=v1.22.0  --service-cidr=10.96.0.0/12  --pod-network-cidr=10.244.0.0/16  --ignore-preflight-errors=Swap --token-ttl=0

命令中的各选项简单说明如下: 

  • --image-repository:指定要使用的镜像仓库,默认为gcr.io;
  • --kubernetes-version:kubernetes程序组件的版本号,它必须要与安装的kubelet程序包的版本号相同;
  • --control-plane-endpoint:控制平面的固定访问端点,可以是IP地址或DNS名称,会被用于集群管理员及集群组件的kubeconfig配置文件的API Server的访问地址;单控制平面部署时可以不使用该选项;
  • --pod-network-cidr:Pod网络的地址范围,其值为CIDR格式的网络地址,通常,Flannel网络插件的默认为10.244.0.0/16,Project Calico插件的默认值为192.168.0.0/16;
  • --service-cidr:Service的网络地址范围,其值为CIDR格式的网络地址,默认为10.96.0.0/12;通常,仅Flannel一类的网络插件需要手动指定该地址;
  • --apiserver-advertise-address:apiserver通告给其他组件的IP地址,一般应该为Master节点的用于集群内部通信的IP地址,0.0.0.0表示节点上所有可用地址;
  • --token-ttl:共享令牌(token)的过期时长,默认为24小时,0表示永不过期;为防止不安全存储等原因导致的令牌泄露危及集群安全,建议为其设定过期时长。未设定该选项时,在token过期后,若期望再向集群中加入其它节点,可以使用如下命令重新创建token,并生成节点加入命令。kubeadm token create --print-join-command

安装部署Kubernetes集群需要注意的是,若各节点未禁用Swap设备,还需要附加选项“--ignore-preflight-errors=Swap”,从而让kubeadm忽略该错误设定。   

安装部署Kubernetes集群-初始化方式二

kubeadm也可通过配置文件加载配置,以定制更丰富的部署选项。以下是个符合前述命令设定方式的使用示例,不过,它明确定义了kubeProxy的模式为ipvs,并支持通过修改imageRepository的值修改获取系统镜像时使用的镜像仓库。

apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
localAPIEndpoint:
# 这里的地址即为初始化的控制平面第一个节点的IP地址;
advertiseAddress: 172.29.1.1
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
# 第一个控制平面节点的主机名称;
name: master01.magedu.com
taints:
- effect: NoSchedule
  key: node-role.kubernetes.io/master
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
# 版本号要与部署的目标版本保持一致;
kubernetesVersion: v1.20.0
imageRepository: registry.aliyuncs.com/google_containers
apiServer:
timeoutForControlPlane: 4m0s
# 控制平面的接入端点,我们这里选择适配到kubeapi.magedu.com这一域名上;
controlPlaneEndpoint: "kubeapi.magedu.com:6443"
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
dns:
type: CoreDNS
etcd:
local:
  dataDir: /var/lib/etcd
networking:
# 要使用的域名,默认为cluster.local
dnsDomain: cluster.local
# Cluster或Service的网络地址;
serviceSubnet: 10.96.0.0/12
# Pod的网络地址,10.244.0.0/16用于适配Flannel网络插件的默认值;
podSubnet: 10.244.0.0/16
controllerManager: {}
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
# 用于配置kube-proxy上为Service指定的代理模式,默认为iptables;
mode: "ipvs"

将上面的内容保存于配置文件中,例如kubeadm-config.yaml,而后执行如下命令即能实现类似前一种初始化方式中的集群初始配置,但这里将Service的代理模式设定为了ipvs。

 ~]# kubeadm init --config kubeadm-config.yaml

安装部署Kubernetes集群-初始化完成后的操作步骤

注意:对于Kubernetes系统的新用户来说,无论使用上述哪种方法,命令运行结束后,请记录最后的kubeadm join命令输出的最后提示的操作步骤。下面的内容是需要用户记录的一个命令输出示例,它提示了后续需要的操作步骤:

# 下面是成功完成第一个控制平面节点初始化的提示信息及后续需要完成的步骤
Your Kubernetes control-plane has initialized successfully!

# 为了完成初始化操作,管理员需要额外手动完成几个必要的步骤
To start using your cluster, you need to run the following as a regular user:

# 第1个步骤提示, Kubernetes集群管理员认证到Kubernetes集群时使用的kubeconfig配置文件
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 我们也可以不做上述设定,而使用环境变量KUBECONFIG为kubectl等指定默认使用的kubeconfig;
Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

# 第2个步骤提示,为Kubernetes集群部署一个网络插件,具体选用的插件则取决于管理员;
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/

# 第3个步骤提示,向集群添加额外的控制平面节点,但本文会略过该步骤,并将在其它文章介绍其实现方式。
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

# 在部署好kubeadm等程序包的其他控制平面节点上以root用户的身份运行类似如下命令,
# 命令中的hash信息对于不同的部署环境来说会各不相同;该步骤只能在其它控制平面节点上执行;
kubeadm join 10.100.21.24:6443 --token 8o15fl.lgt07p1l3tjubk36 \
--discovery-token-ca-cert-hash sha256:83fb9fed1f51284cd34ce59b7afe94e29a0d836e10c5bca9ac1edc9a5ef326c0 \
--control-plane

# 第4个步骤提示,向集群添加工作节点
Then you can join any number of worker nodes by running the following on each as root:

# 在部署好kubeadm等程序包的各工作节点上以root用户运行类似如下命令
kubeadm join 10.100.21.24:6443 --token 8o15fl.lgt07p1l3tjubk36 \
--discovery-token-ca-cert-hash sha256:83fb9fed1f51284cd34ce59b7afe94e29a0d836e10c5bca9ac1edc9a5ef326c0

另外,kubeadm init命令完整参考指南请移步官方文档,地址为https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/。

设定kubectl

kubectl是kube-apiserver的命令行客户端程序,实现了除系统部署之外的几乎全部的管理操作,是kubernetes管理员使用最多的命令之一。kubectl需经由API server认证及授权后方能执行相应的管理操作,kubeadm部署的集群为其生成了一个具有管理员权限的认证配置文件/etc/kubernetes/admin.conf,它可由kubectl通过默认的“$HOME/.kube/config”的路径进行加载。当然,用户也可在kubectl命令上使用--kubeconfig选项指定一个别的位置。

下面复制认证为Kubernetes系统管理员的配置文件至目标用户(例如当前用户root)的家目录下:

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

安装部署Kubernetes集群-部署网络插件

Kubernetes系统上Pod网络的实现依赖于第三方插件进行,这类插件有近数十种之多,较为著名的有flannel、calico、canal和kube-router等,简单易用的实现是为CoreOS提供的flannel项目。下面的命令用于在线部署flannel至Kubernetes系统之上:

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
或在其他正常机器打包,上传flannel.tar.gz
docker save -o flannel.tar.gz quay.io/coreos/flannel:v0.14.0
docker load -i flannel.tar.gz

验证master节点已经就绪

root@master:~# kubectl get nodes

NAME     STATUS   ROLES                  AGE   VERSION
master   Ready    control-plane,master   36m   v1.22.0

安装部署Kubernetes集群-添加节点到集群中

下面的两个步骤,需要分别在node、work上各自完成。

1、若未禁用Swap设备,编辑kubelet的配置文件/etc/default/kubelet,设置其忽略Swap启用的状态错误,内容如下:  KUBELET_EXTRA_ARGS="--fail-swap-on=false"

2、将节点加入第二步中创建的master的集群中,要使用主节点初始化过程中记录的kubeadm join命令,并且在未禁用Swap设备的情况下,额外附加“--ignore-preflight-errors=Swap”选项;

kubeadm join 10.100.21.24:6443 --token pa6vko.04an4vssqjmw4kl2 \
>         --discovery-token-ca-cert-hash sha256:aa10021db66bda2761dcd810a1e42f56fedf4d80978a9d4eab38d0f0b6d0485a

安装部署Kubernetes集群-验证节点添加结果

在每个节点添加完成后,即可通过kubectl验证添加结果。下面的命令及其输出是在node01和node02均添加完成后运行的,其输出结果表明两个Node已经准备就绪。

root@master:~# kubectl get nodes

NAME     STATUS   ROLES                  AGE   VERSION

node     Ready    <none>                 24m   v1.22.0
work     Ready    <none>                 22m   v1.22.0
root@master:~# kubectl get pods -n kube-system -o wide
NAME                             READY   STATUS    RESTARTS       AGE   IP             NODE     NOMINATED NODE   READINESS GATES
coredns-7f6cbbb7b8-q8rdk         1/1     Running   0              30m   10.244.0.2     master   <none>           <none>
coredns-7f6cbbb7b8-s2rl9         1/1     Running   0              30m   10.244.0.3     master   <none>           <none>
etcd-master                      1/1     Running   11             30m   10.100.21.24   master   <none>           <none>
kube-apiserver-master            1/1     Running   11             30m   10.100.21.24   master   <none>           <none>
kube-controller-manager-master   1/1     Running   14             30m   10.100.21.24   master   <none>           <none>
kube-flannel-ds-8v79n            1/1     Running   0              12s   10.100.21.26   work     <none>           <none>
kube-flannel-ds-ksdmx            1/1     Running   0              12s   10.100.21.25   node     <none>           <none>
kube-flannel-ds-l27z5            1/1     Running   0              12s   10.100.21.24   master   <none>           <none>
kube-proxy-f2wsk                 1/1     Running   2 (6m7s ago)   26m   10.100.21.25   node     <none>           <none>
kube-proxy-hgvf4                 1/1     Running   0              30m   10.100.21.24   master   <none>           <none>
kube-proxy-s529q                 1/1     Running   0              10m   10.100.21.26   work     <none>           <none>
kube-scheduler-master            1/1     Running   14             30m   10.100.21.24   master   <none>           <none>

K8 1.22.0安装dashboard管理/图形界面/Web UI(基于kubernetes-dashboard 2.3.1新版本)

步骤为:

下载 -->配置-->安装-->创建证书-->创建dashboard管理员-->用户分配权限--> 查询登录token-->预览

##  根据kubernetes版本下载相应文件
https://github.com/kubernetes/dashboard/releases
##  下载
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml

##  配置修改service type类型变成NodePort, 把type: ClusterIP变成 type: NodePort,如下图所示
  type: NodePort
      nodePort: 32000
          image: registry.aliyuncs.com/google_containers/dashboard:v2.3.1

##  执行安装
kubectl apply -f recommended.yaml


##  创建证书
mkdir dashboard-certs
cd dashboard-certs/
#创建命名空间
kubectl create namespace kubernetes-dashboard
# 创建key文件
openssl genrsa -out dashboard.key 2048
#证书请求
openssl req -days 36000 -new -out dashboard.csr -key dashboard.key -subj '/CN=dashboard-cert'
#自签证书
openssl x509 -req -in dashboard.csr -signkey dashboard.key -out dashboard.crt
#创建kubernetes-dashboard-certs对象
kubectl create secret generic kubernetes-dashboard-certs --from-file=dashboard.key --from-file=dashboard.crt -n kubernetes-dashboard

##  创建dashboard管理员
vim dashboard-admin.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: dashboard-admin
  namespace: kubernetes-dashboard

kubectl create -f ./dashboard-admin.yaml


##  用户分配权限
vim dashboard-admin-bind-cluster-role.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dashboard-admin-bind-cluster-role
  labels:
    k8s-app: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: dashboard-admin
  namespace: kubernetes-dashboard

kubectl create -f ./dashboard-admin-bind-cluster-role.yaml


##  查询登录token
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

##  浏览界面
http://10.100.21.24:3200

// 查询pod 
kubectl get pods --all-namespaces | grep "dashboard"
kubectl get svc -n kubernetes-dashboard -o wide

// 删除pod
kubectl delete deployment kubernetes-dashboard  --namespace=kubernetes-dashboard
kubectl delete deployment dashboard-metrics-scraper --namespace=kubernetes-dashboard

// 查询service
kubectl get service -A

// 删除service
kubectl delete service kubernetes-dashboard  --namespace=kubernetes-dashboard
kubectl delete service dashboard-metrics-scraper  --namespace=kubernetes-dashboard

 // 删除账户和密钥
kubectl delete sa kubernetes-dashboard --namespace=kubernetes-dashboard
kubectl delete secret kubernetes-dashboard-certs --namespace=kubernetes-dashboard
kubectl delete secret kubernetes-dashboard-key-holder --namespace=kubernetes-dashboard
只修改service type类型变成NodePort, 把type: ClusterIP变成 type: NodePort
修改国内源拉取镜像

测试应用编排及服务访问

到此为止,一个master,并附带有两个node的kubernetes集群基础设施已经部署完成,用户随后即可测试其核心功能。例如,下面的命令可将demoapp以Pod的形式编排运行于集群之上,并通过在集群外部进行访问:

~]# kubectl create deployment demoapp --image=ikubernetes/demoapp:v1.0

~]#kubectl scale deployment/demoapp --replicas=3

~]# kubectl create service nodeport demoapp --tcp=80:80

而后,使用如下命令了解Service对象demoapp使用的NodePort,以便于在集群外部进行访问:

 ~]# kubectl get svc -l app=demoapp  

NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGEdemoapp   NodePort   10.107.77.56   <none>        80:31009/TCP   103s

demoapp是一个web应用,因此,用户可以于集群外部通过“http://NodeIP:30529”这个URL访问demoapp上的应用,例如于集群外通过浏览器访问“http://10.100.21.24:31009”。