你好,我是聂鹏程。
上一讲,我以购买火车票为例,为你串讲了分布式技术的应用,帮助你理解所学分布式技术可以应用到哪些业务中。其实,到目前为止,我们主要是从理论上学习相关的分布式技术。但,“纸上得来终觉浅,绝知此事要躬行”。
今天,我就以Kubernetes为例,和你一起搭建一个分布式实验环境。我先简单和你说下这篇文章的内容分配:
话不多说,接下来,我们就一起搭建这个分布式实验环境吧。
Kubernetes是Google开源的容器集群管理系统,是Borg的开源版本。我在第9篇文章中讲解集中式架构时,和你分析过Kubernetes集群属于主从架构的分布式集群。
Kubernetes集群主要由Master节点和Worker节点组成。Master节点就是中心服务器,负责对集群进行调度管理;Worker节点是真正的工作节点,负责运行业务应用的容器。而容器是一种虚拟化技术,通过限制自身使用的资源来实现资源隔离,可以为应用提供一整套运行环境,从而实现了服务运行环境的隔离,进而实现了故障隔离。你可以回顾下第30篇文章中,资源隔离的相关内容。
接下来,我们明确下这次搭建分布式实验室环境的目标:
今天我们要搭建的Kubernetes集群,以3台服务器为例,一台作为Master节点,两台作为Worker节点。服务器应具备的条件如下:
在这次部署中,我采用的机器配置如下:
准备工作完成后,我们就开始搭建集群吧。
搭建Kubernetes集群的步骤,主要包括安装Docker,安装部署kubeadm、kubelet、kubectl,部署Master节点,部署Worker节点,安装网络插件这几步。
其中,安装Docker、部署Master节点和Worker节点涉及分布式的,需要在多个节点上部署,比如Docker节点需要在每个Worker节点部署,Master节点若为集群模式,需要在多个节点上配置主备,Worker节点需要与Master节点建立连接等。
接下来, 我们具体看看如何一步一步搭建出Kubernetes集群吧。
Kubernetes是一个容器集群管理系统,因此每个Worker节点会运行容器,以实现业务运行环境隔离。我们在每台服务器上采用如下命令安装Docker:
apt-get install -y docker.io
kubeadm是Kubernetes社区提供的一个部署工具,该工具将kubelet组件之外的其他组件均采用容器部署,实现了自动化, 避免了手动部署容器的麻烦,简化了部署操作。
其中,Master节点包括API Server、Scheduler、Cluster State Store(默认etcd)和Control Manager Srever核心组件;Worker节点包括kubelet和kube-proxy核心组件。具体的组件功能和原理,你可以再回顾下第9篇文章中的相关内容。
kubelet组件本身是一个管控容器的组件,需要执行配置容器网络等操作,这些操作需要在宿主机上执行,不采用容器部署。因此,kubelet组件需要单独部署,而不能用kubeadm进行部署。
除此之外,我们还需要安装一下kubectl组件。这个组件是Kubernetes的命令行工具,通过kubectl可以部署和管理应用,查看资源,创建、删除和更新组件。
那么,如何部署kubeadm、kubelet和kubectl这三个组件呢?
apt是Linux下常用的安装管理工具,这里我就采用apt来安装这三个组件。
首先,我们需要添加Kubernetes源。
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
然后使用以下命令更新源:
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main
EOF
同样的,使用以下命令来更新源:
apt-get update # 忽略gpg的报错信息
最后,使用如下命令安装kubelet、kubectl和kubeadm:
apt-get install -y kubelet kubeadm kubectl --allow-unauthenticated
安装好这三个组件之后,我们就可以使用kubeadm来一键部署集群节点了。
首先,我们来部署Master节点。
这一步其实就是容器化启动Master节点中的各个组件,直接使用kubeadm工具提供的一条命令kubeadm init即可自动安装。
kubeadm init这条命令底层其实就是将Master的各个组件,比如API Server、etcd等,以Pod形式(容器集合)运行起来。
当然了,你可以部署多个Master节点来实现集群的高可用,比如两个Master节点互为主备(你可以回顾下第31篇文章中介绍的主备机制)。具体的部署方法,你可以参考这篇文章。
除此之外,etcd组件也可以采用集群方式部署,从而保证了数据不会丢失。etcd采用的是Raft强一致性协议,相关技术你可以再回顾下第4篇文章中的相关问题。
在本次部署中我以一个Master节点为例为你讲解集群的搭建,关于Master为集群的方式,各节点上kubernetes配置类似,你可以参考Kubernetes官网。
在这里,我把192.168.124.49这台机器作为Master节点。在该机器上直接执行kubeadm init,即可完成部署:
kubeadm init
如果有外网访问权限,基本就可以部署成功了。那么,我们可以根据如下信息判断自己是否部署成功:
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.124.49:6443 --token uv17vd.q3ber8i5knxg4h0x \
--discovery-token-ca-cert-hash sha256:c55bd70d346d809e1079565cc1fc1a05f001671cc9f2d02c55bbbc4a00bcc2a3
可以看到,想要使用集群,需要执行以下命令,执行结束后才可以使用kubectl。
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
如果没有外网访问权限,会报pull image xxxxxx的错误。
此时不要慌,从报错信息中,我们可以看到哪些镜像拉取不成功。我们可以手动在Docker Hub上寻找相对应的组件及版本,进行拉取,然后再通过Docker打tag,修改为需要的镜像。
比如,以[ERROR ImagePull]: failed to pull image k8s.gcr.io/kube-apiserver:v1.16.3为例,可以通过以下代码进行拉取。
# 可以拉取的相对应的组件和版本
docker pull aiotceo/kube-apiserver:v1.16.3
# 通过打tag的方式修改为所需要的镜像
docker tag aiotceo/kube-apiserver:v1.16.3 k8s.gcr.io/kube-apiserver:v1.16.3
然后重新执行 kubeadm init即可。
从以上操作也可以看出,kubeadm的底层其实就是将容器化组件的操作实现了自动化, 省去了手动部署的麻烦。
部署完Master节点后,我们来继续部署Worker节点。
部署Worker节点与部署Master节点类似,都可以通过命令一键部署。这里,我们使用kubeadm提供的kubeadm join命令来进行自动化部署。
kubeadm join命令的底层与kubeadm init类似,会自动以Pod形式运行Worker节点中需要的组件。不同的是,命令执行后,底层还需要将Worker节点加入到Kubernetes集群中。
执行kubeadm join命令后(具体命令如下所示),就可以看到Kubernetes集群中的节点信息了。这条命令中需要配置Master节点的IP和Port信息,目的是Worker节点根据IP和Port信息建立连接,并在建立连接的基础上,建立心跳机制。
具体的心跳机制,你可以参考第31篇文章中关于故障恢复的内容。
到目前为止,Kubernetes的集群已经完成大半了,下面我们继续部署集群。
根据Master节点部署成功后输出结果的最后几行可以知道,想要加入集群,可以执行kubeadm join命令。我在另外2台机器上都执行了如下命令:
kubeadm join 192.168.124.49:6443 --token uv17vd.q3ber8i5knxg4h0x \
--discovery-token-ca-cert-hash sha256:c55bd70d346d809e1079565cc1fc1a05f001671cc9f2d02c55bbbc4a00bcc2a3
这条命令执行后,一个集中式架构的雏形就搭建完成了。接下来,我们需要安装相应的网络插件,以实现Kubernetes集群中Pod之间的通信。
网络插件有很多,比如Canal、Flannel、Weave等。不同的插件命令不一致,具体命令可参考官网。
这里,我以安装Weave插件为例,通过执行以下命令完成安装:
sysctl net.bridge.bridge-nf-call-iptables=1
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
到这里,集群就部署完成了,是不是很简单呢?接下来,我就通过获取节点和Pod信息来验证一下集群部署是否成功。
可以通过刚刚安装的kubectl组件提供的命令查看集群的相关信息。比如,查看节点的运行状态可以通过kubectl get nodes来获得,查看各个组件对应的Pod运行状态可以通过kubectl get pods来获得。命令执行结果,如下所示:
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# vm1-pc Ready master 11h v1.16.3
# vm2-pc Ready <none> 11h v1.16.3
# vm3-pc Ready <none> 24m v1.16.3
kubectl get pods --all-namespaces
# NAMESPACE NAME READY STATUS RESTARTS AGE
# kube-system coredns-5644d7b6d9-9dprc 1/1 Running 0 11h
# kube-system coredns-5644d7b6d9-ljv5w 1/1 Running 0 11h
# kube-system etcd-vm1-pc 1/1 Running 0 11h
# kube-system kube-apiserver-vm1-pc 1/1 Running 0 11h
# kube-system kube-controller-manager-vm1-pc 1/1 Running 0 11h
# kube-system kube-proxy-qpvtb 1/1 Running 0 25m
# kube-system kube-proxy-v2xnb 1/1 Running 0 11h
# kube-system kube-proxy-wkxzg 1/1 Running 0 11h
# kube-system kube-scheduler-vm1-pc 1/1 Running 0 11h
# kube-system weave-net-6nj4c 2/2 Running 0 25m
# kube-system weave-net-lm6dh 2/2 Running 0 37m
# kube-system weave-net-vwnc2 2/2 Running 0 37m
可以看到,节点全部是Ready状态,各个组件对应的Pod也处于Running状态,表明部署成功。
如果整个安装失败的话,可以重置,重新安装,即重新kubeadm init
kubeadm reset
部署Worker节点时,pod部署不成功。原因可能是因为没有外网访问权限,镜像拉取不下来,可以通过以下命令查看pod的相关信息:
# 检查所有pod是否正常
kubectl get pod --all-namespaces -o wide
#如果pod处于非running状态,则查看该pod:
kubectl describe pod xxxxx -n kube-system
从错误信息里可以查看到是哪个镜像拉取不下来,与部署Master节点时采用的方式一样,到Docker Hub上手动拉取镜像,并设置Tag即可。
至此,Kubernetes集群就配置成功了。
集群环境搭建后,如何验证集群是可用的呢?或者说,如何在集群上运行服务呢?接下来,我就以Nginx服务为例,带你了解如何在Kubernetes集群上进行服务部署。当然,你可以参考这个例子,在Kubernetes集群上部署其他服务。
Kubernetes推荐使用YAML配置文件的方式来创建服务,所以我接下来会使用这种方式部署完成Nginx服务的部署。
部署Nginx服务这个Demo时,我会创建两个Kubernetes对象(Kubernetes对象是Kubernetes系统中的持久实体,用于表示集群的状态),一个是Deployment,一个是Service:
因为Pod是Kubernetes中最小的工作单元,所以Nginx服务都部署在Pod中。下面,我就来创建一个Deployment对象来创建我们期望的Pod状态。
首先,创建一个YAML配置文件,我将其命名为nginx-deployment.yaml。为将用户请求负载均衡到不同的Pod,减轻单个Pod的访问压力,这里我会创建三个Pod共同运行Nginx服务。
文件内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
文件中,replicas字段就是副本数量,也就是Pod数量,设置为3,即创建三个Pod来运行Nginx服务;template字段规定了单个Pod中运行哪些容器,这里运行的是名称为nginx的容器。
kubectl apply -f nginx-deployment.yaml
执行后,就等待对象的创建,可以通过以下命令来查看创建是否成功。
kubectl get deployment
以下是我创建成功后的输出:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 3m17s
同时,你也可以通过以下命令来查看创建的Pod的信息:
kubectl get pod
以下是我的输出结果:
NAME READY STATUS RESTARTS AGE
nginx-deployment-59c9f8dff-dtg4w 1/1 Running 0 3m15s
nginx-deployment-59c9f8dff-f2hmv 1/1 Running 0 3m15s
nginx-deployment-59c9f8dff-lsvdh 1/1 Running 0 3m15s
创建完deployment之后,我们来创建Service服务。同样是通过配置文件来创建,文件名是nginx-service.yaml,内容如下:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
spec:
ports:
- port: 88
targetPort: 80
selector:
app: nginx
type: NodePort
文件中port属性就是service对外提供的端口。
同样的,采用kubectl apply命令创建Nginx服务:
kubectl apply -f nginx-service.yaml
执行完成后,可以通过以下命令来查看创建是否成功:
kubectl get service
以下是我的输出结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12h
nginx-service NodePort 10.101.29.9 <none> 88:30755/TCP 5m12s
现在我们就可以通过访问Nginx服务来查看它是否部署成功了。访问该服务可以通过以下命令:
curl 10.101.29.9:88
结果如下,表明Nginx服务部署成功。
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
在这个过程中,有两个步骤涉及负载均衡的相关知识:
到这里,我们搭建的目标就完成了,下面为你留几个实验题,你可以尝试去搭建一下或运行一下,以进一步加深对分布式技术的理解。
好了,整个搭建环境,我就讲到这里。
其实,到这里,对分布式世界的探索可以说才刚开始,只有动手去实践,你学到的知识才能真正转化为你自己的。加油,赶紧行动起来吧。
今天,我主要带你学习了搭建分布式实验环境。
首先,我以Kubernetes为例,介绍了如何搭建 Kubernetes集群环境,其中包括容器、Master节点、Worker节点等配置和安装。
然后,在搭建好的Kubernetes集群的基础上,我以Nginx服务为例,展示了如何在Kubernetes集群上部署服务。
其实,今天我演示的Demo只是冰山一角。在Kubernetes中,有很多非常实用的功能,比如Kubernetes可以让服务持续不断运行,当有Pod出现故障时,会自动重启另一个Pod来达到Deployment配置文件中规定的期望状态;还可以自动实现版本更迭等。
相信通过本讲的学习,你会对分布式技术有更进一步的认知。加油,赶紧行动起来,为你的服务搭建一个分布式实验环境吧。
我是聂鹏程,感谢你的收听,欢迎你在评论区给我留言分享你的观点,也欢迎你把这篇文章分享给更多的朋友一起阅读。我们下期再会!