欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Kubernetes简介及入门

程序员文章站 2022-06-14 14:54:56
...

如今单体应用(monolithic application)日渐被认为是一种反模式(antipattern),而云平台则成为了应用部署的香饽饽。这个转变可不仅仅像是在别人的机器上启动一个虚机那么简单。如何能有效地利用云的资源和伸缩性,意味着和要过去的单体应用划清界限,转而拥抱新的架构和开发实践。

微服务正逐渐成为云端应用及服务分发的事实标准。应用被拆分成松耦合的小模块,每个模块都有自己的职责。这种新的架构使得团队能够更加独立地完成自己所负责的功能——而不必依赖于整个公司或组织的大的路线图来进行。除此之外,离散的软件组件使得测试更加简单,还能实现流水化部署。

微服务也带来了新的挑战。在虚机上创建和部署服务只是万里长征第一步,如何维护整个软件的生命周期?容器化便是在此驱动下应运而生的。容器化可以解决微服务架构下的许多问题,比如说:

  • 应有软件和宿主环境解耦,提供比较强的可移植性。
  • 容器是轻量且相对透明的,因此更容易扩展。
  • 软件及其依赖共同打包发布。

除此之外,容器还是微服务打包部署的非常棒的解决方案。但容器也不是万能的,说白了也还是软件,是软件就涉及到大规模的部署、维护以及管理。开发人员以前只需要监控和维护单个应用,但现在他们有成百上千的服务要管理。这正是Kubernetes所要解决的问题。

Kubernetes是一个开源平台,它可以用来自动化部署、扩展及管理容器化的应用及服务。Google在部署和维护大批量容器时遇到了挑战,于是便有了Kubernetes,之后又把它开源并捐赠给了云原生计算基金会(Cloud Native Computing Foundation,CNCF)。该基金会致力于促进云原生计算生态的发展。Kubernetes是CNCF孵化成功的第一个项目,也成为开源史上发展速度最快的项目。Kubernetes拥有2300个贡献者,被大小公司广泛采用,财富100强企业中有一半都在使用它。

Kubernetes入门

如何开始学习Kubernetes?Kubernetes生态周边出现了大批的支撑项目。整个生态的大图非常复杂,一个很简单的问题可能又把你带到了一片新的未知领域,这很容易让人产生挫败感。所幸的是,入门还是比较简单的,后面再根据你的实际需去了解更多高级概念就好了。本文将会告诉大家如何:

  • 使用Docker和Kubernetes来设置本地开发环境
  • 使用Helidon创建一个简单的Java微服务
  • 用Docker为微服务构建一个Docker镜像
  • 将微服务部署到Kubernetes集群
  • 在集群上对微服务进行扩容和缩容

在开始之前,本地需要先安装好这些工具:

  • Docker 18.02或更高版本
  • Kubernetes 1.7.4或更新版本
  • JDK 8或更高版本
  • Maven 3.5或更高版本

可以在MacOS、Linux或Windows平台上安装这些软件的最新版本。

如果还没有安装Docker,找到对应的平台,按照指令一步步完成。需要熟悉Docker的一些基本知识。另外需要了解更多技术的朋友们可以参考此文

还需要有一个可用的Kubernetes集群,在本文中我们使用的是Minikube。Minikube会在你本地系统的虚拟机内运行一个单节点的Kubernetes集群,这对我们来说就够用了。

装完了Docker、Minikube也能启动本地Kubernetes集群后,我们还缺少一个微服务。

创建一个基础的微服务

Helidon的Maven原型模板可以帮助我们可以快速地创建一个新工程。下面我们将告诉你如何快速创建并运行一个基础的微服务:

$ mvn archetype:generate -DinteractiveMode=false \
    -DarchetypeGroupId=io.helidon.archetypes \
    -DarchetypeArtifactId=helidon-quickstart-se \
    -DarchetypeVersion=1.0.1 \
    -DgroupId=io.helidon.examples \
    -DartifactId=helidon-quickstart-se \
    -Dpackage=io.helidon.examples.quickstart.se

进到helidon-quickstart-se目录下去构建服务:

$ cd helidon-quickstart-se
$ mvn package

现在我们有了一个可以使用的微服务。这个工程还生成了一个应用jar包。我们来运行下看看是否能正常工作:

