0

具体来说,现有 Kubernetes 集群中有几个资源(当前用 定义YAML),我想在构建过程中进行修改,还有一些我想从头开始创建。在每种情况下,我都希望在多个区域中这样做,以使所有区域保持同步。

有问题的资源是Agones fleets,看起来像这样(实际值已删除,但具有代表性):

apiVersion: agones.dev/v1
kind: Fleet
metadata:
  annotations:
    agones.dev/sdk-version: 1.11.0
  name: test
  namespace: game-servers
  resourceVersion: "12324578"
  selfLink: /apis/agones.dev/v1/namespaces/game-servers/fleets/test
spec:
  replicas: 1
  scheduling: Packed
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        branch: test
        git_commit: 1b12371827fdea31231230901876ffe
    spec:
      health:
        disabled: false
        failureThreshold: 5
        initialDelaySeconds: 10
        periodSeconds: 5
      ports:
      - containerPort: 1234
        name: default
        portPolicy: Dynamic
        protocol: UDP
      sdkServer:
        logLevel: Info
      template:
        metadata:
          creationTimestamp: null
          labels:
            role: game-servers
        spec:
          containers:
          - image: registry.example.com/gameserver:1b12371827fdea31231230901876ffe
            name: agones
            resources:
              limits:
                cpu: 500m
                memory: 512m
              requests:
                cpu: 100m
                memory: 256Mi
          nodeSelector:
            role: game-servers

如果有现有的fleet,我想将最新git commit的注入标签以及要使用的图像(假设它将在注册表中适当地标记)。

如果没有现有的fleet,对于某些值,我想循环并从头开始创建具有与上述相似特征的新车队。我尝试了几种不同的方法,但都失败了——从集群权限问题到尝试for在 Jenkins/Groovy 中使用非常直接的循环时出现的奇怪错误。

4

1 回答 1

0

与 Jenkins 相关的许多事情一样,要完成这项工作,需要几个插件,特别是:

假设:

  • 这些操作将在正确配置为执行 Jenkins 构建的基于 Linux 的容器上运行
  • 将从本地文件系统中读取几个必需的“变量” - 这些可能是管道中早期的构建工件或ENV变量,具体取决于设置
  • 集群上已存在 Kubernetes 服务帐户,具有足够的权限来执行任务
  • 这些帐户的凭据已在 Jenkins 中配置
  • fleetconfig.yaml在本地文件系统上可用,并且是一个完整的车队配置,类似于问题中提出的配置

为了区别对待各种车队,需要根据车队本身的名称应用一些选择标准,然后需要一个循环来遍历每个区域等。

为了简单起见,将有一个基本if语句在类型之间进行选择(这可以很容易地扩展),然后是一个 2 元素循环来循环遍历多个区域(再次很容易扩展为更多)。

这是用StageJenkins 术语完整编写的,但显然不能完全独立执行。它与现有的、经过测试的、工作的配置非常接近,该配置每天运行多次,已经有相当长的一段时间了。

虽然这只是示例资源,但没有理由不能使用它来修改,一般在 Kubernetes 中创建其他资源。

stage('DeployFleets') {
  agent {
    node {
      label 'k8s-node-linux'
    }
  }
  steps {
    script {
      // assume we can read the Fleet name in from a file
      FLEET_NAME = readFile("/path/to/FLEET_NAME")
      // let's assume that test is one of the fleets that is being modified, not created, deal with that first
      container('jenkins-worker'){
        if (FLEET_NAME != 'test') {
          script {
            // again, assume we can read the commit from a file
            def GIT_COMMIT_TAG = readFile("/path/to/GIT_COMMIT")
            //  create a map of 2 fictional regions with an account to use and an cluster adddress for that region
            def DEPLOY_REGIONS = [
              "us-east-1": ["jenkins_service_acct_use1", 'https://useast1-cluster.example.com'],
              "us-east-2": ["jenkins_service_acct_use2", 'https://useast2-cluster.example.com'],
            ]
            // this each construction is needed in order to get around https://issues.jenkins-ci.org/browse/JENKINS-49732 which prevents using a for(element in DEPLOY_REGIONS)
            DEPLOY_REGIONS.each { element ->
              withKubeCredentials([[credentialsId: element.value[0], serverUrl: element.value[1]]]) {
                sh """
                kubectl patch fleet ${FLEET_NAME} -n game-servers --type=json -p='[{"op": "replace", "path": "/spec/template/spec/template/spec/containers/0/image", "value":"registry.example.com/gameserver/${FLEET_NAME}:${GIT_COMMIT_TAG}"}]'
                kubectl patch fleet ${FLEET_NAME} -n game-servers --type=json -p='[{"op": "replace", "path": "/spec/template/metadata/labels/git_commit", "value":"${GIT_COMMIT_TAG}"}]'
                """
              }
            }
          }
        } else {
          // rather than patching here, create a fleet from scratch using a source YAML file as a template
          script {
            def GIT_COMMIT_TAG = readFile("/path/to/GIT_COMMIT")
            def NUM_REPLICAS = 1
            def DEPLOY_REGIONS = [
              "us-east-1": ["jenkins_service_acct_use1", 'https://useast1-cluster.example.com'],
              "us-east-2": ["jenkins_service_acct_use2", 'https://useast2-cluster.example.com'],
            ]
            // see note above about each construct
            DEPLOY_REGIONS.each { element ->
              // assume template available on file system
              def FLEET_CONFIG = readYaml file: "/path/to/fleetconfig.yaml"
              FLEET_CONFIG.metadata.name = env.SOME_SANE_NAME
              FLEET_CONFIG.spec.template.metadata.labels.git_commit = GIT_COMMIT_TAG
              FLEET_CONFIG.spec.replicas = NUM_REPLICAS
              FLEET_CONFIG.spec.template.spec.template.spec.containers[0].image = "registry.example.com/gameserver/${FLEET_NAME}:${GIT_COMMIT_TAG}"
              writeYaml file: "${env.SOME_SANE_NAME}_fleet.yaml", data: FLEET_CONFIG, overwrite: true
              withKubeCredentials([[credentialsId: element.value[0], serverUrl: element.value[1]]]) {
                sh """
                kubectl -n game-servers apply -f "${env.SOME_SANE_NAME}_fleet.yaml"
                """
              }
            }
          }
        }
      }
    }
  }
}

考虑到 Jenkins 通过插件提供给我们的操作实用程序,这并不是特别困难,YAML但是找到一种端到端工作的方法可能是一个挑战。使用 patch 命令kubectl使修补对 Jenkins 来说不那么“原生”,但方便是值得的(例如,另一种方法是使用 REST API)。该foreach结构看起来很奇怪,但需要避免 Jenkins 中长期存在的错误。

于 2021-03-08T14:40:40.207 回答