# spring-cloud-kubernetes-learn
**Repository Path**: caoweidong8/spring-cloud-kubernetes-learn
## Basic Information
- **Project Name**: spring-cloud-kubernetes-learn
- **Description**: spring-cloud-kubernetes-2.0
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 3
- **Created**: 2023-05-19
- **Last Updated**: 2023-05-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Getting Start
## 前言
如果是在本地WSL运行,并且本地配置了maven,我建议cp一个配置文件,然后修改仓库路径为/mnt/+windows下的路径
否则他会在当前目录下载依赖并且没法用
mvn [commond] -s "/mnt/d/linux/settings-linux.xml"
## 前置条件
* docker
* kubectl
* minikube
## 安装/运行 minikube
### 安装
```shell
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
```
### 运行
```shell
# 一定要指定 1.23.8 最新版会有蜜汁问题
minikube start --image-mirror-country='cn' --kubernetes-version=v1.23.8 --driver=docker
```
## 安装kubectl
#### 安装
```shell
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
```
#### 验证
```shell
kubectl version
```
## 服务注册与发现
由于spring-cloud-kubenetes官方文档用的是maven的fabric8插件打包部署到kubenetes平台,但是这个插件已经过时,不再维护,所以改用jkube插件,jkube可以通过xml配置生成对应的k8s部署yaml配置,并自动apply到kubenetes平台,具体文档
https://github.com/eclipse/jkube/tree/master/kubernetes-maven-plugin
### 新建一个maven项目
```shell
#### 略
```
#### 依赖管理
```xml
1.0-SNAPSHOT
2.4.1
2020.0.1
2.8.2
2.22.2
1.6.0
1.8.0
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud-version}
pom
import
org.springframework.boot
spring-boot-dependencies
${spring-boot-version}
pom
import
org.apache.maven.plugins
maven-deploy-plugin
${maven-deploy-plugin.version}
true
```
#### 新建一个子模块
#### 引入依赖
```xml
org.springframework.cloud
spring-cloud-kubernetes-client-discovery
org.springframework.cloud
spring-cloud-kubernetes-client-config
org.springframework.cloud
spring-cloud-commons
org.springframework.cloud
spring-cloud-starter-bootstrap
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.jolokia
jolokia-core
```
#### 新建入口类 App.java
```java
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class App {
@Resource
DiscoveryClient discoveryClient;
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@GetMapping("/")
public String hello() {
return "Hello World";
}
@GetMapping("/services")
public List getServices() {
return discoveryClient.getServices();
}
}
```
#### 指定application name application.yml
```yaml
spring:
application:
name: kubernetes-hello-world
```
#### 添加打包插件
```xml
org.springframework.boot
spring-boot-maven-plugin
${spring-boot-version}
repackage
kubernetes
org.eclipse.jkube
kubernetes-maven-plugin
${jkube.version}
spring-boot-sample
spring
${project.artifactId}
spring-boot
always
jkube-expose
NodePort
resource
build
helm
```
#### 部署
部分命令介绍:(这里前两个 不说了 玩最后一个)
PS: 由于使用的是本地docker仓库,需要执行以下命令,才能是minikube可以从本地仓库拉取镜像,每次都需要在部署的终端下执行
```shell
eval $(minikube docker-env)
```
* 生成k8s描述文件
```shell
mvn clean k8s:resource -Pkubernetes
```
* 生成docker镜像
```shell
mvn package k8s:build -Pkubernetes
```
* 部署到k8s平台(在子模块目录下执行这个)
```shell
mvn k8s:deploy -Pkubernetes
```
* 部署成功后
```shell
[INFO] --- kubernetes-maven-plugin:1.8.0:deploy (default-cli) @ spring-cloud-k8s ---
[INFO] k8s: Using Kubernetes at https://127.0.0.1:59152/ in namespace null with manifest /mnt/d/items/spring-cloud-kubernetes-learn/spring-cloud-k8s/target/classes/META-INF/jkube/kubernetes.yml
[INFO] k8s: Updating a ServiceAccount from kubernetes.yml
[INFO] k8s: Updated ServiceAccount: spring-cloud-k8s/target/jkube/applyJson/default/serviceaccount-spring.json
[INFO] k8s: Creating a Service from kubernetes.yml namespace default name spring-cloud-k8s
[INFO] k8s: Created Service: spring-cloud-k8s/target/jkube/applyJson/default/service-spring-cloud-k8s.json
[INFO] k8s: Creating a Deployment from kubernetes.yml namespace default name spring-cloud-k8s
[INFO] k8s: Created Deployment: spring-cloud-k8s/target/jkube/applyJson/default/deployment-spring-cloud-k8s.json
[INFO] k8s: HINT: Use the command `kubectl get pods -w` to watch your pods start up
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:02 min
[INFO] Finished at: 2022-08-22T09:55:54+08:00
[INFO] ------------------------------------------------------------------------
```
* 查看pod
```shell
kubectl get pods
#NAME READY STATUS RESTARTS AGE
#spring-cloud-k8s-86bc95d68c-c5btk 1/1 Running 0 21s
```
* 转发端口到pod
```shell
# spring-cloud-k8s-86bc95d68c-c5btk 为上述对应pod的NAME
kubectl port-forward spring-cloud-k8s-86bc95d68c-c5btk 8080:8080
```
* 请求本地8080端口 localhost:8080
```shell
curl localhost:8080
#Hello World
curl localhost:8080/service
#{"timestamp":"2022-08-22T02:07:00.302+00:00","status":500,"error":"Internal Server Error","message":"","path":"/services"}
```
这里出现了500错误是因为,我们一开始设置的service account 他会在k8s平台自动创建一个spring账号,但是他并没有相应的权限去获取k8s平台的信息,所以没办法获取的服务的信息,此时我们为spring赋予只读权限,具体日志可以通过一下命令查看,不过不建议,因为没有权限的时候他会一直报错,日志无限增长
```shell
kubectl logs spring-cloud-k8s-86bc95d68c-c5btk
```
* 为spring账户添加权限
```shell
#kubectl create serviceaccount spring # 这是创建spring账户的命令 jkube已经可以通过配置创建可以不执行
#创建一个clusterrolebinding 设置clusterrole为view只读 指定serviceaccount
kubectl create clusterrolebinding spring-api --clusterrole=view --serviceaccount=default:spring --namespace=default
```
* 查询平台服务
```shell
curl localhost:8080/services
# ["hello-world-example","kubernetes","kubernetes-hello-world","spring-cloud-k8s"]
```
到这里就成功将spring Boot部署到k8s平台并且完成服务发现
## ConfigMap 配置管理(k8s原生)
ps: 官方文档使用的工具是Fabric8,本文档用的是jukube 所以这里没有和官方文档的教程走
#### 改写App.java入口类
```java
@Value("${greeting.message}")
String message;
@GetMapping("/config")
public String getMessage(){
return message;
}
```
#### 新建文件src/jkube/configmap.yml
```yaml
metadata:
name: ${project.artifactId}
data:
application.yml: |-
greeting:
message: Say Hello to the World
```
#### 新建文件src/jkube/deployment.yml
```yaml
metadata:
annotations:
configmap.jkube.io/update-on-change: ${project.artifactId}
spec:
replicas: 1
template:
spec:
volumes:
- name: config
configMap:
name: ${project.artifactId}
items:
- key: application.yml
path: application.yml
containers:
- volumeMounts:
- name: config
mountPath: /deployments/config
serviceAccount: spring
```
#### 部署到平台后查看新建的configMap
```shell
mvn k8s:deploy -Pkubernetes
kubectl get cm
# NAME DATA AGE
# kube-root-ca.crt 1 3d1h
# spring-cloud-k8s 1 95m
```
#### 转发端口 请求查看
```shell
kubectl port-forward spring-cloud-k8s-86bc95d68c-c5btk 8080:8080
curl localhost:8080/config
# Say Hello to the World
```
## ConfigMap热刷新
#### 添加AppProperties.java
亲测如果使用@Value()的方式 即使添加了@RefreshScope 也无法热刷新
```java
@RefreshScope
@ConfigurationProperties(prefix = "greeting")
public class AppProperties {
String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
```
#### 改写App.java
```java
@Resource
AppProperties appProperties;
@GetMapping("/config")
public String getMessage() {
return appProperties.getMessage();
}
```
#### 添加applicatoin.yml配置
```yaml
spring:
application:
name: spring-cloud-k8s
management:
endpoint:
refresh:
enabled: true
endpoints:
web:
exposure:
include: "*"
```
#### 添加bootstrap.yml配置
```yaml
spring:
cloud:
kubernetes:
config:
enabled: true
sources:
- namespace: default
# 对应的configMap 的name
name: spring-cloud-k8s
reload:
enabled: true
# 更新策略
strategy: refresh
# 监听 configMap变化
monitoring-config-maps: true
mode: event
```
#### 重新部署与验证
```shell
mvn k8s:deploy -Pkubernetes
# 删除原来的pod 让他重新部署
kubectl delete -n default pod spring-cloud-k8s-85b7b79766-p7h6q
# 转发端口
kubectl port-forward spring-cloud-k8s-85b7b79766-p7h6q 8080:8080
# 请求
curl localhost:8080/config
# Say Hello to the World
```
#### 修改configmap
```yaml
metadata:
name: ${project.artifactId}
data:
application.yml: |-
greeting:
message: Say GoodBey to the World
```
#### 应用修改并查看
```shell
kubectl apply -f configmap.yml
curl localhost:8080/config
# Say GoodBey to the World
```
## 查看Pod信息
当SpringBoot部署到K8s平台后,Spring boot 通过spring-actuator 获取一些pod的信息
```shell
curl localhost:8080/actuator/info
# {
# "kubernetes": {
# "nodeName": "minikube",
# "podIp": "172.17.0.4",
# "hostIp": "192.168.49.2",
# "namespace": "default",
# "podName": "spring-cloud-k8s-858d76bc79-z4kkq",
# "serviceAccount": "spring",
# "inside": true
# }
# }
```
上述信息可以通过 **management.info.kubernetes.enabled** 进行关闭(false)
## Leader选举
选举需要依赖 fabric8
而且不能同时出现 spring-cloud-starter-client-discover 因为两个都对服务发现实现了,同时引入会出现bean的重复定义抛出异常
选举机制:只有一个实例成为 leader,当leader挂了之后上一个leader结点会触发 **OnRevokedEvent** 事件,然后所有的节点进行竞争,成功选举为 leader的节点会触发 **OnGrantedEvent**
#### 新建一个新的子模块 spring-cloud-leader
```xml
org.springframework.cloud
spring-cloud-starter-kubernetes-fabric8
org.springframework.cloud
spring-cloud-kubernetes-fabric8-leader
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-commons
org.springframework.cloud
spring-cloud-starter-bootstrap
org.springframework.boot
spring-boot-starter
org.jolokia
jolokia-core
... 参考上文
... 参考上文
spring-leader
${project.artifactId}
```
以上pom在配置service account的时候指定了新的,因为原来的sa 只有 view 只读权限,而leader选举是通过K8S的ConfigMap来实现的,所以我们需要给当前项目赋予edit权限,让其有权限去修改configMap
#### 编写LeaderController 已经入口
【App.java(单纯的springboot 不需要其他注解 这里省略)】
```java
@RestController
public class LeaderController {
private final String host;
@Value("${spring.cloud.kubernetes.leader.role}")
private String role;
private Context context;
public LeaderController() throws UnknownHostException {
this.host = InetAddress.getLocalHost().getHostName();
}
/**
* 获取当前节点状态
*
* @return info
*/
@GetMapping
public String getInfo() {
if (this.context == null) {
return String.format("I am '%s' but I am not a leader of the '%s'", this.host, this.role);
}
return String.format("I am '%s' and I am the leader of the '%s'", this.host, this.role);
}
/**
* 主动下线
* @return info about leadership
*/
@PutMapping
public ResponseEntity revokeLeadership() {
if (this.context == null) {
String message = String.format("Cannot revoke leadership because '%s' is not a leader", this.host);
return ResponseEntity.badRequest().body(message);
}
this.context.yield();
String message = String.format("Leadership revoked for '%s'", this.host);
return ResponseEntity.ok(message);
}
/**
* 被选举为leader事件
*
* @param event on granted event
*/
@EventListener
public void handleEvent(OnGrantedEvent event) {
System.out.println(String.format("'%s' leadership granted", event.getRole()));
this.context = event.getContext();
}
/**
* leader下线事件
*
* @param event on revoked event
*/
@EventListener
public void handleEvent(OnRevokedEvent event) {
System.out.println(String.format("'%s' leadership revoked", event.getRole()));
this.context = null;
}
}
```
#### application.yml
```yaml
spring:
application:
name: spring-cloud-leader
cloud:
kubernetes:
leader:
# 用于实现leader选举的configMap名称
config-map-name: leader
# 当前服务角色
role: world
```
#### 新建service account 并授予edit权限
```shell
kubectl create serviceaccount spring-leader # 这是创建spring账户的命令 jkube已经可以通过配置创建可以不执行
kubectl create clusterrolebinding spring-api --clusterrole=edit --serviceaccount=default:spring --namespace=default
```
#### 部署项目与验证
```shell
mvn k8s:deploy -Pkubernetes
# 部署完成后查看pod是否正常运行
kubectl get pod
#NAME READY STATUS RESTARTS AGE
#spring-cloud-leader-5bdd657d86-qtch5 1/1 Running 0 27m
# 查看他是否触发了OnGrantedEvent 事件成为了leader
kubectl logs spring-cloud-leader-5bdd657d86-qtch5 |grep 'leadership'
#DefaultCandidate{role=world, id=spring-cloud-leader-5bdd657d86-qtch5} has been granted leadership; context: org.springframework.cloud.kubernetes.commons.leader.LeaderContext@128153a0
# 复制一个节点出来
kubectl scale --replicas=2 deployment.apps/spring-cloud-leader
kubectl get pod
#NAME READY STATUS RESTARTS AGE
#spring-cloud-leader-5bdd657d86-hvm47 1/1 Running 0 15m
#spring-cloud-leader-5bdd657d86-qtch5 1/1 Running 0 49m
# 打开两个终端 分别转发两个服务端口
kubectl port-forward spring-cloud-leader-5bdd657d86-hvm47 8081:8080
kubectl port-forward spring-cloud-leader-5bdd657d86-qtch5 8080:8080
# 查看两个节点
curl localhost:8080
# I am 'spring-cloud-leader-5bdd657d86-qtch5' and I am the leader of the 'world'
curl localhost:8081
# I am 'spring-cloud-leader-5bdd657d86-hvm47' but I am not a leader of the 'world'
# 释放 leader
curl -X PUT localhost:8080
# Leadership revoked for 'spring-cloud-leader-5bdd657d86-qtch5'
# 查看8081 这里是有概率的 我释放了很多次8080 8081才抢到
curl localhost:8081
# I am 'spring-cloud-leader-5bdd657d86-hvm47' and I am the leader of the 'world'
# 查看8080日志多次选举的过程(在我释放了两次后 选举leader失败)
kubectl logs spring-cloud-leader-5bdd657d86-qtch5 | grep leadership
# DefaultCandidate{role=world, id=spring-cloud-leader-5bdd657d86-qtch5} has been granted leadership; context
# DefaultCandidate{role=world, id=spring-cloud-leader-5bdd657d86-qtch5} leadership has been revoked
# DefaultCandidate{role=world, id=spring-cloud-leader-5bdd657d86-qtch5} has been granted leadership; context
# DefaultCandidate{role=world, id=spring-cloud-leader-5bdd657d86-qtch5} leadership has been revoked
# Failure when acquiring leadership for 'DefaultCandidate
```
## loadbalancer and openfeign
#### 新建spring-cloud-balancer模块
设置为pom 并添加打包插件
```xml
pom
kubernetes
org.eclipse.jkube
kubernetes-maven-plugin
${kubernetes.maven.plugin.version}
fmp
resource
build
NodePort
```
#### 新建生产者模块 name-service 依赖以及插件
```xml
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.apache.maven.plugins
maven-deploy-plugin
true
org.springframework.boot
spring-boot-maven-plugin
${spring-boot-version}
repackage
org.eclipse.jkube
kubernetes-maven-plugin
fmp
resource
```
#### App.java springboot即可 略
#### NameController.java
```java
@RestController
public class NameController {
private static final Logger LOG = LoggerFactory.getLogger(NameController.class);
private final String hostName = System.getenv("HOSTNAME");
@GetMapping("/")
public String ribbonPing() {
LOG.info("Ribbon ping");
return hostName;
}
/**
* 返回hostname 并模拟延时
*/
@GetMapping("/name")
public Mono getName(@RequestParam(value = "delay", defaultValue = "0") int delayValue) {
LOG.info(String.format("Returning a name '%s' with a delay '%d'", hostName, delayValue));
delay(delayValue);
return hostName;
}
private void delay(int delayValue) {
try {
Thread.sleep(delayValue);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
```
#### 新建生产者name-service-api模块
```xml
org.springframework.cloud
spring-cloud-starter-openfeign
io.projectreactor
reactor-core
```
#### 添加feign接口
```java
@FeignClient(name = "name-service")
public interface MsNameService {
@GetMapping("/name")
String getName(@RequestParam(value = "delay", defaultValue = "0") int delayValue);
}
```
#### 新建消费者greeting-service 依赖以及插件
```xml
org.springframework.cloud
spring-cloud-starter-kubernetes-client-loadbalancer
org.springframework.cloud
spring-cloud-kubernetes-client-discovery
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.jolokia
jolokia-core
org.example
name-service-api
1.0-SNAPSHOT
org.springframework.boot
spring-boot-maven-plugin
${spring-boot-version}
repackage
org.apache.maven.plugins
maven-compiler-plugin
8
8
kubernetes
org.eclipse.jkube
kubernetes-maven-plugin
${jkube.version}
spring-boot-sample
spring
${project.artifactId}
spring-boot
always
jkube-expose
NodePort
resource
build
helm
```
#### App.java
构建loadbalancer
```java
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "example")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@LoadBalanced
@Bean
RestTemplate loadBalancedWebClientBuilder() {
return new RestTemplateBuilder().build();
}
}
```
#### GreetingController.java
调用nameService
```java
@RestController
public class GreetingController {
private final MsNameService msNameService;
public GreetingController(MsNameService msNameService) {
this.msNameService = msNameService;
}
@GetMapping("/greeting")
public String getGreeting(@RequestParam(value = "delay", defaultValue = "0") int delay) {
return String.format("Hello from %s!", msNameService.getName(delay));
}
}
```
#### 部署验证
进入spring-cloud-loadbalancer目录
```shell
# 构建部署
mvn k8s:deploy -Pkubernetes
#[INFO] k8s: HINT: Use the command `kubectl get pods -w` to watch your pods start up
#[INFO] ------------------------------------------------------------------------
#[INFO] Reactor Summary for spring-cloud-loadbalancer 1.0-SNAPSHOT:
#[INFO]
#[INFO] spring-cloud-loadbalancer .......................... SUCCESS [ 14.484 s]
#[INFO] greeting-service ................................... SUCCESS [01:24 min]
#[INFO] name-service ....................................... SUCCESS [01:41 min]
#[INFO] ------------------------------------------------------------------------
#[INFO] BUILD SUCCESS
#[INFO] ------------------------------------------------------------------------
#[INFO] Total time: 03:22 min
#[INFO] Finished at: 2022-08-23T14:54:56+08:00
#[INFO] ------------------------------------------------------------------------
# 查看
kubectl get pod
#NAME READY STATUS RESTARTS AGE
#greeting-service-58d9ff665d-x6svm 1/1 Running 0 10m
#name-service-d577c996c-hnbds 1/1 Running 0 9m49s
# 转发端口
kubectl port-forward greeting-service-58d9ff665d-x6svm 8080:8080
# 请求验证
curl localhost:8080/greeting
# Hello from name-service-d577c996c-hnbds!
# 新增一个name-service 的pod
kubectl scale --replicas=2 deployment name-service
# 查看两个pod
kc get endpoints/name-service
#NAME ENDPOINTS AGE
#name-service 172.17.0.10:8080,172.17.0.9:8080 34m
# 请求并设置延时
curl localhost:8080/gretting?delay=3000
#Hello from name-service-d577c996c-hnbds!
# 同时再次发起
curl localhost:8080/gretting
#Hello from name-service-d577c996c-whxth!
```
## Security Configurations k8s中的安全配置
#### namespace
K8s 可以通过NAMESPACE去区分命名空间,配置namespace的方式:
* Jkube:
```xml
kubernetes
org.eclipse.jkube
kubernetes-maven-plugin
${jkube.version}
my-namespace
```
#### promession
Spring-cloud-kubenetes 的服务发现以及configMap等都是基于对kubenetes中API来实现的,所以需要为spring-boot程序配置相应的server account 以及 权限
以下是不同依赖对于权限的要求,对于对应的资源,都需要对应的'get','list','watch'权限
| Dependency | Resources |
| :--------------------------------------------- | :------------------------ |
| spring-cloud-starter-kubernetes-fabric8 | pods, services, endpoints |
| spring-cloud-starter-kubernetes-fabric8-config | configmaps, secrets |
| spring-cloud-starter-kubernetes-client | pods, services, endpoints |
| spring-cloud-starter-kubernetes-client-config | configmaps, secrets |
为default用户添加上述权限的示例:
* 创建一个server account
```shell
kubectl create namespace my-namespace
# namespace/my-namespace created
kubectl create serviceaccount spring-security -n my-namespace
# serviceaccount/spring-security created
```
* 添加角色
```yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: my-namespace
name: namespace-reader
rules:
- apiGroups: [""]
resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
verbs: ["get", "list", "watch"]
```
```shell
kubectl apply -f addRole.yml
# role.rbac.authorization.k8s.io/namespace-reader created
```
* 将default设置为我们刚才添加的角色
```yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: namespace-reader-binding
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: spring-security
apiGroup: ""
roleRef:
kind: Role
name: namespace-reader
apiGroup: ""
```
```shell
kubectl apply -f roleBinding.yml
# rolebinding.rbac.authorization.k8s.io/namespace-reader-binding created
```
* 查看
```shell
kubectl get sa -n my-namespace
#NAME SECRETS AGE
#default 1 9m42s
#spring-security 1 9m27s
```
## 服务注册
`spring.cloud.service-registry.auto-registration.enabled` 和`@EnableDiscoveryClient(autoRegister=false)`都可以控制服务是否自动注册
## 配置中心观察器
在前面的ConfigMap中,我们配置的ConfigMap热更新是旧的实现,官方在2020.*之后的版本已经放弃的更新,并且推荐使用Spring Cloud Kubernetes Configuration Watcher 部署到k8s平台上通知到k8s中的服务进行配置更新,其本质是通过/actuator/refresh来通知服务进行配置刷新
#### 部署Spring Cloud Kubernetes Configuration Watcher到k8s
* 新建deployment.yml (kubectl apply -fdeployment.yml )
这个部署文件做了几件事情:
1. 新建了Service指定端口为8888
2. 新建了一个service account
3. 新建了一个role和RoleBinding
4. 为新建的role赋予一些资源和权限
5. 使用官方镜像部署服务
```yaml
---
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: Service
metadata:
labels:
app: spring-cloud-kubernetes-configuration-watcher
name: spring-cloud-kubernetes-configuration-watcher
spec:
ports:
- name: http
port: 8888
targetPort: 8888
selector:
app: spring-cloud-kubernetes-configuration-watcher
type: ClusterIP
- apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: spring-cloud-kubernetes-configuration-watcher
name: spring-cloud-kubernetes-configuration-watcher
- apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app: spring-cloud-kubernetes-configuration-watcher
name: spring-cloud-kubernetes-configuration-watcher:view
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: namespace-reader
subjects:
- kind: ServiceAccount
name: spring-cloud-kubernetes-configuration-watcher
- apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: namespace-reader
rules:
- apiGroups: ["", "extensions", "apps"]
resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
verbs: ["get", "list", "watch"]
- apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-cloud-kubernetes-configuration-watcher-deployment
spec:
selector:
matchLabels:
app: spring-cloud-kubernetes-configuration-watcher
template:
metadata:
labels:
app: spring-cloud-kubernetes-configuration-watcher
spec:
serviceAccount: spring-cloud-kubernetes-configuration-watcher
containers:
- name: spring-cloud-kubernetes-configuration-watcher
image: springcloud/spring-cloud-kubernetes-configuration-watcher:2.0.1-SNAPSHOT
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 8888
path: /actuator/health/readiness
livenessProbe:
httpGet:
port: 8888
path: /actuator/health/liveness
ports:
- containerPort: 8888
```
#### 修改bootstrap.yml
关闭reload
```yaml
spring:
cloud:
kubernetes:
config:
enabled: true
sources:
- namespace: default
name: spring-cloud-k8s
reload:
# enabled: true
strategy: refresh
monitoring-config-maps: true
mode: event
```
#### 新建configMap.yml
${project.artifactId}是对应的configmap 的name 自行修改
这里的重点是添加了一个label spring.cloud.kubernetes.config: "true"
configmap watcher就是通过这个label去决定要不要通知其他服务更新
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: ${project.artifactId}
labels:
spring.cloud.kubernetes.config: "true"
data:
application.yml: |-
greeting:
message: Say Hello from one
```
## 扩展
#### [Spring Cloud Kubernetes Config Server](https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#spring-cloud-kubernetes-configserver)
spring-cloud-config-server在kubernetes中的实现,hello world部署非常简单,使用官方提供的部署配置即可
#### [Spring Cloud Kubernetes Discovery Server](https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#spring-cloud-kubernetes-discoveryserver)
可以获取应用已经实例的信息,部署同上