0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用Jenkins和单个模板部署多个Kubernetes组件

马哥Linux运维 来源:51CTO 2024-01-02 11:40 次阅读

前言

在持续集成和部署中,我们通常需要部署多个实例或组件到Kubernetes集群中。通过Jenkins的管道脚本,我们可以自动化这个过程。在本文中,我将演示如何使用Jenkins Pipeline及单个YAML模板文件(.tpl)来部署多个类似的Kubernetes组件,而不需要为每个组件提供单独的模板文件。

问题背景

Jenkins Pipeline 脚本优化实践:从繁琐到简洁批量生成 Kubernetes 部署模板:从 1 到20顺序模板

pipeline {
    agent none // Use none at the top level, each stage will define its own agent.


    environment {
        REGISTRY = "xxxx/master-metaspace"
        KUBE_CONFIG = "--namespace=master-metaspace --context=master"
        KUBE_YAML_PATH = "/home/jenkins/workspace/yaml/master-metaspace"
        // Assume that 'data' is defined elsewhere or injected as a parameter.
        BASE_WORKSPACE = "xxxxxxx" // 定义一个基础工作空间路径
    }


    stages {
        stage("GetCode") {
            agent { label "build01" }
            steps {
                script {
                    checkout scm: [
                        $class: 'GitSCM',
                        branches: [[name: env.branchName]],
                        extensions: [[$class: 'CloneOption', depth: 1, noTags: false, shallow: true]],
                        userRemoteConfigs: [[credentialsId: 'xxxx', url: env.gitHttpURL]]
                    ]
                }
            }
        }
        
        stage("Docker Builds") {
            parallel {
                stage('Build dataloader-game-ucenter') {
                    agent { label "build01" }
                    when { environment name: 'dataloader', value: 'true' }
                    steps {
                        buildAndPushDockerImage("dataloader-game-ucenter", env.data, env.BASE_WORKSPACE)
                    }
                }
                stage('Build datawriter-game-ucenter') {
                    agent { label "build01" }
                    when { environment name: 'datawriter', value: 'true' }
                    steps {
                        buildAndPushDockerImage("datawriter-game-ucenter", env.data, env.BASE_WORKSPACE)
                    }
                }
                stage('Build game-ucenter') {
                    agent { label "build01" }
                    when { environment name: 'game-ucenter', value: 'true' }
                    steps {
                        buildAndPushDockerImage("game-ucenter", env.data, env.BASE_WORKSPACE)
                    }
                }
            }
        }
        
        stage('Development Deployment') {
            parallel {
                stage("Deploy datawriter-game-ucenter") {
                    when { environment name: 'datawriter-game-ucenter', value: 'true' }
                    agent { label  "huaweiyun-xx" }
                    steps {
                        deployToKubernetes("datawriter-game-ucenter")
                    }
                }
                stage("Deploy dataloader-game-ucenter") {
                    when { environment name: 'dataloader', value: 'true' }
                    agent { label  "huaweiyun-xx" }
                    steps {
                        deployToKubernetes("dataloader-game-ucenter")
                    }
                }
                stage("Deploy game-ucenter") {
                    when { environment name: 'game-ucenter', value: 'true' }
                    agent { label  "huaweiyun-xx" }
                    steps {
                        deployToKubernetes("game-ucenter-1")
                        deployToKubernetes("game-ucenter-2")
                        deployToKubernetes("game-ucenter-3")
                        deployToKubernetes("game-ucenter-4")
                        ............................
                    }
                }
            }
        }
    }
}


// Define methods outside pipeline to avoid repetition


def buildAndPushDockerImage(String imageName, String tag, String workspacePath) {
    sh "cd ${workspacePath} && echo 'Current directory: $(pwd)'" // 使用基础工作空间变量
    sh "cd ${workspacePath}/${imageName}&& docker build --build-arg NODE_ENV=$imageName -t $REGISTRY/$imageName:$tag ."
    withCredentials([usernamePassword(credentialsId: 'xxxxx', passwordVariable: 'dockerPassword', usernameVariable: 'dockerUser')]) {
        sh "docker login -u $dockerUser -p $dockerPassword $REGISTRY"
        sh "docker push $REGISTRY/$imageName:$tag"
    }
}


