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

你好spring-cloud-kubernetes

程序员文章站 2022-06-22 10:50:57
关于spring cloud kubernetes spring cloud kubernetes是springcloud官方推出的开源项目,用于将Spring Cloud和Spring Boot应用运行在kubernetes环境,并且提供了通用的接口来调用kubernetes服务,GitHub上官 ......

关于spring-cloud-kubernetes

spring-cloud-kubernetes是springcloud官方推出的开源项目,用于将spring cloud和spring boot应用运行在kubernetes环境,并且提供了通用的接口来调用kubernetes服务,github上官方地址是:https://github.com/spring-cloud/spring-cloud-kubernetes

该项目的提交者之一,就是springcloud的作者之一spencer gibb:
你好spring-cloud-kubernetes

系列文章列表

本文是《spring-cloud-kubernetes实战系列》的第二篇,全文链接如下:

  1. 《spring-cloud-kubernetes与springcloud gateway》

通过官方demo来了解spring-cloud-kubernetes

spring-cloud-kubernetes项目也提供了丰富的官方demo来帮助开发者了解和学习spring-cloud-kubernetes,您可以参考快速体验官方demo;

实战spring-cloud-kubernetes

今天实战的内容是开发一个简单的java应用,然后将其部署在kubernetes环境(minikube 1.1.1),该应用通过spring-cloud-kubernetes调用当前kubernetes的服务;

环境信息

本次实战的环境和版本信息如下:

  1. 操作系统:centos linux release 7.6.1810
  2. minikube:1.1.1
  3. java:1.8.0_191
  4. maven:3.6.0
  5. fabric8-maven-plugin插件:3.5.37
  6. spring-cloud-kubernetes:1.0.1.release

上面的linux、minikube、java、maven,请确保已准备好,linux环境下minikube的安装和启动请参考《linux安装minikube指南 》

准备工作已经ok,开始编码吧。

源码下载

如果您不打算写代码,也可以从github上下载本次实战的源码,地址和链接信息如下表所示:

名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在github上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议


这个git项目中有多个文件夹,本章源码在springcloudk8sdiscovery这个文件夹下,如下图红框所示:
你好spring-cloud-kubernetes

