【SFA官方翻译】使用 Kubernetes
- 作者: 五速梦信息网
- 时间: 2026年04月04日 13:55
原文链接:https://dzone.com/articles/quick-guide-to-microservices-with-kubernetes-sprin
译者:Darren Luo
在本教程中你将学习如何使用 Kubernetes 和 Docker 快速启动并运行 Spring Boot 微服务项目。
这是“XXX快速指南“系列的下一篇文章。这次,我们将讨论并在 Kubernetes 上运行 Spring Boot 微服务示例。本文的结构将和使用 Spring Boot 2.0、Eureka 和 Spring Cloud 的微服务快速指南非常相似,因为他们都描述了应用程序开发的相同方面。我将重点向你展示 Spring Cloud 和 Kubernetes 在开发方面的异同。本文涉及的话题有:
在云原生开发中使用 Spring Boot 2.0
使用 Spring Cloud Kubernetes 项目为所有微服务提供服务发现
使用 Kubernetes 的 Config Maps 和 Secrets 为应用程序 pod(译者注:Kubernetes中的最小管理单元)注入配置设置
使用 Docker 构建应用程序镜像并使用 YAML 配置文件将他们部署到 Kubernetes上。
将 Spring Cloud Kubernetes 和 Zuul 代理一起使用,为所有微服务公开一个独立的 Swagger API 文档
当你构建微服务环境时,Spring Cloud 和 Kubernetes 可能成为互相威胁的竞争解决方案。Spring Cloud 提供的如 Eureka、Spring Cloud Config 或 Zuul 等组件可能被 Kubernetes 的如 services、config maps、secrets 或 ingresses 等内置对象所替代。但是即使你决定使用 Kubernetes 组件替代 Spring Cloud,你也可以利用整个 Spring Cloud 项目提供的一些有趣的功能。
在开发中帮助我们的一个非常有趣的项目是 Spring Cloud Kubernetes。虽然它还处于孵化阶段,但绝对值得在它上面献上一些时间。它将 Spring Cloud 和 Kubernetes 集成在一起。我将向你展示如何使用客户端发现的实现、与 Ribbon 客户端的服务间通信以及使用 Spring Cloud Kubernetes 的 Zipkin 发现。
employee-servicedepartment-servicorganization-service
Finchley.RELEASEspring-cloud-dependencies
org.springframework.cloud spring-cloud-dependencies Finchley.RELEASE pom import
SNAPSHOTspring-cloud-kubernetes0.3.0.BUILD-SNAPSHOT
本文提供的示例应用程序的源码可以在 Github 上的此 repository 获得。
前提要求
为了能部署和测试我们的示例微服务,我们需要准备一个开发环境。我们通过一下步骤实现:
你至少需要在你本地机器上运行的 Kubernetes(Minikube)或 Openshift(Minishift)的单节点集群实例。你应该启动它并公开他们提供的嵌入式 Docker 客户端。有关 Minishift 的详细说明可以在我的在 Openshift 上部署 Java 应用程序的快速指南里找到。你也可以使用这份说明来运行 Minikube,只需要用“minikube”替换单词“minishift”。事实上,如果你选择 Kubernetes 或 Openshift 并没什么关系,本教程的下一部分对他们都适用。
Spring Cloud Kubernetes 需要访问 Kubernetes API,以便于能够检索为单个服务运行的 pod 的地址列表。如果你使用 Kubernetes,你应该只执行以下命令:
$ kubectl create clusterrolebinding admin --clusterrole=cluster-admin --serviceaccount=default:default
如果你在 Minishift 上部署你的微服务,首先你需要启用 admin-user 插件,然后以集群管理员身份登陆并授予所需权限。
$ minishift addons enable admin-user$ oc login -u system:admin$ oc policy add-role-to-user cluster-reader system:serviceaccount:myproject:default
apiVersion: apps/v1kind: Deploymentmetadata: name: mongodb labels: app: mongodbspec: replicas: 1 selector: matchLabels: app: mongodb template: metadata: labels: app: mongodb spec: containers: - name: mongodb image: mongo:latest ports: - containerPort: 27017 env: - name: MONGO_INITDB_DATABASE valueFrom: configMapKeyRef: name: mongodb key: database-name - name: MONGO_INITDB_ROOT_USERNAME valueFrom: secretKeyRef: name: mongodb key: database-user - name: MONGO_INITDB_ROOT_PASSWORD valueFrom: secretKeyRef: name: mongodb key: database-password---apiVersion: v1kind: Servicemetadata: name: mongodb labels: app: mongodbspec: ports: - port: 27017 protocol: TCP selector: app: mongodb
1. 使用 Config Maps 和 Secrets 注入配置
application.yml
spring: data: mongodb: uri:mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@mongodb/${MONGO_DATABASE}
虽然用户名和密码是敏感字段,但数据库名不是,因此我们可以将将其放在 config map 中。
apiVersion: v1kind: ConfigMapmetadata: name: mongodbdata: database-name: microservices
当然,用户名和密码被定义在 secrets 中。
apiVersion: v1kind: Secretmetadata: name: mongodbtype: Opaquedata: database-password: MTIzNDU2 database-user: cGlvdHI=
要将配置应用于 Kubernetes 集群,我们运行以下命令。
$ kubectl apply -f kubernetes/mongodb-configmap.yaml$ kubectl apply -f kubernetes/mongodb-secret.yaml
完成之后,我们应该将配置属性注入到应用程序的 pod 中。在 Deployment YAML 文件中定义容器配置时,我们必须包含对环境变量和 secrets 的引用,如下所示。
apiVersion: apps/v1kind: Deploymentmetadata: name: employee labels: app: employeespec: replicas: 1 selector: matchLabels: app: employee template: metadata: labels: app: employee spec: containers: - name: employee image: piomin/employee:1.0 ports: - containerPort: 8080 env: - name: MONGO_DATABASE valueFrom: configMapKeyRef: name: mongodb key: database-name - name: MONGO_USERNAME valueFrom: secretKeyRef: name: mongodb key: database-user - name: MONGO_PASSWORD valueFrom: secretKeyRef: name: mongodb key: database-password
2. 用 Kubernetes 构建服务发现
appemployee
apiVersion: v1kind: Servicemetadata: name: employee labels: app: employeespec: ports: - port: 8080 protocol: TCP selector: app: employee
pom.xml
org.springframework.cloud spring-cloud-starter-kubernetes 0.3.0.BUILD-SNAPSHOT
然后我们为应用程序启用客户端发现,就像我们在 Spring Cloud Netflix Eureka 中一直做的发现一样。这允许你按名称查询 Kubernetes endpoit(服务)。这种发现功能也被 Spring Cloud Kubernetes Ribbon 或 Zipkin 项目用来分别为需要负载均衡的微服务获取已定义的 pod 列表,或者可用于追踪或聚合的 Zipkin 服务器。
@SpringBootApplication@EnableDiscoveryClient@EnableMongoRepositories@EnableSwagger2public class EmployeeApplication { public static void main(String[] args) { SpringApplication.run(EmployeeApplication.class, args); } // ...}
employee-serviceemployee
spring: application: name: employee
使用 Docker 构建微服务并在 Kubernetes 上部署
在我们的示例微服务中没有任何不正常。我们已经包含了一些用于构建基于 REST 的微服务、集成 MongoDB 和使用 Swagger2 生成 API 文档的标准 Spring 依赖。
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator io.springfox springfox-swagger2 2.9.2 org.springframework.boot spring-boot-starter-data-mongodb
CrudRepository
public interface EmployeeRepository extends CrudRepository { List findByDepartmentId(Long departmentId); List findByOrganizationId(Long organizationId);}
@Document@Id
@Document(collection = "employee")public class Employee { @Id private String id; private Long organizationId; private Long departmentId; private String name; private int age; private String position; // ...}
该 repository bean 已经被注入到 controller 类中。以下是我们 employee-service 中 REST API 的完整实现。
@RestControllerpublic class EmployeeController { private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeController.class); @Autowired EmployeeRepository repository; @PostMapping("/") public Employee add(@RequestBody Employee employee) { LOGGER.info("Employee add: {}", employee); return repository.save(employee); } @GetMapping("/{id}") public Employee findById(@PathVariable("id") String id) { LOGGER.info("Employee find: id={}", id); return repository.findById(id).get(); } @GetMapping("/") public Iterable findAll() { LOGGER.info("Employee find"); return repository.findAll(); } @GetMapping("/department/{departmentId}") public List findByDepartment(@PathVariable("departmentId") Long departmentId) { LOGGER.info("Employee find: departmentId={}", departmentId); return repository.findByDepartmentId(departmentId); } @GetMapping("/organization/{organizationId}") public List findByOrganization(@PathVariable("organizationId") Long organizationId) { LOGGER.info("Employee find: organizationId={}", organizationId); return repository.findByOrganizationId(organizationId); }}
mvn clean installemployee-service
FROM openjdk:8-jre-alpineENV APP_FILE employee-service-1.0-SNAPSHOT.jarENV APP_HOME /usr/appsEXPOSE 8080COPY target/$APP_FILE $APP_HOME/WORKDIR $APP_HOMEENTRYPOINT ["sh", "-c"]CMD ["exec java -jar $APP_FILE"]
让我们为所有三个示例微服务构建 Docker 镜像。
$ cd employee-service$ docker build -t piomin/employee:1.0 .$ cd department-service$ docker build -t piomin/department:1.0 .$ cd organization-service$ docker build -t piomin/organization:1.0 .
kubectl applyemployee-servicekubernetes
$ kubectl apply -f kubernetes\employee-deployment.yaml$ kubectl apply -f kubernetes\department-deployment.yaml$ kubectl apply -f kubernetes\organization-deployment.yaml
使用 Spring Cloud Kubernetes Ribbon 进行微服务之间的通信
employee-serviceemployee-servicorganization-servicedepartment-service
@LoadBalancedRestTemplate
org.springframework.cloud spring-cloud-starter-netflix-ribbon org.springframework.cloud spring-cloud-starter-kubernetes-ribbon 0.3.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-starter-openfeign
department-service@EnableFeignClientsKubernetesClient
@SpringBootApplication@EnableDiscoveryClient@EnableFeignClients@EnableMongoRepositories@EnableSwagger2public class DepartmentApplication { public static void main(String[] args) { SpringApplication.run(DepartmentApplication.class, args); } // ...}
employee-service
@FeignClient(name = "employee")public interface EmployeeClient { @GetMapping("/department/{departmentId}") List findByDepartment(@PathVariable("departmentId") String departmentId);}
EmployeeClient
@RestControllerpublic class DepartmentController { private static final Logger LOGGER = LoggerFactory.getLogger(DepartmentController.class); @Autowired DepartmentRepository repository; @Autowired EmployeeClient employeeClient; // ... @GetMapping("/organization/{organizationId}/with-employees") public List findByOrganizationWithEmployees(@PathVariable("organizationId") Long organizationId) { LOGGER.info("Department find: organizationId={}", organizationId); List departments = repository.findByOrganizationId(organizationId); departments.forEach(d -> d.setEmployees(employeeClient.findByDepartment(d.getId()))); return departments; }}
5. 使用 Kubernetes Ingress 构建 API 网关
Ingress 是允许传入请求到达下游服务的一组规则。在我们的微服务架构中,ingress 扮演 API 网关的角色。要创建它,我们应该首先准备一个 YAML 描述文件。描述文件应该包含网关可用的主机名和到达下游服务的映射规则。
apiVersion: extensions/v1beta1kind: Ingressmetadata: name: gateway-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: /spec: backend: serviceName: default-http-backend servicePort: 80 rules: - host: microservices.info http: paths: - path: /employee backend: serviceName: employee servicePort: 8080 - path: /department backend: serviceName: department servicePort: 8080 - path: /organization backend: serviceName: organization servicePort: 8080
你必须执行下面命令才能将该配置应用于 Kubernetes 集群。
$ kubectl apply -f kubernetes\ingress.yaml
hosts
http://microservices.info/employee
192.168.99.100 microservices.info
kubectl describe ing gateway-ingress
使用 Swagger2 在网关上启用 API 规范
如果我们想为 Kubernetes 上部署的所有微服务公开一个 Swagger 文档该怎么做?好吧,这里的事情变复杂了。我们可以运行一个有 Swagger UI 的容器,并通过手动公开 ingress 映射所有路径,但是这不是一个好的解决方案。
在这种情况下,我们可以再次使用 Spring Cloud Kubernetes Ribbon,这次是与 Spring Cloud Netflix Zuul 一起使用。Zuul 将作为只为 Swagger API 服务的网关。
gateway-service
org.springframework.cloud spring-cloud-starter-netflix-zuul org.springframework.cloud spring-cloud-starter-kubernetes 0.3.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-starter-netflix-ribbon org.springframework.cloud spring-cloud-starter-kubernetes-ribbon 0.3.0.BUILD-SNAPSHOT io.springfox springfox-swagger-ui 2.9.2 io.springfox springfox-swagger2 2.9.2
Kubernetes discovery 客户端将检测集群上公开的所有服务。我们只想显示三个微服务的文档。这就是我为什么为 Zuul 定义以下 route。
zuul: routes: department: path: /department/** employee: path: /employee/** organization: path: /organization/**
ZuulProperties
@Configurationpublic class GatewayApi { @Autowired ZuulProperties properties; @Primary @Bean public SwaggerResourcesProvider swaggerResourcesProvider() { return () -> { List resources = new ArrayList(); properties.getRoutes().values().stream() .forEach(route -> resources.add(createResource(route.getId(), "2.0"))); return resources; }; } private SwaggerResource createResource(String location, String version) { SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setName(location); swaggerResource.setLocation("/" + location + "/v2/api-docs"); swaggerResource.setSwaggerVersion(version); return swaggerResource; }}
gateway-servicekubectlgetsvchttp://192.168.99.100:31237/swagger-ui.html
总结
实际上我正在为 Spring Cloud Kubernetes 项目做准备,该项目仍处于孵化阶段。Kubernetes 作为一个平台的受欢迎程度在过去几个月中迅速增长,但是它仍有一些弱点。其中之一就是服务间通信。Kubernetes 没有给我们许多允许我们配置更高级规则的开箱即用的机制。这是 Kubernetes 上为服务网格创建如 Istio 或 Linkered 等框架的原因。这些项目仍然是相对较新的解决方案,但 Spring Cloud 是一个稳定坚固的框架。为什么不用它来提供服务发现、服务间通信或者负载均衡呢?感谢 Spring Cloud Kubernetes,这是可能的。
- 上一篇: 【Shell脚本编程系列】知识储备以及建立规范的脚本
- 下一篇: 【Qt】学习笔记(一)
相关文章
-
【Shell脚本编程系列】知识储备以及建立规范的脚本
【Shell脚本编程系列】知识储备以及建立规范的脚本
- 互联网
- 2026年04月04日
-
【Spring】获取资源文件+从File+从InputStream对象获取正文数据
【Spring】获取资源文件+从File+从InputStream对象获取正文数据
- 互联网
- 2026年04月04日
-
【Spring实战】Spring注解配置工作原理源码解析
【Spring实战】Spring注解配置工作原理源码解析
- 互联网
- 2026年04月04日
-
【Qt】学习笔记(一)
【Qt】学习笔记(一)
- 互联网
- 2026年04月04日
-
【QT】C++ GUI Qt4 学习笔记4
【QT】C++ GUI Qt4 学习笔记4
- 互联网
- 2026年04月04日
-
【QT】C++ GUI Qt4 学习笔记2
【QT】C++ GUI Qt4 学习笔记2
- 互联网
- 2026年04月04日