def deployToKubernetes(String kubernetesComponent) {
    String templateFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.tpl"
    String outputFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.yaml"
    sh "sed -e 's/{data}/$data/g' $templateFile > $outputFile"
    sh "sudo kubectl apply -f $outputFile $KUBE_CONFIG"
}

默认jenkins pipeline如上,我们有多个相似的游戏用户中心服务game-ucenter-*运行在Kubernetes集群中,它们都使用非常相似的Kubernetes YAML配置文件,配置文件之间的差异主要是一些标识符的不同(例如,服务的序号)。在传统的做法中,维护一系列几乎一样的模板文件(如game-ucenter-1.tpl, game-ucenter-2.tpl 等)将非常低效且易出错。

为了精简流程和提高效率,我们需要一个方法来通过单一模板生成多个配置文件,并由此部署多个不同的服务实例。

解决方案

使用Jenkins Pipeline中的sed命令和循环结构,我们可以从单一模板生成多个Kubernetes配置文件,并相应地部署每个服务实例。参照generate_templates.sh脚本

#!/bin/bash


# Define the name of the template file.
TEMPLATE_FILE="game-ucenter.tpl"


# Check if the template file exists.
if [ ! -f "$TEMPLATE_FILE" ]; then
    echo "Template file $TEMPLATE_FILE does not exist."
    exit 1
fi


# Loop to create files from game-ucenter-2 to pvp-game-20 based on the template.
for i in $(seq 1 20); do
    # Define the name of the new file.
    NEW_FILE="game-ucenter-${i}.yaml"
    
    # Copy the template to the new file.
    cp $TEMPLATE_FILE $NEW_FILE
    
    # Use 'sed' to replace 'game-ucenter-1' with 'game-ucenter-N' and save inline (-i option).
    sed -i "s/game-ucenter/game-ucenter-${i}/g" $NEW_FILE




    echo "Created file: $NEW_FILE"
done


echo "All files created successfully."



步骤 1: 定义Jenkins Pipeline

在我们的Jenkins脚本中,我们首先定义了基础环境变量和两个函数:buildAndPushDockerImage 和 deployToKubernetes。这些函数将用于构建Docker镜像并部署到Kubernetes

def buildAndPushDockerImage(String imageName, String tag, String workspacePath) {
    sh "cd ${workspacePath} && echo 'Current directory: $(pwd)'" // 使用基础工作空间变量
    sh "cd ${workspacePath}/${imageName}&& docker build --build-arg NODE_ENV=$imageName -t $REGISTRY/$imageName:$tag ."
    withCredentials([usernamePassword(credentialsId: 'xxx', passwordVariable: 'dockerPassword', usernameVariable: 'dockerUser')]) {
        sh "docker login -u $dockerUser -p $dockerPassword $REGISTRY"
        sh "docker push $REGISTRY/$imageName:$tag"
    }
}


def deployToKubernetes(String kubernetesComponent) {
    String templateFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.tpl"
    String outputFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.yaml"
    sh "sed -e 's/{data}/$data/g' $templateFile > $outputFile"
    sh "sudo kubectl apply -f $outputFile $KUBE_CONFIG"
}

步骤 2: 修改deployToKubernetes函数

接下来,我们需要修改deployToKubernetes函数,以便它能够接受组件名称,并使用单一模板文件创建具体的配置文件。

def deployToKubernetes(String kubernetesComponent, int instance=1, int totalInstances=1) {
    // 检查实例值
    if (instance < 1) {
        error("实例数必须大于0")
    }


    // 根据 instance 的值来定义资源的名称和文件名
    String nameSuffix = totalInstances > 1 ? "-${instance}" : "" // 总是添加后缀,除非只有一个实例
    String outputFileName = "${kubernetesComponent}${nameSuffix}.yaml"
    String templateFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.tpl"
    String outputFile = "${KUBE_YAML_PATH}/${outputFileName}"
    String nameReplacement = "${kubernetesComponent}${nameSuffix}"


    sh """
        cat "${templateFile}" 
        | sed 's/{data}/${data}/g' 
        | sed 's/name: ${kubernetesComponent}/name: ${nameReplacement}/g' 
        | sed 's/app: ${kubernetesComponent}/app: ${nameReplacement}/g' 
        > "${outputFile}"
    """


    // 使用 KUBE_CONFIG 应用 Kubernetes 配置
    sh "kubectl apply -f ${outputFile} ${KUBE_CONFIG}"
}

