通过Skaffold在Kubernetes上进行Spring Boot应用程序的CI / CD工作流


众所周知的事实是,使用Kubernetes开发应用程序很麻烦。这就是为什么围绕它开发生态系统,以便开发人员可以专注于对他们最重要的事情,即编写代码的原因。在本文中,我将介绍由Google开发的另一种工具Skaffold 。

那么到底什么是脚手架?

Skaffold处理构建,推送和部署应用程序的工作流程。- Skaffold.dev

它试图解决什么问题?

如前所述,使用Kubernetes开发应用程序并非易事。这就是Skaffold发挥作用的地方,因为它简化了在Kubernetes上运行的应用程序的开发和部署。它管理着整个工作流程,在本地或在远程Kubernetes集群上开发和部署应用程序时,您会获得即时反馈。

1607395942086.png

以下是使用Skaffold的一些好处。

Lightweight

它仅是一个客户端实用程序,因此无需设置群集或进行任何维护。

容易分享

在您的团队成员之间共享是毫不费力的,因为您只需要执行以下操作即可开始:

git clone
skaffold run

易于发展

为了使您的应用程序甚至在本地容器化,您必须做很多事情。对于本地开发,您可能需要在Kubernetes上进行构建,推送和部署应用程序之类的操作。并且有不同的命令集(docker blah,kubectl blah blah等)以及用于工作流的每个阶段的工具。有了Skaffold,您只有一个神奇的命令,skaffold run or skaffold dev而且您很聪明。这并不意味着您不必依赖那些需要将应用程序构建和部署到Kubernetes的工具。只需运行一个命令,开发就会容易得多。

好的。足够的理论,让我们开始吧。

Spring Boot应用程序剖析

在本教程中,我将使用一个Spring Boot应用程序,当通过/statesREST端点访问该应用程序时,该应用程序将显示印度各州及其首都。该应用程序使用内存中的H2数据库,该数据库在应用程序的开头插入行并将其保存在内存中。源代码可在此处获得。

先决条件

对于此演示,必须安装以下内容:

  1. 安装脚手架。
  2. 安装Mac的Docker桌面。
  3. 安装kubectl(可选)。
  4. Minikube(可选)。

我使用过macOS,但是您可以使用任何喜欢的操作系统或有使用经验的操作系统。我已经提到过Minikube和kubetcl安装是可选的,因为如果您已经安装了Docker桌面,则可以使用其他博客文章中提到的步骤来启用Kubernetes 。

如果您不想在安装过程中闲逛,则可以跳过上述步骤,而改用Google Cloud Shell,它可以从浏览器提供开发人员就绪的环境。我已经在文章末尾介绍了这一点。

脚手架入门 要开始使用Skaffold,您需要一个skaffold.yaml文件。为此,我们可以运行以下命令。

skaffold init

但是,您会收到以下错误消息。

skaffold init
2
one or more valid builder configuration (Dockerfile or Jib configuration) must be present to build images with skaffold; please provide at least one build config and try again or run `skaffold init --skip-build`

该错误似乎是不言自明的。它告诉我们Skaffold正在项目中寻找Dockerfile或Jib配置。

Skaffold当前支持以下构建器:

  1. Docker
  2. Jib (with the --XXenableJibInit flag)
  3. Buildpacks (with the --XXenableBuildpacksInit flag) 因此,要解决此错误,我将在pom.xml文件中添加Jib Maven插件。如果您想知道Jib是什么以及它的用途,可以阅读我的上一篇文章。您可以通过将以下内容复制/粘贴到pom.xml文件中来启用Jib支持。

XML格式

<plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>jib-maven-plugin</artifactId>
        <version>2.7.0</version>
        <configuration>
            <from>
                <image>gcr.io/distroless/java:11</image>
            </from>
            <to>
                <image>docker.io/my-docker-id/my-app</image>
            </to>
        </configuration>
</plugin>

启用Jib支持

根据官方文件:

skaffold init还可以识别Maven和Gradle项目,并将自动建议jib建造者。当前,jib工件检测默认情况下处于禁用状态,但可以使用标志启用--XXenableJibInit。 现在运行skaffold init与--XXenableJibInit.然而,它会与下面的错误再次失败。

skaffold init --XXenableJibInit
one or more valid Kubernetes manifests are required to run skaffold

由于我们尚未创建Kubernetes清单(部署,pod,服务等),并且Skaffold存在已知问题,因此我们必须使用以下kubectl命令手动创建它们,以解决此错误,

