我正在尝试使用Kubernetes实现零停机时间部署。但每次我使用新映像升级部署时,我都会看到2-3秒的停机时间。我正在使用Hello-World类应用程序测试它,但仍然无法实现它。我正在使用Helm图表部署我的应用程序。
在线博客和资源之后,我在Deployment.yaml文件中使用了Readiness-Probe和Rolling Update策略。但这没有给我带来任何成功。我创建了一个/health
端点,它只返回200
状态代码作为准备探测的检查。我期望在Kubernetes中使用就绪探针和RollingUpdate策略后,当我升级容器的图像时,我将能够实现服务的零停机时间。对我的服务的请求通过Amazon ELB。
Deployment.yaml文件如下:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: wine-deployment
labels:
app: wine-store
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app: wine-store
replicas: 2
template:
metadata:
labels:
app: wine-store
spec:
containers:
- name: {{ .Chart.Name }}
resources:
limits:
cpu: 250m
requests:
cpu: 200m
image: "my-private-image-repository-with-tag-and-version-goes-here-which-i-have-hidden-here"
imagePullPolicy: Always
env:
- name: GET_HOSTS_FROM
value: dns
ports:
- containerPort: 8089
name: testing-port
readinessProbe:
httpGet:
path: /health
port: 8089
initialDelaySeconds: 3
periodSeconds: 3
Service.yaml文件:
apiVersion: v1
kind: Service
metadata:
name: wine-service
labels:
app: wine-store
spec:
ports:
- port: 80
targetPort: 8089
protocol: TCP
selector:
app: wine-store
Ingress.yaml文件:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: wine-ingress
annotations:
kubernetes.io/ingress.class: public-nginx
spec:
rules:
- host: my-service-my-internal-domain.com
http:
paths:
- path: /
backend:
serviceName: wine-service
servicePort: 80
当我使用helm upgrade
命令升级映像时,我预计停机时间为零。同时,当升级正在进行时,我使用curl命令持续点击我的服务。这个curl命令给我503-service Temporarily un-available
错误2-3秒,然后服务再次启动。我希望这种停机不会发生。
使用蓝绿色部署,因为即使pod已启动,kube-proxy也可能需要一段时间才能将请求转发到新的POD IP。
所以设置新的部署,在所有pod更新服务selector
到新的POD标签之后。关注:https://kubernetes.io/blog/2018/04/30/zero-downtime-deployment-kubernetes-jenkins/
此问题是由使用iptables的服务VIP引起的。你没有做错任何事 - 这是当前Kubernetes的限制。
当新pod上的就绪探测通过并且旧pod终止时,kube-proxy将重写该服务的iptables。但是,在旧pod终止之后但在更新iptables之前,请求可以命中服务,从而产生503。
在这种情况下它可能不相关,但在您的应用程序中实现优雅终止是个好主意。拦截TERM信号并等待您的应用程序完成处理它已收到的任何请求,而不是立即退出。
或者,更多的复制品,低maxUnavailable
和高maxSurge
都将降低请求命中终止pod的可能性。
欲了解更多信息:https://kubernetes.io/docs/concepts/services-networking/service/#proxy-mode-iptables https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods
另一个答案错误地暗示你需要一个活力探测器。虽然拥有一个活跃度探测器是个好主意,但它不会影响您遇到的问题。如果未定义活动探测,则默认状态为“成功”。
在滚动部署的上下文中,活动探测将是无关紧要的 - 一旦新pod上的准备探测通过旧pod将被发送TERM信号并且iptables将被更新。现在旧的pod正在终止,任何活动探测都无关紧要,因为它的唯一功能是在活动探测失败时重启pod。
新舱上的任何活动探测都是无关紧要的。当pod首次启动时,默认情况下它被认为是实时的。只有在活跃度探测器的initialDelaySeconds
开始被检查之后,如果它失败,则pod将被终止。
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes
您描述的问题表明准备探针存在问题。了解活动性和准备性探针之间的差异非常重要。首先,您应该实现和配置两者!
活性探针用于检查容器是否已启动和活动。如果不是这种情况,kubernetes最终将重启容器。
准备情况探测器还会检查依赖关系,例如数据库连接或容器所依赖的其他服务,以实现它的工作。作为一名开发人员,您必须在这里投入更多时间进行实施,而不仅仅是生活探测。您必须公开一个端点,该端点在查询时也会检查所提到的依赖关系。
您当前的配置使用健康端点,该端点通常由活动探针使用。它可能不会检查您的服务是否真的准备好接收流量。
Kubernetes依赖准备探针。在滚动更新期间,它将使旧容器保持运行,直到新服务声明它已准备好接收流量。因此,准备探针必须正确实施。