java微服务部署
1、java代码
java服务名称统一格式
1、提交代码、使用服务名称命名
java-app-producer
java-app-consumer
java-app-daem1
健康检查接口
添加健康检查、方便k8s探针探测
添加一个健康检查接口、使用curl命令传递、传递1就关闭服务、传递0就开启服务、传递status检查服务状态、k8s探针就探测health接口
livenessProbe:
httpGet:
path: /api/actuator/health # 生产者
port: 8081
initialDelaySeconds: 10
periodSeconds: 5
readinessProbe:
httpGet:
path: /api/actuator/health # 生产者
port: 8081
initialDelaySeconds: 5
periodSeconds: 5
消费者的 path 改为 /test/actuator/health,端口改为 8082
关闭服务(变为不健康): curl "http://<服务IP>:<端口>/test/health?cmd=1"
开启服务(变为健康): curl "http://<服务IP>:<端口>/test/health?cmd=0"
查询健康状态: curl "http://<服务IP>:<端口>/test/health?cmd=0"
探针健康检查(K8s自动调用): curl "http://<服务IP>:<端口>/test/actuator/health"
1、生产者
下面是生产者的代码
# 创建目录
mkdir -p daemapp-1/java-app1-producer/src/main/java/com/example/controller
mkdir -p daemapp-1/java-app1-producer/src/main/resources
# Dockerfile
cat > daemapp-1/java-app1-producer/Dockerfile << 'EOF'
FROM openjdk:11.0.7
LABEL maintainer="jigaobo jigaobo@qq.com"
RUN mkdir -p /jigaobo && mkdir /app
WORKDIR /app
COPY target/java-app-producer-1.0.jar /app/
EXPOSE 8081
CMD ["java", "-Duser.timezone=Asia/Shanghai", "-jar", "/app/java-app-producer-1.0.jar", "--spring.config.location=/app/config/application.yml"]
EOF
# pom.xml
cat > daemapp-1/java-app1-producer/pom.xml << 'EOF'
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>java-app-producer</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.13</version>
</parent>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
EOF
# App1Application.java
cat > daemapp-1/java-app1-producer/src/main/java/com/example/App1Application.java << 'EOF'
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class App1Application {
public static void main(String[] args) {
SpringApplication.run(App1Application.class, args);
}
}
EOF
# TestController.java
cat > daemapp-1/java-app1-producer/src/main/java/com/example/controller/TestController.java << 'EOF'
package com.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
// 健康状态标志,默认健康
private static volatile boolean healthy = true;
@GetMapping("/call")
public String callApp1() {
return "调用业务逻辑";
}
// 健康状态控制接口
@GetMapping("/health")
public String health(@RequestParam String cmd) {
if ("1".equals(cmd)) {
healthy = false;
return "服务已关闭";
} else if ("0".equals(cmd)) {
healthy = true;
return "服务已开启";
} else if ("status".equalsIgnoreCase(cmd)) {
return healthy ? "服务健康" : "服务不健康";
} else {
return "未知命令";
}
}
// K8s 探针专用健康检查接口
@GetMapping("/actuator/health")
public String actuatorHealth() {
return healthy ? "UP" : "DOWN";
}
}
EOF
# application.yml
cat > daemapp-1/java-app1-producer/src/main/resources/application.yml << 'EOF'
server:
port: 8081
spring:
application:
name: java-app-producer
cloud:
nacos:
discovery:
server-addr: cluster-ip-nacos:8848
EOF
# logback-spring.xml
cat > daemapp-1/java-app1-producer/src/main/resources/logback-spring.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 取 K8s 注入的环境变量 -->
<springProperty scope="context" name="POD_NAME" source="POD_NAME" defaultValue="unknown"/>
<!-- 日志文件路径 = 挂载目录 + 动态文件名 -->
<property name="LOG_FILE" value="/data/java/logs/${POD_NAME}.log"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${LOG_FILE}</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</configuration>
EOF
2、消费者
下面是消费者的代码
# 创建目录
mkdir -p daemapp-1/java-app2-consumer/src/main/java/com/example/controller
mkdir -p daemapp-1/java-app2-consumer/src/main/java/com/example/client
mkdir -p daemapp-1/java-app2-consumer/src/main/resources
# Dockerfile
cat > daemapp-1/java-app2-consumer/Dockerfile << 'EOF'
FROM openjdk:11.0.7
LABEL maintainer="jigaobo jigaobo@qq.com"
RUN mkdir -p /jigaobo && mkdir /app
WORKDIR /app
COPY target/java-app-consumer-1.0.jar /app/
EXPOSE 8081
#CMD ["java", "-Duser.timezone=Asia/Shanghai", "-jar", "/app/java-app-consumer-1.0.jar"]
CMD ["java", "-Duser.timezone=Asia/Shanghai", "-jar", "/app/java-app-consumer-1.0.jar", "--spring.config.location=/app/config/application.yml"]
EOF
# pom.xml
cat > daemapp-1/java-app2-consumer/pom.xml << 'EOF'
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>java-app-consumer</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.13</version>
</parent>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>3.1.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
EOF
# App2Application.java
cat > daemapp-1/java-app2-consumer/src/main/java/com/example/App2Application.java << 'EOF'
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class App2Application {
public static void main(String[] args) {
SpringApplication.run(App2Application.class, args);
}
}
EOF
# App1Client.java
cat > daemapp-1/java-app2-consumer/src/main/java/com/example/client/App1Client.java << 'EOF'
package com.example.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "java-app-consumer")
public interface App1Client {
@GetMapping("/api/hello")
String hello(@RequestParam("name") String name);
}
EOF
# TestController.java
cat > daemapp-1/java-app2-consumer/src/main/java/com/example/controller/TestController.java << 'EOF'
package com.example.controller;
import com.example.client.App1Client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private App1Client app1Client;
@GetMapping("/call")
public String callApp1() {
return app1Client.hello("Nacos");
}
}
EOF
# application.yml
cat > daemapp-1/java-app2-consumer/src/main/resources/application.yml << 'EOF'
server:
port: 8082
spring:
application:
name: java-app-consumer
cloud:
nacos:
discovery: #服务发现
server-addr: cluster-ip-nacos:8848
EOF
# logback-spring.xml
cat > daemapp-1/java-app2-consumer/src/main/resources/logback-spring.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 取 K8s 注入的环境变量 -->
<springProperty scope="context" name="POD_NAME" source="POD_NAME" defaultValue="unknown"/>
<!-- 日志文件路径 = 挂载目录 + 动态文件名 -->
<property name="LOG_FILE" value="/data/java/logs/${POD_NAME}.log"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${LOG_FILE}</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</configuration>
EOF
3、编译打镜像
mvn clean && mvn package
docker build -t java-app-producer:v1 .
docker build -t java-app-consumer:v1 .
docker save -o /k8s/data/image/producer.tar.gz java-app-producer:v1
docker save -o /k8s/data/image/consumer.tar.gz java-app-consumer:v1
docker load -i /k8s/data/image/producer.tar.gz
docker load -i /k8s/data/image/consumer.tar.gz
2、使用configmap挂载
在 Kubernetes 中使用 ConfigMap 挂载配置文件,可以让你在不重建镜像的情况下灵活修改 Spring Boot或Spring Cloud 的 application.yml 等配置。
#生产者配置
mkdir daemapp1
cat > producer/application.yml << 'EOF'
server:
port: 8081
spring:
application:
name: java-app-producer
cloud:
nacos:
discovery:
server-addr: cluster-ip-nacos:8848 #注册中心地址
EOF
#消费者配置
cat > consumer/application.yml << 'EOF'
server:
port: 8081
spring:
application:
name: java-app-consumer
cloud:
nacos:
discovery:
server-addr: cluster-ip-nacos:8848 #注册中心地址
EOF
#创建cm
kubectl create configmap java-app-producer-config --from-file=application.yml=./producer/application.yml -n <名称空间>
kubectl create configmap java-app-consumer-config --from-file=application.yml=./consumer/application.yml -n <名称空间>
3、pod的yaml文件
注意:先创建PVC、然后创建pod
1、pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: java-logs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: managed-nfs-storage # 按需换成你的 SC
2. 生产者 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app-producer
spec:
replicas: 1
selector:
matchLabels:
app: java-app-producer
template:
metadata:
labels:
app: java-app-producer
spec:
nodename: k8s-33
containers:
- name: java-app-producer
image: java-app-producer:v1
ports:
- containerPort: 8081
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: logs-pvc
mountPath: /data/java/logs
- name: config-volume
mountPath: /app/config/application.yml
subPath: application.yml
livenessProbe:
httpGet:
path: /test/actuator/health
port: 8081
initialDelaySeconds: 10
periodSeconds: 5
readinessProbe:
httpGet:
path: /test/actuator/health
port: 8081
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: logs-pvc
persistentVolumeClaim:
claimName: java-logs-pvc
- name: config-volume
configMap:
name: java-app-producer-config
3. 消费者 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app-consumer
spec:
replicas: 1
selector:
matchLabels:
app: java-app-consumer
template:
metadata:
labels:
app: java-app-consumer
spec:
nodename: k8s-33
containers:
- name: java-app-consumer
image: java-app-consumer:v1
ports:
- containerPort: 8081
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: logs-pvc
mountPath: /data/java/logs
- name: config-volume
mountPath: /app/config/application.yml
subPath: application.yml
# livenessProbe:
# httpGet:
# path: /test/actuator/health
# port: 8081
# initialDelaySeconds: 10
# periodSeconds: 5
# readinessProbe:
# httpGet:
# path: /test/actuator/health
# port: 8081
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: logs-pvc
persistentVolumeClaim:
claimName: java-logs-pvc
- name: config-volume
configMap:
name: java-app-consumer-config

浙公网安备 33010602011771号