说明

1. 节点规划

部署k8s集群的节点按照用途可以划分为如下2类角色:

  • master:集群的master节点,集群的初始化节点,基础配置不低于2C4G
  • slave:集群的slave节点,可以多台,基础配置不低于2C4G

本例为了演示slave节点的添加,会部署一台master+2台slave,节点规划如下:

主机名 节点ip 角色 部署组件
k8s-master 172.21.19.137 master etcd, kube-apiserver, kube-controller-manager, kubectl, kubeadm, kubelet, kube-proxy, flannel
k8s-slave1 172.21.51.67 slave kubectl, kubelet, kube-proxy, flannel
k8s-slave2 172.21.51.68 slave kubectl, kubelet, kube-proxy, flannel

2. 组件版本

组件 版本 说明
Amazon Amazon Linux 2
Kernel Linux 5.10.75-79.358.amzn2.x86_64
etcd 3.4.13-0 使用容器方式部署,默认数据挂载到本地路径
coredns 1.7.0
kubeadm v1.19.8
kubectl v1.19.8
kubelet v1.19.8
kube-proxy v1.19.8
flannel v0.11.0

安装前准备工作

1. 设置hosts解析

操作节点:所有节点(k8s-master,k8s-slave)均需执行

  • 修改hostname
    hostname必须只能包含小写字母、数字、","、"-",且开头结尾必须是小写字母或数字
# 在master节点
$ hostnamectl set-hostname k8s-master #设置master节点的hostname

# 在slave-1节点
$ hostnamectl set-hostname k8s-slave1 #设置slave1节点的hostname

# 在slave-2节点
$ hostnamectl set-hostname k8s-slave2 #设置slave2节点的hostname
  • 添加hosts解析
    $ cat >>/etc/hosts<

2. 调整系统配置

操作节点: 所有的master和slave节点(k8s-master,k8s-slave)需要执行

本章下述操作均以k8s-master为例,其他节点均是相同的操作(ip和hostname的值换成对应机器的真实值)

  • 设置安全组开放端口

如果节点间无安全组限制(内网机器间可以任意访问),可以忽略,否则,至少保证如下端口可通:
k8s-master节点:TCP:6443,2379,2380,60080,60081UDP协议端口全部打开
k8s-slave节点:UDP协议端口全部打开

  • 设置iptables

    iptables -P FORWARD ACCEPT
  • 关闭swap

    swapoff -a
    # 防止开机自动挂载 swap 分区
    sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
  • 关闭selinux和防火墙

    #将 SELinux 设置为 permissive 模式(相当于将其禁用)
    sudo setenforce 0
    sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
    #关闭防火墙
    systemctl disable firewalld && systemctl stop firewalld
  • 确保每个节点上 MAC 地址和 product_uuid 的唯一性

    1. 你可以使用命令 ip link 或 ifconfig -a 来获取网络接口的 MAC 地址
    2. 可以使用 sudo cat /sys/class/dmi/id/product_uuid 命令对 product_uuid 校验

    一般来讲,硬件设备会拥有唯一的地址,但是有些虚拟机的地址可能会重复。 Kubernetes 使用这些值来唯一确定集群中的节点。 如果这些值在每个节点上不唯一,可能会导致安装 失败。

  • 允许 iptables 检查桥接流量

确保 br_netfilter 模块被加载。这一操作可以通过运行 lsmod | grep br_netfilter 来完成。若要显式加载该模块,可执行 sudo modprobe br_netfilter。

为了让你的 Linux 节点上的 iptables 能够正确地查看桥接流量,你需要确保在你的 sysctl 配置中将 net.bridge.bridge-nf-call-iptables 设置为 1。例如:

cat <
  • 设置yum源
    #谷歌源
    $ cat <

#阿里源
$ cat < /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

$ yum clean all && yum makecache

