Running Spring Boot Applications With Minikube – 用Minikube运行Spring Boot应用程序

最后修改: 2018年 5月 2日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this previous article, we covered a theoretical introduction about Kubernetes.

在这篇上篇文章中,我们介绍了关于Kubernetes的理论介绍。

In this tutorial, we’ll discuss how to deploy a Spring Boot application on a local Kubernetes environment, also known as Minikube.

在本教程中,我们将讨论如何在本地Kubernetes环境(也称为Minikube)上部署一个Spring Boot应用程序。

As part of this article, we’ll:

作为本文的一部分,我们将。

  • Install Minikube on our local machine
  • Develop an example application consisting of two Spring Boot services
  • Set up the application on a one-node cluster using Minikube
  • Deploy the application using config files

2. Installing Minikube

2.安装Minikube

The installation of Minikube basically consists of three steps: installing a Hypervisor (like VirtualBox), the CLI kubectl, as well as Minikube itself.

Minikube的安装基本上包括三个步骤:安装一个Hypervisor(如VirtualBox),CLI kubectl,以及Minikube本身。

The official documentation provides detailed instructions for each of the steps, and for all popular operating systems.

官方文档提供了每个步骤的详细说明,并适用于所有流行的作业系统。

After completing the installation, we can start Minikube, set VirtualBox as Hypervisor, and configure kubectl to talk to the cluster called minikube:

完成安装后,我们可以启动Minikube,将VirtualBox设置为Hypervisor,并配置kubectl与名为minikube的集群对话。

$> minikube start
$> minikube config set vm-driver virtualbox
$> kubectl config use-context minikube

After that, we can verify that kubectl communicates correctly with our cluster:

之后,我们可以验证kubectl与我们的集群正确通信。

$> kubectl cluster-info

The output should look like this:

输出应该看起来像这样。

Kubernetes master is running at https://192.168.99.100:8443
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

At this stage, we’ll keep the IP in the response close (192.168.99.100 in our case). We’ll later refer to that as NodeIP, which is needed to call resources from outside of the cluster, e. g. from our browser.

在这个阶段,我们将保持响应中的IP关闭(192.168.99.100在我们的例子中)。我们以后会把它称为NodeIP,这是从集群外部调用资源时需要的,例如从我们的浏览器。

Finally, we can inspect the state of our cluster:

最后,我们可以检查我们集群的状态。

$> minikube dashboard

This command opens a site in our default browser, which provides an extensive overview about the state of our cluster.

这个命令在我们的默认浏览器中打开一个网站,它提供了关于我们集群状态的广泛概述。

4. Demo Application

4.演示应用程序

As our cluster is now running and ready for deployment, we need a demo application.

由于我们的集群现在正在运行并准备部署,我们需要一个演示应用程序。

For this purpose, we’ll create a simple “Hello world” application, consisting of two Spring Boot services, which we’ll call frontend and backend.

为此,我们将创建一个简单的 “Hello world “应用程序,由两个Spring Boot服务组成,我们将称之为frontendbackend

The backend provides one REST endpoint on port 8080, returning a String containing its hostname. The frontend is available on port 8081, it will simply call the backend endpoint and return its response.

后台在8080端口提供一个REST端点,返回一个包含其主机名的String。前端在8081端口提供,它将简单地调用后端端点并返回其响应。

After that, we have to build a Docker image from each app. All files necessary for that are also available on GitHub.

之后,我们必须从每个应用程序中构建一个Docker镜像。为此所需的所有文件也可以在GitHub上找到

For detailed instructions how to build Docker images, have a look at Dockerizing a Spring Boot Application.

关于如何构建Docker镜像的详细说明,请看Dockerizing a Spring Boot Application

We have to make sure here that we trigger the build process on the Docker host of the Minikube cluster, otherwise, Minikube won’t find the images later during deployment. Furthermore, the workspace on our host must be mounted into the Minikube VM:

在这里我们必须确保在Minikube集群的Docker主机上触发构建过程,否则,Minikube在以后的部署过程中不会找到这些图像。此外,我们主机上的工作空间必须被挂载到Minikube虚拟机中。

