Kubernetes 与 Spring 教程

Kubernetes简介

Kubernetes (k8s) 是一个用于自动管理、扩展和部署容器化应用程序的开源系统。

随着微服务的兴起,我们需要一个工具来部署这些独立的应用程序。像 docker 这样的容器非常适合它。他们为交付微服务提供了一个工作环境。

随着微服务的增加,容器的数量也在增加。使用脚本管理这些容器变得很困难。这个问题导致了容器编排工具的创建。 Kubernetes 就是这种需求的答案。

Kubernetes的组件

ComponentOfKubernates.png

个节点

Kubernetes 是容器化应用程序的解决方案。其中一个容器可能是 docker,但还有许多其他容器解决方案可用。为了管理这些容器,我们需要一个与不同供应商无缝对话的抽象层。

Pod 可以被认为是 Kubernetes 的一个工作单元。一个 pod 可以有一个或多个容器。

服务

Kubernetes 上的每个节点都分配了一个 IP。虽然节点中的 pod 可以使用 IP 相互通信,但节点是短暂的。 它们随时可能死亡。每当一个节点死亡时,Kubernetes 都会在其位置创建另一个节点以保持所需的状态。 _**_新的 pod 将分配一个新的 IP。这将在 Pod 通过 IP 交互时产生问题。

为了解决这个问题,Kubernetes 创建了一个分配给 pod 的服务,它们将使用服务而不是 IP 进行交互。即使附加的 ip 发生变化,服务也将保持不变。

控制平面

我们知道 Kubernetes 是关于容器管理的,为了管理它,我们需要一些组件。如果组合在一起,这些有助于有效管理容器的组件将被称为控制平面。

让我们看看构成控制平面的组件。

API网关

顾名思义,它提供了与所有节点交互的网关及其与外部世界的端口。从集群外部到 Pod 的任何通信都可以通过 API 网关进行。

调度器

为了在 pod 死亡时管理所需的状态,我们需要一种机制来检查集群上的状态,并在需要时调度新的 pod。这是从控制平面运行的调度程序的工作。

控制管理器

控制平面中的所有组件都由控制器进程管理。有不同的控制器,如 Node、Jobs、Endpoints、Service 和 Token 控制器。所有这些组合在一起称为控制管理中心。

为了有效地管理,我们需要某种内存。 etcd 充当所有配置映射和机密的数据库。

部署

为了在 Kubernetes 上部署任何东西,我们创建了一个部署对象,它是一个 YAML 文件。它包含与容器映像、其位置以及与 pod 对应的元数据相关的所有信息

服务

Service 是另一个 YAML 文件,其中包含节点通信和服务所需的协议配置。

配置图

通过 pod 部署的应用程序需要许多配置,如果我们将它们保留在 pod 中,我们将不得不为每次更改构建映像

秘密

很多配置都是机密,比如数据库密码,我们不能透露。我们可以将它们保存为秘密而不是纯文本。 Kubernetes 不控制加密机制,但这些秘密作为加密文本保存在 etcd 数据库中。

将示例 Spring Boot 应用程序部署到 Kubernetes

将示例 Spring Boot 应用程序部署到 Kubernetes

现在了解了 Kubernetes 的基本构建块,让我们尝试创建一个应用程序并将其部署到 Kubernetes 上。首先,我们将转到https://start.sprting。io 并创建一个简单的应用程序其中一个端点。我们只会选择响应式 Web 作为依赖项。

我们将创建一个带有 get 端点的端点,端点将通过查询字符串获取一个字符串并欢迎用户。

@RestController
public class SpringK8SDemoController {

    @GetMapping("/welcome")
    public Mono<String> welcome (@RequestParam("name") String param){
        return  Mono.just("Welcome "+ param);
    }
}

在我们创建容器化 docker 文件之前,让我们在 pom.xml k8s-demo 中创建最终的 jar 文件

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        **<finalName>k8s-demo</finalName>**
    </build>

现在我们需要将应用程序容器化。我们将使用 docker 容器。让我们添加一个名为 Dockerfile. 的文件。我们将它添加到项目的根目录中。

FROM openjdk:17-jdk-alpine
EXPOSE 8080
ARG JAR_FILE=target/k8s-demo.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

该文件是不言自明的,它将 OpenJDK 17 添加到容器中并使用 8080 端口进行公开。它只是将文件复制到目标目录并将其命名为 app.jar。最后,它以命令作为入口点开始,即 java -jar app.jar。