对于单实例的业务,例如Deploy dataloader-game-ucenter,我们不需要传递实例编号。

stage("Deploy dataloader-game-ucenter") {
    when { environment name: 'dataloader', value: 'true' }
    agent { label  "huaweiyun-xx" }
    steps {
        deployToKubernetes("dataloader-game-ucenter")
    }
}

对于多实例。我这里生成 规则优点强迫症了。如果多实例我生成的规则要求符合game-ucenter-1,game-ucenter-2,game-ucenter-3......顺序,当单个实例的时候则保持原来的不加标签

                stage("Deploy game-ucenter") {
                    when { environment name: 'game-ucenter', value: 'true' }
                    agent { label  "k8s-node-06" }
                    steps {
                        script {
                          int instances = 2 // 假设我们有2个实例
                          for (int i = 1; i <= instances; i++) {
                            def componentName = "game-ucenter"
                            deployToKubernetes("game-ucenter", i, instances)


                    }
                }
            }
        }

步骤 3: 准备模板文件

我们的模板文件game-ucenter.tpl将包含通用的Kubernetes服务或部署定义,使用占位符game-ucenter-1game-ucenter-2来标识应该被替换的地方。

# game-ucenter-1.tpl (示例部分)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: game-ucenter
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: game-ucenter
  template:
    metadata:
      labels:
        app: game-ucenter
    spec:
      containers:
        - name: game-ucenter
          image: xxxx/xxx/game-ucenter:{data}
          envFrom:
          - configMapRef:
              name: deploy
          ports:
            - containerPort: 80
          resources:
            requests:
              memory: "4096M"
              cpu: "2000m"
            limits:
              memory: "4096M"
              cpu: "2000m" 
          livenessProbe:
            httpGet:
              scheme: HTTP
              path: /test.html
              port: 80
            initialDelaySeconds: 20
            periodSeconds: 120
            successThreshold: 1
            failureThreshold: 3
          readinessProbe:
            httpGet:
              scheme: HTTP
              path: /test.html
              port: 80
            initialDelaySeconds: 20
            periodSeconds: 120
      imagePullSecrets:                                              
        - name: xxx
---


apiVersion: v1
kind: Service
metadata:
  name: game-ucenter
  labels:
    app: game-ucenter
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: game-ucenter


# ...

步骤 4: 执行Jenkins Pipeline

当Jenkins Pipeline运行到"Development Deployment"阶段时,它将循环创建和应用game-ucenter-1.yaml到game-ucenter-2.yaml的配置文件,从而部署2个game-ucenterdeployment服务实例。

27b4be8e-a645-11ee-8b88-92fbcf53809c.jpg

并保证单个实例的原有命名规则:

27ca0a6e-a645-11ee-8b88-92fbcf53809c.jpg

通过这一方法,我们不再需要为每个服务实例维护一个单独的模板文件,而是可以通过一个模板文件和Jenkins Pipeline的自动化来简化服务部署工作。这样做不仅提升了效率,也降低了出错的风险。

注意:

以上代码和命令为示例性质,可能需要根据您具体的Jenkins环境和Kubernetes集群进行相应的调整。在生产环境中部署之前,请确保进行充分的测试。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 模板
    +关注

    关注

    0

    文章

    106

    浏览量

    20479
  • 脚本
    +关注

    关注

    1

    文章

    372

    浏览量

    14637
  • jenkins
    +关注

    关注

    0

    文章

    25

    浏览量

    5110
  • kubernetes
    +关注

    关注

    0

    文章

    219

    浏览量

    8568