$> minikube ssh
$> cd /c/workspace/tutorials/spring-cloud/spring-cloud-kubernetes/demo-backend
$> docker build --file=Dockerfile \
  --tag=demo-backend:latest --rm=true .

After that, we can logout from the Minikube VM, all further steps will be executed on our host using kubectl and minikube command-line tools.

之后,我们可以注销Minikube虚拟机,所有进一步的步骤将在我们的主机上使用kubectlminikube命令行工具执行。

5. Simple Deployment Using Imperative Commands

5.使用强制命令的简单部署

In a first step, we’ll create a Deployment for our demo-backend app, consisting of only one Pod. Based on that, we’ll discuss some commands so we can verify the Deployment, inspect logs, and clean it up at the end.

第一步,我们将为我们的demo-backend应用程序创建一个部署,只由一个Pod组成。在此基础上,我们将讨论一些命令,以便我们能够验证部署,检查日志,并在最后清理它。

5.1. Creating the Deployment

5.1.创建部署

We’ll use kubectl, passing all required commands as arguments:

我们将使用kubectl,将所有需要的命令作为参数传递。

$> kubectl run demo-backend --image=demo-backend:latest \
  --port=8080 --image-pull-policy Never

As we can see, we create a Deployment called demo-backend, which is instantiated from an image also called demo-backend, with version latest.

我们可以看到,我们创建了一个名为demo-backend的部署,它是从一个也叫demo-backend的镜像中实例化出来的,版本为latest

With –port, we specify, that the Deployment opens port 8080 for its Pods (as our demo-backend app listens to port 8080).

通过-port,我们指定部署为其Pod打开8080端口(因为我们的demo-backend应用程序监听8080端口)。

The flag –image-pull-policy Never ensures, that Minikube doesn’t try to pull the image from a registry, but takes it from the local Docker host instead.

标志-image-pull-policy Never确保Minikube不会尝试从注册表中提取镜像,而是从本地Docker主机中获取。

5.2. Verifying the Deployment

5.2.验证部署

Now, we can check whether the deployment was successful:

现在,我们可以检查部署是否成功。

$> kubectl get deployments

The output looks like this:

输出看起来像这样。

NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
demo-backend   1         1         1            1           19s

If we want to have a look at the application logs, we need the Pod ID first:

如果我们想看一下应用程序的日志,我们首先需要Pod ID。

$> kubectl get pods
$> kubectl logs <pod id>

5.3. Creating a Service for the Deployment

5.3.为部署工作创建服务

To make the REST endpoint of our backend app available, we need to create a Service:

为了使我们后端应用程序的REST端点可用,我们需要创建一个服务:

$> kubectl expose deployment demo-backend --type=NodePort

–type=NodePort makes the Service available from outside of the cluster. It will be available at <NodeIP>:<NodePort>, i. e. the service maps any request incoming at <NodePort> to port 8080 of its assigned Pods.

-type=NodePort使得服务可以从集群外使用。它将在<NodeIP>:<NodePort>上可用,也就是说,该服务将任何从<NodePort>传入的请求映射到其分配的Pod的8080端口。

We use the expose command, so NodePort will be set by the cluster automatically (this is a technical limitation), the default range is 30000-32767. To get a port of our choice, we can use a configuration file, as we’ll see in the next section.

我们使用expose命令,所以NodePort将由集群自动设置(这是一个技术限制),默认范围是30000-32767。为了得到我们选择的端口,我们可以使用一个配置文件,我们将在下一节看到。

We can verify that the service was created successfully:

我们可以验证该服务已成功创建。

$> kubectl get services

The output looks like this:

输出看起来像这样。

NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
demo-backend   NodePort    10.106.11.133   <none>        8080:30117/TCP   11m

As we can see, we have one Service called demo-backend, of type NodePort, which is available at the cluster-internal IP 10.106.11.133.

我们可以看到,我们有一个名为demo-backend的服务,类型为NodePort,它在集群内部的IP 10.106.11.133上可用。

