查看原文
其他

K8S部署Springboot项目

木讷大叔爱运维 木讷大叔爱运维 2022-07-13


点击上方蓝色字体,关注我们





读完需 12 分钟

速读需 5 分钟 





适合ingress-nginx接入外部负载均衡的部署一文主要介绍了如何通过ingress-nginx对外暴露服务,以及与外部负载均衡的结合,下面我们通过将SpringBoot项目迁入K8S中,来完整了解下从一个Java项目的整体流程。


环境准备

1.命名空间

K8S通过namespace划分集群资源。因此我们通过prod、test、develop来划分生产环境、测试环境、开发环境。

在此我们主要以test进行演示。


2. 镜像仓库

我们通过harbor仓库来存储springboot项目的镜像,可参考Docker部署spring boot体验来了解helloworld项目从打包到上传harbor仓库的过程。


部署

1.创建命名空间

kubectl create ns test


2.添加harbor认证

通过secret 可以实现类似docker login登录harbor仓库认证过程。

#在对应的namespace下创建secretkubectl create secret docker-registry harbor --namespace test --docker-server=harbor.test.cn --docker-username=admin --docker-password=admin --docker-email=test@test.cn

注意:一定要在对应的namespace下创建secret,否则会导致从harbor仓库pull镜像认证不通过。


3.定义Deployment

通常Deployment、service、ingress 写在一份yaml文件中,为方便演示我们都进行单独分解。

# 1.vim deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: helloworld namespace: testspec: replicas: 1 selector: matchLabels: app: helloworld template: metadata: name: helloworld labels: app: helloworld spec: hostAliases: - ip: "10.11.10.11" hostnames: - "api1.test.cn" - "api2.test.cn" - ip: "10.11.10.12" hostnames: - "api3.test.cn" containers: - name: helloworld env: - name: JAVA_OPTS value: "-Xmx128m -Xms128m -Dspring.profiles.active=test" image: harbor.test.cn/helloworld/helloworld:1311c4520122dfa67bb60e0103c9519fcb370e50 imagePullPolicy: IfNotPresent livenessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 200 timeoutSeconds: 5 readinessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 180 timeoutSeconds: 5 ports: - containerPort: 8080 resources: limits: cpu: "0.5" memory: "500Mi" requests: cpu: "0.5" memory: "500Mi" volumeMounts: - name: logdir mountPath: /logs - name: localtime mountPath: /etc/localtime - name: timezone mountPath: /etc/timezone imagePullSecrets: - name: harbor volumes: - name: logdir emptyDir: {} - name: localtime hostPath: path: /etc/localtime - name: timezone hostPath: path: /etc/timezone
# 2.应用配置文件kubectl apply -f deployment.yaml
# 3.查看# kubectl get pod -n testNAME READY STATUS RESTARTS AGEhelloworld-6f78bd8668-j6hmp           1/1     Running   0          3d18h

要点:

  • hostAliases:  用于指定适用于该项目的hosts解析,可根据实际情况进行添加。

  • env: jvm启动参数通过环境变量env传递,而args只适用于dockder build阶段,因此不能使用。

  • resources: 容器默认会无限制占用宿主机资源,因此需要进行限制。对于java 项目 xms xmx只是堆内存,实际进程所占内存比这还大,例如某项目默认Xms Xmx都是128M,但是pod的资源限制为200M、300M都会导致OOM,因此调整的资源需要比Xmx还要大

  • hostPath: 将宿主机节点文件系统中的文件或目录挂载到集群中,由于基于宿主机的目录,多副本跨节点必须保证目录存在,否则可能导致失败

  • emptyDir: 当pod被分配给节点时,首先创建emptyDir卷,并且只要该pod在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。pod中的容器可以读取和写入emptyDir卷中的相同文件。尽管该卷可以挂在到每个容器中的相同或不同路径上。当出于任何原因从节点中删除pod时,emptyDir中的数据将被永久删除。

  • 容器时区: 挂在宿主机的localtime和timezone,保证项目日志时间正常。

  • livenessProbe: 通过探针livenessProbe进行检测,httpGet获取的状态码等于200或小于400则正常。检测失败后,将根据使用restartPolicy策略。restartPolicy默认为always。

  • readinessProbe: 通过探针readinessProbe进行检测,httpGet获取的状态码等于200或小于400则正常。指示容器是否准备好服务请求。如果就绪探针失败,则端点控制器将从与Pod匹配的所有服务的端点中删除Pod的IP地址。默认每10秒检测一次,连续失败数为3,连续成功数为1。

  • initialDelaySeconds: 如果启动时间超过initialDelaySeconds会导致livenessProbe、readinessProbe检测不成功。readinessProbe 失败导致无法接受请求,livenessProbe失败导致容器不断重启。因此initialDelaySeconds要大于实际启动时间


