docker容器启动成功,并不代表容器中的服务就能处理外部的请求。比方说java web项目启动需要一段时间。
Kubernetes提供了readiness probe来检测pod中的容器是否可以接受外部流量。
可以在java项目中提供一个接口,kubernetes发请求给此接口,当此接口返回数据时,则表明服务准备就绪,可以接受外部请求了。
先看一个简单例子,准备一个spring boot工程,提供一个外部接口。以下服务用的端口号是10012
@GetMapping("/test02/version")
public String version(){
return "app02/version/v1";
}
在node节点上,编写Docker配置文件,并打成镜像
Dockerfile
FROM openjdk:8
ADD *.jar /app/app.jar
ADD entrypoint.sh /app/
# PORT="10012" 是项目端口号
ENV PORT="10012" TIME="Asia/Shanghai" JAVA_OPS="-Xmx256m -Xms256m -XX:+UseConcMarkSweepGC"
RUN set -e \
&& chmod +x /app/entrypoint.sh \
&& ln -snf /usr/share/zoneinfo/$TIME /etc/localtime \
&& echo $TIME > /etc/timezone
ENTRYPOINT ["/app/entrypoint.sh"]
EXPOSE $PORT
STOPSIGNAL SIGTERM
entrypoint.sh
#!/bin/sh
exec java ${JAVA_OPS} -jar /app/app.jar
打成镜像codingsoldier/app02:v1
docker build -t codingsoldier/app02:v1 .
在master节点上编写部署文件
k8s-service.yaml
apiVersion: v1
kind: Service
metadata:
name: service-app02
spec:
selector:
app: app02
ports:
- name: http
port: 10012
targetPort: 10012
k8s-app02.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-app02
spec:
replicas: 2
selector:
matchLabels:
app: app02
template:
metadata:
labels:
app: app02
spec:
containers:
- name: app02
image: codingsoldier/app02:v1
ports:
- name: http
containerPort: 10012
部署服务
kubectl apply -f k8s-service
kubectl apply -f k8s-app02
获取k8s-service的ip
kubectl get svc
重新开一个终端,循环调用接口,不要关闭这个终端,要一直开着。
while true; \
curl http://10.101.75.203:10012/test02/version; \
echo " "; \
do sleep 1; \
done;
现在就来升级版本吧
1、把/test02/version接口返回值改成v2
@GetMapping("/test02/version")
public String version(){
return "app02/version/v2";
}
2、打成jar包,上传到所有node节点
3、生成docker镜像
docker build -t codingsoldier/app02:v2 .
4、修改k8s-app02.yaml镜像为v2
image: codingsoldier/app02:v2
5、重新开一个终端,执行 kubectl get pod -w 动态查看pod状态
6、重新部署下k8s-app02.yaml
kubectl apply -f k8s-app02.yaml
在循环调用的监控中可以看到,服务有短暂的时间无法提供服务。
原因是:docker容器启动成功了,k8s就认为此容器可以提供服务了。但事实上docker容器启动成功的时候,java服务还没启动完成,暂时无法给外部提供服务。
解决办法,使用readiness probe来检测pod中的容器是否可以接受外部流量。
1、java工程新增一个服务就绪接口
//服务就绪接口,提供给k8s检测
@GetMapping("/readiness")
public String readiness(){
return "yes";
}
2、k8s-app02.yaml加上就绪探针
readinessProbe:
httpGet:
port: http
path: /readiness
initialDelaySeconds: 20
periodSeconds: 10
readinessProbe详细的配置:
initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒。
periodSeconds:执行探测的频率。默认是10秒,最小1秒。
timeoutSeconds:探测超时时间。默认1秒,最小1秒。
successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1。
failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1。
httpGet配置项:
host:连接的主机名,默认连接到pod的IP。你可能想在http header中设置”Host”而不是使用IP。
scheme:连接使用的schema,默认HTTP。
path: 访问的HTTP server的path。
httpHeaders:自定义请求的header。HTTP运行重复的header。
port:访问的容器的端口名字或者端口号。端口号必须介于1和65525之间。
3、改下 /test02/version ,的返回值 app02/version/v3
4、修改 k8s-app02.yaml中镜像的版本image: codingsoldier/app02:v3
5、打成jar,上传
6、打成镜像
docker build -t codingsoldier/app02:v3 .
7、重新部署服务
kubectl apply -f k8s-app02.yaml
查看循环调用接口的终端,服务一直可用
查看运行了kubectl get pod -w 的终端
1、新pod处于Running状态,但READY是0/1。pod已经运行,但未就绪,此时不接收外部请求
2、25秒后,新pod处于Running状态,READY是1/1。pod可以接收外部请求了
3、新pod能够接收外部请求后,一个旧pod开始终止
4、由于pod服务数设置为2,所以此时另一个新pod开始创建,过程跟上面的一样,新pod能就收请求后,旧pod终止。
---------------------