原文标题:解决方案

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Kubernetes Ingress 高可靠部署最佳实践

    摘要: 在Kubernetes集群中,Ingress作为集群流量接入层,Ingress的高可靠性显得尤为重要,今天我们主要探讨如何部署一套高性能高可靠的Ingress接入层。简介
    发表于 04-17 14:35

    阿里云容器Kubernetes监控(二) - 使用Grafana展现Pod监控数据

    Heapster的功能。因此Heapster成为了kubernetes中一个必不可少的组件,在阿里云的kubernetes集群中已经内置了Heapster+Influxdb的组合,如果需要将监控的数据进行
    发表于 05-10 15:28

    kubernetes部署与应用

    kubernetes运维笔记
    发表于 10-25 13:08

    kubernetes v112二进制方式集群部署

    kubernetes v112 二进制方式集群部署
    发表于 05-05 16:30

    请问鸿蒙系统上可以部署kubernetes集群吗?

    鸿蒙系统上可以部署kubernetes集群吗
    发表于 06-08 11:16

    Jenkins远程部署Linux服务器的过程

    1、Jenkins远程部署Linux服务器  之前在Jenkins上也有一些使用经验了,但是都是使用团队配置好的Jenkins,自己只需要管自己的项目以及执行构建即可,这一次自己尝试了
    发表于 11-18 18:12

    如何部署基于Mesos的Kubernetes集群

    kubernetes是一个跨多个计算节点的管理容器化应用的系统,它提供了一系列基本的功能,如应用的自动化部署,维护和扩展等。Mesos是Apache下的开源分布式资源管理框架,它被称为是分布式系统
    发表于 10-09 18:04 0次下载
    如何<b class='flag-5'>部署</b>基于Mesos的<b class='flag-5'>Kubernetes</b>集群

    jenkins自动化部署

    本文详细介绍Jenkins的简单使用—jenkins自动化部署
    的头像 发表于 02-06 11:27 4332次阅读
    <b class='flag-5'>jenkins</b>自动化<b class='flag-5'>部署</b>

    Jenkins详细安装与构建部署使用教程

    本文详细介绍了Jenkins安装与构建部署使用教程。Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。Jenkins是基于Java开发的一种持
    发表于 02-06 13:47 1637次阅读
    <b class='flag-5'>Jenkins</b>详细安装与构建<b class='flag-5'>部署</b>使用教程

    Jenkins+Docker一键自动化部署SpringBoot项目

    本文章实现最简单全面的Jenkins+docker+springboot 一键自动部署项目,步骤齐全,少走坑路。
    的头像 发表于 12-14 10:04 598次阅读

    Jenkins+Docker实现一键自动化部署项目!

    本文章实现最简单全面的Jenkins+docker+springboot 一键自动部署项目,步骤齐全,少走坑路。
    的头像 发表于 01-06 15:36 928次阅读

    部署Jenkins服务时如何保障服务的高可用性呢?

    现在的企业很多都在用Jenkins做持续集成,各个业务端都依靠Jenkins,vivo Devops也是使用Jenkins来进行持续构建,部署Jen
    的头像 发表于 02-14 17:02 2463次阅读

    关于Jenkins+docker+springboot一键自动部署项目

    本文章实现最简单全面的Jenkins+docker+springboot 一键自动部署项目,步骤齐全,少走坑路。
    的头像 发表于 05-16 08:59 602次阅读
    关于<b class='flag-5'>Jenkins</b>+docker+springboot一键自动<b class='flag-5'>部署</b>项目

    Jenkins部署启动案例

    电子发烧友网站提供《Jenkins部署启动案例.zip》资料免费下载
    发表于 06-15 14:53 0次下载
    <b class='flag-5'>Jenkins</b><b class='flag-5'>部署</b>启动案例

    Jenkins pipeline是如何连接Kubernetes的呢?

    Kubernetes 是一个开源的容器编排平台,可以帮助开发团队管理和部署容器化的应用程序。
    的头像 发表于 10-23 11:13 1500次阅读
    <b class='flag-5'>Jenkins</b> pipeline是如何连接<b class='flag-5'>Kubernetes</b>的呢?