此篇文章中,我们将讲述如何从configMap中引入参数配置,如何从挂载文件中引入文件配置。其中文件挂载是应用部署中常见的形式。
组件版本说明:
引入maven依赖,核心依赖:spring-cloud-kubernetes-fabric8-config
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-kubernetes-fabric8-configartifactId>
<version>${springcloud-kubernetes-fabric8.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.22version>
dependency>
dependencies>
在 application.yaml 中定义
spring:
application:
name: springboot-cloud-k8s-config-valueref
greeting:
message: ${GREETING_MESSAGE:nice to meet you}
farewell:
message: ${FAREWELL_MESSAGE:see you next time}
在ConfigMap中定义对应的参数
apiVersion: v1
kind: ConfigMap
metadata:
name: springboot-k8s-config-valueref
labels:
app: springboot-k8s-config-valueref
data:
GREETING_MESSAGE: "Say Hello to the World outside"
我们定义两个不同的ConfigMap便于更好地演示
apiVersion: v1
kind: ConfigMap
metadata:
name: springboot-k8s-config-valueref2
labels:
app: springboot-k8s-config-valueref
data:
farewell.message: "Say Farewell to the World outside"
通过maven指令编译一个镜像
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
<plugin>
<groupId>io.fabric8groupId>
<artifactId>docker-maven-pluginartifactId>
<version>${docker.maven.plugin.version}version>
<executions>
<execution>
<id>build-imageid>
<phase>packagephase>
<goals>
<goal>buildgoal>
goals>
execution>
executions>
<configuration>
<images>
<image>
<name>org/${project.artifactId}:${project.version}name>
<build>
<dockerFile>${project.basedir}/DockerfiledockerFile>
build>
image>
images>
configuration>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-deploy-pluginartifactId>
<configuration>
<skip>trueskip>
configuration>
plugin>
<plugin>
<artifactId>maven-surefire-pluginartifactId>
<version>2.22.2version>
plugin>
<plugin>
<artifactId>maven-failsafe-pluginartifactId>
<version>2.22.2version>
plugin>
plugins>
可以通过maven指令或IDE的插件
mvn clean package -Dmaven.test.skip=true
执行后,就可以将构建的镜像推送至本地/远程仓库
REPOSITORY TAG IMAGE ID CREATED SIZE
org/springboot-k8s-config-valueref 1.0-SNAPSHOT 8902aa877999 6 seconds ago 564MB
通过插件,可以进行应用打包 -> 构建docker镜像 -> 在本地/远程仓库中覆盖更新相同版本的镜像 -> 并清除本地临时文件
接下来,我们可以通过仓库中的镜像,发布一个pod
这边使用 configMapRef & configMapKeyRef
进行引用 :
test.yaml示例文件如下:
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: springboot-k8s-config-valueref
labels:
app: springboot-k8s-config-valueref
data:
GREETING_MESSAGE: "Say Hello to the World outside"
- apiVersion: v1
kind: ConfigMap
metadata:
name: springboot-k8s-config-valueref2
labels:
app: springboot-k8s-config-valueref
data:
farewell.message: "Say Farewell to the World outside"
- apiVersion: v1
kind: Service
metadata:
labels:
app: springboot-k8s-config-valueref
name: springboot-k8s-config-valueref
spec:
type: NodePort
selector:
app: springboot-k8s-config-valueref
ports:
- nodePort: 30163
port: 8080
protocol: TCP
targetPort: 8080
- apiVersion: apps/v1
kind: Deployment
metadata:
name: springboot-k8s-config-valueref
labels:
app: springboot-k8s-config-valueref
group: org.example
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
app: springboot-k8s-config-valueref
template:
metadata:
labels:
app: springboot-k8s-config-valueref
spec:
volumes:
- name: autoconfig
containers:
- name: springboot-k8s-config-valueref
image: org/springboot-k8s-config-valueref:1.0-SNAPSHOT
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: springboot-k8s-config-valueref
env:
- name: FAREWELL_MESSAGE
valueFrom:
configMapKeyRef:
name: springboot-k8s-config-valueref2
key: farewell.message
执行情况如下:
$ kubectl apply -f ~/springboot-demo/springboot-config-k8s-valueref/src/main/resources/deploy-valueref.yaml
configmap/springboot-k8s-config-valueref created
configmap/springboot-k8s-config-valueref2 created
service/springboot-k8s-config-valueref created
deployment.apps/springboot-k8s-config-valueref created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
springboot-k8s-config-valueref-57d464c66c-tg8nw 1/1 Running 0 3s
$ kubectl logs -f springboot-k8s-config-valueref-57d464c66c-tg8nw
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.0)
2023-09-18T12:17:05.206Z INFO 1 --- [ main] org.example.BootValueRefApplication : Starting BootValueRefApplication using Java 17.0.8 with PID 1 (/opt/app/springboot-k8s-config-valueref-1.0-SNAPSHOT.jar started by root in /opt/app)
2023-09-18T12:17:05.215Z INFO 1 --- [ main] org.example.BootValueRefApplication : The following 1 profile is active: "kubernetes"
2023-09-18T12:17:07.260Z INFO 1 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=cc47999e-9518-3998-aa7d-05324c2cb413
2023-09-18T12:17:08.015Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-09-18T12:17:08.028Z INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-09-18T12:17:08.029Z INFO 1 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.8]
2023-09-18T12:17:08.150Z INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-09-18T12:17:08.153Z INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2632 ms
2023-09-18T12:17:09.339Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-09-18T12:17:09.412Z INFO 1 --- [ main] org.example.BootValueRefApplication : Started BootValueRefApplication in 6.462 seconds (process running for 7.914)
经过以上步骤,一个简单的应用已经顺利地跑起来了
这边测试是采用 minikube 在本地搭建 K8S集群。
由于本地环境,需要讲暴露服务来访问,minikube service springboot-k8s-config-valueref --url
minikube service springboot-k8s-config-valueref --url
http://127.0.0.1:51650
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
请求服务API
$ curl http://127.0.0.1:51650
hello, 'Say Hello to the World outside', goodbye, 'Say Farewell to the World outside'
返回在外部ConfigMap中配置的参数,通过configMapRef 和 configMapKeyRef 均可以获取到参数
以下通过文件挂载的常见形式加载服务变量,通常直接挂载到jar的执行目录下的/config目录,作为springboot加载配置文件的第一优先级,无需指定自动读取
引入maven依赖,核心依赖:spring-cloud-kubernetes-fabric8-config
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-kubernetes-fabric8-configartifactId>
<version>${springcloud-kubernetes-fabric8.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.22version>
dependency>
dependencies>
在 application.yaml 中定义参数,部分文件挂载的参数可以不在文件中定义
server:
port: 8080
spring:
application:
name: springboot-k8s-config-filemount
dbuser: ${DB_USERNAME:default}
dbpassword: ${DB_PASSWORD:default}
定义 configmap
apiVersion: v1
kind: ConfigMap
metadata:
name: springboot-k8s-config-filemount
labels:
app: springboot-k8s-config-filemount
data:
application.yaml: |-
greeting:
message: "Say Hello to the World outside"
farewell:
message: "Say Goodbye to the World outside"
定义配置类:
@Data
@Configuration
public class DbConfig {
@Value("${dbuser}")
private String dbUsername;
@Value("${dbpassword}")
private String dbPassword;
}
@Data
@Configuration
public class MyConfig {
@Value("${greeting.message:'default greeting message'}")
private String greetingMessage;
@Value("${farewell.message:'default farewell message'}")
private String farewellMessage;
}
通过 maven compiler 构建镜像
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
<plugin>
<groupId>io.fabric8groupId>
<artifactId>docker-maven-pluginartifactId>
<version>${docker.maven.plugin.version}version>
<executions>
<execution>
<id>build-imageid>
<phase>packagephase>
<goals>
<goal>buildgoal>
goals>
execution>
executions>
<configuration>
<images>
<image>
<name>org/${project.artifactId}:${project.version}name>
<build>
<dockerFile>${project.basedir}/DockerfiledockerFile>
build>
image>
images>
configuration>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-deploy-pluginartifactId>
<configuration>
<skip>trueskip>
configuration>
plugin>
<plugin>
<artifactId>maven-surefire-pluginartifactId>
<version>2.22.2version>
plugin>
<plugin>
<artifactId>maven-failsafe-pluginartifactId>
<version>2.22.2version>
plugin>
plugins>
通过指令 或 IDE 插件,将镜像打包
mvn clean package -Dmaven.test.skip=true
将镜像推到仓库
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
org/springboot-config-k8s-filemount 1.0-SNAPSHOT f93c2e1254d5 42 seconds ago 628MB
根据镜像,发布一个Pod
使用 volumes
引入挂载的文件
使用 volumeMounts
指定挂载的文件
针对secret的数据需要在配置前加密,可以使用指定来获取base64加密后的数据: echo -n root | base64
,然后再填充到文件中
$ echo -n root | base64
cm9vdA==
样例文件:test.yaml:
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: Secret
metadata:
name: springboot-k8s-config-filemount-secret
labels:
app: springboot-k8s-config-filemount
data:
dbuser: cm9vdA==
dbpassword: cGFzc3dvcmQ=
- apiVersion: v1
kind: ConfigMap
metadata:
name: springboot-k8s-config-filemount
labels:
app: springboot-k8s-config-filemount
data:
application.yaml: |-
greeting:
message: "Say Hello to the World outside"
farewell:
message: "Say Goodbye to the World outside"
- apiVersion: v1
kind: Service
metadata:
labels:
app: springboot-k8s-config-filemount
name: springboot-k8s-config-filemount
spec:
type: NodePort
selector:
app: springboot-k8s-config-filemount
ports:
- nodePort: 30163
port: 8080
protocol: TCP
targetPort: 8080
- apiVersion: apps/v1
kind: Deployment
metadata:
name: springboot-k8s-config-filemount
labels:
app: springboot-k8s-config-filemount
group: org.example
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
app: springboot-k8s-config-filemount
template:
metadata:
labels:
app: springboot-k8s-config-filemount
spec:
volumes:
- name: config-volume
configMap:
name: springboot-k8s-config-filemount
items:
- key: application.yaml
path: application.yaml
containers:
- name: springboot-k8s-config-filemount
image: org/springboot-config-k8s-filemount:1.0-SNAPSHOT
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: springboot-k8s-config-filemount-secret
key: dbuser
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: springboot-k8s-config-filemount-secret
key: dbpassword
volumeMounts:
- name: config-volume
mountPath: /opt/app/config/application.yaml
subPath: application.yaml
使用 kubectl apply -f test.yaml
的方式发布Pod
$ kubectl apply -f ~/springboot-demo/springboot-config-k8s-filemount/src/main/resources/deploy-filemount.yaml
secret/springboot-k8s-config-filemount-secret created
configmap/springboot-k8s-config-filemount created
service/springboot-k8s-config-filemount created
deployment.apps/springboot-k8s-config-filemount created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
springboot-k8s-config-filemount-89d6bdfcd-vvkqz 1/1 Running 0 3s
$ kubectl logs springboot-k8s-config-filemount-89d6bdfcd-vvkqz
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.0)
2023-09-20T10:38:40.477Z INFO 1 --- [ main] org.example.BootFilemountApplication : Starting BootFileamountApplication using Java 17.0.8 with PID 1 (/opt/app/springboot-config-k8s-filemount-1.0-SNAPSHOT.jar started by root in /opt/app)
2023-09-20T10:38:40.480Z INFO 1 --- [ main] org.example.BootFilemountApplication : The following 1 profile is active: "kubernetes"
2023-09-20T10:38:42.402Z INFO 1 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=49502b73-ffac-39f1-a249-dec4d3facce7
2023-09-20T10:38:43.379Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-09-20T10:38:43.402Z INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-09-20T10:38:43.403Z INFO 1 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.8]
2023-09-20T10:38:43.517Z INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-09-20T10:38:43.520Z INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2845 ms
2023-09-20T10:38:44.714Z INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-09-20T10:38:44.792Z INFO 1 --- [ main] org.example.BootFilemountApplication : Started BootFilemountApplication in 6.37 seconds (process running for 8.022)
应用启动,准备测试
暴露端口 minikube service springboot-k8s-config-filemount --url
minikube service springboot-k8s-config-filemount --url
http://127.0.0.1:55369
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
请求接口,获取注入的参数值
$ curl http://127.0.0.1:55369
hello, 'Say Hello to the World outside', goodbye, 'Say Goodbye to the World outside'. myname: 'root', mypass: 'password'
参数值获取成功注入的参数