$ java -jar ./target/helidon-quickstart-se.jar
[DEBUG] (main) Using Console logging
2019.03.20 12:52:46 INFO io.helidon.webserver.NettyWebServer
Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default'
started: [id: 0xbdfca94d, L:/0:0:0:0:0:0:0:0:8080]
WEB server is up! http://localhost:8080/greet

在另一个终端中执行curl命令:

$ curl -X GET http://localhost:8080/greet
{"message":"Hello World!"}
$ curl -X GET http://localhost:8080/greet/Mary
{"message":"Hello Mary!"}
$ curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}'  /
http://localhost:8080/greet/greeting
$ curl -X GET http://localhost:8080/greet/Maria
{"message":"Hola Maria!"}

这个服务的功能很简单,我们只是用它来作为构建容器镜像的一个demo。在开始Kubernetes之前,我们需要先为这个微服务构建一个Docker镜像。Helidon提供了一个Dockerfile,我们可以直接用它来创建镜像:

docker build -t helidon-quickstart-se target

现在我们来看看Kubernetes能为我们提供些什么。

迁移到Kubernetes

Docker可以用来创建镜像,容器,同时对它们进行本地管理。如果要在生产环境大规模地部署容器,这时候Kubernetes就能派上用场了。

Kubernetes会把相关联的容器按组来部署,这个部署的组就叫做Pod。Pod是一个可部署单元,它可以包含一个或多个容器。比如说,一个Pod可以由两个容器组成:一个容器运行web服务器,一个是服务器的日志服务。接下来我们会为你的微服务创建一个Pod,它只有一个容器:就是helidon-quickstart-se镜像的实例。

Kubernetes的一个职责就是要确保应用可以正常运行。一个可运行并监控的单元就叫做Deployment(部署)。Kubernetes会监控Deployment内的Pods的健康状态,如果Pod中的容器挂了,它会负责去重启。Deployment是部署和扩展Pod的最佳方式。

我们通过一个简单的例子来测试下本地的Kubernetes集群。首先执行下minikube start命令把本地集群启动起来。这个命令会告诉你它的执行状态。看到结束信息后再继续操作。

$ minikube start
  minikube v0.35.0 on darwin (amd64)
  ...
  Done! Thank you for using minikube!

minikube安装完后会带有kubectl,它是操作Kubernetes的主要接口。和Docker的客户端一样,这是一个功能强大的多用途工具,可以用它来管理集群和上面所部署的容器。

我们通过kubectl create来为一个创建好的镜像生成一个简单的Deployment。然后再用kubectl get来查看 Deployment以及内部的Pod的运行状态。过程如下:

$ kubectl create deployment hello-node \
  --image=gcr.io/hello-minikube-zero-install/hello
deployment.apps/hello-node created
$ kubectl get deployments
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
hello-node   0/1     1             0            27s
$ kubectl get pods
NAME                            READY   STATUS  RESTARTS   AGE
hello-node-64c578bdf8-5b7jm     1/1     Running 0          10m

Kubernetes默认会为Pod分配一个只能在集群内部访问的IP地址。如果想从外部访问Pod内的容器,需要把这个Pod声明为一个服务(Service)。Kubernetes中的服务是一层抽象,它定义了如何去访问一个或一组Pod。

通过kubectl expose来创建一个LoadBalancer的服务。这样便可以通过负载均衡器从外部访问我们的服务了。

$ kubectl expose deployment hello-node --type=LoadBalancer --port=8080
service/hello-node exposed
$ kubectl get services
NAME         TYPE          CLUSTER-IP      EXTERNAL-IP PORT(S)
hello-node   LoadBalancer  10.104.108.47   <pending>   8080:30631/TCP
kubernetes   ClusterIP     10.96.0.1       <none>      443/TCP

在云提供商或者其它托管的kubernetes平台上,这个操作会去分配负载均衡器的资源,它的IP地址也能在EXTERNAL-IP中看到。而在Minikube中,可以通过执行service命令来打开浏览器并显示服务的工作状态:

$ minikube service hello-node

完成之后,就可以把它们都删除掉了。这时可以使用kubectl delete命令。

$ kubectl delete service hello-node
service "hello-node" deleted

$ kubectl delete deployment hello-node
deployment.extensions "hello-node" deleted

目前为止我们已经有了一个本地的kubernetes集群,也知道它是如何工作的了。现在我们来看下怎么让我们的镜像工作起来。

部署到kubernetes