开发应用

  1. 基于maven创建一个springboot应用,名为springcloudk8sdiscovery
  2. 该应用完整的pom.xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
         xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelversion>4.0.0</modelversion>
    <parent>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-parent</artifactid>
        <version>2.1.1.release</version>
        <relativepath/> <!-- lookup parent from repository -->
    </parent>
    <groupid>com.bolingcavalry</groupid>
    <artifactid>springcloudk8sdiscovery</artifactid>
    <version>0.0.1-snapshot</version>
    <name>springcloudk8sdiscovery</name>
    <description>demo project for spring boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-boot.version>2.1.1.release</spring-boot.version>
        <maven-compiler-plugin.version>3.5</maven-compiler-plugin.version>
        <maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
        <maven-failsafe-plugin.version>2.18.1</maven-failsafe-plugin.version>
        <maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
        <fabric8.maven.plugin.version>3.5.37</fabric8.maven.plugin.version>
    </properties>

    <dependencymanagement>
        <dependencies>
            <dependency>
                <groupid>org.springframework.boot</groupid>
                <artifactid>spring-boot-dependencies</artifactid>
                <type>pom</type>
                <scope>import</scope>
                <version>${spring-boot.version}</version>
            </dependency>
        </dependencies>
    </dependencymanagement>

    <dependencies>
        <dependency>
            <groupid>org.springframework.cloud</groupid>
            <artifactid>spring-cloud-kubernetes-core</artifactid>
            <version>1.0.1.release</version>
        </dependency>

        <dependency>
            <groupid>org.springframework.cloud</groupid>
            <artifactid>spring-cloud-kubernetes-discovery</artifactid>
            <version>1.0.1.release</version>
        </dependency>

        <dependency>
            <groupid>org.springframework.cloud</groupid>
            <artifactid>spring-cloud-commons</artifactid>
            <version>2.1.1.release</version>
        </dependency>

        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter</artifactid>
            <version>2.1.1.release</version>
        </dependency>

        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-web</artifactid>
            <version>2.1.1.release</version>
        </dependency>

        <!--
            we need that(actuator) so that it can be used in readiness probes.
            readiness checks are needed by arquillian, so that it
            knows when to run the actual test.
        -->
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-actuator</artifactid>
            <version>2.1.1.release</version>
        </dependency>

        <dependency>
            <groupid>com.alibaba</groupid>
            <artifactid>fastjson</artifactid>
            <version>1.2.28</version>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupid>org.springframework.boot</groupid>
                <artifactid>spring-boot-maven-plugin</artifactid>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <!--skip deploy -->
                <groupid>org.apache.maven.plugins</groupid>
                <artifactid>maven-deploy-plugin</artifactid>
                <version>${maven-deploy-plugin.version}</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
            <plugin>
                <groupid>org.apache.maven.plugins</groupid>
                <artifactid>maven-surefire-plugin</artifactid>
                <version>${maven-surefire-plugin.version}</version>
                <configuration>
                    <skiptests>true</skiptests>
                    <!-- workaround for https://issues.apache.org/jira/browse/surefire-1588 -->
                    <usesystemclassloader>false</usesystemclassloader>
                </configuration>
            </plugin>
            <plugin>
                <groupid>io.fabric8</groupid>
                <artifactid>fabric8-maven-plugin</artifactid>
                <version>${fabric8.maven.plugin.version}</version>
                <executions>
                    <execution>
                        <id>fmp</id>
                        <goals>
                            <goal>resource</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>kubernetes</id>
            <build>
                <plugins>
                    <plugin>
                        <groupid>io.fabric8</groupid>
                        <artifactid>fabric8-maven-plugin</artifactid>
                        <version>${fabric8.maven.plugin.version}</version>
                        <executions>
                            <execution>
                                <id>fmp</id>
                                <goals>
                                    <goal>resource</goal>
                                    <goal>build</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <enricher>
                                <config>
                                    <fmp-service>
                                        <type>nodeport</type>
                                    </fmp-service>
                                </config>
                            </enricher>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
        <profile>
            <id>release</id>
            <build>
                <plugins>
                    <plugin>
                        <groupid>io.fabric8</groupid>
                        <artifactid>fabric8-maven-plugin</artifactid>
                        <version>${fabric8.maven.plugin.version}</version>
                        <executions>
                            <execution>
                                <id>fmp</id>
                                <goals>
                                    <goal>resource</goal>
                                    <goal>helm</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>

        <profile>
            <id>integration</id>
            <build>
                <plugins>
                    <plugin>
                        <groupid>io.fabric8</groupid>
                        <artifactid>fabric8-maven-plugin</artifactid>
                        <version>${fabric8.maven.plugin.version}</version>
                        <executions>
                            <execution>
                                <id>fmp</id>
                                <goals>
                                    <goal>resource</goal>
                                    <goal>build</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupid>org.apache.maven.plugins</groupid>
                        <artifactid>maven-failsafe-plugin</artifactid>
                        <version>${maven-failsafe-plugin.version}</version>
                        <executions>
                            <execution>
                                <id>run-integration-tests</id>
                                <phase>integration-test</phase>
                                <goals>
                                    <goal>integration-test</goal>
                                    <goal>verify</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <skiptests>false</skiptests>
                            <skipits>false</skipits>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

上述pom.xml文件有几处需要关注:

a. 直接依赖了spring-cloud-kubernetes的以下两个库,后面才能使用spring-cloud-kubernetes的服务:

org.springframework.cloud:spring-cloud-kubernetes-core:1.0.1.release
org.springframework.cloud:spring-cloud-kubernetes-discovery:1.0.1.release

b. 使用插件fabric8-maven-plugin来构建镜像并部署到minikube环境:

<plugin>
  <groupid>io.fabric8</groupid>
  <artifactid>fabric8-maven-plugin</artifactid>
  <version>${fabric8.maven.plugin.version}</version>
  <executions>
    <execution>
      <id>fmp</id>
      <goals>
        <goal>resource</goal>
      </goals>
    </execution>
  </executions>