让我们构建 docker 镜像并运行它来验证。

mvn clean install
cd target
docker build -t codingsaint/k8s-demo
docker run -p 9090:8080 k8s-demo

该应用程序应该运行,如果您发送 HTTP 请求http://localhost:9090/welcome?nameu003dPallav,它应该响应为 welcome Pallav

Spring Boot 使用部署对象部署

在 Kubernetes 中,我们使用 YAML 格式的配置文件进行部署。配置的标准文件称为部署。让我们创建一个如下的部署文件,我们将讨论它的内容。

让我们在 spring boot 项目的根目录下创建一个 deployment.yaml 文件。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8s-demo

spec:
  selector:
    matchLabels:
      app: k8s-demo
  replicas: 3
  template:
    metadata:
      labels:
        app: k8s-demo
    spec:
      containers:
        - name: k8s-demo
          image: k8s-demo:0.0.1-SNAPSHOT
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080

在上面的文件中,我们使用metadata.name创建了一个类部署对象,命名为 k8s-demo。在规范级别,我们定义应用程序 k8s-demo 应该有 3 个副本

在 spec.selector.spec.container 我们定义容器属性。使用 imagePullPolicy 作为 IfNotPresent 它将首先查看本地 docker 图像,然后查看远程。

服务对象

正如我们讨论 pod 的通信一样,我们需要附加到 pod 的服务。 Kubernetes 中的服务对象可以使用 YAML 文件创建。让我们回顾一下服务文件的内容。我们在根目录下创建这个文件,我们把它命名为 k8s-demo-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: k8s-demo-svc
spec:
  selector:
    app: k8s-demo
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
  type: NodePort

如果您看到 spec ,它清楚地表明选择(选择器)应用程序 k8s-demo。它还告诉协议是TCP。

部署到 Kubernetes 集群

启动 Minikube

minikube start

您应该得到如下输出

PS C:\Users\07pal\development\tutorial\k8s\k8s-demo> minikube start
😄  minikube v1.25.1 on Microsoft Windows 11 Home Single Language 10.0.22000 Build 22000
✨  Using the docker driver based on existing profile
👍  Starting control plane node minikube in cluster minikube
🚜  Pulling base image ...
🔄  Restarting existing docker container for "minikube" ...
🐳  Preparing Kubernetes v1.23.1 on Docker 20.10.12 ...
    ▪ kubelet.housekeeping-interval=5m
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

构建docker镜像

在我们将它部署到集群之前,我们需要 Kubernetes 和 Docker 镜像同步。如果您在 Windows 上,请使用以下命令

minikube docker-env | Invoke-Expression

如果您在 Mac 上,请使用以下内容

eval $(minikube docker-env)

现在我们将从我们创建的 Dockerfile 构建 docker 镜像

docker build -t k8s-demo:0.0.1-SNAPSHOT .

这将创建一个 Docker 映像,我们将使用我们的部署对象进行部署。上面命令的输出应该是这样的

[+] Building 3.4s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 32B                                                                                0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load metadata for docker.io/library/openjdk:17-jdk-alpine                                           3.3s
 => [auth] library/openjdk:pull token for registry-1.docker.io                                                     0.0s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 69B                                                                                   0.0s
 => [1/2] FROM docker.io/library/openjdk:17-jdk-alpine@sha256:4b6abae565492dbe9e7a894137c966a7485154238902f2f25e9  0.0s
 => CACHED [2/2] COPY target/k8s-demo.jar app.jar                                                                  0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:714ae55f7105935be0267470795b5dc890d17c1773b194d5bfda9a45fa2d8b8c                       0.0s
 => => naming to docker.io/library/k8s-demo:0.0.1-SNAPSHOT                                                         0.0s

您可以使用命令验证本地 docker repo 中的图像

码头工人图片

它应该给出类似的输出

