使用Jenkins在Kubernetes中实现零停机时间部署

自从我们添加了 Kubernetes持续部署Azure容器服务 Jenkins更新中心的插件“如何创建零停机时间部署”是我们最常提出的问题之一。我们在Azure上创建了一个快速入门模板,以演示零停机时间部署的外观。尽管我们的示例使用Azure,但该概念很容易适用于所有Kubernetes安装。

滚动更新

Kubernetes支持RollingUpdate策略,以用新的Pod逐渐替换旧的Pod,同时继续为客户提供服务而不会造成停机。要执行RollingUpdate部署:

  • Set .spec.strategy.type to RollingUpdate (the default value).
  • Set .spec.strategy.rollingUpdate.maxUnavailable.spec.strategy.rollingUpdate.maxSurge to some reasonable value.
    • maxUnavailable:更新过程中不可用的Pod的最大数量。这可以是副本数的绝对数量或百分比。默认值为25%。
    • maxSurge:可以在所需数量的广告连播中创建的最大广告连播数。同样,它可以是绝对数量或副本数量的百分比;默认值为25%。
  • Configure the readinessProbe for your service container to help Kubernetes determine the state of the pods. Kubernetes will only route the client traffic to the pods with a healthy liveness probe.

我们将使用官方Tomcat映像的部署来演示此操作:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tomcat-deployment-rolling-update
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: tomcat
        role: rolling-update
    spec:
      containers:
      - name: tomcat-container
        image: tomcat:${TOMCAT_VERSION}
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /
            port: 8080
  strategy:
    type: RollingUpdate
    rollingUp      maxSurge: 50%

If the Tomcat running in the current deployments is version 7, we can replace ${TOMCAT_VERSION} with 8 和 apply this to the Kubernetes cluster. With the Kubernetes持续部署 或者 Azure容器服务 插件,可以从环境变量中获取该值,从而简化了部署过程。

在幕后,Kubernetes像这样管理更新:

部署过程

  • 最初,所有Pod都在运行Tomcat 7,并且前端服务将流量路由到这些Pod。
  • 在滚动更新期间,Kubernetes删除了一些Tomcat 7容器并创建了相应的新Tomcat 8容器。它确保:
    • at most maxUnavailable pods in the desired Pods can be unavailable, that is, at least (replicas - maxUnavailable) pods should be serving the client traffic, which is 2-1=1 in our case.
    • 最多maxSurge在更新过程中可以创建更多Pod,在我们的示例中为2 * 50%= 1。
  • 卸下一个Tomcat 7吊舱,并创建一个Tomcat 8吊舱。 Kubernetes不会将流量路由到任何一个,因为它们的就绪性探测尚未成功。
  • 当准备就绪探针确定新的Tomcat 8 Pod准备就绪时,Kubernetes将开始向其路由通信。这意味着在更新过程中,用户可能会同时看到旧服务和新服务。
  • 通过删除Tomcat 7 Pod和创建Tomcat 8 Pod,然后将流量路由到就绪Pod,继续进行滚动更新。
  • 最后,所有pod都位于Tomcat 8上。

滚动更新策略可确保我们始终有一些Ready后端Pod服务于客户端请求,因此不会造成服务停机。但是,需要格外注意:

  • 在更新期间,旧的Pod和新的Pod都可以满足请求。如果在服务层中没有明确定义的会话亲和力,则可能会将用户路由到新的Pod,然后再路由回旧的Pod。
  • 这还要求您为数据和API保持明确定义的前向和后向兼容性,这可能是一个挑战。
  • 吊舱启动后,可能需要很长时间才能准备好通行。可能需要很长的时间才能使用比通常少的后端Pod来提供流量。通常,这应该不成问题,因为我们倾向于在服务不太繁忙时进行生产升级。但这也会延长问题1的时间范围。
  • 我们无法对正在创建的新容器进行全面测试。将应用程序更改从开发人员/质量保证环境迁移到生产环境可能会带来破坏现有功能的持续风险。准备就绪探针可以做一些工作来检查准备就绪,但是,它应该是可以定期运行的轻量级任务,不适合用作开始完整测试的入口点。

蓝色/绿色部署

TechTarget引用的蓝色/绿色部署

蓝色/绿色部署是用于发布软件代码的变更管理策略。蓝色/绿色部署(也可以称为A / B部署)需要两个完全相同的硬件环境,并且配置方式完全相同。当一个环境处于活动状态并为最终用户提供服务时,另一环境则保持空闲状态。

容器技术提供了运行所需服务的独立环境,这使得创建蓝/绿部署所需的相同环境变得异常容易。松散耦合的服务-副本集以及Kubernetes中基于标签/选择器的服务路由使在不同的后端环境之间切换变得容易。使用这些技术,可以按以下步骤完成Kubernetes中的蓝色/绿色部署:

  • 在部署之前,基础架构的准备工作如下:
    • Prepare the blue deployment 和 green deployment with TOMCAT_VERSION=7TARGET_ROLE set to blue or green respectively.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tomcat-deployment-${TARGET_ROLE}
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: tomcat
        role: ${TARGET_ROLE}
    spec:
      containers:
      - name: tomcat-container
        image: tomcat:${TOMCAT_VERSION}
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /
            port: 8080
  • Prepare the public service endpoint, which initially routes to one of the backend environments, say TARGET_ROLE=blue.
kind: Service
apiVersion: v1
metadata:
  name: tomcat-service
  labels:
    app: tomcat
    role: ${TARGET_ROLE}
    env: prod
