前面已经提到,微服务架构离不开容器技术。
为什么需要容器呢?我们先来看一个集装箱的例子:在一艘货轮上,货物按照整齐的规格码放整齐,从而可以封装进集装箱。集装箱之间不会相互影响,这大大地提升了运输效率。
容器就好比这个集装箱,运行的各式应用程序是货物。为了让应用程序在生产机上跑起来,往往需要做各种配置,非常繁琐,还经常会由于系统版本等原因,和开发环境不一致,从而导致“这个程序本地好好的,放到服务器上就出Bug”这类情况,这就是环境不标准,容器可以对运行环境标准化,很好的解决这类问题。此外,不同的应用程序需要不同的应用环境,如果都部署在一台物理机上,很可能会发生包、依赖冲突,导致无法运维,有了容器后,不同的应用程序放置在不同的容器中,相互隔离开、不会相互影响。其实,虚拟机加一些脚本,也能解决上述的标准化和隔离问题,但是容器更加轻量级,性能损耗比虚拟机低很多,并且多数集成了环境的自描述语言(例如DockerFile),更方便进行维护。
Docker是目前最流行的容器技术之一,按照官方的解释说明:Docker是开源的引擎,用于在开发或运维中构建、部署和运行应用程序。
需要指出的是,很多人把容器技术和Docker划等号,这是不对的。目前的主流容器技术,除了Docker外,还有Rkt、LXD等。
已经有了Docker,为什么还需要Kuberntes呢?因为从单击的Docker到分布式的容器集群,还有很多路要走。Kubernetes是分布式容器集群操作平台,可以轻松地完成部署、调度、扩容等操作。如果说Docker是手动挡汽车的话,那么Kubernetes相当于自动驾驶汽车,只需要很少的步骤,就可以完成复杂的容器集群管理工作。Kubernetes构建于容器引擎之上,除了支持Docker外,也支持Rtk,本书以Kubernetes和Docker为例进行讨论。
为了适应复杂的业务需求,Kubernetes中内置了不同层级的操作单元:
Kubernetes提供了强大的集群管理功能,当然,它的集群环境的配置较为复杂,并非简短篇幅可以说清楚。
本书的核心是微服务架构,而非Kubernetes的使用,因此,我们不会详细讲解k8s集群的配置。
幸运的是,k8s为我们提供了minikube,它一个用于快速开发的单机k8s环境,拥有与k8s集群完全相同的功能。本章的剩余章节,我们将使用minikube来进行讲解。
关于minikube的安装,可以参考官方的这篇minikube安装教程,这里不做详细展开。
需要特别指出:minikube只限于开发和学习使用。对于生产环境,请务必配置Kubernetes的分布式集群,大家可以参考官方文档。
minikube安装妥当后,让我们来部署第一个Deployment。
首先,启动minikube。第一次启动需要下载ISO镜像,时间较长,请耐心等待一下。
minikube start --disk-size 50g --memory 4096 --insecure-registry "192.168.99.0/24"
上述第一次start实际是配置了minikube虚拟机的参数,我们简单解释一下:
提醒一下,上述minikube参数只对第一次启动(实际是创建)生效,一旦虚拟机生成完毕,这些参数的修改都不会生效了。
Kubernetes支持两种操作方式:命令行参数、yaml文件定义。鉴于维护性等角度,我们更推荐推荐后者,即用yaml文件的方式。
Deployment描述文件,lmsia-abc-server-deployment.yaml
apiVersion: apps/v1
// Deployment
kind: Deployment
metadata:
name: lmsia-abc-server-deployment
spec:
selector:
matchLabels:
app: lmsia-abc-server
replicas: 2
// Pod define
template:
metadata:
labels:
app: lmsia-abc-server
spec:
containers:
- name: lmsia-abc-server-ct
image: coder4/lmsia-abc-server:1.0
ports:
- containerPort: 8080
- containerPort: 3000
我们来解读一下这个yaml文件,采用自底向上的步骤:
理解了文件内容后,让我们来新建这个部署:
kubectl apply -f ./lmsia-abc-server-deployment.yaml
我们来看看启动了哪些Pod。这里我们以标签为查询参数。
kubectl get pods -l app=lmsia-abc-server
NAME READY STATUS RESTARTS AGE
lmsia-abc-server-deployment-bd4949ff9-jcczg 1/1 Running 0 10m
lmsia-abc-server-deployment-bd4949ff9-zqsvc 1/1 Running 0 10m
不难发现,启动了两个Pod,和我们在yaml文件中设定的副本数一致。
注意:上图展示的是最终结果,Pod的启动前需要先拉取镜像,因此会存在“非Running”的中间状态。
截至目前,我们已经通过Deployment的方式,成功的启动了两个Pod。前面已经介绍,镜像中的微服务对外暴露了两个端口:REST(HTTP)服务的8080端口,和RPC服务的3000端口。接下来,我们尝试访问Pod内的HTTP服务。
先来获取一下IP地址,以第一个Pod为例:
kubectl describe pod lmsia-abc-server-deployment-bd4949ff9-jcczg
Name: lmsia-abc-server-deployment-bd4949ff9-jcczg
....
Status: Running
IP: 172.17.0.5
Controlled By: ReplicaSet/lmsia-abc-server-deployment-bd4949ff9
....
由于结果较多,这里只截取了关键的几行,可以从结果中看到,名字为“lmsia-abc-server-deployment-bd4949ff9-jcczg”的Pod,它的IP是“"172.17.0.5"。
尝试访问一下,会报"No route to host"错误:
curl http://172.17.0.5:8080/lmsia-abc/api/
curl: (7) Failed to connect to 172.17.0.5 port 8080: No route to host
为什么会这样呢?因为我们启动的minikube集群实际是一个虚拟机,172.17.0.5是虚拟机的内网地址。我们执行命令的命令行,是在虚拟机外部。相当与我们从外网要访问内网地址,这自然是无法成功访问的。 要说明的是,我们这里并没有访问跟路径,而是访问了“lmsia-abc/api/”,大家可以暂且认为这是一个合法的url pattern,我们将在微服务开发中对此进行讲解。
如何解决呢,有两种方案:
登录到minikube虚拟机很简单:
minikube ssh
$
注意:若需要登录到minikube虚拟机后再执行的操作,我们会增加一个$符号,以便区分。
登录到minikube虚拟机后,再次尝试Pod上的HTTP服务,可以成功访问了:
$curl http://172.17.0.5:8080/lmsia-abc/api/
Hello, REST
至此,我们成功的创建了Deployment、查看了Pod的信息、访问了Pod上的Rest服务。
最后,我们学习下如何删除Deployment。在虚拟机环境下,是没有kubectl可以使用的,所以首先要退出虚拟机。
$exit
然后再来删除Deployment,命令可以成功执行:
kubectl delete deployment lmsia-abc-server-deployment
deployment.extensions "lmsia-abc-server-deployment" deleted
再来看一下相关的Pod信息,发现已经找不到对应Pod了:
kubectl get pods -l app=lmsia-abc-server
No resources found.