本文来自正在规划的Go语言&云原生自我提升系列,欢迎关注后续文章。
上一篇中我们已成功构建了应用容器,下一步学习如何将其转化为完全可信赖、可伸缩的分布式系统。实现这一目标,需要用到Kubernetes集群。现在大部分公有云都提供云端Kubernetes服务,只需几条命令就可轻松创建一个集群。对于Kubernetes新手强烈推荐使用这种方法。即便最终你计划在裸金属要上运行Kubernetes,这也一种快速上手学习Kubernetes很好的方式,之后再学习如何在物理机上进行安装。此外,管理Kubernetes集群本身是一项复杂的任务,对大部分人来说将这管理工作交给云厂商更为合理,尤其是大部分云厂商都免费提供管理服务。
当然,使用云厂商解决方案需要支付云端资源及活跃网络连接的费用。出于这种原因,本地部署更有吸引力,这时minikube工具提供了轻松在本地电脑虚拟机中运行本地Kubernetes 集群的方式。虽然这种选择不错,但minikube创建的是单节点集群,并不能展示Kubernetes完整集群的方方面面。因此推荐使用云端解决方案上手,除非无法满足你的工作场景。更新的替代方案是运行Docker嵌套Docker的集群,这样可以在单机中启动多节点集群。这一项目仍处于beta阶段,所以请注意可能会遇到一些意料外的问题。
如果读者坚持要用裸机,本系列后续会有一个关于使用树莓派构建集群的教程。其中使用kubeadm工具,可适配到其它非树莓派的主机上。
在公有云上安装Kubernetes
本文包含在三大云厂商上安装Kubernetes:亚马逊云、微软Azure和谷歌云平台。
如果选择使用云厂商管理Kubernetes,仅需安装其中的一个,在配置好集群后又不希望在其它地方安装Kubernetes的话就可以跳到Kubernetes客户端一节了。
谷歌Kubernetes引擎
Google云平台提供托管的Kubernetes-as-a-Service,称为Google Kubernetes Engine (GKE)。使用GKE,需要注册Google云平台并配置好账单信息、安装gcloud
工具。
安装好gcloud
之后,首先设置默认地区:
1 |
$ gcloud config set compute/zone us-west1-a |
然后可以创建一个集群:
1 |
$ gcloud container clusters create kuar-cluster --num-nodes=3 |
这可能会耗费几分钟。集群准备完毕后,可以通过如下命令获取集群认证信息:
1 |
$ gcloud container clusters get-credentials kuar-cluster |
如果遇到问题,可以在Google官方文档中找到有关创建GKE集群的完整教程。
使用Azure Kubernetes服务安装Kubernetes
Microsoft Azure在Azure容器服务中提供了托管的Kubernetes-as-a-Service。Azure容器服务最简单的方式是使用内置的Azure Cloud Shell。可以点击右上角工具栏的shell图标来激活shell:
shell有一个az
工具自动安装、配置Azure所需的环境。
也可以在本地机器上安装az
CLI。
启动了shell之后,可以运行:
1 |
$ az group create --name=kuar --location=westus |
创建完资源组,可使用如下命令创建集群:
1 |
$ az aks create --resource-group=kuar --name=kuar-cluster |
这会花费几分钟。创建好集群后,可通过如下命令获取集群的认证信息:
1 |
$ az aks get-credentials --resource-group=kuar --name=kuar-cluster |
如尚未安装kubectl
工具,可使用如下命令安装:
1 |
$ az aks install-cli |
可以在Azure官方文档中找到完整的Kubernetes安装教程。
在亚马逊云安装Kubernetes
亚马逊云提供的托管Kubernetes服务称为弹性Kubernetes服务EKS).。创建EKS集群最简单的方式是通过开源的eksctl
命令行工具。
安装好eksctl
后,可运行如下命令来创建集群:
1 |
$ eksctl create cluster |
有关安装选项的更多详情(如节点大小等),请查看命令的帮助:
1 |
$ eksctl create cluster --help |
集群安装包括kubectl
命令行工具相关的配置。如果读者未安装过kubectl
,请参照官方文档的教程。
在本地使用minikube安装Kubernetes
如果想要在本地体验或是不希望支付云端的费用,可以使用minikube
安装一个单节点集群。或者如果安装了Docker Desktop,它自带有一个Kubernetes的单机安装版。
虽然minikube
(或Docker Desktop)可以很好地模拟Kubernetes集群,但它仅用于本地开发、学习和体验。因其是运行于单节点的VM中,并不提供分布式Kubernetes集群的可靠性。此外,本系列文章中讲述的一些功能需要与云服务商进行集成。这些功能在minikube
下要么不能使用要么使用受限。
注:要使用minikube
的需要在电脑上安装有虚拟机软件。对Linux和macOS,通常使用VirtualBox。而Windows中的默认选项是Hyper-V虚拟机。在使用minikube
之前应确保已安装了虚拟机软件。
可在GitHub上找到minikube
。其中有Linux、macOS和Windows的二进制文件供下载。安装好minikube
之后,可使用如下命令创建一个本地集群:
1 |
$ minikube start |
这会创建一个本地虚拟机,带有Kubernetes,同时创建一个本地kubectl
配置指向该集群。前面已提到,这个集群为单节点,所以虽然可用,但与大部分Kubernetes生产环境部署有一些分别。
使用完集群后,可以通过如下命令停用VM:
1 |
$ minikube stop |
如需删除集群,可运行:
1 |
$ minikube delete |
在Docker中运行Kubernetes
还有一种运行Kubernetes的方式,不久前开发的,使用Docker容器来代替虚拟机模拟多个Kubernetes节点。kind项目提供了一种在Docker中启动和管理测试集群的体验(kind表示Kubernetes IN Docker)。kind仍处于开发中((pre 1.0)),但已广泛用于快速构建Kubernetes进行测试。
在各种平台上如何安装请参见kind官方网站 。安装完成后,只需运行如下命令进行创建:
1 2 3 4 |
$ kind create cluster --wait 5m $ export KUBECONFIG="$(kind get kubeconfig-path)" $ kubectl cluster-info $ kind delete cluster |
与Kind相对应的还有Rancher Lab所推出用于安装轻量级k3s的工具k3d
1 |
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash |
Windows上可使用Chocolatey安装:
1 |
choco install k3d |
安装完成后可通过如下命令创建集群
1 |
k3d cluster create mycluster |
Kubernetes客户端
官方的Kubernetes客户端是kubectl
:一款与Kubernetes API进行交互的命令行工具。kubectl
可用于管理大部分Kubernetes对象,比如Pods、副本集和服务。kubectl
也可用于查看和验证集群的整体健康状态。
我们将使用kubectl
工具来查看刚刚创建的集群。
查看集群状态
可通过如下命令来查看集群的版本:
1 |
$ kubectl version |
这会显示两个版本:一个是本地kubectl
工具的版本,还有一个是Kubernetes API服务端版本。
注:如果两者版本不一致也不必担心。Kubernetes工具对Kubernetes API各版本具有向前及向后兼容,只要工具和集群的小版本保持一致且不在老集群中使用新功能就没有问题。Kubernetes遵循语义化版本规范,小版本是中间的那个数(如1.18.2中的18)。保障在支持版本范围内即可。
现在已可与Kubernetes集群间进行通讯,下面就更深入地查看集群功能。
首先对集群进行简单的诊断。这种方式可验证集群整体上是否健康:
1 |
$ kubectl get componentstatuses |
输出如下:
1 2 3 4 |
NAME STATUS MESSAGE ERROR scheduler Healthy ok controller-manager Healthy ok etcd-0 Healthy {"health": "true"} |
注:因为Kubernetes在不断的迭代升级,所以kubectl
命令的输出可能会变化。如果你的输出结果和上面不完全一样请不必担心。
这里可以看到Kubernetes集群的组成部分。controller-manager
负责运行规范集群内行为各种控制器,例如,确保服务的副本可用且健康。scheduler
负责将不同的Pod放到集群的各节点上。最后,etcd
服务用于所有API对象所进行的存储。
列举Kubernetes节点
接下来,我们列举出集群中的所有节点:
1 2 3 4 5 6 |
$ kubectl get nodes NAME STATUS ROLES AGE VERSION kube0 Ready control-plane,master 45d v1.22.4 kube1 Ready <none> 45d v1.22.4 kube2 Ready <none> 45d v1.22.4 kube3 Ready <none> 45d v1.22.4 |
可以看到4个启动了45天的节点。在Kubernetes中,节点分隔成包含API服务、调度器等容器的管理集群的control-plane
节点,还有容器所运行的worker
节点。Kubernetes通常会将任务调度到control-plane
节点来确保工作负载不会损害集群的整体操作。
可以使用kubectl describe
命令来获取具体节点的详细信息,如kube1
:
1 |
$ kubectl describe nodes kube1 |
首先可以看到有关节点的基本信息:
1 2 3 4 5 |
Name: kube1 Role: Labels: beta.kubernetes.io/arch=arm beta.kubernetes.io/os=linux kubernetes.io/hostname=node-1 |
可以看到该节点运行于Linux操作系统和ARM处理器之上。
接着,我们看到kube1
本身的一些信息(为保持简洁删去了日期信息):
1 2 3 4 5 6 7 8 |
Conditions: Type Status ... Reason Message ----- ------ ------ ------- NetworkUnavailable False ... FlannelIsUp Flannel... MemoryPressure False ... KubeletHasSufficientMemory kubelet... DiskPressure False ... KubeletHasNoDiskPressure kubelet... PIDPressure False ... KubeletHasSufficientPID kubelet... Ready True ... KubeletReady kubelet... |
这些状态表明节点有充足的磁盘和内存空间,并向Kubernetes主节点报告其为健康的。接下来为有关机器容量的信息:
1 2 3 4 5 6 7 8 9 10 |
Capacity: alpha.kubernetes.io/nvidia-gpu: 0 cpu: 4 memory: 882636Ki pods: 110 Allocatable: alpha.kubernetes.io/nvidia-gpu: 0 cpu: 4 memory: 882636Ki pods: 110 |
再下来是有关节点软件的信息,包括所运行的Docker的版本、Kubernetes版本及Linux内核版本等:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
System Info: Machine ID: 44d8f5dd42304af6acde62d233194cc6 System UUID: c8ab697e-fc7e-28a2-7621-94c691120fb9 Boot ID: e78d015d-81c2-4876-ba96-106a82da263e Kernel Version: 4.19.0-18-amd64 OS Image: Debian GNU/Linux 10 (buster) Operating System: linux Architecture: amd64 Container Runtime Version: containerd://1.4.12 Kubelet Version: v1.22.4 Kube-Proxy Version: v1.22.4 PodCIDR: 10.244.1.0/24 PodCIDRs: 10.244.1.0/24 |
最后是有关当前节点上所运行的Pod的信息:
1 2 3 4 5 6 7 8 9 10 11 12 |
Non-terminated Pods: (3 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits --------- ---- ------------ ---------- --------------- ------------- kube-system kube-dns... 260m (6%) 0 (0%) 140Mi (16%) 220Mi (25%) kube-system kube-fla... 0 (0%) 0 (0%) 0 (0%) 0 (0%) kube-system kube-pro... 0 (0%) 0 (0%) 0 (0%) 0 (0%) Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted. CPU Requests CPU Limits Memory Requests Memory Limits ------------ ---------- --------------- ------------- 260m (6%) 0 (0%) 140Mi (16%) 220Mi (25%) No events. |
通过输出信息可以看到节点中的Pod(如为集群提供DNS服务的kube-dns
Pod),每个Pod向节点请求的CPU、内存以及整体资源。值得一提的是Kubernetes同时跟踪机器上所运行的每个Pod对资源的请求和上限。有关请求和上限会在Pods一文中进行详细讲解,但总的来说,每个Pod所请求的资源节点可保留,而Pod的上限资源则是Pod所能消耗的最大量。Pod的上限资源可大于请求量,额外的资源在最佳性能的基础上进行提供。但并不保证在节点中会提供。
集群组成
Kubernetes有意思的一个方面是组成集群的很多部分实际上是使用Kubernetes自身部署的。我们接下来会讨论其中的一部分。这些组成部分使用到一些概念要在后续文章中才会介绍到。所有这些部分都运行在kube-system
命名空间中。
Kubernetes代理
Kubernetes代理负责将网络流量路由到集群中的负载均衡服务。完成这一任务,代理必须运行在集群中的每个节点上。Kubernetes有一个名为DaemonSet的对象,我们会在DaemonSets一文中进行讨论,在很多集群中都使用到了它。如果集群使用DaemonSet来运行Kubernetes代理,可通过如下命令查看代理:
1 2 3 |
$ kubectl get daemonSets --namespace=kube-system kube-proxy NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR kube-proxy 5 5 5 5 5 ... 45d |
按照集群的配置,kube-proxy
的DaemonSet可能使用其它的名称,或是完全不使用DaemonSet。但不论怎样,每个节点中都需要运行kube-proxy
。
Kubernetes DNS
Kubernetes还运行着一个DNS服务,它为集群中所定义的服务提供命名和服务发现。这一DNS服务在集群上以副本服务运行。DNS服务以管理着其它副本的Kubernetes部署运行(名称可能是coredns
等)。
1 2 3 |
$ kubectl get deployments --namespace=kube-system core-dns NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE core-dns 1 1 1 1 45d |
还有一个为DNS服务执行负载均衡的Kubernetes服务:
1 2 3 |
$ kubectl get services --namespace=kube-system core-dns NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE core-dns 10.96.0.10 <none> 53/UDP,53/TCP 45d |
这表示集群的DNS服务地址为10.96.0.10。如果登录到集群中的容器,会发现它写入了容器中的/etc/resolv.conf 文件。
Kubernetes UI
小结
希望至此读者已可以启动自己的Kubernetes集群,并可使用一些命令来查看所创建集群的信息。接下来我们会花大量时间来了解Kubernetes集群的命令行,以及掌握kubectl
工具。后续文章中读者会使用kubectl
来查看Kubernetes API中的各种对象。