spec:
  type: LoadBalancer
  selector:
    app: tomcat
    role: ${TARGET_ROLE}
  ports:
    - port: 80
      targetPort: 8080
  • (可选)准备一个测试端点,以便我们可以访问后端环境进行测试。它们类似于公共服务终结点,但是仅供开发人员/运营团队内部访问。
kind: Service
apiVersion: v1
metadata:
  name: tomcat-test-${TARGET_ROLE}
  labels:
    app: tomcat
    role: test-${TARGET_ROLE}
spec:
  type: LoadBalancer
  selector:
    app: tomcat
    role: ${TARGET_ROLE}
  ports:
    - port: 80
      targetPort: 8080
  • Update the application in the inactive environment, say green environment. Set TARGET_ROLE=greenTOMCAT_VERSION=8 in the deployment config to update the green environment.
  • Test the deployment via the tomcat-test-green test endpoint to ensure the green environment is ready to serve client traffic.
  • Switch the frontend Service routing to the green environment by updating the Service config with TARGET_ROLE=green.
  • 在公共端点上运行其他测试,以确保其正常运行。
  • 现在,蓝色环境处于空闲状态,我们可以:
    • 将其保留在旧应用程序中,以便在新应用程序出现问题时我们可以回滚
    • 更新它以使其成为活动环境的热备份
    • 减少其副本数以节省占用的资源

Resources

与滚动更新相比,蓝/绿*公共服务要么路由到旧应用程序,要么路由到新应用程序,但绝不会同时路由到这两个应用程序。

  • 新Pod准备就绪所需的时间不会影响公共服务质量,因为只有在所有新Pod经过测试准备就绪后,流量才会路由到新Pod。
  • 在新环境为任何公共流量服务之前,我们可以对其进行全面测试。只需记住这是在生产中,测试就不会污染实时应用程序数据。

詹金斯自动化

Jenkins提供易于设置的工作流程来自动化您的部署。用 管道 支持,可以灵活地构建零停机时间部署工作流程并可视化部署步骤。 为了简化Kubernetes资源的部署过程,我们发布了 Kubernetes持续部署Azure容器服务 插件基于 kubernetes客户端。您可以将资源部署到Azure Kubernetes服务(AKS)或常规Kubernetes群集,而无需kubectl,它支持资源配置中的变量替换,因此您可以将特定于环境的资源部署到群集,而无需更新资源配置。 我们创建了一条詹金斯管道,以演示向AKS部署的蓝色/绿色。流程如下所示:

詹金斯管道

  • 预清洁:清洁工作区。
  • SCM:从源代码管理管理系统中提取代码。
  • 准备映像:准备应用程序Docker映像并将其上传到某个Docker存储库。
  • 检查环境:确定活动和不活动的环境,这会驱动以下部署。
  • 部署:将新的应用程序资源配置部署到非活动环境。使用Azure容器服务插件,可以通过以下方式完成此操作:
acsDeploy azureCredentialsId: 'stored-azure-credentials-id',
          configFilePaths: "glob/path/to/*/resource-config-*.yml",
          containerService: "aks-name | AKS",
          resourceGroupName: "resource-group-name",
          enableConfigSubstitution: true
  • 验证已分阶段:验证到非活动环境的部署以确保其正常运行。同样,请注意,这是在生产环境中的,因此请注意不要在测试期间污染实时应用程序数据。
  • 确认:(可选)发送电子邮件通知以供用户手动批准,以继续进行实际的环境切换。
  • 切换:将前端服务端点路由切换到非活动环境。这只是AKS Kubernetes集群的另一项服务部署。
  • 验证产品:验证前端服务端点在新环境中是否正常工作。
  • 后期清理:对临时文件进行后期清理。

对于滚动更新策略,只需将部署配置部署到Kubernetes集群,这是一个简单的单一步骤。

放在一起

我们在Azure上构建了一个快速入门模板,以演示如何使用Jenkins将零停机时间部署到AKS(Kubernetes)。去 Jenkins在Kubernetes上进行蓝绿色部署 然后单击“部署到Azure”按钮以获取有效的演示。该模板将规定:

  • 一个具有以下资源的AKS集群:
    • Two similar deployments representing the environments "blue" 和 "green". Both are initially set up with the tomcat:7 image.
    • Two test endpoint services (tomcat-test-bluetomcat-test-green), which are connected to the corresponding deployments, 和 can be used to test if the deployments are ready for production use.
    • A production service endpoint (tomcat-service) which represents the public endpoint that the users will access. Initially it is routing to the "blue" environment.
  • 在Ubuntu 16.04 VM上运行的Jenkins主服务器,配置了Azure服务主体凭据。 Jenkins实例有两个示例作业:
    • AKS Kubernetes滚动更新部署管道,以演示将滚动更新部署到AKS。
    • AKS Kubernetes蓝色/绿色部署管道,用于向AKS演示蓝色/绿色部署。
    • 我们没有在快速入门模板中包括电子邮件确认步骤。要添加它,您需要在Jenkins系统配置中配置电子邮件SMTP服务器详细信息,然后在Switch之前添加一个Pipeline阶段:
stage('Confirm') {
    mail (to: 'to@example.com',
        subject: "Job '${env.JOB_NAME}' (${env.BUILD_NUMBER}) is waiting for input",
        body: "Please go to ${env.BUILD_URL}.")
    input 'Ready to go?'
}

跟着 脚步 来设置资源,您可以通过启动Jenkins构建作业来尝试。