关于spring-cloud-kubernetes

spring-cloud-kubernetes是springcloud官方推出的开源项目,用于将Spring Cloud和Spring Boot应用运行在kubernetes环境,并且提供了通用的接口来调用kubernetes服务,主要提供了应用程序使用k8s本身功能:服务注册发现、客户端负载均衡、从Kubernetes ConfigMap和Secrets加载应用程序属性 。 ConfigMap或Secret更改时,重新加载应用程序属性。GitHub上官方地址是:https://github.com/spring-cloud/spring-cloud-kubernetes

官网文档地址:https://cloud.spring.io/spring-cloud-kubernetes/1.1.x/reference/html/

入门程序

环境和版本:
linux系统
k8s集群
kubectl
idea
jdk8
maven

spring-boot工程
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.xxx.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>
     </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>        <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>2.1.1.RELEASE</version>
                 <executions>
                     <execution>
                         <goals>
                             <goal>repackage</goal>
                         </goals>
                     </execution>
                 </executions>
             </plugin>        </plugins>
     </build>
 </project>


配置文件

spring.application.name=springcloudk8sdiscovery

    1

启动类

package com.xxx.cloud.k8s.demo;
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);
     }
 }

接口

package com.xxx.cloud.k8s.demo.controller;
import com.alibaba.fastjson.JSON;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cloud.client.discovery.DiscoveryClient;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;import java.text.SimpleDateFormat;
 import java.util.Date;/**
  * @date: 2020/4/21 9:02
  * @author: lhl
  * @version: V0.1
  * */
 @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());
     }
 }


服务部署
打包spring-boot工程

mvn clean -DskipTests=true package

    1

在targe\目录下生成可执行jar :springcloudk8sdiscovery-0.0.1-SNAPSHOT.jar

上传到linux服务器

创建Dockerfile文件

#基础镜像,如果本地仓库没有,会从远程仓库拉取
 FROM 私服/jdk8版本
#容器中创建目录
RUN mkdir -p /usr/local/cloudk8s-demo
#编译后的jar包copy到容器中创建到目录内
COPY springcloudk8sdiscovery-0.0.1-SNAPSHOT.jar /usr/local/cloudk8s-demo/app.jar
#指定容器启动时要执行的命令
ENTRYPOINT ["java","-jar","/usr/local/cloudk8s-demo/app.jar"]

    1

创建 kubernetes.yml文件

apiVersion: v1
 kind: Service
 metadata:
   labels:
     app: springcloudk8sdiscovery
   name: springcloudk8sdiscovery
   namespace: default
 spec:
   ports:
   - name: http
     port: 8080
     protocol: TCP
     targetPort: 8080
   selector:
     app: springcloudk8sdiscovery
   type: NodePort
 ---
 apiVersion: extensions/v1beta1
 kind: Deployment
 metadata:
   labels:
     app: springcloudk8sdiscovery
   name: springcloudk8sdiscovery
 spec:
   replicas: 1
   selector:
     matchLabels:
       app: springcloudk8sdiscovery
   template:
     metadata:
       labels:
         app: springcloudk8sdiscovery
     spec:
       containers:
       - image: 私服/test/cloudk8s-demo
         imagePullPolicy: IfNotPresent
         name: springcloudk8sdiscovery
         ports:
         - containerPort: 8080
           name: http
           protocol: TCP
         securityContext:
           privileged: false

 
    43

创建 start.sh 脚本文件

#!/bin/bash
 imageVersion=2
 docker build -t 私服/test/cloudk8s-demo:${imageVersion} . docker push私服/test/cloudk8s-demo:${imageVersion} kubectl delete -f kubernetes.yml kubectl create -f kubernetes.yml


docker image 版本修改相应需要修改 kubernetes.yml 中的镜像版本

    1

修改start.sh为可执行 chmod +x start.sh

执行脚本 sh start.sh

查看服务是否启动

kubectl get pods

    1

READY下面的前后数一样则启动成功 1/1,且STATUS为Running状态,如果为0/1则启动失败,启动失败,通过命令:kubectl describe pod podName查看服务详情或者kubectl logs -f podName 查看日志

通过 kubectl get svc 查看服务端口,通过ip:端口访问服务查询服务列表
入门程序部署完成
通过feign调用k8s启动的服务的工程

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>    <groupId>com.xxx</groupId>
     <artifactId>cloud-k8s-feign</artifactId>
     <version>1.0-SNAPSHOT</version>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.0.9.RELEASE</version>
         <relativePath/>
     </parent>
     <properties>
         <springcloud.kubernetes.version>1.0.1.RELEASE</springcloud.kubernetes.version>
         <springcloud.version>2.0.3.RELEASE</springcloud.version>
     </properties>
     <dependencies>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-kubernetes-core</artifactId>
             <version>${springcloud.kubernetes.version}</version>
         </dependency>        <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-kubernetes-discovery</artifactId>
             <version>${springcloud.kubernetes.version}</version>
         </dependency>        <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
             <version>${springcloud.kubernetes.version}</version>
         </dependency>        <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-commons</artifactId>
             <version>${springcloud.version}</version>
         </dependency>        <dependency>
             <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
             <groupId>org.springframework.cloud</groupId>
         </dependency>
         <dependency>
             <artifactId>spring-cloud-starter-openfeign</artifactId>
             <groupId>org.springframework.cloud</groupId>
         </dependency>        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
     </dependencies>    <build>
         <plugins>
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <executions>
                     <execution>
                         <goals>
                             <goal>repackage</goal>
                         </goals>
                     </execution>
                 </executions>
             </plugin>
         </plugins>
     </build>    <dependencyManagement>
         <dependencies>
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-dependencies</artifactId>
                 <version>Finchley.SR3</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
         </dependencies>
     </dependencyManagement></project>

  