创建部署:

kubectl create deployment states --image=docker.io/hiashish/indian-states --dry-run -oyaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: states
  name: states
spec:
  replicas: 1
  selector:
    matchLabels:
      app: states
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: states
    spec:
      containers:
        - image: docker.io/hiashish/indian-states
          name: indian-states
          resources: {}
status: {}

创建服务:

kubectl expose deployment states --type=NodePort --port=8080 --dry-run -oyaml     
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: states
  name: states
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: states
  type: NodePort
status:
  loadBalancer: {}

现在,我们已经创建了部署和服务。请确保将以上命令的输出复制到目录中的YAML文件中k8s。

现在运行 skaffold init --XXenableJibInit

skaffold init --XXenableJibInit
apiVersion: skaffold/v2beta10
kind: Config
metadata:
  name: indian-states
build:
  artifacts:
  - image: docker.io/hiashish/indian-states
    jib:
      project: com.example:indian-states
deploy:
  kubectl:
    manifests:
    - k8s/mydeployment.yaml
    - k8s/myservice.yaml
Do you want to write this configuration to skaffold.yaml? [y/n]: y
Configuration skaffold.yaml was written
You can now run [skaffold build] to build the artifacts
or [skaffold run] to build and deploy
or [skaffold dev] to enter development mode, with auto-redeploy

最后,skaffold.yaml创建一个文件。

使用skaffold dev命令 现在,我们已经完成了必需的设置,以开始持续构建和部署Kubernetes应用程序。现在,我们只需运行以下命令即可在本地启动CI / CD工作流程。

skaffold dev
Listing files to watch...
 - docker.io/hiashish/indian-states
Generating tags...
 - docker.io/hiashish/indian-states -> docker.io/hiashish/indian-states:31ff588-dirty
Checking cache...
 - docker.io/hiashish/indian-states: Found Locally
Tags used in deployment:
 - docker.io/hiashish/indian-states -> docker.io/hiashish/indian-states:43f7c470a60b876c7579ed3041b64024b774e9808851ad83b6817701d0188cc5
Starting deploy...
 - deployment.apps/states created
 - service/states created
Waiting for deployments to stabilize...
 - deployment/states is ready.
Deployments stabilized in 3.986641128s
Press Ctrl+C to exit
Watching for changes...
[indian-states] 
[indian-states]   .   ____          _            __ _ _
[indian-states]  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
[indian-states] ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
[indian-states]  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
[indian-states]   '  |____| .__|_| |_|_| |_\__, | / / / /
[indian-states]  =========|_|==============|___/=/_/_/_/
[indian-states]  :: Spring Boot ::                (v2.4.0)
[indian-states] 
[indian-states] 2020-12-07 12:31:57.906  INFO 1 --- [           main] c.e.i.IndianStatesApplication            : Starting IndianStatesApplication using Java 11.0.6 on states-7c55b8d5b6-vx5hq with PID 1 (/app/classes started by root in /)
[indian-states] 2020-12-07 12:31:57.924  INFO 1 --- [           main] c.e.i.IndianStatesApplication            : No active profile set, falling back to default profiles: default
[indian-states] 2020-12-07 12:32:00.127  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
[indian-states] 2020-12-07 12:32:00.175  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 24 ms. Found 0 JDBC repository interfaces.
[indian-states] 2020-12-07 12:32:01.969  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
[indian-states] 2020-12-07 12:32:02.015  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
[indian-states] 2020-12-07 12:32:02.016  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.39]
[indian-states] 2020-12-07 12:32:02.242  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
[indian-states] 2020-12-07 12:32:02.243  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 4107 ms
[indian-states] 2020-12-07 12:32:03.449  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
[indian-states] 2020-12-07 12:32:04.078  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
[indian-states] 2020-12-07 12:32:04.880  INFO 1 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
[indian-states] 2020-12-07 12:32:05.939  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
[indian-states] 2020-12-07 12:32:06.002  INFO 1 --- [           main] c.e.i.IndianStatesApplication            : Started IndianStatesApplication in 9.688 seconds (JVM running for 11.632)

如您所见,该应用程序现已构建并部署到本地Kubernetes集群。我们首先必须NodePort使用kubectl命令来检查应用程序的本地访问应用程序。

kubectl get all 
NAME                          READY   STATUS    RESTARTS   AGE
pod/states-7c55b8d5b6-vx5hq   1/1     Running   0          5m47s
NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          21h
service/states       NodePort    10.110.135.236   <none>        8080:30925/TCP   5m47s
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/states   1/1     1            1           5m48s
NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/states-7c55b8d5b6   1         1         1       5m48s

