1. 系统环境
java JDK 11
docker 19.03.9
k8s 1.18
2. eureka架构图
3. eureka配置
application.yml
eureka:
instance:
prefer-ip-address: false # 我们使用的是hostname注册,要设置为false,否则注册不成功
client:
register-with-eureka: true #相互注册
fetch-registry: true
service-url:
defaultZone: http://eureka-0.eureka:8761/eureka,http://eureka-1.eureka:8761/eureka,http://eureka-2.eureka:8761/eureka
主机名使用的是k8s的pod名称+服务名
Pod的Name怎么组成的:
statefulSet控制器的Name + 序号
defaultZone也可以在k8s的部署文件中配置
这里把eureka的 hostname配置放到了部署文件中
4 dockerfile
FROM openjdk:11-jre
ARG JAR_FILE
ENV PROFILE default
ENV JAVA_OPTS -server
ENTRYPOINT java -Dspring.profiles.active=${PROFILE} -Duser.timezone=Asia/Shanghai ${JAVA_OPTS} -jar /usr/share/app.jar
EXPOSE 8761
ADD target/${JAR_FILE} /usr/share/app.jar
生成docker镜像
docker build -t registry.com/kubernetes/eureka:latest
5. 部署到k8s
创建 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 进行通信。
它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
为什么使用headless:
因为给Pod分配一个域,让其他Pod可以通过dnsName访问到这组Eureka的Pod
5.1 创建eureka.yml
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: eureka
namespace: dev
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: eureka.com
http:
paths:
- path: /
backend:
serviceName: eureka
servicePort: 8761
---
apiVersion: v1
kind: Service
metadata:
name: eureka
namespace: dev
spec:
clusterIP: None
ports:
- name: eureka
port: 8761
selector:
app: eureka
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: eureka
namespace: dev
spec:
serviceName: eureka
replicas: 3
selector:
matchLabels:
app: eureka
template:
metadata:
labels:
app: eureka
spec:
terminationGracePeriodSeconds: 1 #当删除Pod时,等待时间
containers:
- name: eureka
image: registry.com/eureka:1.0.0
imagePullPolicy: Always
ports:
- protocol: TCP
containerPort: 8761
env:
- name: APP_NAME
value: "eureka"
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: EUREKA_SERVER
value: "http://eureka-0.eureka:8761/eureka/,http://eureka-1.eureka:8761/eureka/,http://eureka-2.eureka:8761/eureka/"
- name: EUREKA_INSTANCE_HOSTNAME
value: ${POD_NAME}.eureka
# - name: PORT
# value: "8761"
- name: PROFILE
value: "test"
readinessProbe: #就绪探针
tcpSocket:
port: 8761
initialDelaySeconds: 20 #延迟加载时间
periodSeconds: 5 #重试时间间隔
timeoutSeconds: 10 #超时时间设置
failureThreshold: 5 #探测失败的重试次数
livenessProbe: #存活探针
tcpSocket:
port: 8761
initialDelaySeconds: 60 #延迟加载时间
periodSeconds: 5 #重试时间间隔
timeoutSeconds: 5 #超时时间设置
failureThreshold: 3 #探测失败的重试次数
podManagementPolicy: "Parallel" #并行部署
- 匹配Pod name(网络标识)的模式为:(statefulset名称)−(序号),比如上面的示例:eureka-0,eureka-1,eureka-2。
- StatefulSet为每个Pod副本创建了一个DNS域名,这个域名的格式为: $(podname).(headless Service name),也就意味着服务间是通过Pod域名来通信而非Pod IP,因为当Pod所在Node发生故障时,Pod会被飘移到其它Node上,Pod IP会发生变化,但是Pod域名不会有变化。
- StatefulSet使用Headless服务来控制Pod的域名,这个域名的FQDN为:(servicename).(namespace).svc.cluster.local,其中,“cluster.local”指的是集群的域名。
StatefulSet使用场景:
1.稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现。
2.稳定的网络标识符,即Pod重新调度后其PodName和HostName不变。
3.有序部署,有序扩展,基于init containers来实现。
4.有序收缩。
5.2 部署Eureka Server到kubernetes
kubectl apply -f eureka.yaml
#如果发现部署错了,可以执行kubectl delete -f erueka.yaml,删除这个yaml部署的所有资源
5.3. 访问Eurek UI
这里需要先安装ingress,具体看这篇文章 安装ingress
通过命令查看域名配置:
由于ingress配置了域名,先修改本地hosts,把域名解析到ingress-controller的Pod所在的NodeIP。
然后输入域名即可: