手把手教你部署一个最小化的 Kubernetes 集群,


虽然网上有大量从零搭建 K8S 的文章,但大都针对老版本,若直接照搬去安装最新的 1.20 版本会遇到一堆问题。故此将我的安装步骤记录下来,希望能为读者提供 copy and paste 式的集群搭建帮助。

1. 部署准备工作

部署最小化 K8S 集群:master + node1 + node2

Ubuntu 是一款基于 Debian Linux 的以桌面应用为主的操作系统,内容涵盖文字处理、电子邮件、软件开发工具和 Web 服务等,可供用户免费下载、使用和分享。

  1. ➜ vgs  
  2. Current machine states:  
  3. master                    running (virtualbox) 
  4. node1                     running (virtualbox)  
  5. node2                     running (virtualbox) 

1.1 基础环境信息

  •  设置系统主机名以及 Host 文件各节点之间的相互解析
    •  使用这个的 Vagrantfile 启动的三节点服务已经配置好了
    •  以下使用 master 节点进行演示查看,其他节点操作均一致 
  1. # hostnamectl  
  2. vagrant@k8s-master:~$ hostnamectl  
  3.    Static hostname: k8s-master  
  4. # hosts  
  5. vagrant@k8s-master:~$ cat /etc/hosts  
  6. 127.0.0.1        localhost  
  7. 127.0.1.1        vagrant.vm    vagrant  
  8. 192.168.30.30    k8s-master  
  9. 192.168.30.31    k8s-node1  
  10. 192.168.30.32    k8s-node2  
  11. # ping  
  12. vagrant@k8s-master:~$ ping k8s-node1  
  13. PING k8s-node1 (192.168.30.31) 56(84) bytes of data. 
  14. 64 bytes from k8s-node1 (192.168.30.31): icmp_seq=1 ttl=64 time=0.689 ms 

1.2 阿里源配置

  •  配置 Ubuntu 的阿里源来加速安装速度
    •  阿里源镜像地址 
  1. # 登录服务器  
  2. ➜ vgssh master/node1/nod2  
  3. Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-50-generic x86_64)  
  4. # 设置阿里云Ubuntu镜像  
  5. $ sudo cp /etc/apt/sources.list{,.bak}  
  6. $ sudo vim /etc/apt/sources.list  
  7. # 配置kubeadm的阿里云镜像源  
  8. $ sudo vim /etc/apt/sources.list  
  9. deb https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main  
  10. $ sudo gpg --keyserver keyserver.ubuntu.com --recv-keys BA07F4FB  
  11. $ sudo gpg --export --armor BA07F4FB | sudo apt-key add -  
  12. # 配置docker安装  
  13. $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -  
  14. $ sudo apt-key fingerprint 0EBFCD88  
  15. $ sudo vim /etc/apt/sources.list  
  16. deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable  
  17. # 更新仓库  
  18. $ sudo apt update  
  19. $ sudo apt dist-upgrade 

1.3 基础工具安装

  •  部署阶段的基础工具安装
    •  基础组件 docker
    •  部署工具 kubeadm
    •  路由规则 ipvsadm
    •  时间同步 ntp 
  1. # 基础工具安装  
  2. $ sudo apt install -y \  
  3.     docker-ce docker-ce-cli containerd.io \  
  4.     kubeadm ipvsadm \  
  5.     ntp ntpdate \  
  6.     nginx supervisor  
  7. # 将当前普通用户加入docker组(需重新登录)  
  8. $ sudo usermod -a -G docker $USER  
  9. # 服务启用  
  10. $ sudo systemctl enable docker.service  
  11. $ sudo systemctl start docker.service  
  12. $ sudo systemctl enable kubelet.service  
  13. $ sudo systemctl start kubelet.service 

1.4 操作系统配置

  •  操作系统相关配置
    •  关闭缓存
    •  配置内核参数
    •  调整系统时区
    •  升级内核版本(默认为4.15.0的版本) 
  1. # 关闭缓存  
  2. $ sudo swapoff -a  
  3. # 为K8S来调整内核参数  
  4. $ sudo touch /etc/sysctl.d/kubernetes.conf  
  5. $ sudo cat > /etc/sysctl.d/kubernetes.conf <<EOF  
  6. net.bridge.bridge-nf-call-iptables = 1 # 开启网桥模式(必须)  
  7. net.bridge.bridge-nf-call-ip6tables = 1 # 开启网桥模式(必须)  
  8. net.ipv6.conf.all.disable_ipv6 = 1 # 关闭IPv6协议(必须)  
  9. net.ipv4.ip_forward = 1 # 转发模式(默认开启)  
  10. vm.panic_on_oom=0 # 开启OOM(默认开启)  
  11. vm.swappiness = 0 # 禁止使用swap空间  
  12. vm.overcommit_memory=1 # 不检查物理内存是否够用  
  13. fs.inotify.max_user_instances=8192  
  14. fs.inotify.max_user_watches=1048576  
  15. fs.file-max = 52706963 # 设置文件句柄数量  
  16. fs.nr_open = 52706963 # 设置文件的最大打开数量  
  17. net.netfilter.nf_conntrack_max = 2310720  
  18. EOF 
  19. # 查看系统内核参数的方式  
  20. $ sudo sysctl -a | grep xxx  
  21. # 使内核参数配置文件生效  
  22. $ sudo sysctl -p /etc/sysctl.d/kubernetes.conf  
  1. # 设置系统时区为中国/上海  
  2. $ sudo timedatectl set-timezone Asia/Shanghai  
  3. # 将当前的UTC时间写入硬件时钟  
  4. $ sudo timedatectl set-local-rtc 0 