</plugin>

c. 为fabric8-maven-plugin插件准备了三个profile,本次实战主要用到kubernetes这个:

<profile> 
  <id>kubernetes</id>  
  <build> 
    <plugins> 
      <plugin> 
        <groupid>io.fabric8</groupid>  
        <artifactid>fabric8-maven-plugin</artifactid>  
        <version>${fabric8.maven.plugin.version}</version>  
        <executions> 
          <execution> 
            <id>fmp</id>  
            <goals>
              <goal>resource</goal>  
              <goal>build</goal> 
            </goals> 
          </execution> 
        </executions>  
        <configuration> 
          <enricher> 
            <config> 
              <fmp-service>
                <!--部署到kubernetes后,会创建一个类型为nodeport的service--> 
                <type>nodeport</type> 
              </fmp-service> 
            </config> 
          </enricher> 
        </configuration> 
      </plugin> 
    </plugins> 
  </build> 
</profile>

以上就是pom.xml的内容了,主要是添加spring-cloud-kubernetes的依赖,以及使用fabric8来构建和部署;

  1. 在application.properties文件中设置应用名称:
spring.application.name=springcloudk8sdiscovery
  1. 创建应用启动类springcloudk8sdiscoveryapplication,可见这是个很普通的springboot启动类:
package com.bolingcavalry.springcloudk8sdiscovery;

import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.cloud.client.discovery.enablediscoveryclient;


@springbootapplication
@enablediscoveryclient
public class springcloudk8sdiscoveryapplication {

    public static void main(string[] args) {
        springapplication.run(springcloudk8sdiscoveryapplication.class, args);
    }
}
  1. 创建controller类,对外提供http服务,部署完成后通过这些http服务来验证功能:
@restcontroller
public class discoverycontroller {

    @autowired
    private discoveryclient discoveryclient;

    /**
     * 探针检查响应类
     * @return
     */
    @requestmapping("/health")
    public string health() {
        return "health";
    }

    /**
     * 返回远程调用的结果
     * @return
     */
    @requestmapping("/getservicedetail")
    public string getservicedetail(
            @requestparam(value = "servicename", defaultvalue = "") string servicename) {
        return "service [" + servicename + "]'s instance list : " + json.tojsonstring(discoveryclient.getinstances(servicename));
    }

    /**
     * 返回发现的所有服务
     * @return
     */
    @requestmapping("/services")
    public string services() {
        return this.discoveryclient.getservices().tostring()
                + ", "
                + new simpledateformat("yyyy-mm-dd hh:mm:ss").format(new date());
    }
}

上述代码有几点需要注意:

a. health方法用于响应kubernetes的探针检查;

b. getservicedetail方法接收名为servicename的参数,然后去服务列表中检查对应的服务对象并返回;

c. services方法返回的是所有服务的名称;

以上就是所有代码了,功能是通过autowire得到discoveryclient实例,再调用该实例的api取得服务信息。

接下来我们将应用构建并部署到minikube环境;

编译构建

  1. 请确保当前电脑上java、maven、minikube都是正常的;
  2. 在pom.xml文件所在目录执行以下命令,即可编译构建部署一次性完成:
mvn clean package fabric8:deploy -pkubernetes

构建成功后,控制台输出信息如下:

...
[info] 
[info] <<< fabric8-maven-plugin:3.5.37:deploy (default-cli) < install @ springcloudk8sdiscovery <<<
[info] 
[info] 
[info] --- fabric8-maven-plugin:3.5.37:deploy (default-cli) @ springcloudk8sdiscovery ---
[info] f8: using kubernetes at https://192.168.121.133:8443/ in namespace default with manifest /usr/local/work/demo/springcloudk8sdiscovery/target/classes/meta-inf/fabric8/kubernetes.yml 
[info] using namespace: default
[info] updating a service from kubernetes.yml
[info] updated service: target/fabric8/applyjson/default/service-springcloudk8sdiscovery.json
[info] using namespace: default
[info] updating deployment from kubernetes.yml
[info] updated deployment: target/fabric8/applyjson/default/deployment-springcloudk8sdiscovery.json
[info] f8: hint: use the command `kubectl get pods -w` to watch your pods start up
[info] ------------------------------------------------------------------------
[info] build success
[info] ------------------------------------------------------------------------
[info] total time:  11.207 s
[info] finished at: 2019-06-09t18:50:09+08:00
[info] ------------------------------------------------------------------------
  1. 用kubectl命令查看部署和服务,都处于正常状态:
