如何从容器内部获取环境变量作为 Jenkinsfile 变量?

问题描述 投票:0回答:2

我们有多个 Jenkins ssh 代理、多个具有不同 jdk 版本的构建容器,并且容器使用 java 将内容(声纳结果等)发布到其他服务器。

容器需要信任与主机相同的服务器(Jenkins ssh 代理)。因此容器的jdk内的java cacerts需要与主机的cacerts匹配。为此,我添加了参数:

agent {
  docker {
    registryUrl "https://private.registry"
    registryCredentialsId "private-registry-creds"
    image "build_container_jdk17"
    args "-v /host/cacerts:/usr/share/jdk-17.0.6+10/lib/security/cacerts:ro"
  }
}

从 Jenkinsfile 启动容器时。

问题是容器之间的jdk路径发生变化。容器内的jdk路径也存储在环境变量$JAVA_HOME中。

从容器内部获取 JAVA_HOME 环境变量以在卷命令行参数上使用的最简单方法是什么?

agent {
  docker {
    registryUrl "https://private.registry"
    registryCredentialsId "private-registry-creds"
    image "build_container_jdk17"
    args "-v /host/cacerts:${CONTAINER_JAVA_HOME}/lib/security/cacerts:ro"
  }
}

我尝试使用:

args '-v /host/cacerts:${JAVA_HOME}/lib/security/cacerts:ro'

希望冒号右侧的环境变量能够从容器内部进行计算。这导致“无效的卷规格”。

我认为有一种方法可以在一个阶段启动容器,设置变量并使用该变量在下一阶段重新启动。我想在尝试这个之前我会问一下,因为它看起来过于复杂,而且我可能缺少一些明显的解决方案。

java docker jenkins jenkins-pipeline
2个回答
0
投票

您有两个选择:

  1. 事先检查图像。环境变量很可能已经在图像中设置: 例如:
    docker inspect jenkins/jenkins:lts | jq -r '.[].Config.Env[] | select(contains("JAVA_HOME")) | split("=")[1]'
  2. 启动镜像并回显环境变量 例如:
    docker run --rm --entrypoint='printenv' jenkins/jenkins:lts JAVA_HOME

两个选项都会输出

/opt/java/openjdk
,这又可以传递到体积定义的 local 评估中

# opt 1 
docker run --rm \
  -v "/mnt/mypath/myfile:`docker inspect jenkins/jenkins:lts | jq -r '.[].Config.Env[] | select(contains(\"JAVA_HOME\")) | split("=")[1]'`/mypath/myfile" \
  jenkins/jenkins:lts
# or opt 2
docker run --rm \
  -v "/mnt/mypath/myfile:`docker run --rm --entrypoint='printenv' jenkins/jenkins:lts JAVA_HOME`/mypath/myfile" \
  jenkins/jenkins:lts

选项 1 应该更快,但需要

jq
解析检查的 json 输出。 尊重引号和反引号。


0
投票

在他的回答中@mbwmd 给出了两个选项来从 docker 容器内部获取环境变量。这些都是有效的,这取决于您的用例,您会选择哪一个。

我想扩展这个答案,并从 Jenkins 管道的角度提供详细信息,因为这是我问题的一部分。

当您使用管道时,管道代理也是容器的主机。 “docker检查”选项可能更可取:

pipeline {
  agent { label 'jenkins_ssh_agent' }
  environment {
    CONTAINER_JAVA_HOME = get_container_java_home()
    DOCKER_ARGS = "-v /host/cacerts:${CONTAINER_JAVA_HOME}/lib/security/cacerts:ro"
  }
  stages {
    stage ('Build') {
      agent {
        docker {
          label 'jenkins_ssh_agent'
          registryUrl 'https://private.registry'
          registryCredentialsId 'private-registry-creds'
          image 'build_container_jdk17:1'
          args "${DOCKER_ARGS}"
          reuseNode true
        }
      }
      steps {
        script {
          // java should now trusts trusted.private.server like the host does.
          sh(script: 'java -jar connect.jar https://trusted.private.server/config.xml')
        }
      }
    }
  }
}
get_container_java_home() {
  return sh(returnStdout: true, script: 'docker inspect --format \'' {{ range .Config.Env }}{{println .}}{{end}}\' private.registry/build_container_jdk17:1 | grep JAVA_HOME |cut -d \'=\' -f 2').trim();
}

docker检查命令源自@Vonc的答案:https://stackoverflow.com/a/30343218/6502579。如果您愿意,您也可以像 @mbwmd 在他的回答中建议的那样使用 jq 。我没有 jq 可用,想避免依赖。

此选项的优点是您不需要启动容器来获取环境变量。

缺点可能是您必须从管道运行 docker 命令。根据管道设置,这在某些情况下可能会导致问题。

选项 #2 通过使用阶段来保存环境变量来避免使用 docker 命令:

pipeline {
  agent none
  stages {
    stage ('Checkout') {
      agent {
        docker {
          registryUrl 'https://private.registry'
          registryCredentialsId 'private-registry-creds'
          image 'build_container_jdk17:1'
        }
      }
      steps {
        script {
          // this command does not need java to trust any servers.
          checkout(/*configure checkout*/)
          env.CONTAINER_JAVA_HOME=sh(script: 'echo $JAVA_HOME', returnStdout: true).trim()
        }
      }
    }
    stage('Build') {
      agent {
        docker {
          registryUrl 'https://private.registry'
          registryCredentialsId 'private-registry-creds'
          image 'build_container_jdk17:1'
          args "-v /host/cacerts:${CONTAINER_JAVA_HOME}/lib/security/cacerts:ro"
        }
      }
      steps {
        script {
          // java should now trusts trusted.private.server like the host does.
          sh(script: 'java -jar connect.jar https://trusted.private.server/config.xml')
        }
      }
    }
  }
}

如果您正在运行多个阶段并且不需要在第一次运行容器时设置参数,那么这是一个不错的选择。

© www.soinside.com 2019 - 2024. All rights reserved.