We have to take a closer look at column PORT(S): as port 8080 was defined in the Deployment, the Service forwards traffic to this port. However, if we want to call the demo-backend from our browser, we have to use port 30117, which is reachable from outside of the cluster.

我们必须仔细看看PORT(S)列:由于端口8080是在部署中定义的,服务将流量转发到这个端口。然而,如果我们想从我们的浏览器中调用demo-backend,我们必须使用30117端口,这是从集群外部可以到达的。

5.4. Calling the Service

5.4.调用服务

Now, we can call our backend service for the first time:

现在,我们可以第一次调用我们的后端服务。

$> minikube service demo-backend

This command will start our default browser, opening <NodeIP>:<NodePort>. In our example, that would be http://192.168.99.100:30117.

这个命令将启动我们的默认浏览器,打开<NodeIP>:<NodePort>.在我们的例子中,这将是http://192.168.99.100:30117

5.5. Cleaning up Service and Deployment

5.5.清理服务和部署

Afterward, we can remove Service and Deployment:

之后,我们可以删除服务和部署。

$> kubectl delete service demo-backend
$> kubectl delete deployment demo-backend

6. Complex Deployment Using Configuration Files

6.使用配置文件的复杂部署

For more complex setups, configuration files are a better choice, instead of passing all parameters via command line arguments.

对于更复杂的设置,配置文件是一个更好的选择,而不是通过命令行参数传递所有参数。

Configurations files are a great way of documenting our deployment, and they can be versioned controlled.

配置文件是记录我们的部署的一个很好的方式,而且它们可以被版本控制。

6.1. Service Definition for Our Backend App

6.1.我们的后端应用程序的服务定义

Let’s redefine our service for the backend using a config file:

让我们用一个配置文件来重新定义我们的后端服务。

kind: Service
apiVersion: v1
metadata:
  name: demo-backend
spec:
  selector:
    app: demo-backend
  ports:
  - protocol: TCP
    port: 8080
  type: ClusterIP

We create a Service named demo-backend, indicated by the metadata: name field.

我们创建一个名为Servicedemo-backend,由metadata: name字段表示。

It targets TCP port 8080 on any Pod with the app=demo-backend label.

它的目标是任何带有app=demo-backend标签的Pod上的TCP 8080端口。

Finally, type: ClusterIP indicates that it is only available from inside of the cluster (as we want to call the endpoint from our demo-frontend app this time, but not directly from a browser anymore, as in the previous example).

最后,type:ClusterIP表示它只在集群内部可用(因为我们这次想从我们的demo-frontend应用程序中调用端点,而不是像前面的例子那样直接从浏览器调用)。

6.2. Deployment Definition for Backend App

6.2.后端应用程序的部署定义

Next, we can define the actual Deployment:

接下来,我们可以定义实际的部署。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-backend
spec:
  selector:
      matchLabels:
        app: demo-backend
  replicas: 3
  template:
    metadata:
      labels:
        app: demo-backend
    spec:
      containers:
        - name: demo-backend
          image: demo-backend:latest
          imagePullPolicy: Never
          ports:
            - containerPort: 8080

We create a Deployment named demo-backend, indicated by the metadata: name field.

我们创建一个名为Deploymentdemo-backend,由metadata: name字段表示。

The spec: selector field defines how the Deployment finds which Pods to manage. In this case, we merely select on one label defined in the Pod template (app: demo-backend).

spec: selector字段定义了部署如何找到要管理的Pod。在这种情况下,我们只是选择Pod模板中定义的一个标签(app: demo-backend)。

We want to have three replicated Pods, which we indicate by the replicas field.

我们希望有三个复制的Pod,我们用replicas字段表示。

The template field defines the actual Pod:

模板字段定义了实际的Pod。

  • The Pods are labeled as app: demo-backend
  • The template: spec field indicates that each Pod replication runs one container, demo-backend, with version latest
  • The Pods open port 8080

6.3. Deployment of the Backend App