前面我们通过kubectl create命令创建了一个简单的部署。通常来说,你可以给kubectl传入一个yaml文件,里面详细描述清楚部署的细节信息。这种方式支持定义Kubernetes部署的所有参数。通过YAML文件来定义部署的好处是它可以和项目源码一起进行维护和管理。

Helidon的启动工程中包含了一个模板配置,它在target/app.yaml里面定义了一个部署和服务。用编辑器来打开它,看看里面是什么内容。

 

$ cat target/app.yaml
kind: Service
apiVersion: v1
metadata:
  name: helidon-quickstart-se
  labels:
    app: helidon-quickstart-se

spec:
  type: NodePort
  selector:
    app: helidon-quickstart-se
  ports:
  - port: 8080
    targetPort: 8080
    name: http
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: helidon-quickstart-se
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: helidon-quickstart-se
        version: v1
    spec:
      containers:
      - name: helidon-quickstart-se
        image: helidon-quickstart-se
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
---

这看上去不过是一堆元数据信息,仔细看会发现它定义了一个Deployment,由一个包含了helidon-quickstart-se容器在内的Pod组成,同时它还定义了一个服务,以便从外部进行访问。注意,服务中的app和部署中的app的名字是一样的。

Deployment中定义的镜像名字也就是本地镜像的名字:helidon-quickstart-se。如果将它部署在Kubernetes中,Kubernetes会优先从本地查找这个镜像。我们使用的是本地镜像,并且Docker也运行在本地机器上,看起来没什么问题。不过Minikube有一个问题是,它自己在虚拟机中运行了一个Docker实例,是无法找到我们之前构建的那个镜像的。

当然Minikube也提供了一个方便的解决办法:docker-env。这个命令会打印出一组shell环境变量,它能告诉Docker客户端去使用Minikube中运行的Docker服务。把这个命令嵌在eval中运行,它便会自动在当前的shell环境中设置好环境变量,这在Linux, Unix, Mac上都是支持的。

$ eval $(minikube docker-env)

现在再唤起docker客户端,它连接的就是Minikube虚拟机中的Docker服务了。注意的是这只在当前shell中起作用,而不是永久改变了环境变量。

我们再和之前一样重新构建一下镜像,这时镜像便会存储到Minikube内部的虚拟机中了,也就是成了本地镜像了:

$ docker build -t helidon-quickstart-se target
Sending build context to Docker daemon  5.877MB
Step 1/5 : FROM openjdk:8-jre-slim
8-jre-slim: Pulling from library/openjdk
f7e2b70d04ae: Pull complete
05d40fc3cf34: Pull complete
b235bdb95dc9: Pull complete
9a9ecf5ba38f: Pull complete
91327716c461: Pull complete

Digest: sha256:...
Status: Downloaded newer image for openjdk:8-jre-slim
 ---> bafe4a0f3a02
Step 2/5 : RUN mkdir /app
 ---> Running in ec2d3dad6e73
Removing intermediate container ec2d3dad6e73
 ---> a091fb56d8c5
Step 3/5 : COPY libs /app/libs
 ---> a8a9ec8475ac
Step 4/5 : COPY helidon-quickstart-se.jar /app
 ---> b49c72bbfa4c
Step 5/5 : CMD ["java", "-jar", "/app/helidon-quickstart-se.jar"]
 ---> Running in 4a332d65a10d
Removing intermediate container 4a332d65a10d
 ---> 248aaf1a5246
Successfully built 248aaf1a5246
Successfully tagged helidon-quickstart-se:latest

 

Kubernetes集群中已经创建好本地镜像后,我们便可以创建Deployment和Service了:

$ kubectl create -f target/app.yaml
service/helidon-quickstart-se created
deployment.extensions/helidon-quickstart-se created

$ kubectl get pods
NAME                                     READY   STATUS    RESTARTS
helidon-quickstart-se-786bd599ff-n874p   1/1     Running   0
$ kubectl get service
NAME             TYPE       CLUSTER-IP    EXTERNAL-IP PORT(S)
helidon-quick... NodePort   10.100.20.26  <none>      8080:31803/TCP
kubernetes       ClusterIP  10.96.0.1     <none>      443/TCP

在开始测试这个刚部署完的Kubernetes服务前,还有最后一件事。之前我们创建了一个LoadBalancer类型的服务。这样便可以通过负载均衡器所配置的外部IP地址来访问服务里的Pod。这只是服务发布的一种方式,还有一种类型是我们现在要用的NodePort。NodePort通过端口映射的方式将集群的所有节点对外进行发布。