配置文件

spring:
   application:
     name: k8s-feignproduct-infra-service:
   ribbon:
     KubernetesNamespace: defaultbackend:
   ribbon:
     eureka:
       enabled: false
     client:
       enabled: true
     ServerListRefreshInterval: 5000hystrix:
   command:
     BackendCall:
       execution:
         isolation:
           thread:
             timeoutInMilliseconds: 5000
   threadpool:
     BackendCallThread:
       coreSize: 5
 feign:
   hystrix:
     enabled: true
 server:
   port: 11101


启动类

package com.xxx.cloud.k8s.feign;
import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.openfeign.EnableFeignClients;/**
  * @date: 2020/4/21 16:02
  * @author: lhl
  * @version: V0.1
  * */
 @SpringBootApplication
 @EnableDiscoveryClient
 @EnableFeignClients
 public class K8sFeignApplication {     public static void main(String[] args) {
         SpringApplication.run(K8sFeignApplication.class, args);
     }
 }


    22

接口

package com.xxx.cloud.k8s.feign.controller;
import com.xxx.cloud.k8s.feign.feign.TestClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;/**
  * @date: 2020/4/21 16:05
  * @author: lhl
  * @version: V0.1
  *
  */
 @RestController
 public class TestController {    @Autowired
     private TestClient testClient;    @GetMapping("test1")
     public String test1() {
         return testClient.services();
     }}


feign 接口

package com.xxx.cloud.k8s.feign.feign;
import com.xxx.cloud.k8s.feign.hystrix.TestClientFallback;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.RequestMapping;/**
  * @date: 2020/4/21 16:02
  * @author: lhl
  * @version: V0.1
  *
  */
 @FeignClient(name = "${springcloudk8sdiscovery:springcloudk8sdiscovery}", fallback = TestClientFallback.class)
 public interface TestClient {    @RequestMapping("/services")
     String services();
 }
     18hystrix fallback类
 package com.xxx.cloud.k8s.feign.hystrix;
import com.xxx.cloud.k8s.feign.feign.TestClient;
 import org.springframework.stereotype.Component;/**
  * @date: 2020/4/21 16:03
  * @author: lhl
  * @version: V0.1
  *
  */
 @Component
 public class TestClientFallback implements TestClient {
     @Override
     public String services() {
         return "hystrix call back";
     }


}


其他步骤和入门程序差不多

start.sh文件

Dockerfile

start.sh
#!/bin/bash
imageVersion=2
docker build -t 私服/test/cloud-k8s-feign:${imageVersion} .
 docker push 私服/test/cloud-k8s-feign:${imageVersion}
  kubectl delete -f kubernetes.yml
  kubectl create -f kubernetes.yml

#基础镜像,如果本地仓库没有,会从远程仓库拉取
FROM 私服/oraclejdk8
#容器中创建目录
RUN mkdir -p /usr/local/cloudk8s-feign-demo
#编译后的jar包copy到容器中创建到目录内
COPY cloud-k8s-feign-1.0-SNAPSHOT.jar /usr/local/cloudk8s-feign-demo/app.jar
#指定容器启动时要执行的命令
ENTRYPOINT ["java","-jar","/usr/local/cloudk8s-feign-demo/app.jar"]


修改start.sh文件的docker镜像版本需要也需要改kubernetes.yml的docker镜像版本
 kubernetes.yml apiVersion: v1
 kind: Service
 metadata:
   labels:
     app: k8s-feign
   name: k8s-feign
   namespace: default
 spec:
   ports:
   - name: http
     port: 11101
     protocol: TCP
     targetPort: 11101
   selector:
     app: k8s-feign
   type: NodePort
 ---
 apiVersion: extensions/v1beta1
 kind: Deployment
 metadata:
   labels:
     app: k8s-feign
   name: k8s-feign
 spec:
   replicas: 3
   selector:
     matchLabels:
       app: k8s-feign
   template:
     metadata:
       labels:
         app: k8s-feign
     spec:
       containers:
       - image: 私服/test/cloud-k8s-feign:1
         imagePullPolicy: IfNotPresent
         name: k8s-feign
         ports:
         - containerPort: 11101
           name: http
           protocol: TCP
         securityContext:
           privileged: false

   

运行脚本文件start.sh
产看服务是否运行
查看端口号
通过接口 test1访问服务
Ip:port/test1
可以通过接口test1,以feign调用的方式访问到入门程序的services接口
k8s安全设计

生产环境k8s服务发现会报错:

Message: Forbidden!Configured service account doesn't have access. Service account may have been revoked. services is forbidden: User "system:serviceaccount:default:default" cannot list resource "services" in API group "" in the namespace "default"
    1

通过官方发布,为权限问题

在生产级别环境,可能需要给用户角色授权

kind: Role
 apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   namespace: YOUR-NAME-SPACE
   name: namespace-reader
 rules:
   - apiGroups: ["", "extensions", "apps"]
     resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
     verbs: ["get", "list", "watch"]---
kind: RoleBinding
 apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: namespace-reader-binding
   namespace: YOUR-NAME-SPACE
 subjects:
 - kind: ServiceAccount
   name: default
   apiGroup: ""
 roleRef:
   kind: Role
   name: namespace-reader
   apiGroup: ""