6.3.后台应用程序的部署

We can now trigger the deployment:

我们现在可以触发部署。

$> kubectl create -f backend-deployment.yaml

Let’s verify that the deployment was successful:

让我们验证一下部署是否成功。

$> kubectl get deployments

The output looks like this:

输出看起来像这样。

NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
demo-backend   3         3         3            3           25s

We can also check whether the Service is available:

我们还可以检查该服务是否可用。

$> kubectl get services

The output looks like this:

输出看起来像这样。

NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
demo-backend    ClusterIP   10.102.17.114   <none>        8080/TCP         30s

As we can see, the Service is of type ClusterIP, and it doesn’t provide an external port in the range 30000-32767, different from our previous example in section 5.

我们可以看到,服务的类型是ClusterIP,它没有提供30000-32767范围内的外部端口,这与我们之前在第5节的例子不同。

6.4. Deployment and Service Definition for Our Frontend App

6.4.我们的前端应用程序的部署和服务定义

After that, we can define Service and Deployment for the frontend:

之后,我们可以为前台定义服务和部署。

kind: Service
apiVersion: v1
metadata:
  name: demo-frontend
spec:
  selector:
    app: demo-frontend
  ports:
  - protocol: TCP
    port: 8081
    nodePort: 30001
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-frontend
spec:
  selector:
      matchLabels:
        app: demo-frontend
  replicas: 3
  template:
    metadata:
      labels:
        app: demo-frontend
    spec:
      containers:
        - name: demo-frontend
          image: demo-frontend:latest
          imagePullPolicy: Never
          ports:
            - containerPort: 8081

Both frontend and backend are almost identical, the only difference between backend and frontend is the spec of the Service:

前台和后台几乎都是一样的,后台和前台的唯一区别是服务的规格

For the frontend, we define the type as NodePort (as we want to make the frontend available to outside of the cluster). The backend only has to be reachable from within the cluster, therefore, the type was ClusterIP.

对于前端,我们将类型定义为NodePort(因为我们想让前端在集群外可用)。后端只需要在集群内可以到达,因此,类型ClusterIP

As said before, we also specify NodePort manually, using the nodePort field.

如前所述,我们也可以使用nodePort字段,手动指定nodePort

6.5. Deployment of the Frontend App

6.5.前端应用程序的部署

We can now trigger this deployment the same way:

我们现在可以用同样的方式触发这个部署。

$> kubectl create -f frontend-deployment.yaml

Let’s quickly verify that the deployment was successful and the Service is available:

让我们快速验证一下部署是否成功,服务是否可用。

$> kubectl get deployments
$> kubectl get services

After that, we can finally call the REST endpoint of the frontend application:

之后,我们终于可以调用前端应用程序的REST端点。

$> minikube service demo-frontend

This command will again start our default browser, opening <NodeIP>:<NodePort>, which is http://192.168.99.100:30001 for this example.

这个命令将再次启动我们的默认浏览器,打开<NodeIP>:<NodePort>,在这个例子中是http://192.168.99.100:30001

6.6. Cleaning up Services and Deployments

6.6.清理服务和部署

In the end, we can clean up by removing Services and Deployments:

最后,我们可以通过删除服务和部署来进行清理。

$> kubectl delete service demo-frontend
$> kubectl delete deployment demo-frontend
$> kubectl delete service demo-backend
$> kubectl delete deployment demo-backend

7. Conclusion

7.结论

In this article, we had a quick look at how to deploy a Spring Boot “Hello world” app on a local Kubernetes cluster using Minikube.

在这篇文章中,我们快速了解了如何使用Minikube在本地Kubernetes集群上部署Spring Boot “Hello world “应用。

We discussed in detail, how to:

我们详细讨论了,如何。

  • Install Minikube on our local machine
  • Develop and build an example consisting of two Spring Boot apps
  • Deploy the services on a one-node cluster, using imperative commands with kubectl as well as configuration files

As always, the full source code of the examples is available over on GitHub.

一如既往,这些示例的完整源代码可在GitHub上获得over