1.5 开启 ipvs 服务

  •  开启 ipvs 服务
    •  kube-proxy 开启 ipvs 的前置条件 
  1. # 载入指定的个别模块  
  2. $ modprobe br_netfilter  
  3. # 修改配置  
  4. $ cat > /etc/sysconfig/modules/ipvs.modules <<EOF  
  5. #!/bin/bash  
  6. modprobe -- ip_vs  
  7. modprobe -- ip_vs_rr  
  8. modprobe -- ip_vs_wrr  
  9. modprobe -- ip_vs_sh  
  10. modprobe -- nf_conntrack_ipv  
  11. EOF  
  12. # 加载配置  
  13. $ chmod 755 /etc/sysconfig/modules/ipvs.modules \  
  14.     && bash /etc/sysconfig/modules/ipvs.modules \  
  15.     && lsmod | grep -e ip_vs -e nf_conntrack_ipv 

2. 部署 Master 节点

节点最低配置: 2C+2G 内存;从节点资源尽量充足

kubeadm 工具的 init 命令,即可初始化以单节点部署的 master。为了避免翻墙,这里可以使用阿里云的谷歌源来代替。在执行 kubeadm 部署命令的时候,指定对应地址即可。当然,可以将其加入本地的镜像库之中,更易维护。

  •  注意事项
    •  阿里云谷歌源地址
    •  使用 kubeadm 定制控制平面配置 
  1. # 登录服务器  
  2. ➜ vgssh master  
  3. Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-50-generic x86_64)  
  4. # 部署节点(命令行)  
  5. # 注意pod和service的地址需要不同(否则会报错)  
  6. $ sudo kubeadm init \  
  7.     --kubernetes-version=1.20.2 \  
  8.     --image-repository registry.aliyuncs.com/google_containers \  
  9.     --apiserver-advertise-address=192.168.30.30 \  
  10.     --pod-network-cidr=10.244.0.0/16 \ 
  11.     --service-cidr=10.245.0.0/16  
  12. # 部署镜像配置(配置文件)  
  13. $ sudo kubeadm init --config ./kubeadm-config.yaml  
  14. Your Kubernetes control-plane has initialized successfully!  
  1. # 查看IP段是否生效(iptable)  
  2. $ ip route show  
  3. 10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1  
  4. 10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink  
  5. 10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink  
  6. # # 查看IP段是否生效(ipvs)  
  7. $ ipvsadm -L -n  
  8. IP Virtual Server version 1.2.1 (size=4096)  
  9. Prot LocalAddress:Port Scheduler Flags  
  10.   -> RemoteAddress:Port           Forward Weight ActiveConn InActConn 
  •  配置文件定义
    •   接口使用了 v1beta2 版本
    •   配置主节点 IP 地址为 192.168.30.30
    •   为 flannel 分配的是 10.244.0.0/16 网段
    •   选择的 kubernetes 是当前最新的 1.20.2 版本
    •   加入了 controllerManager 的水平扩容功能 
  1. # kubeadm-config.yaml  
  2. # sudo kubeadm config print init-defaults > kubeadm-config.yaml  
  3. apiVersion: kubeadm.k8s.io/v1beta2  
  4. imageRepository: registry.aliyuncs.com/google_containers  
  5. kind: ClusterConfiguration  
  6. kubernetesVersion: v1.20.2  
  7. apiServer:  
  8.   extraArgs:  
  9.     advertise-address: 192.168.30.30  
  10. networking:  
  11.   podSubnet: 10.244.0.0/16  
  12. controllerManager:  
  13.   ExtraArgs:  
  14.     horizontal-pod-autoscaler-use-rest-clients: "true"  
  15.     horizontal-pod-autoscaler-sync-period: "10s"  
  16.     node-monitor-grace-period: "10s" 
  •  执行成功之后会输出如下信息,需要安装如下步骤操作下
    •  第一步 在 kubectl 默认控制和操作集群节点的时候,需要使用到 CA 的密钥,传输过程是通过 TLS 协议保障通讯的安全性。通过下面 3 行命令拷贝密钥信息到当前用户家目录下,这样 kubectl 执行时会首先访问 .kube 目录,使用这些授权信息访问集群。
    •  第二步 之后添加 worker 节点时,要通过 token 才能保障安全性。因此,先把显示的这行命令保存下来,以备后续使用会用到。 
  1. # master setting step one  
  2. To start cluster, you need to run the following as a regular user:  
  3.   mkdir -p $HOME/.kube  
  4.   sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config  
  5.   sudo chown $(id -u):$(id -g) $HOME/.kube/config  
  6. Alternatively, if you are the root user, you can run:  
  7.   export KUBECONFIG=/etc/kubernetes/admin.conf 
  8. # master setting step two  
  9. You should now deploy a pod network to the cluster.  
  10. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed:  
  11.   https://kubernetes.io/docs/concepts/cluster-administration/addons/  
  12. Join any number of worker nodes by running the following on each as root:  
  13. kubeadm join 192.168.30.30:6443 \  
  14.   --token lebbdi.p9lzoy2a16tmr6hq \  
  15.   --discovery-token-ca-cert-hash \  
  16.   sha256:6c79fd83825d7b2b0c3bed9e10c428acf8ffcd615a1d7b258e9b500848c20cae 
  •  将子节点加入主节点中 
  1. $ kubectl get nodes  
  2. NAME         STATUS     ROLES                  AGE   VERSION  
  3. k8s-master   NotReady   control-plane,master   62m   v1.20.2  
  4. k8s-node1    NotReady   <none>                 82m   v1.20.2  
  5. k8s-node2    NotReady   <none>                 82m   v1.20.2  
  1. # 查看token令牌  
  2. $ sudo kubeadm token list  
  3. # 生成token令牌  
  4. $ sudo kubeadm token create  
  5. # 忘记sha编码  
  6. $ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt \ 
  7.     | openssl rsa -pubin -outform der 2>/dev/null \  
  8.     | openssl dgst -sha256 -hex | sed 's/^.* //'  
  1. # 生成一个新的 token 令牌(比上面的方便)  
  2. $ kubeadm token generate  
  3. # 直接生成 join 命令(比上面的方便)  
  4. $ kubeadm token create <token_generate> --print-join-command --ttl=0 
  •    执行完成之后可以通过如下命令,查看主节点信息

         默认生成四个命名空间

         1.  default、kube-system、kube-public、kube-node-lease

          部署的核心服务有以下几个 (kube-system)

         1.  coredns、etcd

         2.  kube-apiserver、kube-scheduler

         3.  kube-controller-manager、kube-controller-manager

         此时 master 并没有 ready 状态(需要安装网络插件),下一章节中,我们将安装 flannel 这个网络插件

  1. # 命名空间  
  2. $ kubectl get namespace  
  3. NAME              STATUS   AGE  
  4. default           Active   19m  
  5. kube-node-lease   Active   19m  
  6. kube-public       Active   19m  
  7. kube-system       Active   19m  
  8. # 核心服务  
  9. $ kubectl get pod -n kube-system  
  10. NAME                                 READY   STATUS    RESTARTS   AGE  
  11. coredns-7f89b7bc75-bh42f             1/1     Running   0          19m  
  12. coredns-7f89b7bc75-dvzpl             1/1     Running   0          19m  
  13. etcd-k8s-master                      1/1     Running   0          19m  
  14. kube-apiserver-k8s-master            1/1     Running   0          19m  
  15. kube-controller-manager-k8s-master   1/1     Running   0          19m  
  16. kube-proxy-5rlpv                     1/1     Running   0          19m  
  17. kube-scheduler-k8s-master            1/1     Running   0          19m 

