{"id":15777672,"url":"https://github.com/v5tech/spring-cloud-kubernetes-samples","last_synced_at":"2025-05-07T02:42:42.664Z","repository":{"id":149461795,"uuid":"532470244","full_name":"v5tech/spring-cloud-kubernetes-samples","owner":"v5tech","description":"spring-cloud-kubernetes云原生","archived":false,"fork":false,"pushed_at":"2022-10-27T14:58:15.000Z","size":9945,"stargazers_count":2,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"kubernetes","last_synced_at":"2024-10-11T18:05:34.345Z","etag":null,"topics":["cloud-native","cloudnative","spring-cloud-kubernetes"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/v5tech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-09-04T07:35:47.000Z","updated_at":"2024-04-15T05:17:14.000Z","dependencies_parsed_at":"2023-04-19T03:16:41.987Z","dependency_job_id":null,"html_url":"https://github.com/v5tech/spring-cloud-kubernetes-samples","commit_stats":null,"previous_names":["v5tech/spring-cloud-kubernetes-samples"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v5tech%2Fspring-cloud-kubernetes-samples","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v5tech%2Fspring-cloud-kubernetes-samples/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v5tech%2Fspring-cloud-kubernetes-samples/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v5tech%2Fspring-cloud-kubernetes-samples/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/v5tech","download_url":"https://codeload.github.com/v5tech/spring-cloud-kubernetes-samples/tar.gz/refs/heads/kubernetes","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252802589,"owners_count":21806531,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloud-native","cloudnative","spring-cloud-kubernetes"],"created_at":"2024-10-04T18:00:52.561Z","updated_at":"2025-05-07T02:42:42.635Z","avatar_url":"https://github.com/v5tech.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# spring-cloud-kubernetes-samples\n\n\n\nspring cloud kubernetes 微服务云原生示例。\n\n\n\n本示例基于最新的spring boot、spring cloud、spring cloud kubernetes版本。基于spring cloud kubernetes的新特性([New Features For Spring Cloud Kubernetes In Spring Cloud 2021.0.0-M3](https://spring.io/blog/2021/10/26/new-features-for-spring-cloud-kubernetes-in-spring-cloud-2021-0-0-m3))，主要演示`Configuration Watcher`、`Config Server`、`Discovery Server`三大组件。\n\n\n\n* Configuration Watcher\n\n组件spring-cloud-kubernetes-configuration-watcher，当`ConfigMap`或`Secret`内容发生变化时，Configuration Watcher组件会观测到该事件，请求应用程序的`/refresh`端点，应用程序会自动`reload`，而通过`PropertySource`或`Environment`方式读取属性的值会自动刷新。**特别注意：使用@value注解方式的属性值不会自动刷新噢**\n\n* Config Server\n\n组件spring-cloud-kubernetes-configserver，该组件基于Spring Cloud Config Server，用于整合除configmap、secret以外的配置信息。\n\n* Discovery Server\n\n组件spring-cloud-kubernetes-discoveryserver，该组件以HTTP的方式对外提供kubernetes集群中可用的服务信息。结合`spring-cloud-starter-kubernetes-discoveryclient`使用可以在没有`~/.kube/config`文件的情况下访问kubernetes集群中的服务。\n\n\n\n以上组件不需要进行二次开发，由spring cloud kubernetes提供，只需要部署到kubernetes集群中即可。在本示例中直接部署`manifests`目录下的文件即可。\n\n其源码及官方文档：\n\nhttps://github.com/spring-cloud/spring-cloud-kubernetes/tree/v2.1.3/spring-cloud-kubernetes-controllers\n\nhttps://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#spring-cloud-kubernetes-configuration-watcher\n\nhttps://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#spring-cloud-kubernetes-configserver\n\nhttps://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#spring-cloud-kubernetes-discoveryserver\n\n建议参考源码中的部署文件，spring cloud kubernetes文档中的部署文件有误，在实际使用过程中会因kubernetes权限的问题而导致服务间调用报错。\n\n\n\n**以上三大组件不是spring cloud kubernetes微服务的必要组件，但正是有了这三大组件使得使用spring cloud kubernetes在本地开发及调用kubernetes集群中的服务有了便捷性。开发人员即使本地没有`~/.kube/config`文件，只有和kubernetes在同一个局域网内就可以正常开发及调用集群中的服务。**\n\n\n## 一、环境配置\n\n### 1、开发环境\n\n- **JDK 1.8.0_201**\n- **SpringBoot 2.7.3**\n\n![Snipaste_2022-09-14_10-11-26](./Screenshots/Snipaste_2022-09-14_10-11-26.png)\n\n- **SpringCloud 2021.0.4**\n\n![Snipaste_2022-09-14_10-09-54](./Screenshots/Snipaste_2022-09-14_10-09-54.png)\n\n- **SpringCloudKubernetes：2.1.3**\n\n![Snipaste_2022-09-14_10-10-24](./Screenshots/Snipaste_2022-09-14_10-10-24.png)\n\n**注：spring boot、spring cloud、spring cloud kubernetes均使用目前最新的版本。**\n\n### 2、kubernetes集群运行环境\n\n![Snipaste_2022-09-13_11-33-11](./Screenshots/Snipaste_2022-09-13_13-14-55.png)\n\n### 3、配置本地/etc/hosts文件\n\n/etc/hosts\n\n```\n192.168.101.74 kubepi.cloudnative.io\n192.168.101.74 configserver.cloudnative.io\n192.168.101.74 discoveryserver.cloudnative.io\n192.168.101.74 configsample.cloudnative.io\n192.168.101.74 discoverysample.cloudnative.io\n192.168.101.74 gateway.cloudnative.io\n192.168.101.74 weiboservice.cloudnative.io\n192.168.101.74 weatherservice.cloudnative.io\n```\n\n## 二、应用目录介绍\n\n```\nconfig-sample      # 演示configmap、secret读取及自动更新\ndiscovery-sample   # spring cloud kubernetes服务发现及feign调用\ngateway-sample     # spring cloud kubernetes整合gateway网关应用，聚合所有的服务\nweather-service    # golang开发的天气预报服务\nweibo-service      # python开发的微博头条服务\n```\n\n##  三、部署Configuration Watcher、Config Server、Discovery Server组件\n\n### 1、应用manifests文件\n\n```bash\nk apply -f manifests\nk get deploy\nk get pod -owide\nk get cm\nk get svc\nk get ingress\n```\n\n![Snipaste_2022-09-13_13-01-36](./Screenshots/Snipaste_2022-09-13_13-01-36.png)\n\n![](./Screenshots/Snipaste_2022-09-13_13-12-06.png)\n\n**注意：**\n\n* 此处应使用源码中的部署文件，官方文档中的部署文件有问题。部署后服务间调用会报权限相关的错误。\n\nhttps://github.com/spring-cloud/spring-cloud-kubernetes/tree/v2.1.3/spring-cloud-kubernetes-controllers\n\n* 此处的ingress仅仅是便于在开发调试，实际生产环境中并不需要创建ingress。\n\n### 2、访问Discovery Server\n\n其接口API可参考 https://github.com/spring-cloud/spring-cloud-kubernetes/blob/v2.1.3/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-discoveryserver/src/main/java/org/springframewok/cloud/kubernetes/discoveryserver/DiscoveryServerController.java\n\n* http://discoveryserver.cloudnative.io/apps\n\n```bash\n❯ http discoveryserver.cloudnative.io/apps\nHTTP/1.1 200 OK\nConnection: keep-alive\nContent-Type: application/json\nDate: Tue, 13 Sep 2022 05:25:16 GMT\nTransfer-Encoding: chunked\n\n[\n    {\n        \"name\": \"spring-cloud-kubernetes-configserver\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"172.18.104.66\",\n                \"instanceId\": \"804d70c0-ac11-4b23-8229-74ce97bb7034\",\n                \"metadata\": {\n                    \"app\": \"spring-cloud-kubernetes-configserver\",\n                    \"http\": \"8888\",\n                    \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configserver\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-configserver\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":8888,\\\"targetPort\\\":8888}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configserver\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 8888,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"spring-cloud-kubernetes-configserver\",\n                \"uri\": \"http://172.18.104.66:8888\"\n            }\n        ]\n    },\n    {\n        \"name\": \"kubernetes\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"192.168.101.20\",\n                \"instanceId\": \"\",\n                \"metadata\": {\n                    \"component\": \"apiserver\",\n                    \"https\": \"6443\",\n                    \"provider\": \"kubernetes\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 6443,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"kubernetes\",\n                \"uri\": \"http://192.168.101.20:6443\"\n            },\n            {\n                \"cluster\": null,\n                \"host\": \"192.168.101.22\",\n                \"instanceId\": \"\",\n                \"metadata\": {\n                    \"component\": \"apiserver\",\n                    \"https\": \"6443\",\n                    \"provider\": \"kubernetes\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 6443,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"kubernetes\",\n                \"uri\": \"http://192.168.101.22:6443\"\n            },\n            {\n                \"cluster\": null,\n                \"host\": \"192.168.101.24\",\n                \"instanceId\": \"\",\n                \"metadata\": {\n                    \"component\": \"apiserver\",\n                    \"https\": \"6443\",\n                    \"provider\": \"kubernetes\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 6443,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"kubernetes\",\n                \"uri\": \"http://192.168.101.24:6443\"\n            }\n        ]\n    },\n    {\n        \"name\": \"spring-cloud-kubernetes-discoveryserver\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"172.18.104.70\",\n                \"instanceId\": \"c953b710-9e81-4a62-9f02-7a4184f59520\",\n                \"metadata\": {\n                    \"app\": \"spring-cloud-kubernetes-discoveryserver\",\n                    \"http\": \"8761\",\n                    \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":80,\\\"targetPort\\\":8761}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 8761,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"spring-cloud-kubernetes-discoveryserver\",\n                \"uri\": \"http://172.18.104.70:8761\"\n            }\n        ]\n    },\n    {\n        \"name\": \"spring-cloud-kubernetes-configuration-watcher\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"172.18.104.69\",\n                \"instanceId\": \"402de4ed-89b3-43c7-be8b-e8e892c4cc9f\",\n                \"metadata\": {\n                    \"app\": \"spring-cloud-kubernetes-configuration-watcher\",\n                    \"http\": \"8888\",\n                    \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":8888,\\\"targetPort\\\":8888}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 8888,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"spring-cloud-kubernetes-configuration-watcher\",\n                \"uri\": \"http://172.18.104.69:8888\"\n            }\n        ]\n    }\n]\n```\n\n* http://discoveryserver.cloudnative.io/apps/{name}\n\n```bash\n❯ http discoveryserver.cloudnative.io/apps/spring-cloud-kubernetes-discoveryserver\nHTTP/1.1 200 OK\nConnection: keep-alive\nContent-Type: application/json\nDate: Tue, 13 Sep 2022 05:27:30 GMT\nTransfer-Encoding: chunked\n\n[\n    {\n        \"cluster\": null,\n        \"host\": \"172.18.104.70\",\n        \"instanceId\": \"c953b710-9e81-4a62-9f02-7a4184f59520\",\n        \"metadata\": {\n            \"app\": \"spring-cloud-kubernetes-discoveryserver\",\n            \"http\": \"8761\",\n            \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":80,\\\"targetPort\\\":8761}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n        },\n        \"namespace\": \"default\",\n        \"port\": 8761,\n        \"scheme\": \"http\",\n        \"secure\": false,\n        \"serviceId\": \"spring-cloud-kubernetes-discoveryserver\",\n        \"uri\": \"http://172.18.104.70:8761\"\n    }\n]\n```\n\n* http://discoveryserver.cloudnative.io/app/{name}/{instanceId}\n\n```bash\n❯ http discoveryserver.cloudnative.io/app/spring-cloud-kubernetes-discoveryserver/c953b710-9e81-4a62-9f02-7a4184f59520\nHTTP/1.1 200 OK\nConnection: keep-alive\nContent-Length: 762\nContent-Type: application/json\nDate: Tue, 13 Sep 2022 05:30:43 GMT\n\n{\n    \"cluster\": null,\n    \"host\": \"172.18.104.70\",\n    \"instanceId\": \"c953b710-9e81-4a62-9f02-7a4184f59520\",\n    \"metadata\": {\n        \"app\": \"spring-cloud-kubernetes-discoveryserver\",\n        \"http\": \"8761\",\n        \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":80,\\\"targetPort\\\":8761}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n    },\n    \"namespace\": \"default\",\n    \"port\": 8761,\n    \"scheme\": \"http\",\n    \"secure\": false,\n    \"serviceId\": \"spring-cloud-kubernetes-discoveryserver\",\n    \"uri\": \"http://172.18.104.70:8761\"\n}\n```\n\n### 3、访问Config Server\n\n访问地址：http://configserver.cloudnative.io/{applicationname}/{profile}\n\n```bash\n❯ http configserver.cloudnative.io/spring-cloud-kubernetes-configserver/default\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Type: application/json\nDate: Tue, 13 Sep 2022 05:39:20 GMT\nTransfer-Encoding: chunked\n\n{\n    \"label\": null,\n    \"name\": \"spring-cloud-kubernetes-configserver\",\n    \"profiles\": [\n        \"default\"\n    ],\n    \"propertySources\": [\n        {\n            \"name\": \"https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #1)\",\n            \"source\": {\n                \"eureka.client.enabled\": false,\n                \"spring.cloud.kubernetes.enabled\": true,\n                \"spring.config.activate.on-cloud-platform\": \"kubernetes\"\n            }\n        },\n        {\n            \"name\": \"https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #0)\",\n            \"source\": {\n                \"chaos.monkey.assaults.latency-active\": true,\n                \"chaos.monkey.assaults.level\": 3,\n                \"chaos.monkey.enabled\": false,\n                \"chaos.monkey.watcher.restController\": true,\n                \"chaos.monkey.watcher.service\": false,\n                \"eureka.client.serviceUrl.defaultZone\": \"http://localhost:8761/eureka/\",\n                \"management.endpoint.chaosmonkey.enabled\": true,\n                \"management.endpoint.health.show-details\": \"always\",\n                \"management.endpoint.restart.enabled\": true,\n                \"management.endpoints.web.exposure.include\": \"*\",\n                \"spring.cloud.kubernetes.enabled\": false\n            }\n        }\n    ],\n    \"state\": null,\n    \"version\": null\n}\n---\n❯ http configserver.cloudnative.io/spring-cloud-kubernetes-configserver/kubernetes\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Type: application/json\nDate: Tue, 13 Sep 2022 05:40:03 GMT\nTransfer-Encoding: chunked\n\n{\n    \"label\": null,\n    \"name\": \"spring-cloud-kubernetes-configserver\",\n    \"profiles\": [\n        \"kubernetes\"\n    ],\n    \"propertySources\": [\n        {\n            \"name\": \"https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #1)\",\n            \"source\": {\n                \"eureka.client.enabled\": false,\n                \"spring.cloud.kubernetes.enabled\": true,\n                \"spring.config.activate.on-cloud-platform\": \"kubernetes\"\n            }\n        },\n        {\n            \"name\": \"https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #0)\",\n            \"source\": {\n                \"chaos.monkey.assaults.latency-active\": true,\n                \"chaos.monkey.assaults.level\": 3,\n                \"chaos.monkey.enabled\": false,\n                \"chaos.monkey.watcher.restController\": true,\n                \"chaos.monkey.watcher.service\": false,\n                \"eureka.client.serviceUrl.defaultZone\": \"http://localhost:8761/eureka/\",\n                \"management.endpoint.chaosmonkey.enabled\": true,\n                \"management.endpoint.health.show-details\": \"always\",\n                \"management.endpoint.restart.enabled\": true,\n                \"management.endpoints.web.exposure.include\": \"*\",\n                \"spring.cloud.kubernetes.enabled\": false\n            }\n        }\n    ],\n    \"state\": null,\n    \"version\": null\n}\n```\n\n### 4、Configuration Watcher\n\n该组件的实现原理是当configmap、secret内容发生变化后会，会向目标应用程序的`/actuator/refresh`端点发起请求进而刷新应用程序内属性的值。\n\n要实现以上功能，需满足以下条件：\n\n* 应用程序需开启`/actuator/refresh`端点，并对外暴露（添加spring-boot-starter-actuator依赖，并在配置文件中进行相应配置）\n\n```xml\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n            \u003cartifactId\u003espring-boot-starter-actuator\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n```\n\nbootstrap.yaml\n\n```yaml\nmanagement:\n  endpoint:\n    health:\n      show-details: always\n      enabled: true\n    restart:\n      enabled: true\n    info:\n      enabled: true\n  endpoints:\n    web:\n      exposure:\n        include: '*'\n```\n\n* 若修改了actuator端点的端口则需在kubernetes service中进行声明\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n  name: config-sample\n  annotations:\n    # actuator 端口地址\n    boot.spring.io/actuator: http://:8080/actuator\nspec:\n  selector:\n    app: config-sample\n  type: ClusterIP\n  ports:\n    - name: http\n      port: 8080\n      targetPort: 8080\n```\n\n* 需要在configmap、secret部署文件中添加label`spring.cloud.kubernetes.config: \"true\"`或`spring.cloud.kubernetes.secret: \"true\"`\n\nconfigmap.yaml\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: config-sample\n  labels:\n    # spring-cloud-kubernetes-configuration-watcher 监听 label\n    spring.cloud.kubernetes.config: \"true\"\ndata:\n  application.yml: |-\n    spring:\n      cloud:\n        config:\n          profile: kubernetes\n    ---\n    spring:\n      config:\n        activate:\n          on-profile: default\n    greeting:\n      message: HelloWorld! --- from ConfigMap default profile 111\n```\n\nsecret.yaml\n\n```yaml\napiVersion: v1\nkind: Secret\ntype: Opaque\nmetadata:\n  name: config-sample\n  labels:\n    # spring-cloud-kubernetes-configuration-watcher 监听 label\n    spring.cloud.kubernetes.secret: \"true\"\ndata:\n  secret.username: YWRtaW4NCg==\n  secret.password: SmlhZHVvYmFvODg2\n```\n\n* Configuration Watcher默认的刷新策略是2分钟，为了便于调试为Configuration Watcher创建了configmap对框架中该属性值进行了覆盖。\n\n![Snipaste_2022-09-14_10-20-19](./Screenshots/Snipaste_2022-09-14_10-20-19.png)\n\n![Snipaste_2022-09-14_10-21-26](./Screenshots/Snipaste_2022-09-14_10-21-26.png)\n\n## 四、configmap-sample（服务配置刷新）\n\n该示例演示spring cloud kubernetes从configmap、secret读取属性配置，整合spring cloud config server及Configuration Watcher做到configmap或secret内容变更不重启服务直接刷新配置。\n\n**注意事项：**\n\n* 该示例中使用kubernetes的原生api进行演示，它会读取本地的`~/.kube/config`文件，需提前准备好该文件，当然如果是kubernetes集群部署则可忽略。\n\n* 因为是在本地开发，所以需要添加config client相关依赖，旨在从config server拉取应用程序配置，当然如果是kubernetes集群部署则不需要config server的存在。\n\n### 1、pom.xml中添加依赖\n\n```xml\n        \u003c!--\n        依赖spring-cloud-kubernetes-discoveryserver组件\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-kubernetes-discoveryclient\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        --\u003e\n        \u003c!-- kubernetes原生api，会读取本机~/.kube/config文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-kubernetes-client\u003c/artifactId\u003e\n            \u003cversion\u003e2.1.3\u003c/version\u003e\n        \u003c/dependency\u003e\n        \u003c!-- 从configmap、secret加载应用配置文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-kubernetes-client-config\u003c/artifactId\u003e\n            \u003cversion\u003e2.1.3\u003c/version\u003e\n        \u003c/dependency\u003e\n        \u003c!-- spring-cloud-config-clien 从config server加载配置文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-config-client\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n            \u003cartifactId\u003espring-boot-starter-web\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n            \u003cartifactId\u003espring-boot-starter-actuator\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n            \u003cartifactId\u003espring-boot-configuration-processor\u003c/artifactId\u003e\n            \u003coptional\u003etrue\u003c/optional\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.projectlombok\u003c/groupId\u003e\n            \u003cartifactId\u003elombok\u003c/artifactId\u003e\n            \u003coptional\u003etrue\u003c/optional\u003e\n        \u003c/dependency\u003e\n```\n\n###  2、配置bootstrap.yml\n\n```yaml\nserver:\n  port: 8080\n\nlogging:\n  level:\n    org.springframework.cloud.kubernetes: DEBUG\n\n# 需对外暴露actuator\nmanagement:\n  endpoint:\n    health:\n      show-details: always\n      enabled: true\n    restart:\n      enabled: true\n    info:\n      enabled: true\n  endpoints:\n    web:\n      exposure:\n        include: '*'\n#  health:\n#    kubernetes:\n#      enabled: false\n#  info:\n#    kubernetes:\n#      enabled: false\n\nspring:\n  application:\n    name: config-sample\n  jackson:\n    serialization:\n      fail-on-empty-beans: false\n  config:\n    import: optional:configserver:http://configserver.cloudnative.io\n  cloud:\n    kubernetes:\n      client:\n        namespace: default\n      enabled: true\n      discovery:\n        # 开启服务注册发现\n        enabled: true\n        # 允许访问所有namespaces\n        all-namespaces: false\n        include-not-ready-addresses: false\n\n---\n\nspring:\n  config:\n    activate:\n      on-profile: kubernetes\n      on-cloud-platform: kubernetes\n    import: optional:configserver:http://spring-cloud-kubernetes-configserver:8888\n```\n\n**配置说明：**\n\n* management.endpoint和management.endpoints部分内容为actuator的端点配置部分，主要是开放`/refresh`端点，便于Configuration Watcher感知到configmap或secret内容变化刷新应用配置。另在开发阶段我们对外暴露了所有端点便于调试观察应用程序配置等信息，在生产环境务必进行取舍。\n* spring.application.name 应用程序名称，该内容应和configmap、secret的名称保持一致。\n* spring.config.import:optional:configserver:http://configserver.cloudnative.io 配置从configserver导入配置信息。该属性配置是spring boot提供的功能。\n* spring.cloud.kubernetes.client.namespace 配置客户端访问svc的namespace，如不配置结合下文的配置将会读取kubernetes集群中所有的服务。建议配置！\n* spring.config.active 配置项等同于spring.profile.active。后者在最新版的spring boot框架中被标记为过期，不建议使用。其后面的配置项内容仅在kubernetes集群环境中生效，同理访问spring cloud config server的svc地址。\n\n### 3、打包部署\n\n#### 3.1 spring-boot-maven-plugin打包制作镜像\n\n```bash\n# 编译打包\n❯ mvn clean package -Dmaven.test.skip=true\n[INFO] Scanning for projects...\n[INFO] \n[INFO] ----------------\u003c com.cloudnative.sample:config-sample \u003e----------------\n[INFO] Building config-sample 1.1.0\n[INFO] --------------------------------[ jar ]---------------------------------\n[INFO] \n[INFO] --- maven-clean-plugin:3.2.0:clean (default-clean) @ config-sample ---\n[INFO] Deleting /Users/amz/develop/workspace/spring-cloud-kubernetes-samples/config-sample/target\n[INFO] \n[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ config-sample ---\n[INFO] Using 'UTF-8' encoding to copy filtered resources.\n[INFO] Using 'UTF-8' encoding to copy filtered properties files.\n[INFO] Copying 3 resources\n[INFO] Copying 1 resource\n[INFO] \n[INFO] --- maven-compiler-plugin:3.10.1:compile (default-compile) @ config-sample ---\n[INFO] Changes detected - recompiling the module!\n[INFO] Compiling 5 source files to /Users/amz/develop/workspace/spring-cloud-kubernetes-samples/config-sample/target/classes\n[INFO] \n[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ config-sample ---\n[INFO] Not copying test resources\n[INFO] \n[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ config-sample ---\n[INFO] Not compiling test sources\n[INFO] \n[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ config-sample ---\n[INFO] Tests are skipped.\n[INFO] \n[INFO] --- maven-jar-plugin:3.2.2:jar (default-jar) @ config-sample ---\n[INFO] Building jar: /Users/amz/develop/workspace/spring-cloud-kubernetes-samples/config-sample/target/config-sample-1.1.0.jar\n[INFO] \n[INFO] --- spring-boot-maven-plugin:2.7.3:repackage (repackage) @ config-sample ---\n[INFO] Replacing main artifact with repackaged archive\n[INFO] ------------------------------------------------------------------------\n[INFO] BUILD SUCCESS\n[INFO] ------------------------------------------------------------------------\n[INFO] Total time:  6.373 s\n[INFO] Finished at: 2022-09-14T11:38:00+08:00\n[INFO] ------------------------------------------------------------------------\n# 打docker镜像并推送到私服\n❯ mvn spring-boot:build-image -Dmaven.test.skip=true\n[INFO] Scanning for projects...\n[INFO] \n[INFO] ----------------\u003c com.cloudnative.sample:config-sample \u003e----------------\n[INFO] Building config-sample 1.1.0\n[INFO] --------------------------------[ jar ]---------------------------------\n[INFO] \n[INFO] \u003e\u003e\u003e spring-boot-maven-plugin:2.7.3:build-image (default-cli) \u003e package @ config-sample \u003e\u003e\u003e\n[INFO] \n[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ config-sample ---\n[INFO] Using 'UTF-8' encoding to copy filtered resources.\n[INFO] Using 'UTF-8' encoding to copy filtered properties files.\n[INFO] Copying 3 resources\n[INFO] Copying 1 resource\n[INFO] \n[INFO] --- maven-compiler-plugin:3.10.1:compile (default-compile) @ config-sample ---\n[INFO] Nothing to compile - all classes are up to date\n[INFO] \n[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ config-sample ---\n[INFO] Not copying test resources\n[INFO] \n[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ config-sample ---\n[INFO] Not compiling test sources\n[INFO] \n[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ config-sample ---\n[INFO] Tests are skipped.\n[INFO] \n[INFO] --- maven-jar-plugin:3.2.2:jar (default-jar) @ config-sample ---\n[INFO] \n[INFO] --- spring-boot-maven-plugin:2.7.3:repackage (repackage) @ config-sample ---\n[INFO] Replacing main artifact with repackaged archive\n[INFO] \n[INFO] \u003c\u003c\u003c spring-boot-maven-plugin:2.7.3:build-image (default-cli) \u003c package @ config-sample \u003c\u003c\u003c\n[INFO] \n[INFO] \n[INFO] --- spring-boot-maven-plugin:2.7.3:build-image (default-cli) @ config-sample ---\n[INFO] Building image 'reg.anchnet.com/cloudnative/config-sample:1.1.0'\n[INFO] \n[INFO]  \u003e Executing lifecycle version v0.13.2\n[INFO]  \u003e Using build cache volume 'pack-cache-c44afd82185f.build'\n[INFO] \n[INFO]  \u003e Running creator\n[INFO]     [creator]     ===\u003e ANALYZING\n[INFO]     [creator]     Restoring data for sbom from previous image\n[INFO]     [creator]     ===\u003e DETECTING\n[INFO]     [creator]     6 of 19 buildpacks participating\n[INFO]     [creator]     paketo-buildpacks/ca-certificates   3.0.2\n[INFO]     [creator]     paketo-buildpacks/bellsoft-liberica 9.0.2\n[INFO]     [creator]     paketo-buildpacks/syft              1.3.1\n[INFO]     [creator]     paketo-buildpacks/executable-jar    6.0.2\n[INFO]     [creator]     paketo-buildpacks/dist-zip          5.0.2\n[INFO]     [creator]     paketo-buildpacks/spring-boot       5.3.0\n[INFO]     [creator]     ===\u003e RESTORING\n[INFO]     [creator]     Restoring metadata for \"paketo-buildpacks/ca-certificates:helper\" from app image\n[INFO]     [creator]     Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:helper\" from app image\n[INFO]     [creator]     Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:java-security-properties\" from app image\n[INFO]     [creator]     Restoring metadata for \"paketo-buildpacks/bellsoft-liberica:jre\" from app image\n[INFO]     [creator]     Restoring metadata for \"paketo-buildpacks/syft:syft\" from cache\n[INFO]     [creator]     Restoring metadata for \"paketo-buildpacks/spring-boot:spring-cloud-bindings\" from app image\n[INFO]     [creator]     Restoring metadata for \"paketo-buildpacks/spring-boot:web-application-type\" from app image\n[INFO]     [creator]     Restoring metadata for \"paketo-buildpacks/spring-boot:helper\" from app image\n[INFO]     [creator]     Restoring data for \"paketo-buildpacks/syft:syft\" from cache\n[INFO]     [creator]     Restoring data for sbom from cache\n[INFO]     [creator]     ===\u003e BUILDING\n[INFO]     [creator]     \n[INFO]     [creator]     Paketo CA Certificates Buildpack 3.0.2\n[INFO]     [creator]       https://github.com/paketo-buildpacks/ca-certificates\n[INFO]     [creator]       Launch Helper: Reusing cached layer\n[INFO]     [creator]     \n[INFO]     [creator]     Paketo BellSoft Liberica Buildpack 9.0.2\n[INFO]     [creator]       https://github.com/paketo-buildpacks/bellsoft-liberica\n[INFO]     [creator]       Build Configuration:\n[INFO]     [creator]         $BP_JVM_TYPE                 JRE             the JVM type - JDK or JRE\n[INFO]     [creator]         $BP_JVM_VERSION              8.*             the Java version\n[INFO]     [creator]       Launch Configuration:\n[INFO]     [creator]         $BPL_DEBUG_ENABLED           false           enables Java remote debugging support\n[INFO]     [creator]         $BPL_DEBUG_PORT              8000            configure the remote debugging port\n[INFO]     [creator]         $BPL_DEBUG_SUSPEND           false           configure whether to suspend execution until a debugger has attached\n[INFO]     [creator]         $BPL_HEAP_DUMP_PATH                          write heap dumps on error to this path\n[INFO]     [creator]         $BPL_JAVA_NMT_ENABLED        true            enables Java Native Memory Tracking (NMT)\n[INFO]     [creator]         $BPL_JAVA_NMT_LEVEL          summary         configure level of NMT, summary or detail\n[INFO]     [creator]         $BPL_JFR_ARGS                                configure custom Java Flight Recording (JFR) arguments\n[INFO]     [creator]         $BPL_JFR_ENABLED             false           enables Java Flight Recording (JFR)\n[INFO]     [creator]         $BPL_JMX_ENABLED             false           enables Java Management Extensions (JMX)\n[INFO]     [creator]         $BPL_JMX_PORT                5000            configure the JMX port\n[INFO]     [creator]         $BPL_JVM_HEAD_ROOM           0               the headroom in memory calculation\n[INFO]     [creator]         $BPL_JVM_LOADED_CLASS_COUNT  35% of classes  the number of loaded classes in memory calculation\n[INFO]     [creator]         $BPL_JVM_THREAD_COUNT        250             the number of threads in memory calculation\n[INFO]     [creator]         $JAVA_TOOL_OPTIONS                           the JVM launch flags\n[INFO]     [creator]       BellSoft Liberica JRE 8.0.312: Reusing cached layer\n[INFO]     [creator]       Launch Helper: Reusing cached layer\n[INFO]     [creator]       Java Security Properties: Reusing cached layer\n[INFO]     [creator]     \n[INFO]     [creator]     Paketo Syft Buildpack 1.3.1\n[INFO]     [creator]       https://github.com/paketo-buildpacks/syft\n[INFO]     [creator]     \n[INFO]     [creator]     Paketo Executable JAR Buildpack 6.0.2\n[INFO]     [creator]       https://github.com/paketo-buildpacks/executable-jar\n[INFO]     [creator]       Class Path: Contributing to layer\n[INFO]     [creator]         Writing env/CLASSPATH.delim\n[INFO]     [creator]         Writing env/CLASSPATH.prepend\n[INFO]     [creator]       Process types:\n[INFO]     [creator]         executable-jar: java org.springframework.boot.loader.JarLauncher (direct)\n[INFO]     [creator]         task:           java org.springframework.boot.loader.JarLauncher (direct)\n[INFO]     [creator]         web:            java org.springframework.boot.loader.JarLauncher (direct)\n[INFO]     [creator]     \n[INFO]     [creator]     Paketo Spring Boot Buildpack 5.3.0\n[INFO]     [creator]       https://github.com/paketo-buildpacks/spring-boot\n[INFO]     [creator]       Creating slices from layers index\n[INFO]     [creator]         dependencies\n[INFO]     [creator]         spring-boot-loader\n[INFO]     [creator]         snapshot-dependencies\n[INFO]     [creator]         application\n[INFO]     [creator]       Launch Helper: Reusing cached layer\n[INFO]     [creator]       Spring Cloud Bindings 1.8.0: Reusing cached layer\n[INFO]     [creator]       Web Application Type: Reusing cached layer\n[INFO]     [creator]       4 application slices\n[INFO]     [creator]       Image labels:\n[INFO]     [creator]         org.opencontainers.image.title\n[INFO]     [creator]         org.opencontainers.image.version\n[INFO]     [creator]         org.springframework.boot.version\n[INFO]     [creator]     ===\u003e EXPORTING\n[INFO]     [creator]     Reusing layer 'paketo-buildpacks/ca-certificates:helper'\n[INFO]     [creator]     Reusing layer 'paketo-buildpacks/bellsoft-liberica:helper'\n[INFO]     [creator]     Reusing layer 'paketo-buildpacks/bellsoft-liberica:java-security-properties'\n[INFO]     [creator]     Reusing layer 'paketo-buildpacks/bellsoft-liberica:jre'\n[INFO]     [creator]     Reusing layer 'paketo-buildpacks/executable-jar:classpath'\n[INFO]     [creator]     Reusing layer 'paketo-buildpacks/spring-boot:helper'\n[INFO]     [creator]     Reusing layer 'paketo-buildpacks/spring-boot:spring-cloud-bindings'\n[INFO]     [creator]     Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'\n[INFO]     [creator]     Adding layer 'launch.sbom'\n[INFO]     [creator]     Reusing 5/5 app layer(s)\n[INFO]     [creator]     Reusing layer 'launcher'\n[INFO]     [creator]     Reusing layer 'config'\n[INFO]     [creator]     Reusing layer 'process-types'\n[INFO]     [creator]     Adding label 'io.buildpacks.lifecycle.metadata'\n[INFO]     [creator]     Adding label 'io.buildpacks.build.metadata'\n[INFO]     [creator]     Adding label 'io.buildpacks.project.metadata'\n[INFO]     [creator]     Adding label 'org.opencontainers.image.title'\n[INFO]     [creator]     Adding label 'org.opencontainers.image.version'\n[INFO]     [creator]     Adding label 'org.springframework.boot.version'\n[INFO]     [creator]     Setting default process type 'web'\n[INFO]     [creator]     Saving reg.anchnet.com/cloudnative/config-sample:1.1.0...\n[INFO]     [creator]     *** Images (5f7286a1f97d):\n[INFO]     [creator]           reg.anchnet.com/cloudnative/config-sample:1.1.0\n[INFO]     [creator]     Reusing cache layer 'paketo-buildpacks/syft:syft'\n[INFO]     [creator]     Reusing cache layer 'cache.sbom'\n[INFO] \n[INFO] Successfully built image 'reg.anchnet.com/cloudnative/config-sample:1.1.0'\n[INFO] \n[INFO]  \u003e Pushing image 'reg.anchnet.com/cloudnative/config-sample:1.1.0' 100%\n[INFO]  \u003e Pushed image 'reg.anchnet.com/cloudnative/config-sample:1.1.0'\n[INFO] ------------------------------------------------------------------------\n[INFO] BUILD SUCCESS\n[INFO] ------------------------------------------------------------------------\n[INFO] Total time:  49.317 s\n[INFO] Finished at: 2022-09-14T11:39:46+08:00\n[INFO] ------------------------------------------------------------------------\n```\n\n**说明：**\n\n* 在spring-boot 2.3版本后spring-boot-maven-plugin有一项新特性，就是可以直接打docker镜像并推送到私服。本地不需要安装docker环境，也不需要提供Dockerfile文件。\n\n```xml\n\u003cplugin\u003e\n    \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-maven-plugin\u003c/artifactId\u003e\n    \u003cconfiguration\u003e\n      \u003clayers\u003e\n        \u003cenabled\u003etrue\u003c/enabled\u003e\n      \u003c/layers\u003e\n      \u003cimage\u003e\n        \u003cname\u003e${docker.registry.organization}/${project.artifactId}:${project.version}\u003c/name\u003e\n        \u003cpublish\u003etrue\u003c/publish\u003e\n        \u003cpullPolicy\u003eIF_NOT_PRESENT\u003c/pullPolicy\u003e\n      \u003c/image\u003e\n      \u003cgoal\u003ebuild-image\u003c/goal\u003e\n      \u003cdocker\u003e\n        \u003chost\u003etcp://172.16.62.15:2375\u003c/host\u003e\n        \u003ctlsVerify\u003efalse\u003c/tlsVerify\u003e\n        \u003cpublishRegistry\u003e\n          \u003cusername\u003e${env.DOCKER_USERNAME}\u003c/username\u003e\n          \u003cpassword\u003e${env.DOCKER_PASSWORD}\u003c/password\u003e\n        \u003c/publishRegistry\u003e\n      \u003c/docker\u003e\n      \u003cpullPolicy\u003eIF_NOT_PRESENT\u003c/pullPolicy\u003e\n    \u003c/configuration\u003e\n\u003c/plugin\u003e\n```\n\n如上xml配置，只需要配置好远程docker地址，及环境变量中配置好docker registry的用户名密码，就可直接打包并推送。\n\n#### 3.2 kubernetes集群部署\n\n直接应用**k8s**目录的部署文件即可。\n\n```bash\n❯ k apply -f k8s\nconfigmap/config-sample created\ndeployment.apps/config-sample created\nservice/config-sample created\ningress.networking.k8s.io/configsample-ingress created\nserviceaccount/admin-user unchanged\nclusterrolebinding.rbac.authorization.k8s.io/admin-user unchanged\nsecret/config-sample unchanged\n❯ k get pod -owide\nNAME                                                              READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES\nconfig-sample-866487d6d7-jnb49                                    1/1     Running   0          46m     172.18.199.236   node7   \u003cnone\u003e           \u003cnone\u003e\nnfs-client-provisioner-67cd9c9567-w8k7q                           1/1     Running   12         71d     172.18.104.4     node2   \u003cnone\u003e           \u003cnone\u003e\nnginx-6799fc88d8-2fv2t                                            1/1     Running   0          6d22h   172.18.225.68    node8   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-configserver-deployment-7d5667c44f7j9z7   1/1     Running   0          22h     172.18.104.71    node9   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-configuration-watcher-deployment-5zltx9   1/1     Running   0          23h     172.18.104.69    node9   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-discoveryserver-deployment-9d5d86d7lhnh   1/1     Running   0          23h     172.18.104.70    node9   \u003cnone\u003e           \u003cnone\u003e\n❯ k get cm\nNAME                                            DATA   AGE\nconfig-sample                                   1      47m\ngrafana-cert-cm                                 2      19d\nkube-root-ca.crt                                1      112d\nkubernetesconfigserver                          1      22h\nspring-cloud-kubernetes-configuration-watcher   1      23h\n❯ k get svc\nNAME                                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE\nconfig-sample                                   ClusterIP   10.102.84.68     \u003cnone\u003e        8080/TCP   47m\nkubernetes                                      ClusterIP   10.96.0.1        \u003cnone\u003e        443/TCP    112d\nspring-cloud-kubernetes-configserver            ClusterIP   10.109.120.151   \u003cnone\u003e        8888/TCP   23h\nspring-cloud-kubernetes-configuration-watcher   ClusterIP   10.110.146.208   \u003cnone\u003e        8888/TCP   23h\nspring-cloud-kubernetes-discoveryserver         ClusterIP   10.97.205.220    \u003cnone\u003e        80/TCP     23h\n❯ k get ingress\nNAME                      CLASS    HOSTS                            ADDRESS     PORTS   AGE\nconfigsample-ingress      \u003cnone\u003e   configsample.cloudnative.io      localhost   80      47m\nconfigserver-ingress      \u003cnone\u003e   configserver.cloudnative.io      localhost   80      23h\ndiscoveryserver-ingress   \u003cnone\u003e   discoveryserver.cloudnative.io   localhost   80      23h\n```\n\n至此，该服务已部署完毕，接下来我们进行测试。\n\n### 4、测试\n\n首先查看kubernetes集群中服务注册中心中的服务情况。\n\n```bash\n❯ http discoveryserver.cloudnative.io/apps\nHTTP/1.1 200 OK\nConnection: keep-alive\nContent-Type: application/json\nDate: Wed, 14 Sep 2022 04:41:09 GMT\nTransfer-Encoding: chunked\n\n[\n    {\n        \"name\": \"config-sample\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"172.18.199.236\",\n                \"instanceId\": \"9672c3cb-4a84-4a65-9a34-4ec0c086c330\",\n                \"metadata\": {\n                    \"boot.spring.io/actuator\": \"http://:8080/actuator\",\n                    \"http\": \"8080\",\n                    \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{\\\"boot.spring.io/actuator\\\":\\\"http://:8080/actuator\\\"},\\\"name\\\":\\\"config-sample\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":8080,\\\"targetPort\\\":8080}],\\\"selector\\\":{\\\"app\\\":\\\"config-sample\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 8080,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"config-sample\",\n                \"uri\": \"http://172.18.199.236:8080\"\n            }\n        ]\n    },\n    {\n        \"name\": \"spring-cloud-kubernetes-configserver\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"172.18.104.71\",\n                \"instanceId\": \"cbaa7e51-01d8-43f1-b7c6-f9e4d17b709f\",\n                \"metadata\": {\n                    \"app\": \"spring-cloud-kubernetes-configserver\",\n                    \"http\": \"8888\",\n                    \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configserver\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-configserver\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":8888,\\\"targetPort\\\":8888}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configserver\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 8888,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"spring-cloud-kubernetes-configserver\",\n                \"uri\": \"http://172.18.104.71:8888\"\n            }\n        ]\n    },\n    {\n        \"name\": \"spring-cloud-kubernetes-configuration-watcher\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"172.18.104.69\",\n                \"instanceId\": \"402de4ed-89b3-43c7-be8b-e8e892c4cc9f\",\n                \"metadata\": {\n                    \"app\": \"spring-cloud-kubernetes-configuration-watcher\",\n                    \"http\": \"8888\",\n                    \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":8888,\\\"targetPort\\\":8888}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 8888,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"spring-cloud-kubernetes-configuration-watcher\",\n                \"uri\": \"http://172.18.104.69:8888\"\n            }\n        ]\n    },\n    {\n        \"name\": \"spring-cloud-kubernetes-discoveryserver\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"172.18.104.70\",\n                \"instanceId\": \"c953b710-9e81-4a62-9f02-7a4184f59520\",\n                \"metadata\": {\n                    \"app\": \"spring-cloud-kubernetes-discoveryserver\",\n                    \"http\": \"8761\",\n                    \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":80,\\\"targetPort\\\":8761}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 8761,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"spring-cloud-kubernetes-discoveryserver\",\n                \"uri\": \"http://172.18.104.70:8761\"\n            }\n        ]\n    },\n    {\n        \"name\": \"kubernetes\",\n        \"serviceInstances\": [\n            {\n                \"cluster\": null,\n                \"host\": \"192.168.101.20\",\n                \"instanceId\": \"\",\n                \"metadata\": {\n                    \"component\": \"apiserver\",\n                    \"https\": \"6443\",\n                    \"provider\": \"kubernetes\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 6443,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"kubernetes\",\n                \"uri\": \"http://192.168.101.20:6443\"\n            },\n            {\n                \"cluster\": null,\n                \"host\": \"192.168.101.22\",\n                \"instanceId\": \"\",\n                \"metadata\": {\n                    \"component\": \"apiserver\",\n                    \"https\": \"6443\",\n                    \"provider\": \"kubernetes\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 6443,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"kubernetes\",\n                \"uri\": \"http://192.168.101.22:6443\"\n            },\n            {\n                \"cluster\": null,\n                \"host\": \"192.168.101.24\",\n                \"instanceId\": \"\",\n                \"metadata\": {\n                    \"component\": \"apiserver\",\n                    \"https\": \"6443\",\n                    \"provider\": \"kubernetes\"\n                },\n                \"namespace\": \"default\",\n                \"port\": 6443,\n                \"scheme\": \"http\",\n                \"secure\": false,\n                \"serviceId\": \"kubernetes\",\n                \"uri\": \"http://192.168.101.24:6443\"\n            }\n        ]\n    }\n]\n```\n\n接下来查看服务配置中心中的配置情况：\n\n* kubernetes profile\n\n```bash\n❯ http configserver.cloudnative.io/config-sample/kubernetes\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Type: application/json\nDate: Wed, 14 Sep 2022 04:42:49 GMT\nTransfer-Encoding: chunked\n\n{\n    \"label\": null,\n    \"name\": \"config-sample\",\n    \"profiles\": [\n        \"kubernetes\"\n    ],\n    \"propertySources\": [\n        {\n            \"name\": \"configmap.config-sample.default\",\n            \"source\": {\n                \"greeting.message\": \"HelloWorld! --- from ConfigMap kubernetes profile 444\",\n                \"spring.cloud.config.profile\": \"kubernetes\",\n                \"spring.config.activate.on-profile\": \"kubernetes\"\n            }\n        },\n        {\n            \"name\": \"secrets.config-sample.default\",\n            \"source\": {\n                \"secret.password\": \"Jiaduobao886\",\n                \"secret.username\": \"admin\"\n            }\n        },\n        {\n            \"name\": \"https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #1)\",\n            \"source\": {\n                \"eureka.client.enabled\": false,\n                \"spring.cloud.kubernetes.enabled\": true,\n                \"spring.config.activate.on-cloud-platform\": \"kubernetes\"\n            }\n        },\n        {\n            \"name\": \"https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #0)\",\n            \"source\": {\n                \"chaos.monkey.assaults.latency-active\": true,\n                \"chaos.monkey.assaults.level\": 3,\n                \"chaos.monkey.enabled\": false,\n                \"chaos.monkey.watcher.restController\": true,\n                \"chaos.monkey.watcher.service\": false,\n                \"eureka.client.serviceUrl.defaultZone\": \"http://localhost:8761/eureka/\",\n                \"management.endpoint.chaosmonkey.enabled\": true,\n                \"management.endpoint.health.show-details\": \"always\",\n                \"management.endpoint.restart.enabled\": true,\n                \"management.endpoints.web.exposure.include\": \"*\",\n                \"spring.cloud.kubernetes.enabled\": false\n            }\n        }\n    ],\n    \"state\": null,\n    \"version\": null\n}\n```\n\n* local profile\n\n```bash\n❯ http configserver.cloudnative.io/config-sample/local\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Type: application/json\nDate: Wed, 14 Sep 2022 04:43:53 GMT\nTransfer-Encoding: chunked\n\n{\n    \"label\": null,\n    \"name\": \"config-sample\",\n    \"profiles\": [\n        \"local\"\n    ],\n    \"propertySources\": [\n        {\n            \"name\": \"configmap.config-sample.default\",\n            \"source\": {\n                \"greeting.message\": \"HelloWorld! --- from ConfigMap local profile 222\",\n                \"spring.cloud.config.profile\": \"kubernetes\",\n                \"spring.config.activate.on-profile\": \"local\"\n            }\n        },\n        {\n            \"name\": \"secrets.config-sample.default\",\n            \"source\": {\n                \"secret.password\": \"Jiaduobao886\",\n                \"secret.username\": \"admin\"\n            }\n        },\n        {\n            \"name\": \"https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #1)\",\n            \"source\": {\n                \"eureka.client.enabled\": false,\n                \"spring.cloud.kubernetes.enabled\": true,\n                \"spring.config.activate.on-cloud-platform\": \"kubernetes\"\n            }\n        },\n        {\n            \"name\": \"https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #0)\",\n            \"source\": {\n                \"chaos.monkey.assaults.latency-active\": true,\n                \"chaos.monkey.assaults.level\": 3,\n                \"chaos.monkey.enabled\": false,\n                \"chaos.monkey.watcher.restController\": true,\n                \"chaos.monkey.watcher.service\": false,\n                \"eureka.client.serviceUrl.defaultZone\": \"http://localhost:8761/eureka/\",\n                \"management.endpoint.chaosmonkey.enabled\": true,\n                \"management.endpoint.health.show-details\": \"always\",\n                \"management.endpoint.restart.enabled\": true,\n                \"management.endpoints.web.exposure.include\": \"*\",\n                \"spring.cloud.kubernetes.enabled\": false\n            }\n        }\n    ],\n    \"state\": null,\n    \"version\": null\n}\n```\n\n具体访问路径格式遵循如下规则：\n\n```\nhttp://{config-server}:{port}/{applicationname}/{profile}\n```\n\n我们可以看到可以成功从configmap、secret及远程git仓库读取配置文件。\n\n#### 4.1、kubernetes环境服务测试\n\n###### 4.1.1 读取configmap\n\n```bash\n❯ http configsample.cloudnative.io/configmap/env\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 53\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 04:47:45 GMT\n\nHelloWorld! --- from ConfigMap kubernetes profile 444\n\n\n❯ http configsample.cloudnative.io/configmap/properties\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 53\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 04:47:47 GMT\n\nHelloWorld! --- from ConfigMap kubernetes profile 444\n\n\n❯ http configsample.cloudnative.io/configmap/value\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 53\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 04:47:52 GMT\n\nHelloWorld! --- from ConfigMap kubernetes profile 444\n```\n\n以上接口分别对应如下的代码：\n\n```java\n@RestController\n@RequestMapping(\"/configmap\")\npublic class ConfigMapController {\n\n    @Value(\"${greeting.message}\")\n    private String message;\n\n    @Autowired\n    private ConfigMapRead configMapRead;\n\n    @Autowired\n    private Environment environment;\n\n    @GetMapping(\"/value\")\n    public String value() {\n        return message;\n    }\n\n    @GetMapping(\"/properties\")\n    public String properties() {\n        return configMapRead.getMessage();\n    }\n\n    @GetMapping(\"/env\")\n    public String env() {\n        return environment.getProperty(\"greeting.message\");\n    }\n\n}\n```\n\n可见均可以正常加载。\n\n###### 4.1.2 读取secret\n\n```bash\n❯ http configsample.cloudnative.io/secret/env\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 18\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 04:49:31 GMT\n\nadmin|Jiaduobao886\n\n\n❯ http configsample.cloudnative.io/secret/properties\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 18\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 04:49:34 GMT\n\nadmin|Jiaduobao886\n\n\n❯ http configsample.cloudnative.io/secret/value\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 18\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 04:49:39 GMT\n\nadmin|Jiaduobao886\n```\n\n以上接口分别对应如下的代码：\n\n```java\n@RestController\n@RequestMapping(\"/secret\")\npublic class SecretController {\n\n    @Value(\"${secret.username}\")\n    private String username;\n\n    @Value(\"${secret.password}\")\n    private String password;\n\n    @Autowired\n    private SecretRead secretRead;\n\n    @Autowired\n    private Environment environment;\n\n    @GetMapping(\"/value\")\n    public String value() {\n        return username + \"|\" + password;\n    }\n\n    @GetMapping(\"/properties\")\n    public String properties() {\n        return secretRead.getUsername() + \"|\" + secretRead.getPassword();\n    }\n\n    @GetMapping(\"/env\")\n    public String env() {\n        return environment.getProperty(\"secret.username\") + \"|\" + environment.getProperty(\"secret.password\");\n    }\n\n}\n```\n\n###### 4.1.3 获取服务列表\n\n```bash\n❯ http configsample.cloudnative.io/\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Type: application/json\nDate: Wed, 14 Sep 2022 05:07:51 GMT\nTransfer-Encoding: chunked\n\n{\n    \"config-sample\": [\n        {\n            \"cluster\": null,\n            \"host\": \"172.18.199.236\",\n            \"instanceId\": \"9672c3cb-4a84-4a65-9a34-4ec0c086c330\",\n            \"metadata\": {\n                \"boot.spring.io/actuator\": \"http://:8080/actuator\",\n                \"http\": \"8080\",\n                \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{\\\"boot.spring.io/actuator\\\":\\\"http://:8080/actuator\\\"},\\\"name\\\":\\\"config-sample\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":8080,\\\"targetPort\\\":8080}],\\\"selector\\\":{\\\"app\\\":\\\"config-sample\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n            },\n            \"namespace\": \"default\",\n            \"port\": 8080,\n            \"scheme\": \"http\",\n            \"secure\": false,\n            \"serviceId\": \"config-sample\",\n            \"uri\": \"http://172.18.199.236:8080\"\n        }\n    ],\n    \"kubernetes\": [\n        {\n            \"cluster\": null,\n            \"host\": \"192.168.101.20\",\n            \"instanceId\": \"\",\n            \"metadata\": {\n                \"component\": \"apiserver\",\n                \"https\": \"6443\",\n                \"provider\": \"kubernetes\"\n            },\n            \"namespace\": \"default\",\n            \"port\": 6443,\n            \"scheme\": \"http\",\n            \"secure\": false,\n            \"serviceId\": \"kubernetes\",\n            \"uri\": \"http://192.168.101.20:6443\"\n        },\n        {\n            \"cluster\": null,\n            \"host\": \"192.168.101.22\",\n            \"instanceId\": \"\",\n            \"metadata\": {\n                \"component\": \"apiserver\",\n                \"https\": \"6443\",\n                \"provider\": \"kubernetes\"\n            },\n            \"namespace\": \"default\",\n            \"port\": 6443,\n            \"scheme\": \"http\",\n            \"secure\": false,\n            \"serviceId\": \"kubernetes\",\n            \"uri\": \"http://192.168.101.22:6443\"\n        },\n        {\n            \"cluster\": null,\n            \"host\": \"192.168.101.24\",\n            \"instanceId\": \"\",\n            \"metadata\": {\n                \"component\": \"apiserver\",\n                \"https\": \"6443\",\n                \"provider\": \"kubernetes\"\n            },\n            \"namespace\": \"default\",\n            \"port\": 6443,\n            \"scheme\": \"http\",\n            \"secure\": false,\n            \"serviceId\": \"kubernetes\",\n            \"uri\": \"http://192.168.101.24:6443\"\n        }\n    ],\n    \"spring-cloud-kubernetes-configserver\": [\n        {\n            \"cluster\": null,\n            \"host\": \"172.18.104.71\",\n            \"instanceId\": \"cbaa7e51-01d8-43f1-b7c6-f9e4d17b709f\",\n            \"metadata\": {\n                \"app\": \"spring-cloud-kubernetes-configserver\",\n                \"http\": \"8888\",\n                \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configserver\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-configserver\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":8888,\\\"targetPort\\\":8888}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configserver\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n            },\n            \"namespace\": \"default\",\n            \"port\": 8888,\n            \"scheme\": \"http\",\n            \"secure\": false,\n            \"serviceId\": \"spring-cloud-kubernetes-configserver\",\n            \"uri\": \"http://172.18.104.71:8888\"\n        }\n    ],\n    \"spring-cloud-kubernetes-configuration-watcher\": [\n        {\n            \"cluster\": null,\n            \"host\": \"172.18.104.69\",\n            \"instanceId\": \"402de4ed-89b3-43c7-be8b-e8e892c4cc9f\",\n            \"metadata\": {\n                \"app\": \"spring-cloud-kubernetes-configuration-watcher\",\n                \"http\": \"8888\",\n                \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":8888,\\\"targetPort\\\":8888}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-configuration-watcher\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n            },\n            \"namespace\": \"default\",\n            \"port\": 8888,\n            \"scheme\": \"http\",\n            \"secure\": false,\n            \"serviceId\": \"spring-cloud-kubernetes-configuration-watcher\",\n            \"uri\": \"http://172.18.104.69:8888\"\n        }\n    ],\n    \"spring-cloud-kubernetes-discoveryserver\": [\n        {\n            \"cluster\": null,\n            \"host\": \"172.18.104.70\",\n            \"instanceId\": \"c953b710-9e81-4a62-9f02-7a4184f59520\",\n            \"metadata\": {\n                \"app\": \"spring-cloud-kubernetes-discoveryserver\",\n                \"http\": \"8761\",\n                \"kubectl.kubernetes.io/last-applied-configuration\": \"{\\\"apiVersion\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\",\\\"metadata\\\":{\\\"annotations\\\":{},\\\"labels\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"name\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"ports\\\":[{\\\"name\\\":\\\"http\\\",\\\"port\\\":80,\\\"targetPort\\\":8761}],\\\"selector\\\":{\\\"app\\\":\\\"spring-cloud-kubernetes-discoveryserver\\\"},\\\"type\\\":\\\"ClusterIP\\\"}}\\n\"\n            },\n            \"namespace\": \"default\",\n            \"port\": 8761,\n            \"scheme\": \"http\",\n            \"secure\": false,\n            \"serviceId\": \"spring-cloud-kubernetes-discoveryserver\",\n            \"uri\": \"http://172.18.104.70:8761\"\n        }\n    ]\n}\n```\n\n其对应的代码如下：\n\n```java\n    @Autowired\n    private DiscoveryClient discoveryClient;\n\n    @GetMapping(\"/\")\n    public Object index() {\n        Map\u003cString, Object\u003e map = new TreeMap\u003c\u003e();\n        discoveryClient.getServices().forEach(serviceId -\u003e map.put(serviceId, discoveryClient.getInstances(serviceId)));\n        return map;\n    }\n```\n\n###### 4.1.4 访问/actuator端点\n\n* /actuator/info\n\n```bash\n❯ http configsample.cloudnative.io/actuator/info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Type: application/vnd.spring-boot.actuator.v3+json\nDate: Wed, 14 Sep 2022 05:18:34 GMT\nTransfer-Encoding: chunked\n\n{\n    \"kubernetes\": {\n        \"hostIp\": \"192.168.101.86\",\n        \"inside\": true,\n        \"namespace\": \"default\",\n        \"nodeName\": \"node7\",\n        \"podIp\": \"172.18.199.236\",\n        \"podName\": \"config-sample-866487d6d7-jnb49\",\n        \"serviceAccount\": \"admin-user\"\n    }\n}\n```\n\n* /actuator/configprops\n\n内容太多，略去\n\n* /actuator/health\n\n```bash\n❯ http configsample.cloudnative.io/actuator/health\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Type: application/vnd.spring-boot.actuator.v3+json\nDate: Wed, 14 Sep 2022 05:19:57 GMT\nTransfer-Encoding: chunked\n\n{\n    \"components\": {\n        \"clientConfigServer\": {\n            \"details\": {\n                \"propertySources\": [\n                    \"bootstrapProperties-configClient\",\n                    \"bootstrapProperties-configmap.config-sample.default\",\n                    \"bootstrapProperties-secrets.config-sample.default\",\n                    \"bootstrapProperties-https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #1)\",\n                    \"bootstrapProperties-https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #0)\",\n                    \"configserver:configmap.config-sample.default\",\n                    \"configserver:secrets.config-sample.default\",\n                    \"configserver:https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #1)\",\n                    \"configserver:https://github.com/ryanjbaxter/s1-2021-config/Config resource 'file [/tmp/config-repo-861021739807758125/application.yaml' via location '' (document #0)\",\n                    \"configClient\"\n                ]\n            },\n            \"status\": \"UP\"\n        },\n        \"discoveryComposite\": {\n            \"components\": {\n                \"discoveryClient\": {\n                    \"details\": {\n                        \"services\": [\n                            \"config-sample\",\n                            \"spring-cloud-kubernetes-configuration-watcher\",\n                            \"spring-cloud-kubernetes-configserver\",\n                            \"spring-cloud-kubernetes-discoveryserver\",\n                            \"kubernetes\"\n                        ]\n                    },\n                    \"status\": \"UP\"\n                }\n            },\n            \"status\": \"UP\"\n        },\n        \"diskSpace\": {\n            \"details\": {\n                \"exists\": true,\n                \"free\": 317222281216,\n                \"threshold\": 10485760,\n                \"total\": 321883471872\n            },\n            \"status\": \"UP\"\n        },\n        \"kubernetes\": {\n            \"details\": {\n                \"hostIp\": \"192.168.101.86\",\n                \"inside\": true,\n                \"labels\": {\n                    \"app\": \"config-sample\",\n                    \"pod-template-hash\": \"866487d6d7\"\n                },\n                \"namespace\": \"default\",\n                \"nodeName\": \"node7\",\n                \"podIp\": \"172.18.199.236\",\n                \"podName\": \"config-sample-866487d6d7-jnb49\",\n                \"serviceAccount\": \"admin-user\"\n            },\n            \"status\": \"UP\"\n        },\n        \"livenessState\": {\n            \"status\": \"UP\"\n        },\n        \"ping\": {\n            \"status\": \"UP\"\n        },\n        \"readinessState\": {\n            \"status\": \"UP\"\n        },\n        \"refreshScope\": {\n            \"status\": \"UP\"\n        }\n    },\n    \"groups\": [\n        \"liveness\",\n        \"readiness\"\n    ],\n    \"status\": \"UP\"\n}\n```\n\n\n\n#### 4.2 本地环境测试\n\n启动本地代码，启动时设置profile为local进行测试，注意观察启动日志。\n\n![Snipaste_2022-09-14_12-57-31](./Screenshots/Snipaste_2022-09-14_12-57-31.png)\n![Snipaste_2022-09-14_12-59-28](./Screenshots/Snipaste_2022-09-14_12-59-28.png)\n\n通过启动日志我们发现：\n\n1、程序以`local` profile 启动，访问了远程config server，从远端config server加载了配置信息；\n\n2、程序尝试使用`standard`配置创建Kubernetes ApiClient；\n\n3、程序读取了`$KUBECONFIG` 或 `$HOME/.kube/config`文件，当然本次启动是读取了`$HOME/.kube/config`文件；\n\n4、程序使用了kubernetes官方提供的原生api sdk `io.kubernetes.client`；\n\n5、程序从kubernetes集群中发现了5个服务。\n\n6、程序对外暴露了18个`actuator`端点。\n\n\n\n### 5、热更新\n\n#### 5.1、 kubernetes集群环境\n\n##### 5.1.1 configmap热更新\n\n测试前首先查看configmap的值如下：\n\n```bash\n❯ http configsample.cloudnative.io/configmap/value\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 53\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 05:23:51 GMT\n\nHelloWorld! --- from ConfigMap kubernetes profile 444\n```\n\n修改configmap，将444修改为555，并应用部署\n\n```bash\n❯ k apply -f k8s/configmap.yml\nconfigmap/config-sample configured\n```\n\n* 观察Configuration Watcher日志输出：\n\n![Snipaste_2022-09-14_13-33-16](./Screenshots/Snipaste_2022-09-14_13-33-16.png)\n![Snipaste_2022-09-14_13-33-39](./Screenshots/Snipaste_2022-09-14_13-33-39.png)\n\nConfiguration Watcher监听到configmap内容变更，并向目标应用程序发起了`/actuator/refresh`请求。\n\n* 观察应用程序config-sample日志输出：\n\n![Snipaste_2022-09-14_13-30-20](./Screenshots/Snipaste_2022-09-14_13-30-20.png)\n\n应用程序已经感知到配置变更进行了reload。\n\n* 访问应用程序\n\n![Snipaste_2022-09-14_13-38-35](./Screenshots/Snipaste_2022-09-14_13-38-35.png)\n\n可见，除了**value**方式外，其他两种模式配置均已更新为最新值。\n\n##### 5.1.2 secret热更新\n\n测试前首先查看secret的值如下：\n\n```bash\n❯ http configsample.cloudnative.io/secret/value\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 18\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 05:41:43 GMT\n\nadmin|Jiaduobao886\n```\n\n修改secret，将Jiaduobao886修改为Wanglaoji886，并应用部署\n\n```bash\n❯ k apply -f k8s/secret.yml\nsecret/config-sample configured\n```\n\n* 观察Configuration Watcher日志输出：\n\n![Snipaste_2022-09-14_13-45-11](./Screenshots/Snipaste_2022-09-14_13-45-11.png)\n![Snipaste_2022-09-14_13-45-29](./Screenshots/Snipaste_2022-09-14_13-45-29.png)\n\nConfiguration Watcher监听到configmap内容变更，并向目标应用程序发起了`/actuator/refresh`请求。\n\n* 观察应用程序config-sample日志输出：\n\n![Snipaste_2022-09-14_13-46-50](./Screenshots/Snipaste_2022-09-14_13-46-50.png)\n\n应用程序已经感知到配置变更进行了reload。\n\n* 访问应用程序\n\n![Snipaste_2022-09-14_13-49-47](./Screenshots/Snipaste_2022-09-14_13-49-47.png)\n\n可见，除了**value**方式外，其他两种模式配置均已更新为最新值。\n\n\n\n#### 5.2 本地环境\n\n\n\n**若程序在本地模式启动，configmap、secret即使内容发生变更，程序自身内容不会立即生效。这个很好理解，因为`/actuator/refresh`是由`Configuration Watcher`来触发，而`Configuration Watcher`部署在kubernetes集群内部，它的网络和你本地的网络是不通的，所以没法发起该请求刷新配置。本地只需要重新启动服务即可从configmap、secret中读取到最新的配置。**\n\n\n\n### 6、configmap、secret删除测试\n\n删除前先查看configmap、secret中的值如下所示：\n\n```bash\n❯ http configsample.cloudnative.io/configmap/env\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 53\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 05:58:31 GMT\n\nHelloWorld! --- from ConfigMap kubernetes profile 444\n\n❯ http configsample.cloudnative.io/secret/env\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 18\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 05:58:23 GMT\n\nadmin|Jiaduobao886\n```\n\n接下来删除configmap、secret\n\n```bash\n❯ k delete cm config-sample\nconfigmap \"config-sample\" deleted\n❯ k delete secret config-sample\nsecret \"config-sample\" deleted\n```\n\n我们会发现Configuration Watcher和应用程序自身都感知到了此次内容变化。接下来我们再次访问configmap、secret观察其输出如下：\n\n```bash\n❯ http configsample.cloudnative.io/configmap/env\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 53\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 06:01:28 GMT\n\nHelloWorld! --- from ConfigMap kubernetes profile 444\n\n\n❯ http configsample.cloudnative.io/secret/env\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 18\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 06:01:34 GMT\n\nadmin|Jiaduobao886\n```\n\n我们神奇的发现获取到的值还是原来的值。由此可以推测，当不小心误删除configmap、secret时，只有不手动重启应用程序，程序中仍能读取到删除前的值。\n\n## 五、discovery-sample（服务发现、feign调用、负载均衡）\n\n该示例演示spring cloud kubernetes使用`spring-cloud-starter-kubernetes-discoveryclient`配合`spring-cloud-kubernetes-discoveryserver`组件在没有`~/.kube/config`文件的情况下整合kubernetes做服务注册发现。该模式适用于本地开发环境，大多数场景下，由于开发环境安全或网络限制，不可能所有人能拿到`~/.kube/config`文件，此时如采用前文中使用的`spring-cloud-starter-kubernetes-client`那是没办法在本地开展工作的。因此该示例演示了该场景下该如何进行开发及调用线上kubernetes服务，只需要确保本地环境和kubernetes集群在同一个局域网内即可。\n\n### 1、pom.xml中添加依赖\n\n```xml\n        \u003c!-- 依赖spring-cloud-kubernetes-discoveryserver组件，直接与其通信，不需要本地存在 ~/.kube/config文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-kubernetes-discoveryclient\u003c/artifactId\u003e\n            \u003cversion\u003e2.1.3\u003c/version\u003e\n        \u003c/dependency\u003e\n        \u003c!-- 从configmap、secret加载应用配置文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-kubernetes-client-config\u003c/artifactId\u003e\n            \u003cversion\u003e2.1.3\u003c/version\u003e\n        \u003c/dependency\u003e\n        \u003c!-- spring-cloud-config-clien 从config server加载配置文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-config-client\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003c!--\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-kubernetes-client-loadbalancer\u003c/artifactId\u003e\n            \u003cversion\u003e2.1.3\u003c/version\u003e\n        \u003c/dependency\u003e\n        --\u003e\n        \u003c!-- loadbalancer组件，不建议使用spring-cloud-starter-kubernetes-client-loadbalancer组件，该组件仍然会使用本地~/.kube/config文件进行通信 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-loadbalancer\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-openfeign\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n            \u003cartifactId\u003espring-boot-starter-actuator\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n            \u003cartifactId\u003espring-boot-starter-web\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n```\n\n**依赖说明：**\n\n* spring-cloud-starter-kubernetes-discoveryclient配合spring-cloud-kubernetes-discoveryserver使用，需事先在kubernetes集群中部署好spring-cloud-kubernetes-discoveryserver服务，并创建好ingress供外部调用。\n* spring-cloud-starter-kubernetes-client-config 从configmap、secret加载应用配置文件\n* spring-cloud-config-client 从config server加载配置文件\n* spring-cloud-starter-loadbalancer loadbalancer组件，不建议使用spring-cloud-starter-kubernetes-client-loadbalancer组件，该组件仍然会使用本地~/.kube/config文件进行通信\n* spring-cloud-starter-openfeign 创建feign client\n* spring-boot-starter-actuator 提供`/actuator`端点\n\n### 2、配置bootstrap.yml\n\napplication.yml 该文件放一些通用配置类信息\n\n```yaml\nserver:\n  port: 9080\n\nspring:\n  main:\n    allow-bean-definition-overriding: true\n  application:\n    name: discovery-sample\n  jackson:\n    serialization:\n      fail-on-empty-beans: false\n\nmanagement:\n  endpoint:\n    health:\n      show-details: always\n      enabled: true\n    restart:\n      enabled: true\n    info:\n      enabled: true\n  endpoints:\n    web:\n      exposure:\n        include: '*'\n#  health:\n#    kubernetes:\n#      enabled: false\n#  info:\n#    kubernetes:\n#      enabled: false\n\nlogging:\n  level:\n    org.springframework.cloud.kubernetes: DEBUG\n    org.springframework.cloud.openfeign: TRACE\n```\n\nbootstrap-local.yml 本地模式启动时的配置文件\n\n```yaml\nspring:\n  config:\n    activate:\n      on-profile: local\n    import: optional:configserver:http://configserver.cloudnative.io\n  cloud:\n    loadbalancer:\n      enabled: true\n      ribbon:\n        enabled: false\n    kubernetes:\n      enabled: true\n      config:\n        name: discovery-sample\n        namespace: default\n        enabled: true\n        enable-api: true\n      secrets:\n        name: discovery-sample\n        namespace: default\n        enabled: true\n        enable-api: true\n      reload:\n        enabled: true\n        mode: event\n        strategy: refresh\n        monitoring-config-maps: true\n        monitoring-secrets: true\n      loadbalancer:\n        enabled: true\n        mode: SERVICE\n      discovery:\n        # 开启服务注册发现\n        enabled: true\n        # 允许访问所有namespaces\n        all-namespaces: true\n        include-not-ready-addresses: false\n        discovery-server-url: http://discoveryserver.cloudnative.io\n\n#feign:\n#  client:\n#    config-sample-url: http://configsample.cloudnative.io\n#    weibo-service-url: http://weiboservice.cloudnative.io\n#    weather-service-url: http://weatherservice.cloudnative.io\n```\n\nbootstrap-kubernetes.yml kubernetes集群模式启动时的配置文件\n\n```yaml\nspring:\n  config:\n    activate:\n      on-profile: kubernetes\n    import: optional:configserver:http://spring-cloud-kubernetes-configserver:8888\n  cloud:\n    loadbalancer:\n      enabled: true\n      ribbon:\n        enabled: false\n    kubernetes:\n      enabled: true\n      config:\n        name: discovery-sample\n        namespace: default\n        enabled: true\n        enable-api: true\n      secrets:\n        name: discovery-sample\n        namespace: default\n        enabled: true\n        enable-api: true\n      reload:\n        enabled: true\n        mode: event\n        strategy: refresh\n        monitoring-config-maps: true\n        monitoring-secrets: true\n      loadbalancer:\n        enabled: true\n        mode: SERVICE\n      discovery:\n        # 开启服务注册发现\n        enabled: true\n        # 允许访问所有namespaces\n        all-namespaces: true\n        include-not-ready-addresses: false\n        discovery-server-url: http://spring-cloud-kubernetes-discoveryserver\n\n#feign:\n#  client:\n#    config-sample-url: http://config-sample:8080\n#    weibo-service-url: http://weibo-service:5000\n#    weather-service-url: http://weather-service:8080\n```\n\n**配置文件说明：**\n\n* spring.config.import部分的配置分别从ingress或集群内svc访问configserver加载应用配置文件；\n* spring.cloud.loadbalancer 部分配置是和loadbalancer相关的配置\n* spring.cloud.kubernetes.config 应用读取configmap的配置\n* spring.cloud.kubernetes.secrets 应用读取secrets的配置\n* spring.cloud.kubernetes.reload configmap、secret热加载配置\n* spring.cloud.kubernetes.loadbalancer 部分配置，有SERVICE、POD两种模式\n* spring.cloud.kubernetes.discovery kubernetes服务发现部分配置，discovery-server-url为`spring-cloud-kubernetes-discoveryserver`组件的访问地址。\n\n\n\n**注意：在使用`spring-cloud-starter-kubernetes-discoveryclient`模式时，configmap、secrets、reload部分的配置项均需要显式声明配置，否则热更新不生效。**\n\n### 3、打包部署\n\n```bash\n❯ mvn clean package -Dmaven.test.skip=true\n❯ mvn spring-boot:build-image -Dmaven.test.skip=true\n❯ k apply -f k8s\nconfigmap/discovery-sample created\ndeployment.apps/discovery-sample created\nservice/discovery-sample created\ningress.networking.k8s.io/discoverysample-ingress created\nserviceaccount/admin-user unchanged\nclusterrolebinding.rbac.authorization.k8s.io/admin-user unchanged\nsecret/discovery-sample unchanged\n❯ k get pod -owide\nNAME                                                              READY   STATUS    RESTARTS   AGE    IP               NODE    NOMINATED NODE   READINESS GATES\nconfig-sample-866487d6d7-jnb49                                    1/1     Running   0          171m   172.18.199.236   node7   \u003cnone\u003e           \u003cnone\u003e\ndiscovery-sample-654dc778f9-p44ns                                 1/1     Running   0          30s    172.18.199.243   node7   \u003cnone\u003e           \u003cnone\u003e\nnfs-client-provisioner-67cd9c9567-w8k7q                           1/1     Running   12         71d    172.18.104.4     node2   \u003cnone\u003e           \u003cnone\u003e\nnginx-6799fc88d8-2fv2t                                            1/1     Running   0          7d     172.18.225.68    node8   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-configserver-deployment-7d5667c44f7j9z7   1/1     Running   0          25h    172.18.104.71    node9   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-configuration-watcher-deployment-5zltx9   1/1     Running   0          25h    172.18.104.69    node9   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-discoveryserver-deployment-9d5d86d7lhnh   1/1     Running   0          25h    172.18.104.70    node9   \u003cnone\u003e           \u003cnone\u003e\n❯ k get cm\nNAME                                            DATA   AGE\nconfig-sample                                   1      47s\ndiscovery-sample                                1      40s\ngrafana-cert-cm                                 2      19d\nkube-root-ca.crt                                1      112d\nkubernetesconfigserver                          1      25h\nspring-cloud-kubernetes-configuration-watcher   1      25h\n❯ k get svc\nNAME                                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE\nconfig-sample                                   ClusterIP   10.102.84.68     \u003cnone\u003e        8080/TCP   171m\ndiscovery-sample                                ClusterIP   10.97.4.185      \u003cnone\u003e        9080/TCP   42s\nkubernetes                                      ClusterIP   10.96.0.1        \u003cnone\u003e        443/TCP    112d\nspring-cloud-kubernetes-configserver            ClusterIP   10.109.120.151   \u003cnone\u003e        8888/TCP   25h\nspring-cloud-kubernetes-configuration-watcher   ClusterIP   10.110.146.208   \u003cnone\u003e        8888/TCP   25h\nspring-cloud-kubernetes-discoveryserver         ClusterIP   10.97.205.220    \u003cnone\u003e        80/TCP     25h\n❯ k get ingress\nNAME                      CLASS    HOSTS                            ADDRESS     PORTS   AGE\nconfigsample-ingress      \u003cnone\u003e   configsample.cloudnative.io      localhost   80      171m\nconfigserver-ingress      \u003cnone\u003e   configserver.cloudnative.io      localhost   80      25h\ndiscoverysample-ingress   \u003cnone\u003e   discoverysample.cloudnative.io   localhost   80      44s\ndiscoveryserver-ingress   \u003cnone\u003e   discoveryserver.cloudnative.io   localhost   80      25h\n```\n\n### 4、kubernetes集群测试\n\n```bash\n❯ http discoverysample.cloudnative.io/info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 121\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:04:45 GMT\n\ninvoke by discovery-sample-654dc778f9-m8qtb，receive data: 2022-09-14 15:04:45:kubernetes:config-sample-866487d6d7-jnb49\n---\n❯ http discoverysample.cloudnative.io/r_info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 61\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:04:57 GMT\n\n2022-09-14 15:04:57:kubernetes:config-sample-866487d6d7-jnb49\n```\n\n服务部署成功。对应的代码如下：\n\n```java\n@FeignClient(value = \"config-sample\",url = \"${feign.client.config-sample-url:http://config-sample:8080}\")\npublic interface FeignService {\n\n    @GetMapping(\"/info\")\n    String info();\n\n}\n```\n\n```java\n    @Autowired\n    private FeignService feignService;\n\n    @GetMapping(\"/info\")\n    public String invokeInfo() {\n        return String.format(\"invoke by %s，receive data: %s\", hostName, feignService.info());\n    }\n\n    @GetMapping(\"/r_info\")\n    public String info(){\n        String serviceUrl = environment.getProperty(\"feign.client.config-sample-url\",\"http://config-sample:8080\");\n        return restTemplate.getForObject(serviceUrl+\"/info\",String.class);\n    }\n```\n\n如上分别使用`feign`和`RestTemplate`调用了`config-sample`服务。\n\n我们为`config-sample`和`discovery-sample`服务启动多个pod测试负载均衡。\n\n```bash\n❯ k scale --replicas 3 deployment config-sample\ndeployment.apps/config-sample scaled\n❯ k scale --replicas 3 deployment discovery-sample\ndeployment.apps/discovery-sample scaled\n❯ k get pod -owide\nNAME                                                              READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES\nconfig-sample-866487d6d7-jnb49                                    1/1     Running   0          3h35m   172.18.199.236   node7   \u003cnone\u003e           \u003cnone\u003e\nconfig-sample-866487d6d7-kbp2p                                    1/1     Running   0          13m     172.18.104.74    node9   \u003cnone\u003e           \u003cnone\u003e\nconfig-sample-866487d6d7-qrg2q                                    1/1     Running   0          13m     172.18.225.118   node8   \u003cnone\u003e           \u003cnone\u003e\ndiscovery-sample-654dc778f9-7zlp2                                 1/1     Running   0          10m     172.18.104.77    node9   \u003cnone\u003e           \u003cnone\u003e\ndiscovery-sample-654dc778f9-m8qtb                                 1/1     Running   0          21m     172.18.225.115   node8   \u003cnone\u003e           \u003cnone\u003e\ndiscovery-sample-654dc778f9-psl4h                                 1/1     Running   0          10m     172.18.199.249   node7   \u003cnone\u003e           \u003cnone\u003e\nnfs-client-provisioner-67cd9c9567-w8k7q                           1/1     Running   12         72d     172.18.104.4     node2   \u003cnone\u003e           \u003cnone\u003e\nnginx-6799fc88d8-2fv2t                                            1/1     Running   0          7d      172.18.225.68    node8   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-configserver-deployment-7d5667c44f7j9z7   1/1     Running   0          25h     172.18.104.71    node9   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-configuration-watcher-deployment-5zltx9   1/1     Running   0          26h     172.18.104.69    node9   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-discoveryserver-deployment-9d5d86d7lhnh   1/1     Running   0          26h     172.18.104.70    node9   \u003cnone\u003e           \u003cnone\u003e\n```\n\n访问应用进行测试：\n\n```bash\n# RestTemplate方式负载均衡\n❯ http discoverysample.cloudnative.io/r_info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 61\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:25:02 GMT\n\n2022-09-14 15:25:02:kubernetes:config-sample-866487d6d7-qrg2q\n\n\n❯ http discoverysample.cloudnative.io/r_info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 61\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:25:03 GMT\n\n2022-09-14 15:25:03:kubernetes:config-sample-866487d6d7-kbp2p\n\n\n❯ http discoverysample.cloudnative.io/r_info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 61\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:25:05 GMT\n\n2022-09-14 15:25:05:kubernetes:config-sample-866487d6d7-jnb49\n\n# FeignClient方式负载均衡\n❯ http discoverysample.cloudnative.io/info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 121\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:26:42 GMT\n\ninvoke by discovery-sample-654dc778f9-m8qtb，receive data: 2022-09-14 15:26:42:kubernetes:config-sample-866487d6d7-qrg2q\n\n\n❯ http discoverysample.cloudnative.io/info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 121\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:26:44 GMT\n\ninvoke by discovery-sample-654dc778f9-7zlp2，receive data: 2022-09-14 15:26:44:kubernetes:config-sample-866487d6d7-kbp2p\n\n\n❯ http discoverysample.cloudnative.io/info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 121\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:26:46 GMT\n\ninvoke by discovery-sample-654dc778f9-7zlp2，receive data: 2022-09-14 15:26:46:kubernetes:config-sample-866487d6d7-kbp2p\n```\n\n### 5、本地调用kubernetes集群中的服务\n\n主要演示在本地开发模式如何直接调用kubernetes集群中的服务。\n\n![Snipaste_2022-09-14_15-31-08](./Screenshots/Snipaste_2022-09-14_15-31-08.png)\n![Snipaste_2022-09-14_15-31-26](./Screenshots/Snipaste_2022-09-14_15-31-26.png)\n\n访问本地应用接口\n\n```bash\n❯ http :9080/info\nHTTP/1.1 500 \nConnection: close\nContent-Type: application/json\nDate: Wed, 14 Sep 2022 07:33:14 GMT\nTransfer-Encoding: chunked\n\n{\n    \"error\": \"Internal Server Error\",\n    \"path\": \"/info\",\n    \"status\": 500,\n    \"timestamp\": \"2022-09-14T07:33:14.792+00:00\"\n}\n\n\n❯ http :9080/r_info\nHTTP/1.1 500 \nConnection: close\nContent-Type: application/json\nDate: Wed, 14 Sep 2022 07:33:21 GMT\nTransfer-Encoding: chunked\n\n{\n    \"error\": \"Internal Server Error\",\n    \"path\": \"/r_info\",\n    \"status\": 500,\n    \"timestamp\": \"2022-09-14T07:33:21.025+00:00\"\n}\n```\n\n此时程序报500，观察应用控制台日志如下：\n\n![Snipaste_2022-09-14_15-35-10](./Screenshots/Snipaste_2022-09-14_15-35-10.png)\n\n可见此时程序是直接访问kubernetes中的svc地址，很显然这在本地是不通的。因为我们在声明feign client时做了如下配置\n\n```java\n@FeignClient(value = \"config-sample\",url = \"${feign.client.config-sample-url:http://config-sample:8080}\")\n```\n\n我们只需要调整configmap中的配置，为`feign.client.config-sample-url`配置`ingress`访问地址，就可以正常访问kubernetes集群中的服务了。调整configmap如下并进行应用：\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: discovery-sample\n  labels:\n    # spring-cloud-kubernetes-configuration-watcher 监听 label\n    spring.cloud.kubernetes.config: \"true\"\ndata:\n  application.yml: |-\n    spring:\n      config:\n        activate:\n          on-profile: local\n    feign:\n      client:\n        config-sample-url: http://configsample.cloudnative.io\n        weibo-service-url: http://weiboservice.cloudnative.io\n        weather-service-url: http://weatherservice.cloudnative.io\n    ---\n    spring:\n      config:\n        activate:\n          on-profile: kubernetes\n    feign:\n      client:\n        config-sample-url: http://config-sample:8080\n        weibo-service-url: http://weibo-service:5000\n        weather-service-url: http://weather-service:8080\n```\n\n```bash\n❯ k apply -f k8s\nconfigmap/discovery-sample configured\ndeployment.apps/discovery-sample configured\nservice/discovery-sample unchanged\ningress.networking.k8s.io/discoverysample-ingress unchanged\nserviceaccount/admin-user unchanged\nclusterrolebinding.rbac.authorization.k8s.io/admin-user unchanged\nsecret/discovery-sample unchanged\n```\n\n重启本地应用程序进行访问，此时发现可以正常调用到kubernetes集群中的服务了：\n\n```bash\n❯ http :9080/info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 92\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:41:58 GMT\nKeep-Alive: timeout=60\n\ninvoke by null，receive data: 2022-09-14 15:41:58:kubernetes:config-sample-866487d6d7-qrg2q\n\n\n❯ http :9080/r_info\nHTTP/1.1 200 \nConnection: keep-alive\nContent-Length: 61\nContent-Type: text/plain;charset=UTF-8\nDate: Wed, 14 Sep 2022 07:42:04 GMT\nKeep-Alive: timeout=60\n\n2022-09-14 15:42:04:kubernetes:config-sample-866487d6d7-jnb49\n```\n\n\n\n## 六、 gateway-sample（网关聚合微服务）\n\n### 1、pom.xml中添加依赖\n\n```xml\n        \u003c!-- 依赖spring-cloud-kubernetes-discoveryserver组件，直接与其通信，不需要本地存在 ~/.kube/config文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-kubernetes-discoveryclient\u003c/artifactId\u003e\n            \u003cversion\u003e2.1.3\u003c/version\u003e\n        \u003c/dependency\u003e\n        \u003c!-- 从configmap、secret加载应用配置文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-kubernetes-client-config\u003c/artifactId\u003e\n            \u003cversion\u003e2.1.3\u003c/version\u003e\n        \u003c/dependency\u003e\n        \u003c!-- spring-cloud-config-clien 从config server加载配置文件 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-config-client\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-gateway\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-circuitbreaker-reactor-resilience4j\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003c!-- loadbalancer组件，不建议使用spring-cloud-starter-kubernetes-client-loadbalancer组件，该组件仍然会使用本地~/.kube/config文件进行通信 --\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.cloud\u003c/groupId\u003e\n            \u003cartifactId\u003espring-cloud-starter-loadbalancer\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n            \u003cartifactId\u003espring-boot-starter-actuator\u003c/artifactId\u003e\n        \u003c/dependency\u003e\n```\n\n### 2、配置bootstrap.yml\n\napplication.yml 该文件放一些通用配置类信息\n\n```yaml\nserver:\n  port: 8070\n\nspring:\n  main:\n    allow-bean-definition-overriding: true\n  application:\n    name: gateway-sample\n  jackson:\n    serialization:\n      fail-on-empty-beans: false\n\nlogging:\n  level:\n    org.springframework.cloud.kubernetes: DEBUG\n    org.springframework.cloud.gateway: INFO\n\nmanagement:\n  endpoint:\n    health:\n      show-details: always\n      enabled: true\n    restart:\n      enabled: true\n    info:\n      enabled: true\n    gateway:\n      enabled: true\n  endpoints:\n    web:\n      exposure:\n        include: '*'\n```\n\nbootstrap-local.yml 本地模式启动时的配置文件\n\n```yaml\nspring:\n  config:\n    activate:\n      on-profile: local\n    import: optional:configserver:http://configserver.cloudnative.io\n  cloud:\n    loadbalancer:\n      enabled: true\n      ribbon:\n        enabled: false\n    gateway:\n      enabled: true\n      discovery:\n        locator:\n          enabled: true\n          lower-case-service-id: true\n          url-expression: \"'http://'+serviceId+':'+port\"\n    kubernetes:\n      enabled: true\n      config:\n        name: gateway-sample\n        namespace: default\n        enabled: true\n        enable-api: true\n      secrets:\n        name: gateway-sample\n        namespace: default\n        enabled: true\n        enable-api: true\n      reload:\n        enabled: true\n        mode: event\n        strategy: refresh\n        monitoring-config-maps: true\n        monitoring-secrets: true\n      loadbalancer:\n        enabled: true\n        mode: SERVICE\n      discovery:\n        # 开启服务注册发现\n        enabled: true\n        # 允许访问所有namespaces\n        all-namespaces: true\n        include-not-ready-addresses: false\n        discovery-server-url: http://discoveryserver.cloudnative.io\n```\n\nbootstrap-kubernetes.yml kubernetes集群模式启动时的配置文件\n\n```yaml\nspring:\n  config:\n    activate:\n      on-profile: kubernetes\n    import: optional:configserver:http://spring-cloud-kubernetes-configserver:8888\n  cloud:\n    loadbalancer:\n      enabled: true\n      ribbon:\n        enabled: false\n    gateway:\n      enabled: true\n      discovery:\n        locator:\n          enabled: true\n          lower-case-service-id: true\n          url-expression: \"'http://'+serviceId+':'+port\"\n    kubernetes:\n      enabled: true\n      config:\n        name: gateway-sample\n        namespace: default\n        enabled: true\n        enable-api: true\n      secrets:\n        name: gateway-sample\n        namespace: default\n        enabled: true\n        enable-api: true\n      reload:\n        enabled: true\n        mode: event\n        strategy: refresh\n        monitoring-config-maps: true\n        monitoring-secrets: true\n      loadbalancer:\n        enabled: true\n        mode: SERVICE\n      discovery:\n        # 开启服务注册发现\n        enabled: true\n        # 允许访问所有namespaces\n        all-namespaces: true\n        include-not-ready-addresses: false\n        discovery-server-url: http://spring-cloud-kubernetes-discoveryserver\n```\n\n注意留意spring.cloud.gateway部分的配置。\n\n### 3、打包部署\n\n```bash\n❯ mvn clean package -Dmaven.test.skip=true\n❯ mvn spring-boot:build-image -Dmaven.test.skip=true\n❯ k apply -f k8s\n\nconfigmap/gateway-sample created\ndeployment.apps/gateway-sample created\nservice/gateway-sample created\ningress.networking.k8s.io/gateway-ingress created\nserviceaccount/admin-user unchanged\nclusterrolebinding.rbac.authorization.k8s.io/admin-user unchanged\nsecret/gateway-sample unchanged\n❯ k get pod -owide\nNAME                                                              READY   STATUS    RESTARTS   AGE    IP               NODE    NOMINATED NODE   READINESS GATES\nconfig-sample-866487d6d7-jnb49                                    1/1     Running   0          4h     172.18.199.236   node7   \u003cnone\u003e           \u003cnone\u003e\nconfig-sample-866487d6d7-kbp2p                                    1/1     Running   0          39m    172.18.104.74    node9   \u003cnone\u003e           \u003cnone\u003e\nconfig-sample-866487d6d7-qrg2q                                    1/1     Running   0          39m    172.18.225.118   node8   \u003cnone\u003e           \u003cnone\u003e\ndiscovery-sample-654dc778f9-m8qtb                                 1/1     Running   0          47m    172.18.225.115   node8   \u003cnone\u003e           \u003cnone\u003e\ngateway-sample-684d7cd57c-md4mx                                   1/1     Running   0          35s    172.18.199.251   node7   \u003cnone\u003e           \u003cnone\u003e\nnfs-client-provisioner-67cd9c9567-w8k7q                           1/1     Running   12         72d    172.18.104.4     node2   \u003cnone\u003e           \u003cnone\u003e\nnginx-6799fc88d8-2fv2t                                            1/1     Running   0          7d1h   172.18.225.68    node8   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-configserver-deployment-7d5667c44f7j9z7   1/1     Running   0          26h    172.18.104.71    node9   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-configuration-watcher-deployment-5zltx9   1/1     Running   0          26h    172.18.104.69    node9   \u003cnone\u003e           \u003cnone\u003e\nspring-cloud-kubernetes-discoveryserver-deployment-9d5d86d7lhnh   1/1     Running   0          26h    172.18.104.70    node9   \u003cnone\u003e           \u003cnone\u003e\n❯ k get cm\nNAME                                            DATA   AGE\nconfig-sample                                   1      70m\ndiscovery-sample                                1      69m\ngateway-sample                                  1      39s\ngrafana-cert-cm                                 2      19d\nkube-root-ca.crt                                1      112d\nkubernetesconfigserver                          1      26h\nspring-cloud-kubernetes-configuration-watcher   1      26h\n❯ k get svc\nNAME                                            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE\nconfig-sample                                   ClusterIP   10.102.84.68     \u003cnone\u003e        8080/TCP   4h1m\ndiscovery-sample                                ClusterIP   10.104.120.36    \u003cnone\u003e        9080/TCP   47m\ngateway-sample                                  ClusterIP   10.103.47.114    \u003cnone\u003e        8070/TCP   42s\nkubernetes                                      ClusterIP   10.96.0.1        \u003cnone\u003e        443/TCP    112d\nspring-cloud-kubernetes-configserver            ClusterIP   10.109.120.151   \u003cnone\u003e        8888/TCP   26h\nspring-cloud-kubernetes-configuration-watcher   ClusterIP   10.110.146.208   \u003cnone\u003e        8888/TCP   26h\nspring-cloud-kubernetes-discoveryserver         ClusterIP   10.97.205.220    \u003cnone\u003e        80/TCP     26h\n❯ k get ingress\nNAME                      CLASS    HOSTS                            ADDRESS     PORTS   AGE\nconfigsample-ingress      \u003cnone\u003e   configsample.cloudnative.io      localhost   80      4h1m\nconfigserver-ingress      \u003cnone\u003e   configserver.cloudnative.io      localhost   80      26h\ndiscoverysample-ingress   \u003cnone\u003e   discoverysample.cloudnative.io   localhost   80      70m\ndiscoveryserver-ingress   \u003cnone\u003e   discoveryserver.cloudnative.io   localhost   80      26h\ngateway-ingress           \u003cnone\u003e   gateway.cloudnative.io           localhost   80      44s\n```\n\n### 4、测试网关\n\n#### 4.1、访问/actuator/gateway/routes`端点\n\n```bash\n❯ http gateway.cloudnative.io/actuator/gateway/routes\nHTTP/1.1 200 OK\nConnection: keep-alive\nContent-Type: application/json\nDate: Wed, 14 Sep 2022 07:51:06 GMT\nTransfer-Encoding: chunked\n\n[\n    {\n        \"filters\": [\n            \"[[StripPrefix parts = 1], order = 0]\",\n            \"[[SpringCloudCircuitBreakerResilience4JFilterFactory name = 'config-sample', fallback = forward:/fallback], order = 0]\"\n        ],\n        \"order\": 0,\n        \"predicate\": \"Paths: [/config-sample/**], match trailing slash: true\",\n        \"route_id\": \"d8dd5d97-0bb5-4cc9-be22-57aac0fce27f\",\n        \"uri\": \"lb://config-sample\"\n    },\n    {\n        \"filters\": [\n            \"[[StripPrefix parts = 1], order = 0]\",\n            \"[[SpringCloudCircuitBreakerResilience4JFilterFactory name = 'discovery-sample', fallback = forward:/fallback], order = 0]\"\n        ],\n        \"order\": 0,\n        \"predicate\": \"Paths: [/discovery-sample/**], match trailing slash: true\",\n        \"route_id\": \"c87a442e-f0d8-4833-8436-28681c517a97\",\n        \"uri\": \"lb://discovery-sample\"\n    },\n    {\n        \"filters\": [\n            \"[[StripPrefix parts = 1], order = 0]\",\n            \"[[SpringCloudCircuitBreakerResilience4JFilterFactory name = 'weibo-service', fallback = forward:/fallback], order = 0]\"\n        ],\n        \"order\": 0,\n        \"predicate\": \"Paths: [/news/**], match trailing slash: true\",\n        \"route_id\": \"c4aaf2aa-4e98-4967-8a94-78869591331d\",\n        \"uri\": \"lb://weibo-service\"\n    },\n    {\n        \"filters\": [\n            \"[[StripPrefix parts = 1], order = 0]\",\n            \"[[SpringCloudCircuitBreakerResilience4JFilterFactory name = 'weather-service', fallback = forward:/fallback], order = 0]\"\n        ],\n        \"order\": 0,\n        \"predicate\": \"Paths: [/weather/**], mat","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fv5tech%2Fspring-cloud-kubernetes-samples","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fv5tech%2Fspring-cloud-kubernetes-samples","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fv5tech%2Fspring-cloud-kubernetes-samples/lists"}