### 3. 安装Docker
```bash
#安装docker
sudo yum update -y

#Amazon Linux 2
sudo amazon-linux-extras install docker
#Amazon Linux。
yum list docker-ce --showduplicates | sort -r  # 查看所有的可用版本
sudo yum install docker-ce-20.10.7 -y

#配置docker加速
$ mkdir -p /etc/docker
cat >/etc/docker/daemon.json<

部署kubernetes

1. 安装 kubeadm, kubelet 和 kubectl

官方文档:链接
操作节点: 所有的master和slave节点(k8s-master,k8s-slave) 需要执行

$ yum install -y kubelet-1.23.0 kubeadm-1.23.0 kubectl-1.23.0 --disableexcludes=kubernetes
## 查看kubeadm 版本
$ kubectl version -o json
#设置kubelet开机启动
$ systemctl enable kubelet

2. 初始化配置文件

操作节点: 只在master节点(k8s-master)执行

#kubeadm config print 命令打印默认配置
kubeadm config print init-defaults > defaults.yaml
#将旧版本的配置对象转换为最新支持的版本
kubeadm config migrate --old-config defaults.yaml --new-config kubeadm.yaml
# apiserver地址,因为单master,所以配置master的节点内网IP
sed -i 's/advertiseAddress:.*$/advertiseAddress: 172.21.19.137/g' kubeadm.yaml
# 修改节点名称(此处配置master节点)
sed -i 's/name: node/name: k8s-master/g' kubeadm.yaml
# 修改成阿里镜像源
sed -i 's#imageRepository:.*$#imageRepository: registry.aliyuncs.com/google_containers#g' kubeadm.yaml
# Pod 网段,flannel插件需要使用这个网段
sed -i "/networking:/a\  podSubnet: 10.244.0.0/16" kubeadm.yaml

# 查看文件内容
$ cat kubeadm.yaml
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 172.21.19.137
  bindPort: 6443
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  imagePullPolicy: IfNotPresent
  name: k8s-master
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: v1.23.0
networking:
  podSubnet: 10.244.0.0/16
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
scheduler: {}

对于上面的资源清单的文档比较杂,要想完整了解上面的资源对象对应的属性: 文档地址

3. 提前下载镜像

操作节点:只在master节点(k8s-master)执行

# 查看kubeadm 要使用的镜像列表。配置文件用于自定义任何镜像或镜像存储库。
[root@k8s-master ~]# kubeadm config images list --config kubeadm.yaml
registry.aliyuncs.com/google_containers/kube-apiserver:v1.23.0
registry.aliyuncs.com/google_containers/kube-controller-manager:v1.23.0
registry.aliyuncs.com/google_containers/kube-scheduler:v1.23.0
registry.aliyuncs.com/google_containers/kube-proxy:v1.23.0
registry.aliyuncs.com/google_containers/pause:3.6
registry.aliyuncs.com/google_containers/etcd:3.5.1-0
registry.aliyuncs.com/google_containers/coredns:v1.8.6

# 拉取 kubeadm 使用的镜像到本地
[root@k8s-master ~]# kubeadm config images pull --config kubeadm.yaml
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-apiserver:v1.23.0
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-controller-manager:v1.23.0
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-scheduler:v1.23.0
[config/images] Pulled registry.aliyuncs.com/google_containers/kube-proxy:v1.23.0
[config/images] Pulled registry.aliyuncs.com/google_containers/pause:3.6
[config/images] Pulled registry.aliyuncs.com/google_containers/etcd:3.5.1-0
[config/images] Pulled registry.aliyuncs.com/google_containers/coredns:v1.8.6

4. 初始化master节点

操作节点:只在master节点(k8s-master)执行

$ sudo kubeadm init --config=kubeadm.yaml

说明:

  • Kubeadm 对集群所有的节点,使用相同的 KubeletConfiguration。 KubeletConfiguration 存放于 kube-system 命名空间下的某个 ConfigMap 对象中。
  • 执行 init、join 和 upgrade 等子命令会促使 kubeadm 将 KubeletConfiguration 写入到文件 /var/lib/kubelet/config.yaml 中, 继而把它传递给本地节点的 kubelet。

若初始化成功后,最后会提示如下信息:

...
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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

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 172.21.19.137:6443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:d7189ba1021dbc1da5c55ba9c2211e652e9e0a62838df870c87e31ce318f2912

接下来按照上述提示信息操作,配置kubectl客户端的认证

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

⚠️注意:此时使用 kubectl get nodes查看节点应该处于notReady状态,因为还未配置网络插件

若执行初始化过程中出错,根据错误信息调整后,执行kubeadm reset后再次执行init操作即可

5. 添加slave节点到集群中

操作节点:所有的slave节点(k8s-slave)需要执行
在每台slave节点,执行如下命令,该命令是在kubeadm init成功后提示信息中打印出来的,需要替换成实际init后打印出的命令。

kubeadm join 172.21.19.137:6443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:d7189ba1021dbc1da5c55ba9c2211e652e9e0a62838df870c87e31ce318f2912

如果忘记添加命令,可以通过如下命令生成:

$ kubeadm token create --print-join-command

6. 安装flannel插件

操作节点:只在master节点(k8s-master)执行

  • 下载flannel的yaml文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
  • 修改配置,指定网卡名称,大概在文件的192行,添加一行配置:
$ vi kube-flannel.yml
...      
      containers:
      - name: kube-flannel
        image: quay.io/coreos/flannel:v0.15.1
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        - --iface=eth0  # 如果机器存在多网卡的话,指定内网网卡的名称,默认不指定的话会找第一块网
        resources:
          requests:
            cpu: "100m"
...
  • 执行安装flannel网络插件
# 先拉取镜像,此过程国内速度比较慢
$ docker pull quay.io/coreos/flannel:v0.15.1
# 执行flannel安装
$ kubectl apply -f kube-flannel.yml

7. 设置master节点是否可调度(可选)

操作节点:k8s-master
默认部署成功后,master节点无法调度业务pod,如需设置master节点也可以参与pod的调度,需执行:

$ kubectl taint node k8s-master node-role.kubernetes.io/master:NoSchedule-

课程后期会部署系统组件到master节点,因此,此处建议设置k8s-master节点为可调度

8. 设置kubectl自动补全

操作节点:k8s-master

$ yum install bash-completion -y
$ source /usr/share/bash-completion/bash_completion
$ source <(kubectl completion bash)
$ echo "source <(kubectl completion bash)" >> ~/.bashrc

8. 验证集群

操作节点: 在master节点(k8s-master)执行

$ kubectl get nodes  #观察集群节点是否全部Ready

创建测试nginx服务

$ kubectl run  test-nginx --image=nginx:alpine

查看pod是否创建成功,并访问pod ip测试是否可用

$ kubectl get po -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP           NODE         NOMINATED NODE   READINESS GATES
test-nginx-5bd8859b98-5nnnw   1/1     Running   0          9s    10.244.1.2   k8s-slave1              
$ curl 10.244.1.2
...
Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

9. 部署dashboard

  • 部署服务
# 推荐使用下面这种方式
$ wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
$ vi recommended.yaml
# 修改Service为NodePort类型,文件的32行上下
......
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  ports:
    - port: 443
      targetPort: 8443
  selector:
    k8s-app: kubernetes-dashboard
  type: NodePort  # 加上type=NodePort变成NodePort类型的服务
......
  • 查看访问地址,本例为30113端口

    $ kubectl apply -f recommended.yaml
    $ kubectl -n kubernetes-dashboard get svc
    NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
    dashboard-metrics-scraper   ClusterIP   10.104.197.219           8000/TCP        99s
    kubernetes-dashboard        NodePort    10.98.27.124             443:30113/TCP   99s
  • 使用浏览器访问 https://172.21.51.143:30113

  • 创建ServiceAccount进行访问
$ vi dashboard-admin.conf
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: admin
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: admin
  namespace: kubernetes-dashboard

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

$ kubectl apply -f dashboard-admin.conf
$ kubectl -n kubernetes-dashboard get secret |grep admin-token
admin-token-fqdpf                  kubernetes.io/service-account-token   3      7m17s
# 使用该命令拿到token,然后粘贴到
$ kubectl -n kubernetes-dashboard get secret admin-token-fqdpf -o jsonpath={.data.token}|base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6Ik1rb2xHWHMwbWFPMjJaRzhleGRqaExnVi1BLVNRc2txaEhETmVpRzlDeDQifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi10b2tlbi1mcWRwZiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjYyNWMxNjJlLTQ1ZG...

10. 清理环境

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

# 在全部集群节点执行
kubeadm reset
ifconfig cni0 down && ip link delete cni0
ifconfig flannel.1 down && ip link delete flannel.1
rm -rf /run/flannel/subnet.env
rm -rf /var/lib/cni/
mv /etc/kubernetes/ /tmp
mv /var/lib/etcd /tmp
mv ~/.kube /tmp
iptables -F
iptables -t nat -F
ipvsadm -C
ip link del kube-ipvs0
ip link del dummy0

报错

1. error: open /var/lib/kubelet/config.yaml: no such file or directory"

原因是没有还需要执行:

kubeadm init

2.【kubeadm初始化报错】Failed to run kubelet" err="failed to run Kubelet: misconfiguration: kubelet cgroup driver: \"systemd\" is different from docker cgroup driver: \"cgroupfs\"

解决方法:请点击链接