3. 部署 flannel 网络

网络服务用于管理 K8S 集群中的服务网络

flannel 网络需要指定 IP 地址段,即上一步中通过编排文件设置的 10.244.0.0/16。其实可以通过 flannel 官方和 HELM 工具直接部署服务,但是原地址是需要搭梯子的。所以,可以将其内容保存在如下配置文件中,修改对应镜像地址。

  • 部署 flannel 服务的官方下载地址 
  1. # 部署flannel服务  
  2. # 1.修改镜像地址(如果下载不了的话)  
  3. # 2.修改Network为--pod-network-cidr的参数IP段  
  4. $ kubectl apply -f ./kube-flannel.yml  
  5. # 如果部署出现问题可通过如下命令查看日志  
  6. $ kubectl logs kube-flannel-ds-6xxs5 --namespace=kube-system  
  7. $ kubectl describe pod kube-flannel-ds-6xxs5 --namespace=kube-system 

  •  如果使用当中存在问题的,可以参考官方的问题手册
    •   因为我们这里使用的是 Vagrant 虚拟出来的机器进行 K8S 的部署,但是在运行对应 yaml 配置的时候,会报错。通过查看日志发现是因为默认绑定的是虚拟机上面的 eth0 这块网卡,而这块网卡是 Vagrant 使用的,我们应该绑定的是 eth1 才对。
    •   Vagrant 通常为所有 VM 分配两个接口,第一个为所有主机分配的 IP 地址为 10.0.2.15,用于获得 NAT 的外部流量。这样会导致 flannel 部署存在问题。通过官方问题说明,我们可以使用 --iface=eth1 这个参数选择第二个网卡。
    •  对应的参数使用方式,可以参考 flannel use –iface=eth1 中的回答自行添加,而这里我直接修改了启动的配置文件,在启动服务的时候通过 args 修改了,如下所示。 
  1. $ kubectl get pods -n kube-system  
  2. NAME                                 READY   STATUS    RESTARTS   AGE  
  3. coredns-7f89b7bc75-bh42f             1/1     Running   0          61m  
  4. coredns-7f89b7bc75-dvzpl             1/1     Running   0          61m  
  5. etcd-k8s-master                      1/1     Running   0          62m  
  6. kube-apiserver-k8s-master            1/1     Running   0          62m  
  7. kube-controller-manager-k8s-master   1/1     Running   0          62m  
  8. kube-flannel-ds-zl148                1/1     Running   0          44s  
  9. kube-flannel-ds-ll523                1/1     Running   0          44s  
  10. kube-flannel-ds-wpmhw                1/1     Running   0          44s  
  11. kube-proxy-5rlpv                     1/1     Running   0          61m  
  12. kube-scheduler-k8s-master            1/1     Running   0          62m 
  •  配置文件如下所示:
  1. ---  
  2. apiVersion: policy/v1beta1  
  3. kind: PodSecurityPolicy  
  4. metadata:  
  5.   name: psp.flannel.unprivileged  
  6.   annotations:  
  7.     seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default  
  8.     seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default  
  9.     apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default  
  10.     apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default  
  11. spec:  
  12.   privileged: false  
  13.   volumes:  
  14.     - configMap  
  15.     - secret  
  16.     - emptyDir  
  17.     - hostPath  
  18.   allowedHostPaths:  
  19.     - pathPrefix: "/etc/cni/net.d"  
  20.     - pathPrefix: "/etc/kube-flannel"  
  21.     - pathPrefix: "/run/flannel"  
  22.   readOnlyRootFilesystem: false  
  23.   # Users and groups  
  24.   runAsUser:  
  25.     rule: RunAsAny  
  26.   supplementalGroups:  
  27.     rule: RunAsAny  
  28.   fsGroup:  
  29.     rule: RunAsAny  
  30.   # Privilege Escalation  
  31.   allowPrivilegeEscalation: false  
  32.   defaultAllowPrivilegeEscalation: false  
  33.   # Capabilities  
  34.   allowedCapabilities: ["NET_ADMIN", "NET_RAW"]  
  35.   defaultAddCapabilities: []  
  36.   requiredDropCapabilities: []  
  37.   # Host namespaces  
  38.   hostPID: false  
  39.   hostIPC: false  
  40.   hostNetwork: true  
  41.   hostPorts:  
  42.     - min: 0  
  43.       max: 65535  
  44.   # SELinux  
  45.   seLinux:  
  46.     # SELinux is unused in CaaSP  
  47.     rule: "RunAsAny"  
  48. ---  
  49. kind: ClusterRole  
  50. apiVersion: rbac.authorization.k8s.io/v1  
  51. metadata:  
  52.   name: flannel  
  53. rules:  
  54.   - apiGroups: ["extensions"]  
  55.     resources: ["podsecuritypolicies"]  
  56.     verbs: ["use"]  
  57.     resourceNames: ["psp.flannel.unprivileged"]  
  58.   - apiGroups:  
  59.       - ""  
  60.     resources:  
  61.       - pods  
  62.     verbs:  
  63.       - get  
  64.   - apiGroups:  
  65.       - ""  
  66.     resources:  
  67.       - nodes  
  68.     verbs:  
  69.       - list  
  70.       - watch  
  71.   - apiGroups:  
  72.       - ""  
  73.     resources:  
  74.       - nodes/status  
  75.     verbs:  
  76.       - patch  
  77. ---  
  78. kind: ClusterRoleBinding  
  79. apiVersion: rbac.authorization.k8s.io/v1  
  80. metadata:  
  81.   name: flannel  
  82. roleRef:  
  83.   apiGroup: rbac.authorization.k8s.io  
  84.   kind: ClusterRole  
  85.   name: flannel  
  86. subjects:  
  87.   - kind: ServiceAccount  
  88.     name: flannel  
  89.     namespace: kube-system  
  90. ---  
  91. apiVersion: v1  
  92. kind: ServiceAccount  
  93. metadata:  
  94.   name: flannel  
  95.   namespace: kube-system  
  96. ---  
  97. kind: ConfigMap  
  98. apiVersion: v1  
  99. metadata:  
  100.   name: kube-flannel-cfg  
  101.   namespace: kube-system  
  102.   labels:  
  103.     tier: node  
  104.     app: flannel  
  105. data:  
  106.   cni-conf.json: |  
  107.     {  
  108.       "name": "cbr0",  
  109.       "cniVersion": "0.3.1",  
  110.       "plugins": [  
  111.         {  
  112.           "type": "flannel",  
  113.           "delegate": {  
  114.             "hairpinMode": true,  
  115.             "isDefaultGateway": true  
  116.           }  
  117.         },  
  118.         {  
  119.           "type": "portmap",  
  120.           "capabilities": {  
  121.             "portMappings": true  
  122.           }  
  123.         }  
  124.       ]  
  125.     }  
  126.   net-conf.json: |  
  127.     {  
  128.       "Network": "10.244.0.0/16",  
  129.       "Backend": {  
  130.         "Type": "vxlan"  
  131.       }  
  132.     }  
  133. ---  
  134. apiVersion: apps/v1  
  135. kind: DaemonSet  
  136. metadata:  
  137.   name: kube-flannel-ds  
  138.   namespace: kube-system  
  139.   labels:  
  140.     tier: node  
  141.     app: flannel  
  142. spec:  
  143.   selector:  
  144.     matchLabels:  
  145.       app: flannel  
  146.   template:  
  147.     metadata:  
  148.       labels:  
  149.         tier: node  
  150.         app: flannel  
  151.     spec:  
  152.       affinity:  
  153.         nodeAffinity:  
  154.           requiredDuringSchedulingIgnoredDuringExecution:  
  155.             nodeSelectorTerms:  
  156.               - matchExpressions:  
  157.                   - key: kubernetes.io/os  
  158.                     operator: In  
  159.                     values:  
  160.                       - linux  
  161.       hostNetwork: true  
  162.       priorityClassName: system-node-critical  
  163.       tolerations:  
  164.         - operator: Exists  
  165.           effect: NoSchedule  
  166.       serviceAccountName: flannel  
  167.       initContainers:  
  168.         - name: install-cni  
  169.           image: quay.io/coreos/flannel:v0.13.1-rc1  
  170.           command:  
  171.             - cp  
  172.           args:  
  173.             - -f  
  174.             - /etc/kube-flannel/cni-conf.json  
  175.             - /etc/cni/net.d/10-flannel.conflist  
  176.           volumeMounts:  
  177.             - name: cni  
  178.               mountPath: /etc/cni/net.d  
  179.             - name: flannel-cfg  
  180.               mountPath: /etc/kube-flannel/  
  181.       containers:  
  182.         - name: kube-flannel  
  183.           image: quay.io/coreos/flannel:v0.13.1-rc1  
  184.           command:  
  185.             - /opt/bin/flanneld  
  186.           args:  
  187.             - --ip-masq  
  188.             - --kube-subnet-mgr  
  189.             - --iface=eth1  
  190.           resources:  
  191.             requests:  
  192.               cpu: "100m"  
  193.               memory: "50Mi"  
  194.             limits:  
  195.               cpu: "100m"  
  196.               memory: "50Mi"  
  197.           securityContext:  
  198.             privileged: false  
  199.             capabilities:  
  200.               add: ["NET_ADMIN", "NET_RAW"]  
  201.           env:  
  202.             - name: POD_NAME  
  203.               valueFrom:  
  204.                 fieldRef:  
  205.                   fieldPath: metadata.name  
  206.             - name: POD_NAMESPACE  
  207.               valueFrom:  
  208.                 fieldRef:  
  209.                   fieldPath: metadata.namespace  
  210.           volumeMounts:  
  211.             - name: run  
  212.               mountPath: /run/flannel  
  213.             - name: flannel-cfg  
  214.               mountPath: /etc/kube-flannel/  
  215.       volumes:  
  216.         - name: run  
  217.           hostPath:  
  218.             path: /run/flannel  
  219.         - name: cni  
  220.           hostPath:  
  221.             path: /etc/cni/net.d  
  222.         - name: flannel-cfg  
  223.           configMap: 
  224.             name: kube-flannel-cfg 
  •  至此集群部署成功!如果有参数错误需要修改,你也可以在 reset 后重新 init 集群。 
  1. $ kubectl get nodes  
  2. NAME         STATUS   ROLES                  AGE   VERSION  
  3. k8s-master   Ready    control-plane,master   62m   v1.20.2  
  4. k8s-node1    Ready    control-plane,master   82m   v1.20.2  
  5. k8s-node2    Ready    control-plane,master   82m   v1.20.2  
  6. # 重启集群  
  7. $ sudo kubeadm reset  
  8. $ sudo kubeadm init 

