Kubernetes 部署 Spring Cloud 注册中心 Eureka Server
Java JDK 版本:openjdk:8-jdk
Docker 版本: version 19.03.8
kubernetes 版本:1.14.0
SpringBoot 版本:2.0.3.RELEASE
SpringCloud 版本:Finchley.RELEASE
Eureka 是 Netflix 开发的服务发现框架,本身是一个基于 REST 的服务。Eureka 包含 Eureka Server 和 Eureka Client 两个组件,Eureka Server 提供服务注册服务,Eureka Client 会将信息注册到 Eureka Server,然后各个 Eureka Client 间就能通过 Eureka Server 获取已经注册服务实例的节点位置信息和状态等信息。
SpringCloud 是一套非常火爆的微服务架构,它很多组件都需要 Eureka Server 充作注册中心来完成服务间负载均衡和维护服务列表信息等功能。
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。现在我们很多服务都是以 Docker 镜像方式运行在各个服务器上,并且依赖 Kubernetes 来对服务镜像进行编排,接下来要部署的 Eureka Server 也是要用 StaetfulSet 方式部署到 Kubernetes 中运行。
现阶段实际往 Kubernetes 中迁移的项目大多数都是之前未使用 Kubernetes 的项目,由于 Kubernetes 自己有一套服务发现、负载均衡机制(ETCD、CoreDNS、Service),所以觉得用 Eureka 来当注册中心就不能和 Kubernetes 的 Service 配合起来,也就不能使用过 Kubernetes 提供的负载能力,使之带来了开发的不便。当然,之前的老项目很多是基于 SpringCloud + docker 部署方式部署的,迁移的原则就是减少重构开发量,故而对于一些老项目迁移到 Kubernetes 中的话,还是需要部署 Eureka 来避免大规模改动代码。
4.0.0
eureka-server
1.0.0
jar
org.springframework.boot
spring-boot-starter-parent
2.0.3.RELEASE
UTF-8
UTF-8
1.8
Finchley.RELEASE
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
io.micrometer
micrometer-core
net.logstash.logback
logstash-logback-encoder
4.10
org.springframework.boot
spring-boot-maven-plugin
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
需要在配置文件中设置两个参数:
server.port: 程序的 server 端口,用于外部访问 Eureka UI 与服务注册。
management.server.port: 程序的监控数据端口,这里主要用其中的 /actuator/health 端口进行健康检查。
bootstrap.yml
server:
port: 8761 #启动端口
management:
server:
port: 8762
endpoints:
web:
exposure:
include: '*'
application.yml
eureka:
environment: dev
instance:
hostname: localhost
client:
registerWithEureka: false #false:不作为一个客户端注册到注册中心
fetchRegistry: false #为true时,可以启动,但报异常:Cannot execute request on any known server
serviceUrl:
defaultZone: http://localhost:8761/eureka/
启动类加上 @EnableEurekaServer 注解来开启 Eureka Server 功能
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
}
}
执行 Maven 命令将项目编译成一个可执行 JAR。
$ mvn clean install
创建构建 Docker 镜像需要的 Dockerfile 文件,将 Maven 编译的 JAR 复制到镜像内部,然后设置三个变量,分别是:
JVM_OPTS 设置一些必要的 JVM 启动参数。
JAVA_OPTS:Java JVM 启动参数变量,这里需要在这里加一个时区参数。
APP_OPTS:Spring 容器启动参数变量,方便后续操作时能通过此变量配置 Spring 参数。
Dockerfile
FROM openjdk:8-jdk
VOLUME /tmp
ADD eureka-server-1.0.0.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JVM_OPTS=" -Xms2048m -Xmx2048m -Xss256k -Duser.timezone=Asia/Shanghai -Djava.security.egd=file:/dev/./urandom"
ENV JAVA_OPTS=""
ENV APP_OPTS=" -spring.profiles.active=local "
ENTRYPOINT [ "sh", "-c", "java $JVM_OPTS $JAVA_OPTS -jar /app.jar $APP_OPTS" ]
执行 Docker Build 命令构建 Docker 镜像
docker build -t sscloud/eureka-server:1 .
坑点:注意版本号 后面的 . 否则会提示语法错误
docker tag aaf5e5e08b37 192.168.0.21:5000/eureka-server:1
aaf5e5e08b37 是构建后镜像的ID , 通过 docker images 查看
192.168.0.21:5000 是docker 私有仓库的地址和端口
docker push 192.168.0.21:5000/eureka-server:1
创建 Eureka 部署文件,用于在 Kubernetes 中部署 Eureka,这里选择用 StatefulSet (有状态集)方式来部署,这样能保证它 Eureka Pod 名是有序的,如果部署为 Deployment,那么得部署三个 Deployment 对象,比较繁琐。并且 StatefulSet 支持 Service Headless 方式创建 Service 来对内部服务访问,如果是 CluserIP 方式创建 Service 会分一个虚拟 IP 给该 Service,那么服务通过 Service 访问 Pod 每次都需要经过 Kube-proxy 代理流量,这样会增加与注册中心的通信造成一定性能损耗。Headless 方式部署的 Service 不会分配虚拟 IP,而是用轮询的访问,每次都直接与 Pod 的 IP 进行通信。
eureka.yaml
apiVersion: v1
kind: Service
metadata:
name: eureka-server
namespace: sscloud
labels:
app: eureka-server
spec:
clusterIP: None
ports:
- name: server
port: 8761
targetPort: 8761
- name: management
port: 8762
selector:
app: eureka-server
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: eureka-server
namespace: sscloud
labels:
app: eureka-server
spec:
serviceName: eureka-server
replicas: 3
podManagementPolicy: Parallel #Pod启停顺序管理
selector:
matchLabels:
app: eureka-server
template:
metadata:
labels:
app: eureka-server
spec:
terminationGracePeriodSeconds: 10 #当删除Pod时,等待时间
containers:
- name: eureka
image: 192.168.0.21:5000/eureka-server:1
ports:
- name: server
containerPort: 8761
- name: management
containerPort: 8762
env:
- name: APP_NAME
value: "eureka-server"
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: APP_OPTS
value: "
--spring.application.name=${APP_NAME}
--eureka.instance.hostname=${POD_NAME}.${APP_NAME}
--registerWithEureka=true
--fetchRegistry=true
--eureka.instance.preferIpAddress=false
--eureka.client.serviceUrl.defaultZone=http://eureka-0.${APP_NAME}:8761/eureka/,http://eureka-1.${APP_NAME}:8761/eureka/,http://eureka-2.${APP_NAME}:8761/eureka/
"
resources:
limits:
cpu: 2000m
memory: 1024Mi
requests:
cpu: 2000m
memory: 1024Mi
readinessProbe: #就绪探针
initialDelaySeconds: 20 #延迟加载时间
periodSeconds: 5 #重试时间间隔
timeoutSeconds: 10 #超时时间设置
failureThreshold: 5 #探测失败的重试次数
httpGet:
path: /actuator/health
port: 8762
livenessProbe: #存活探针
initialDelaySeconds: 60 #延迟加载时间
periodSeconds: 5 #重试时间间隔
timeoutSeconds: 5 #超时时间设置
failureThreshold: 3 #探测失败的重试次数
httpGet:
path: /actuator/health
port: 8762
env 参数说明:
APP_NAME: 和服务名称一致,将服务名称传入容器环境中。
POD_NAME: Pod名称,将 Pod 名称传入容器环境中。
APP_OPTS: Dockerfile 中定义的变量,用于设置 Spring 启动参数,这里主要设置此值与 APP_NAME 和 POD_NAME 两值配合使用。
其它参数说明:
resources: 对 Pod 使用计算资源的限制,最好两个值设置成一致,Kubernetes 中会对 Pod 设置 QoS 等级,跟这两个值的设置挂钩,limits 与 request 值一致时 Qos 等级最高,当资源不足时候 QoS 等级低的最先被杀死,等级高的一般不会受太大影响。
readinessProbe: 就绪探针,Pod 启动时只有就绪探针探测成功后才对外提供访问,用它可用避免 Pod 启动而内部程序没有启动的情况下就允许外部流量流入这种情况。
livenessProbe: 存活探针,定期检测 Docker 内部程序是否存活。
spec.podManagementPolicy: pod的启动顺序策略
OrderedReady: 顺序启停 Pod,默认设置。
Parallel: 并行启停 Pod,而不遵循一个 Pod 启动后再启动另一个这种规则。
-n:创建应用到指定的 Namespace 中。
查看命名空间
kubectl get namespaces
创建命名空间
namespace.yml
apiVersion: v1
kind: Namespace
metadata:
name: sscloud
在 k8s 主机上执行命令
kubectl create -f namespace.yaml
服务部署
kubectl apply -f eureka.yaml -n sscloud
创建一个类型为 NodePort 类型的 Service,供 Kubernetes 集群外部访问 Eureka UI 界面,方便观察服务注册情况。
eureka-node.yaml
apiVersion: v1
kind: Service
metadata:
name: eureka-nodeport
namespace: sscloud
labels:
app: eureka-nodeport
spec:
type: NodePort
ports:
- name: eureka-server
port: 8761
targetPort: 8761
nodePort: 31000
selector:
app: eureka-server
kubectl apply -f eureka-node.yaml -n sscloud
本人的 Kubernetes 集群 IP 地址为 192.168.0.249,且上面设置 NodePort 端口为 31000,所以这里访问 http://192.168.0.249:31000 地址,查看 Eureka UI 界面。