Skip to content

Commit

Permalink
add example
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielLiu1123 committed Feb 2, 2023
1 parent f00557c commit 2d2cb16
Show file tree
Hide file tree
Showing 24 changed files with 614 additions and 168 deletions.
138 changes: 138 additions & 0 deletions spring-cloud-alibaba-docs/src/main/asciidoc/kubernetes-config.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
== Spring Cloud Alibaba Kubernetes Config

The purpose of this module is to use Kubernetes ConfigMap/Secret as a distributed configuration center to achieve dynamic configuration updates without restarting the application.

=== Quick Start

Maven:

[source,xml]
----
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-kubernetes-config</artifactId>
</dependency>
----

Gradle:

[source,groovy]
----
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-kubernetes-config'
----

First you need a Kubernetes cluster, you can use https://www.docker.com/products/docker-desktop/[docker-desktop]
or https://minikube.sigs.k8s.io/docs/[minikube] to create a cluster.

- Clone the project

[source,shell]
----
git clone --depth=1 https://github.com/alibaba/spring-cloud-alibaba.git
----

- Create Role and RoleBinding for ServiceAccount

[source,shell]
----
# Created a ClusterRole just for the example, but in fact, you can control resources more finely, only need the get,list,watch permissions of ConfigMap/Secret
kubectl create clusterrole config-cluster-reader --verb=get,list,watch --resource=configmaps,secrets
# Bind ClusterRole to ServiceAccount (namespace: default, name: default)
kubectl create clusterrolebinding config-cluster-reader-default-default --clusterrole config-cluster-reader --serviceaccount default:default
----

- Build and Start

[source,shell]
----
./mvnw clean package -pl com.alibaba.cloud:kubernetes-config-example -am -DskipTests
docker build -f spring-cloud-alibaba-examples/kubernetes-config-example/Dockerfile -t kubernetes-config-example:latest .
kubectl apply -f spring-cloud-alibaba-examples/kubernetes-config-example/deployment.yaml
----

[source,shell]
----
# Execute the following command after the application startup, the startup process should be very fast (less than 3s)
curl http://localhost:`kubectl get service kubernetes-config-example -o jsonpath='{..nodePort}'`/price
# You should see a response of `100`
----

- Add ConfigMap

[source,shell]
----
# This ConfigMap is being monitored by the current application, so when this ConfigMap is added, the application will automatically update the configuration
kubectl apply -f spring-cloud-alibaba-examples/kubernetes-config-example/configmap-example-01.yaml
# Visit again
curl http://localhost:`kubectl get svc kubernetes-config -o jsonpath='{..nodePort}'`/price
# You should see a response of `200`
----

You can modify the configuration in `configmap-example-01.yaml`, and then re-apply the file to observe the change of the interface result.

Through the above operations, you can see that the application can dynamically update the configuration without restarting.

- Delete Resources

[source,shell]
----
# Delete all resources created by the above operations
kubectl delete -f spring-cloud-alibaba-examples/kubernetes-config-example/deployment.yaml
kubectl delete -f spring-cloud-alibaba-examples/kubernetes-config-example/configmap-example-01.yaml
kubectl delete clusterrole config-cluster-reader
kubectl delete clusterrolebinding config-cluster-reader-default-default
----

=== Main Features

- Dynamic update configuration(ConfigMap/Secret)

You can manually configure whether to monitor configuration file changes.

- Configuration priority

Through configuration, choose to use local configuration or remote configuration first.

- Supports multiple configuration file formats

Supports configuration files in `yaml`, `properties`, `json` and key-value pair.

=== Core Configurations