4. 部署 dashboard 服务

以 WEB 页面的可视化 dashboard 来监控集群的状态

这个还是会遇到需要搭梯子下载启动配置文件的问题,下面是对应的下载地址,可以下载之后上传到服务器上面在进行部署。

  •  部署 dashboard 服务的官方下载地址 
  1. # 部署flannel服务  
  2. $ kubectl apply -f ./kube-dashboard.yaml  
  3. # 如果部署出现问题可通过如下命令查看日志  
  4. $ kubectl logs \  
  5.     kubernetes-dashboard-c9fb67ffc-nknpj \  
  6.     --namespace=kubernetes-dashboard  
  7. $ kubectl describe pod \  
  8.     kubernetes-dashboard-c9fb67ffc-nknpj \  
  9.     --namespace=kubernetes-dashboard  
  1. $ kubectl get svc -n kubernetes-dashboard  
  2. NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE  
  3. dashboard-metrics-scraper   ClusterIP   10.245.214.11    <none>        8000/TCP   26s  
  4. kubernetes-dashboard        ClusterIP   10.245.161.146   <none>        443/TCP    26s 

需要注意的是 dashboard 默认不允许外网访问,即使通过 kubectl proxy 允许外网访问。但 dashboard 又只允许 HTTPS 访问,这样 kubeadm init 时自签名的 CA 证书是不被浏览器承认的。