Minikube还有一个很方便的功能。可以使用service命令加上--url参数来获取服务的URL。执行下这个命令,然后用它返回的URL来测试下我们的服务。

$ minikube service helidon-quickstart-se –url
http://192.168.99.101:31803
$ curl -X GET http://192.168.99.101:31803/greet
{"message":"Hello World!"}

这样一个微服务就算是在Kubernetes中部署好了,很赞吧〜在继续Kubernetes的容器之旅前,我们先来看下它的一些基础功能。

监控

当我们在命令行下运行服务时,可以直接看到web服务器的启动信息。容器也会去捕获这些输出信息,可以通过kubectl logs来查看到。如果服务没有正常运行,可以先通过它来检查下。

$ kubectl logs helidon-quickstart-se-786bd599ff-n874p
[DEBUG] (main) Using Console logging
2019.03.23 01:00:53 INFO io.helidon.webserver.NettyWebServer
  Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default'
  started: [id: 0x9f01de18, L:/0.0.0.0:8080]
WEB server is up! http://localhost:8080/greet

当我们使用本地集群来进行开发部署时,这个命令尤其有用。大规模部署的话,也有很多方法能收集、存储和使用这些日志数据。有不少开源项目和全自动化的商业解决方案,可以到网上去搜索一下。

扩展

如果你的服务只是应用程序中的一个小模块,它只负责向用户返回“hi“。但你们团队明天要参加一个电视节目,因此你希望将服务进行扩容以便支撑更多的用户。部署的可伸缩性是Kubernetes的一大特色。只需要修改下部署文件中定义的副本数量,再通过kubectl apply来应用下变更就可以了。

编辑target/app.yaml并应用更改,将副本数从1扩展到5。

$ grep replicas target/app.yaml
replicas: 5

$ kubectl apply -f target/app.yaml
service/helidon-quickstart-se unchanged
deployment.extensions/helidon-quickstart-se configured

之前只有1个Pod,现在我们能看到部署了5个。由于Kubernetes采用的是声明式的配置,只有必需的变更才会提交到集群上。在这个case中,会往部署中新增4个Pod。

 

$ kubectl get pods
NAME                                     READY      STATUS    RESTARTS
helidon-quickstart-se-786bd599ff-5gm29   1/1        Running   0
helidon-quickstart-se-786bd599ff-fkg8g   1/1        Running   0
helidon-quickstart-se-786bd599ff-g7945   1/1        Running   0
helidon-quickstart-se-786bd599ff-h6c5n   1/1        Running   0
helidon-quickstart-se-786bd599ff-n874p   1/1        Running   0

缩容也很简单,再修改下部署的定义然后应用下变更:

$ grep replicas target/app.yaml
replicas: 2
$ kubectl apply -f target/app.yaml
service/helidon-quickstart-se unchanged
deployment.extensions/helidon-quickstart-se configured

$ kubectl get pods
NAME        READY       STATUS    RESTARTS
helidon-quickstart-se-786bd599ff-h6c5n      1/1     Running   0
helidon-quickstart-se-786bd599ff-n874p  1/1     Running   0

Kubernetes还有不少更高级的扩展功能,比如Pod水平自动伸缩(Horizontal Pod Autoscaling),以及在托管云平台上按需自动伸缩节点资源。

最后

你还可以继续尝试一下Kubernetes的其它更高级的功能,不过这已经超出本文的范围了。可以看一下它的官方文档来了解一下。

服务使用完之后,可以通过kubectl delete将它从集群中删除:

$ kubectl delete service helidon-quickstart-se
service "helidon-quickstart-se" deleted
$ kubectl delete deployment helidon-quickstart-se
deployment.extensions "helidon-quickstart-se" deleted

除了丰富的文档,Kubernetes还有很多免费的在线学习课程。它的社区也非常活跃,帮助很大。。

总结

容器化是微服务部署的一层很好的抽象。它能将服务及宿主环境进行解耦,使之具备可移植性和可伸缩性。从本文中也能看出,Kubernetes使得大规模的容器管理成为了可能。

当然了,这只是开始。你可以从它的文档中了解到更高级的一些功能。欢迎来到Kubernetes的世界!欢迎参考此文资料内容