[root@minikube springcloudk8sdiscovery]# kubectl get deployments
name                      ready   up-to-date   available   age
springcloudk8sdiscovery   1/1     1            1           75m
[root@minikube springcloudk8sdiscovery]# kubectl get svc
name                      type        cluster-ip      external-ip   port(s)          age
kubernetes                clusterip   10.96.0.1       <none>        443/tcp          33h
springcloudk8sdiscovery   nodeport    10.102.167.79   <none>        8080:31583/tcp   75m
  1. 执行命令minikube service springcloudk8sdiscovery --url,得到的是可以从外部访问的服务地址:http://192.168.121.133:31583 ,其中192.168.121.133是宿主机ip地址;
  2. 在浏览器*问地址http://192.168.121.133:31583/services ,如下图,返回的"所有服务"其实是kubernetes中的所有service:
    你好spring-cloud-kubernetes
  3. 为了验证当前namespace下的所有服务都能被发现,我们再创建个服务实施,执行以下命令,会创建名为my-tomcat的部署和服务:
kubectl run my-tomcat --image=tomcat:7.0.94-jre7-alpine --replicas=2 --port=8080 \
&& kubectl expose deployment my-tomcat --port=8080 --target-port=8080 --external-ip=192.168.50.7 --type=loadbalancer

由于下载镜像需要一定时间,所以需要稍作等待;

  1. 再去访问地址http://192.168.121.133:31583/services ,如下图,my-tomcat赫然在列:
    你好spring-cloud-kubernetes
  2. 访问地址http://192.168.121.133:31583/getservicedetail?servicename=my-tomcat ,会得到名为my-tomcat的服务信息,该信息格式化后的内容如下所示:
[
    {
        "host": "172.17.0.4",
        "instanceid": "91201db9-8aa6-11e9-a5b5-000c29fd2001",
        "metadata": {
            "run": "my-tomcat"
        },
        "port": 8080,
        "scheme": "http://",
        "secure": false,
        "serviceid": "my-tomcat",
        "uri": "http://172.17.0.4:8080"
    },
    {
        "host": "172.17.0.5",
        "instanceid": "91223cda-8aa6-11e9-a5b5-000c29fd2001",
        "metadata": {
            "$ref": "$[0].metadata"
        },
        "port": 8080,
        "scheme": "http://",
        "secure": false,
        "serviceid": "my-tomcat",
        "uri": "http://172.17.0.5:8080"
    }
]

可见spring-cloud-kubernetes的discoveryclient服务将kubernetes中的"service"资源与springcloud中的服务对应起来了,有了这个discoveryclient,我们在kubernetes环境就不需要eureka来做注册发现了,而是直接使用kubernetes的服务机制,此时不得不感慨springcloud的对discoveryclient的设计是如此的精妙。

至此,spring-cloud-kubernetes的初体验就结束了,通过简单的编码我们的程序在kubernetes环境可以取得service资源的信息,随着学习的深入,我们会用到更多的spring-cloud-kubernetes能力,感谢spring-cloud-kubernetes的设计者,让我们的springcloud应用畅游在在kubernetes世界。

疑惑待解

您可能会有些疑惑:上面的代码都是和springcloud相关的,和spring-cloud-kubernetes没什么关系呀,为什么程序运行起来后就能取得kubernetes环境中的服务信息呢?
此问题如果不弄清楚,后面的学习很难展开,因为我们都不知道自己的代码与kubernetes环境有什么关系,和kubernetes有没有交互?

以上问题,欢迎访问,这里面有详细的分析。

欢迎关注我的公众号

你好spring-cloud-kubernetes