我采用的方案是 Nginx 作为反向代理,使用 Lets Encrypt 提供的有效证书对外提供服务,再经由 proxy_pass 指令反向代理到 kubectl proxy 上,如下所示。此时,本地可经由 8888 访问到 dashboard 服务,再通过 Nginx 访问它。

  1. # 代理(可以使用supervisor)  
  2. $ kubectl proxy --accept-hosts='^*$'  
  3. $ kubectl proxy --port=8888 --accept-hosts='^*$'  
  4. # 测试代理是否正常(默认监听在8001端口上)  
  5. $ curl -X GET -L http://localhost:8001  
  6. # 本地(可以使用nginx)  
  7. proxy_pass http://localhost:8001;  
  8. proxy_pass http://localhost:8888;  
  9. # 外网访问如下URL地址  
  10. https://mydomain/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login 
  •  配置文件整理
    •  nginx
    •  supervisor 
  1. # k8s.conf  
  2. client_max_body_size     80M;  
  3. client_body_buffer_size  128k;  
  4. proxy_connect_timeout    600;  
  5. proxy_read_timeout       600;  
  6. proxy_send_timeout       600;  
  7. server {  
  8.     listen       8080 ssl;  
  9.     server_name  _;  
  10.     ssl_certificate     /etc/kubernetes/pki/ca.crt;  
  11.     ssl_certificate_key /etc/kubernetes/pki/ca.key;  
  12.     access_log /var/log/nginx/k8s.access.log;  
  13.     error_log  /var/log/nginx/k8s.error.log  error; 
  14.     location / {  
  15.         proxy_set_header   X-Forwarded-Proto $scheme;  
  16.         proxy_set_header   Host              $http_host;  
  17.         proxy_set_header   X-Real-IP         $remote_addr;  
  18.         proxy_pass http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/;  
  19.     } 
  20. }  
  1. # k8s.conf  
  2. [program:k8s-master]  
  3. command=kubectl proxy --accept-hosts='^*$'  
  4. user=vagrant  
  5. environment=KUBECONFIG="/home/vagrant/.kube/config"  
  6. stopasgroup=true  
  7. stopasgroup=true  
  8. autostart=true  
  9. autorestart=unexpected  
  10. stdout_logfile_maxbytes=1MB  
  11. stdout_logfile_backups=10  
  12. stderr_logfile_maxbytes=1MB  
  13. stderr_logfile_backups=10  
  14. stderr_logfile=/var/log/supervisor/k8s-stderr.log  
  15. stdout_logfile=/var/log/supervisor/k8s-stdout.log 
  •  配置文件如下所示 
  1. # Copyright 2017 The Kubernetes Authors.  
  2. #  
  3. # Licensed under the Apache License, Version 2.0 (the "License");  
  4. # you may not use this file except in compliance with the License.  
  5. # You may obtain a copy of the License at 
  6. #  
  7. #     http://www.apache.org/licenses/LICENSE-2.0  
  8. #  
  9. # Unless required by applicable law or agreed to in writing, software  
  10. # distributed under the License is distributed on an "AS IS" BASIS,  
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  12. # See the License for the specific language governing permissions and  
  13. # limitations under the License. 
  14. apiVersion: v1  
  15. kind: Namespace  
  16. metadata:  
  17.   name: kubernetes-dashboard  
  18. ---  
  19. apiVersion: v1  
  20. kind: ServiceAccount  
  21. metadata:  
  22.   labels:  
  23.     k8s-app: kubernetes-dashboard  
  24.   name: kubernetes-dashboard  
  25.   namespace: kubernetes-dashboard  
  26. ---  
  27. kind: Service  
  28. apiVersion: v1  
  29. metadata:  
  30.   labels:  
  31.     k8s-app: kubernetes-dashboard  
  32.   name: kubernetes-dashboard  
  33.   namespace: kubernetes-dashboard  
  34. spec:  
  35.   ports:  
  36.     - port: 443  
  37.       targetPort: 8443  
  38.   selector:  
  39.     k8s-app: kubernetes-dashboard  
  40. ---  
  41. apiVersion: v1  
  42. kind: Secret  
  43. metadata:  
  44.   labels: 
  45.     k8s-app: kubernetes-dashboard  
  46.   name: kubernetes-dashboard-certs  
  47.   namespace: kubernetes-dashboard  
  48. type: Opaque 
  49. ---  
  50. apiVersion: v1  
  51. kind: Secret  
  52. metadata:  
  53.   labels:  
  54.     k8s-app: kubernetes-dashboard  
  55.   name: kubernetes-dashboard-csrf  
  56.   namespace: kubernetes-dashboard  
  57. type: Opaque  
  58. data:  
  59.   csrf: "" 
  60. ---  
  61. apiVersion: v1  
  62. kind: Secret  
  63. metadata:  
  64.   labels:  
  65.     k8s-app: kubernetes-dashboard  
  66.   name: kubernetes-dashboard-key-holder  
  67.   namespace: kubernetes-dashboard  
  68. type: Opaque  
  69. ---  
  70. kind: ConfigMap  
  71. apiVersion: v1 
  72.  metadata:  
  73.   labels:  
  74.     k8s-app: kubernetes-dashboard  
  75.   name: kubernetes-dashboard-settings  
  76.   namespace: kubernetes-dashboard 
  77. ---  
  78. kind: Role  
  79. apiVersion: rbac.authorization.k8s.io/v1  
  80. metadata:  
  81.   labels:  
  82.     k8s-app: kubernetes-dashboard  
  83.   name: kubernetes-dashboard  
  84.   namespace: kubernetes-dashboard  
  85. rules:  
  86.   # Allow Dashboard to get, update and delete Dashboard exclusive secrets.  
  87.   - apiGroups: [""]  
  88.     resources: ["secrets"]  
  89.     resourceNames:  
  90.       [  
  91.         "kubernetes-dashboard-key-holder",  
  92.         "kubernetes-dashboard-certs",  
  93.         "kubernetes-dashboard-csrf",  
  94.       ]  
  95.     verbs: ["get", "update", "delete"]  
  96.     # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.  
  97.   - apiGroups: [""]  
  98.     resources: ["configmaps"]  
  99.     resourceNames: ["kubernetes-dashboard-settings"]  
  100.     verbs: ["get", "update"]  
  101.     # Allow Dashboard to get metrics.  
  102.   - apiGroups: [""]  
  103.     resources: ["services"]  
  104.     resourceNames: ["heapster", "dashboard-metrics-scraper"]  
  105.     verbs: ["proxy"]  
  106.   - apiGroups: [""]  
  107.     resources: ["services/proxy"]  
  108.     resourceNames:  
  109.       [  
  110.         "heapster",  
  111.         "http:heapster:",  
  112.         "https:heapster:",  
  113.         "dashboard-metrics-scraper",  
  114.         "http:dashboard-metrics-scraper",  
  115.       ]  
  116.     verbs: ["get"] 
  117. ---  
  118. kind: ClusterRole  
  119. apiVersion: rbac.authorization.k8s.io/v1  
  120. metadata:  
  121.   labels:  
  122.     k8s-app: kubernetes-dashboard  
  123.   name: kubernetes-dashboard  
  124. rules: 
  125.   # Allow Metrics Scraper to get metrics from the Metrics server  
  126.   - apiGroups: ["metrics.k8s.io"]  
  127.     resources: ["pods", "nodes"]  
  128.     verbs: ["get", "list", "watch"] 
  129. ---  
  130. apiVersion: rbac.authorization.k8s.io/v1  
  131. kind: RoleBinding  
  132. metadata:  
  133.   labels:  
  134.     k8s-app: kubernetes-dashboard  
  135.   name: kubernetes-dashboard  
  136.   namespace: kubernetes-dashboard  
  137. roleRef:  
  138.   apiGroup: rbac.authorization.k8s.io  
  139.   kind: Role  
  140.   name: kubernetes-dashboard  
  141. subjects:  
  142.   - kind: ServiceAccount  
  143.     name: kubernetes-dashboard  
  144.     namespace: kubernetes-dashboard 
  145. ---  
  146. apiVersion: rbac.authorization.k8s.io/v1  
  147. kind: ClusterRoleBinding  
  148. metadata:  
  149.   name: kubernetes-dashboard  
  150. roleRef:  
  151.   apiGroup: rbac.authorization.k8s.io  
  152.   kind: ClusterRole  
  153.   name: kubernetes-dashboard  
  154. subjects:  
  155.   - kind: ServiceAccount  
  156.     name: kubernetes-dashboard  
  157.     namespace: kubernetes-dashboard  
  158. ---  
  159. kind: Deployment  
  160. apiVersion: apps/v1  
  161. metadata:  
  162.   labels:  
  163.     k8s-app: kubernetes-dashboard  
  164.   name: kubernetes-dashboard  
  165.   namespace: kubernetes-dashboard  
  166. spec:  
  167.   replicas: 1  
  168.   revisionHistoryLimit: 10  
  169.   selector:  
  170.     matchLabels:  
  171.       k8s-app: kubernetes-dashboard  
  172.   template:  
  173.     metadata:  
  174.       labels:  
  175.         k8s-app: kubernetes-dashboard  
  176.     spec:  
  177.       containers:  
  178.         - name: kubernetes-dashboard  
  179.           image: registry.cn-shanghai.aliyuncs.com/jieee/dashboard:v2.0.4  
  180.           imagePullPolicy: Always  
  181.           ports:  
  182.             - containerPort: 8443  
  183.               protocol: TCP  
  184.           args:  
  185.             - --auto-generate-certificates  
  186.             - --namespace=kubernetes-dashboard  
  187.             # Uncomment the following line to manually specify Kubernetes API server Host  
  188.             # If not specified, Dashboard will attempt to auto discover the API server and connect  
  189.             # to it. Uncomment only if the default does not work.  
  190.             # - --apiserver-host=http://my-address:port  
  191.           volumeMounts:  
  192.             - name: kubernetes-dashboard-certs  
  193.               mountPath: /certs  
  194.               # Create on-disk volume to store exec logs  
  195.             - mountPath: /tmp  
  196.               name: tmp-volume  
  197.           livenessProbe:  
  198.             httpGet:  
  199.               scheme: HTTPS  
  200.               path: /  
  201.               port: 8443  
  202.             initialDelaySeconds: 30  
  203.             timeoutSeconds: 30  
  204.           securityContext:  
  205.             allowPrivilegeEscalation: false  
  206.             readOnlyRootFilesystem: true  
  207.             runAsUser: 1001  
  208.             runAsGroup: 2001  
  209.       volumes:  
  210.         - name: kubernetes-dashboard-certs  
  211.           secret:  
  212.             secretName: kubernetes-dashboard-certs  
  213.         - name: tmp-volume  
  214.           emptyDir: {}  
  215.       serviceAccountName: kubernetes-dashboard  
  216.       nodeSelector:  
  217.         "kubernetes.io/os": linux  
  218.       # Comment the following tolerations if Dashboard must not be deployed on master  
  219.       tolerations:  
  220.         - key: node-role.kubernetes.io/master  
  221.           effect: NoSchedule 
  222. ---  
  223. kind: Service  
  224. apiVersion: v1  
  225. metadata:  
  226.   labels:  
  227.     k8s-app: dashboard-metrics-scraper  
  228.   name: dashboard-metrics-scraper  
  229.   namespace: kubernetes-dashboard  
  230. spec:  
  231.   ports:  
  232.     - port: 8000  
  233.       targetPort: 8000  
  234.   selector:  
  235.     k8s-app: dashboard-metrics-scraper  
  236. ---  
  237. kind: Deployment  
  238. apiVersion: apps/v1  
  239. metadata:  
  240.   labels:  
  241.     k8s-app: dashboard-metrics-scraper  
  242.   name: dashboard-metrics-scraper  
  243.   namespace: kubernetes-dashboard  
  244. spec:  
  245.   replicas: 1  
  246.   revisionHistoryLimit: 10  
  247.   selector:  
  248.     matchLabels:  
  249.       k8s-app: dashboard-metrics-scraper  
  250.   template:  
  251.     metadata:  
  252.       labels:  
  253.         k8s-app: dashboard-metrics-scraper  
  254.       annotations:  
  255.         seccomp.security.alpha.kubernetes.io/pod: "runtime/default"  
  256.     spec:  
  257.       containers:  
  258.         - name: dashboard-metrics-scraper  
  259.           image: registry.cn-shanghai.aliyuncs.com/jieee/metrics-scraper:v1.0.4  
  260.           ports:  
  261.             - containerPort: 8000  
  262.               protocol: TCP  
  263.           livenessProbe:  
  264.             httpGet:  
  265.               scheme: HTTP  
  266.               path: /  
  267.               port: 8000  
  268.             initialDelaySeconds: 30  
  269.             timeoutSeconds: 30  
  270.           volumeMounts:  
  271.             - mountPath: /tmp  
  272.               name: tmp-volume  
  273.           securityContext:  
  274.             allowPrivilegeEscalation: false  
  275.             readOnlyRootFilesystem: true  
  276.             runAsUser: 1001  
  277.             runAsGroup: 2001  
  278.       serviceAccountName: kubernetes-dashboard  
  279.       nodeSelector:  
  280.         "kubernetes.io/os": linux  
  281.       # Comment the following tolerations if Dashboard must not be deployed on master  
  282.       tolerations:  
  283.         - key: node-role.kubernetes.io/master  
  284.           effect: NoSchedule  
  285.       volumes:  
  286.         - name: tmp-volume  
  287.           emptyDir: {} 
  •  第一种:登录 dashboard 的方式(配置文件)
    •  采用 token 方式
    •  采用秘钥文件方式

  1. # 创建管理员帐户(dashboard)  
  2. $ cat <<EOF | kubectl apply -f -  
  3. apiVersion: v1  
  4. kind: ServiceAccount  
  5. metadata:  
  6.   name: admin-user  
  7.   namespace: kubernetes-dashboard  
  8. EOF  
  1. # 将用户绑定已经存在的集群管理员角色  
  2. $ cat <<EOF | kubectl apply -f -  
  3. apiVersion: rbac.authorization.k8s.io/v1  
  4. kind: ClusterRoleBinding  
  5. metadata:  
  6.   name: admin-user  
  7. roleRef:  
  8.   apiGroup: rbac.authorization.k8s.io  
  9.   kind: ClusterRole  
  10.   name: cluster-admin  
  11. subjects:  
  12. - kind: ServiceAccount  
  13.   name: admin-user  
  14.   namespace: kubernetes-dashboard  
  15. EOF  
  1. # 获取可用户于访问的token令牌  
  2. $ kubectl -n kubernetes-dashboard describe secret \  
  3.     $(kubectl -n kubernetes-dashboard get secret \  
  4.     | grep admin-user | awk '{print $1}') 
  •  登录界面展示
    •   针对 Chrome 浏览器,在空白处点击然后输入:thisisunsafe
    •   针对 Firefox 浏览器,遇到证书过期,添加例外访问

  •  第二种:授权 dashboard 权限(不适用配置文件)
    •   如果登录之后提示权限问题的话,可以执行如下操作
    •   把 serviceaccount 绑定在 clusteradmin
    •   授权 serviceaccount 用户具有整个集群的访问管理权限 
  1. # 创建serviceaccount  
  2. $ kubectl create serviceaccount dashboard-admin -n kube-system  
  3. # 把serviceaccount绑定在clusteradmin  
  4. # 授权serviceaccount用户具有整个集群的访问管理权限  
  5. $ kubectl create clusterrolebinding \  
  6.     dashboard-cluster-admin --clusterrole=cluster-admin \  
  7.     --serviceaccount=kube-system:dashboard-admin  
  8. # 获取serviceaccount的secret信息,可得到token令牌的信息  
  9. $ kubectl get secret -n kube-system  
  10. # 通过上边命令获取到dashboard-admin-token-slfcr信息  
  11. $ kubectl describe secret <dashboard-admin-token-slfcr> -n kube-system 
  12. # 浏览器访问登录并把token粘贴进去登录即可  
  13. https://192.168.30.30:8080/  
  14. # 快捷查看token的命令  
  15. $ kubectl describe secrets -n kube-system \  
  16.     $(kubectl -n kube-system get secret | awk '/admin/{print $1}') 

5. 参考链接

  •  十分钟搭建好 K8S 集群
  •  基于阿里云 ubuntu 的 k8s-1.8.2 环境搭建
  •  从零开始在 ubuntu 上安装和使用 k8s 集群及报错解决 

相关内容