注意:

  1. 对于SpringBoot项目的日志文件,我们并没有进行持久化存储,而是通过emptyDir临时存储,然后通过写入ELK做长期存储。

  2. 对于SpringBoot项目的数据文件,无论通过hostPath还是emptyDir都不合适,需通过PVC进行持久化存储。


4.定义service

# 1.vim service.yamlapiVersion: v1kind: Servicemetadata: name: helloworld namespace: testspec: type: NodePort selector: app: helloworld ports: - port: 8080 targetPort: 8080
# 2.应用配置文件kubectl apply -f service.yaml# 3.查看状态# kubectl get svc -n testNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEhelloworld NodePort 10.1.139.205 <none> 8080:30949/TCP 6d
# 4.访问# curl 10.1.138.205:8080Hello,world

对于NodePort类型的service,通过集群所有节点的IP都可以访问服务。

# curl 192.168.3.218:30949 Hello,world!# curl 192.168.3.219:30949 Hello,world!# curl 192.168.3.217:30949 Hello,world!
# 原因:# 所有节点lvs信息都有对service 30949端口的转发,因此集群内所有节点都可通过service访问服务ipvsadm -l -n |grep -A 2 -B 2 30949TCP 192.168.3.217:30949 rr -> 10.244.2.100:8080


5.定义ingress-ingress

此部分细节可参考适合ingress-nginx接入外部负载均衡的部署选择适合自己的部署方式,本文我们使用默认的Deployment+NodePort进行部署。

# 1.vim ingress.yaml apiVersion: extensions/v1beta1kind: Ingressmetadata: name: helloworld namespace: testspec: rules: - host: hello.test.cn http: paths: - path: / backend: serviceName: helloworld servicePort: 8080# 2.应用kubectl apply -f ingress.yaml# 3.查看# kubectl get ing -n testNAME CLASS HOSTS ADDRESS PORTS AGEhelloworld <none> hello.test.cn 10.1.217.16 80 4d18h# kubectl get svc -n ingress-nginxNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEingress-nginx NodePort 10.1.217.16 <none> 80:30687/TCP,443:31826/TCP 15h# kubectl get svc -n ingress-nginxNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEingress-nginx NodePort 10.1.217.16 <none> 80:30687/TCP,443:31826/TCP 15h# 4.访问# curl -x 192.168.3.218:30687 hello.test.cnHello,world!


注意: 默认ingress-nginx部署并不能让我们从外部通过80端口访问到服务,只能通过NodePort暴露的端口访问。



总结

以上是整个SpringBoot项目的部署过程及需要注意的地方,个人认为K8S部署SpringBoot项目最主要的应该是资源限制、健康检查及存储这三点。

  • 资源限制保证集群内容器合理占用宿主机资源,避免资源无限占用导致集群问题;

  • 健康检查保证集群内容器正常运行,合理摘除不健康的节点,保证请求的转发到健康节点;

  • 选择合适的存储方式,保证项目的运行时数据、日志文件合理存储;


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存