[source,yaml]
----
spring:
cloud:
k8s:
config:
enabled: true
namespace: default # The namespace where the configuration is located (global configuration). If it is inside the Kubernetes cluster, it defaults to the namespace where the current pod is located; if it is outside the Kubernetes cluster, it defaults to the namespace of the current context
preference: remote # Configuration priority (global configuration), remote is preferred to use remote configuration, local is preferred to use local configuration, and the default is remote
refreshable: true # Whether to enable dynamic update configuration (global configuration), the default is true
refresh-on-delete: false # Whether to automatically refresh when deleting the configuration, enabling this configuration may bring certain risks, if your configuration items only exist on the remote side but not locally, if you delete the configmap by mistake, it may cause abnormalities in the program, so the default value is false
fail-on-missing-config: true
config-maps:
- name: my-configmap # configmap name
namespace: default # The namespace where configmap is located will override the global configuration of the namespace
preference: remote # Configuration priority, which will override the global configuration of preference
refreshable: true # Whether to enable dynamic update configuration, it will override the refresh-enabled global configuration
secrets:
- name: my-secret # secret name
namespace: default # The namespace where the secret is located will override the global configuration of the namespace
preference: remote # Configuration priority, which will override the global configuration of preference
refreshable: false # Whether to enable dynamic update configuration will override the global configuration of refresh-enabled, because secrets generally do not require dynamic refresh, so the default value is false
----

=== Best Practices

Spring Cloud provides the capability of dynamically refreshing the Environment at runtime, which mainly dynamically updates the properties of two types of beans:

- Beans annotated with `@ConfigurationProperties`
- Beans annotated with `@RefreshScope`

A good practice is to use `@ConfigurationProperties` to organize your configurations.
56 changes: 56 additions & 0 deletions spring-cloud-alibaba-examples/kubernetes-config-example/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<groupId>com.alibaba.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>kubernetes-config-example</artifactId>
<name>Kubernetes Config Example</name>
<description>Example demonstrating how to use Spring Cloud Alibaba Kubernetes Config</description>
<packaging>jar</packaging>

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-kubernetes-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.cloud.examples.kubernetes.config;

import com.alibaba.cloud.examples.kubernetes.config.properties.BlacklistProperties;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

/**
* @author Freeman
*/
@SpringBootApplication
@EnableConfigurationProperties(BlacklistProperties.class)
public class KubernetesConfigApplication {

public static void main(String[] args) {
SpringApplication.run(KubernetesConfigApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.cloud.examples.kubernetes.config.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

import static com.alibaba.cloud.examples.kubernetes.config.filter.BlacklistFilter.HEADER_USER_ID;

/**
* @author Freeman
*/
@RestController
public class EchoController {

@GetMapping("/echo")
public String echo(@RequestHeader(HEADER_USER_ID) String userId) {
return String.format("Hello, %s", userId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.cloud.examples.kubernetes.config.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.cloud.examples.kubernetes.config.properties.BlacklistProperties;

import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

/**
* @author Freeman
*/
@Component
public class BlacklistFilter extends OncePerRequestFilter {
/**
* User id header.
*/
public static final String HEADER_USER_ID = "X-User-Id";

private final BlacklistProperties blacklistProperties;

public BlacklistFilter(BlacklistProperties blacklistProperties) {
this.blacklistProperties = blacklistProperties;
}

@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp,
FilterChain chain) throws ServletException, IOException {
String userId = req.getHeader(HEADER_USER_ID);
if (userId == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
HEADER_USER_ID + " header is required!");
return;
}
if (blacklistProperties.getUserIds().contains(userId)) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "User is blacklisted!");
return;
}
chain.doFilter(req, resp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.cloud.examples.kubernetes.config.properties;

import java.util.Set;

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* @author Freeman
*/
@Data
@ConfigurationProperties(prefix = "blacklist")
public class BlacklistProperties {
private Set<String> userIds;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
server:
port: 8080
spring:
application:
name: kubernetes-config-example
cloud:
k8s:
config:
config-maps:
- name: configmap-01
namespace: default
refreshable: true
preference: remote
secrets:
- name: secret-01
namespace: default
refreshable: false
refresh-on-delete: false
fail-on-missing-config: false
blacklist:
user-ids:
- 1
- 2
2 changes: 2 additions & 0 deletions spring-cloud-alibaba-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
<module>integrated-example/integrated-praise-consumer</module>
<module>integrated-example/integrated-common</module>
<module>integrated-example/integrated-frontend</module>

<module>kubernetes-config-example</module>
</modules>

<build>
Expand Down

0 comments on commit 2d2cb16

Please sign in to comment.