该NodePort分配给我们的应用程序是30925.让我们调用/states我们的应用程序的REST端点,并看看会发生什么。

curl localhost:30925/states
[{"name":"Andra Pradesh","capital":"Hyderabad"},{"name":"Arunachal Pradesh","capital":"Itangar"},{"name":"Assam","capital":"Dispur"},{"name":"Bihar","capital":"Patna"},{"name":"Chhattisgarh","capital":"Raipur"},{"name":"Goa","capital":"Panaji"},{"name":"Gujarat","capital":"Gandhinagar"},{"name":"Haryana","capital":"Chandigarh"},{"name":"Himachal Pradesh","capital":"Shimla"},{"name":"Jharkhand","capital":"Ranchi"},{"name":"Karnataka","capital":"Bangalore"},{"name":"Kerala","capital":"Thiruvananthapuram"},{"name":"Madhya Pradesh","capital":"Bhopal"},{"name":"Maharashtra","capital":"Mumbai"},{"name":"Manipur","capital":"Imphal"},{"name":"Meghalaya","capital":"Shillong"},{"name":"Mizoram","capital":"Aizawi"},{"name":"Nagaland","capital":"Kohima"},{"name":"Orissa","capital":"Bhubaneshwar"},{"name":"Rajasthan","capital":"Jaipur"},{"name":"Sikkim","capital":"Gangtok"},{"name":"Tamil Nadu","capital":"Chennai"},{"name":"Telangana","capital":"Hyderabad"},{"name":"Tripura","capital":"Agartala"},{"name":"Uttaranchal","capital":"Dehradun"},{"name":"Uttar Pradesh","capital":"Lucknow"},{"name":"West Bengal","capital":"Kolkata"},{"name":"Punjab","capital":"Chandigarh"}]

看起来很棒!

让我们做一个小的代码更改,看看Skaffold是否可以重新触发整个工作流程。我将replicas在部署YAML文件中从1更改为2,看看Skaffold是否可以使用增加的来重新部署应用程序replicas。

已重新部署应用程序:

Tags used in deployment:
 - docker.io/hiashish/indian-states -> docker.io/hiashish/indian-states:43f7c470a60b876c7579ed3041b64024b774e9808851ad83b6817701d0188cc5
Starting deploy...
 - deployment.apps/states configured
Waiting for deployments to stabilize...
 - deployment/states is ready.
Deployments stabilized in 4.032230153s
Watching for changes...
[indian-states] 
[indian-states]   .   ____          _            __ _ _
[indian-states]  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
[indian-states] ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
[indian-states]  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
[indian-states]   '  |____| .__|_| |_|_| |_\__, | / / / /
[indian-states]  =========|_|==============|___/=/_/_/_/
[indian-states]  :: Spring Boot ::                (v2.4.0)
[indian-states]

现在,replicaset使用再次检查我们的应用程序kubectl。

kubectl get all            
NAME                          READY   STATUS    RESTARTS   AGE
pod/states-7c55b8d5b6-br9zx   1/1     Running   0          20s
pod/states-7c55b8d5b6-vx5hq   1/1     Running   0          16m
NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          21h
service/states       NodePort    10.110.135.236   <none>        8080:30925/TCP   16m
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/states   2/2     2            2           16m

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/states-7c55b8d5b6   2         2         2       16m

如您所见,重新部署后,副本数增加到了2个,这是预期的。

skaffold runCommand

这类似于skaffold dev,但是主要区别在于中描述的工作流程skaffold.yaml 仅执行一次。建议将其用于生产工作流程。

使用Cloud Shell

如果您在本地安装了所有必需的依赖项(Docker,Minikube,Skaffold),那就很好了。否则,您可以通过使用Google的Cloud Shell复制本地Kubernetes环境来跳过安装部分,就像我在先决条件部分中所述的那样。Cloud Shell提供了基于浏览器的终端/ CLI和编辑器,并且预先安装了Skaffold,Minikube和Docker,并且它是免费的。只需运行以下命令即可。确保Docker和Minikube在Cloud Shell环境中启动并运行。

git clone https://github.com/yrashish/indian-states

skaffold dev

如您在上面看到的,我们还可以在Cloud Shell中运行Spring Boot应用程序,并获得了预期的输出。


原文链接:http://codingdict.com