REPOSITORY                    TAG              IMAGE ID       CREATED         SIZE
**k8s-demo                      0.0.1-SNAPSHOT   714ae55f7105   5 days ago      346MB**
gcr.io/k8s-minikube/kicbase   v0.0.29          64d09634c60d   5 weeks ago     1.14GB
mysql                         latest           ecac195d15af   3 months ago    516MB
mongo                         latest           fefd78e9381a   3 months ago    699MB
jaegertracing/all-in-one      latest           9844aed41d42   4 months ago    59MB
docker101tutorial             latest           c492a391575a   4 months ago    28.3MB
postgres                      12               91d892a67245   4 months ago    314MB
consul                        latest           b74a0a01afc4   5 months ago    116MB
alpine/git                    latest           b8f176fa3f0d   8 months ago    25.1MB
testcontainers/ryuk           0.3.1            ee7515743e6f   13 months ago   12MB
postgres                      11.5-alpine      da01ecfbabe1   2 years ago     71.8MB
openjdk                       8-jdk-alpine     a3562aa0b991   2 years ago     105MB

在 Kubernetes 上部署

让我们使用我们创建的部署对象将它部署在 Kubernetes 上。

kubectl apply -f .\deployment.yaml

上述命令会将镜像从 docker 发布到 Kubernetes 集群并按照 deployment.yaml 中的说明进行部署。输出应该看起来像

PS C:\Users\07pal\development\tutorial\k8s\k8s-demo> kubectl apply -f .\deployment.yaml
**deployment.apps/k8s-demo created**

我们可以使用以下方法验证我们的 pod 是否已启动并正在运行

kubectl get pods

您将看到 pod 名称作为输出

PS C:\Users\07pal\development\tutorial\k8s\k8s-demo> kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
k8s-demo-675766fff7-92kxk   1/1     Running   0          102s
k8s-demo-675766fff7-grsdm   1/1     Running   0          102s
k8s-demo-675766fff7-z6z4s   1/1     Running   0          102s

如果要检查单个 pod 的日志,可以使用 kubectl logs 作为

kubectl logs  k8s-demo-675766fff7-92kxk

我们可以看到 spring boot 应用程序在集群中运行。下面的输出可以作为证明

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.3)

2022-01-29 08:23:38.136  INFO 1 --- [           main] c.c.k8sdemo.K8sDemoApplication           : Starting K8sDemoApplication v0.0.1-SNAPSHOT using Java 17-ea on k8s-demo-675766fff7-92kxk with PID 1 (/app.jar started by root in /)
2022-01-29 08:23:38.138  INFO 1 --- [           main] c.c.k8sdemo.K8sDemoApplication           : No active profile set, falling back to default profiles: default
2022-01-29 08:23:42.756  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
2022-01-29 08:23:42.824  INFO 1 --- [           main] c.c.k8sdemo.K8sDemoApplication           : Started K8sDemoApplication in 6.006 seconds (JVM running for 7.407)

创建服务

它在集群上运行,我们将无法直接访问它,所以让我们创建一个服务。我们将使用上面创建的服务文件来创建服务

kubectl apply -f .\k8s-demo-svc.yaml

您可以通过 kubectl get svckubectl get service 验证您的服务

kubectl get svc
NAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
k8s-demo-svc   NodePort    10.99.108.29   <none>        8080:31019/TCP   2m15s
kubernetes     ClusterIP   10.96.0.1      <none>        443/TCP          22m

由于我们在 windows 上,甚至 Kubernetes 也在 docker 中运行,我们需要代理来访问 pod,否则在 linux 上我们可以使用集群 IP 和端口 31019(如上所示,对于您的情况会有所不同)。

让我们使用以下命令点击 pod。它将使用代理打开您的浏览器

minikube service k8s-demo-svc

它还将给出以下输出

PS C:\Users\07pal\development\tutorial\k8s\k8s-demo> minikube service k8s-demo-svc
|-----------|--------------|-------------|---------------------------|
| NAMESPACE |     NAME     | TARGET PORT |            URL            |
|-----------|--------------|-------------|---------------------------|
| default   | k8s-demo-svc |        8080 | http://192.168.49.2:31019 |
|-----------|--------------|-------------|---------------------------|
🏃  Starting tunnel for service k8s-demo-svc.
|-----------|--------------|-------------|------------------------|
| NAMESPACE |     NAME     | TARGET PORT |          URL           |
|-----------|--------------|-------------|------------------------|
| default   | k8s-demo-svc |             | **http://127.0.0.1:52260** |
|-----------|--------------|-------------|------------------------|
🎉  Opening service default/k8s-demo-svc in default browser...
❗  Because you are using a Docker driver on windows, the terminal needs to be open to run it.

这里 http://127.0.0.1:52260是您可以访问已部署 Pod 的 URL。所以你可以通过http://127.0.0.1:52260/welcome?messageu003dPallav检查它

它将为您提供适当的输出。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