You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jenkins SCM Pipeline参数化容器镜像名称失败问题求助

Jenkins SCM Pipeline参数化容器镜像报错解决

问题背景

我正将基于虚拟机代理的Jenkins多配置项目转换为SCM Pipeline,计划通过IMAGE_NAME参数指定容器镜像启动构建。但使用参数时触发镜像名称格式验证错误,直接写死镜像名则运行正常。我不想用需要用户交互的参数,也不想切换到权限配置复杂的非SCM Pipeline,虽已找到无需参数的可行方案,但仍希望解决参数化的问题。

出错的Pipeline代码

pipeline {
   agent none
   parameters {
      string(name: 'IMAGE_NAME', defaultValue: 'registry.internal.mycompany.com/myplatform:myversion', description: 'Define the [host/]image[:version] for the container image of which to run the build.')
   }
   stages {
      stage('Compile') {
         agent {
            docker {
               image '${params.IMAGE_NAME}'
            }
         }
         steps {
            sh 'ls -l'
            sh './compile.sh'
         }
         post {
            always {
               cleanWs()
            }
         }
      }
   }
}

报错信息

11:01:58  [Pipeline] withEnv
11:01:58  [Pipeline] {
11:01:59  [Pipeline] }
11:01:59  [Pipeline] // withEnv
11:01:59  [Pipeline] }
11:01:59  [Pipeline] // node
11:01:59  [Pipeline] }
11:01:59  [Pipeline] // stage
11:01:59  [Pipeline] End of Pipeline
11:01:59  ERROR: Name must follow the pattern '^[a-zA-Z0-9]+((\.|_|__|-+)[a-zA-Z0-9]+)*$'
11:01:59    at hudson.util.FormValidation._errorWithMarkup(FormValidation.java:268)
11:01:59    at hudson.util.FormValidation.errorWithMarkup(FormValidation.java:254)
11:01:59    at hudson.util.FormValidation.error(FormValidation.java:145)
11:01:59    at hudson.util.FormValidation.error(FormValidation.java:170)
11:01:59    at org.jenkinsci.plugins.docker.commons.credentials.ImageNameValidator.validateName(ImageNameValidator.java:289)
11:01:59    at org.jenkinsci.plugins.docker.commons.credentials.ImageNameValidator.validateUserAndRepo(ImageNameValidator.java:115)
11:01:59    at org.jenkinsci.plugins.docker.commons.credentials.ImageNameValidator.checkUserAndRepo(ImageNameValidator.java:141)
11:01:59    at org.jenkinsci.plugins.docker.commons.credentials.ImageNameValidator$checkUserAndRepo.call(Unknown Source)
11:01:59    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
11:01:59    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
11:01:59    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
11:01:59    at org.jenkinsci.plugins.docker.workflow.Docker.check(Docker.groovy:100)
11:01:59    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
11:01:59    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
11:01:59    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
11:01:59    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
11:01:59    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
11:01:59    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
11:01:59    at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1463)
11:01:59    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:921)
11:01:59    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:181)
11:01:59    at org.jenkinsci.plugins.docker.workflow.Docker$Image.methodMissing(Docker.groovy)
11:01:59    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
11:01:59    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
11:01:59    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
11:01:59    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
11:01:59    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
11:01:59    at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:951)
11:01:59    at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1279)
11:01:59    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1227)
11:01:59    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
11:01:59    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:68)
11:01:59    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
11:01:59    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:157)
11:01:59    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:169)
11:01:59    at org.jenkinsci.plugins.docker.workflow.Docker$Image.<init>(Docker.groovy:110)
11:01:59    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
11:01:59    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
11:01:59    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
11:01:59    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
11:01:59    at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:83)
11:01:59    at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:105)
11:01:59    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:59)
11:01:59    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:238)
11:01:59    at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.constructorCall(DefaultInvoker.java:25)
11:01:59    at org.jenkinsci.plugins.docker.workflow.Docker.image(Docker.groovy:75)
11:01:59    at org.jenkinsci.plugins.docker.workflow.declarative.DockerPipelineScript.runImage(DockerPipelineScript.groovy:54)
11:01:59    at org.jenkinsci.plugins.docker.workflow.declarative.AbstractDockerPipelineScript.configureRegistry(AbstractDockerPipelineScript.groovy:63)
11:01:59    at org.jenkinsci.plugins.docker.workflow.declarative.AbstractDockerPipelineScript.run(AbstractDockerPipelineScript.groovy:50)
11:01:59    at org.jenkinsci.plugins.pipeline.modeldefinition.agent.CheckoutScript.checkoutAndRun(CheckoutScript.groovy:61)
11:01:59    at ___cps.transform___(Native Method)
11:01:59    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:97)
11:01:59    at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:83)
11:01:59    at jdk.internal.reflect.GeneratedMethodAccessor188.invoke(Unknown Source)
11:01:59    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
11:01:59    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
11:01:59    at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
11:01:59    at com.cloudbees.groovy.cps.impl.LocalVariableBlock$LocalVariable.get(LocalVariableBlock.java:39)
11:01:59    at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)
11:01:59    at com.cloudbees.groovy.cps.impl.LocalVariableBlock.evalLValue(LocalVariableBlock.java:28)
11:01:59    at com.cloudbees.groovy.cps.LValueBlock$BlockImpl.eval(LValueBlock.java:55)
11:01:59    at com.cloudbees.groovy.cps.LValueBlock.eval(LValueBlock.java:16)
11:01:59    at com.cloudbees.groovy.cps.Next.step(Next.java:83)
11:01:59    at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
11:01:59    at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
11:01:59    at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:136)
11:01:59    at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:275)
11:01:59    at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
11:01:59    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)
11:01:59    at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)
11:01:59    at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:187)
11:01:59    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:420)
11:01:59    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:95)
11:01:59    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:330)
11:01:59    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:294)
11:01:59    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
11:01:59    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
11:01:59    at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:139)
11:01:59    at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
11:01:59    at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:68)
11:01:59    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
11:01:59    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
11:01:59    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
11:01:59    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
11:01:59    at java.base/java.lang.Thread.run(Thread.java:829)
11:01:59  Finished: FAILURE

无需参数的可行方案

pipeline {
   agent none
   stages {
      stage('Checkout') {
         agent any
         steps {
            checkout accurev(depot: 'DEPOT', serverName: 'AccuRev', stream: 'MY_PIPELINE_STREAM', wspaceORreftree: 'none')
         }
      }
      stage('Compile') {
         agent {
            docker {
               image 'registry.internal.mycompany.com/myplatform:myversion'
            }
         }
         steps {
            sh 'ls -l'
            sh './compile.sh'
         }
         post {
            always {
               cleanWs()
            }
         }
      }
   }
}

问题原因及解决方案

原因

在声明式Pipeline的docker agent配置中,使用单引号包裹${params.IMAGE_NAME},导致Groovy未解析变量,直接将字符串${params.IMAGE_NAME}传给镜像名称验证器,该字符串不符合镜像名的正则规则,因此触发报错。

解决方法

将单引号替换为双引号,让Groovy正确解析变量:

pipeline {
   agent none
   parameters {
      string(name: 'IMAGE_NAME', defaultValue: 'registry.internal.mycompany.com/myplatform:myversion', description: '定义构建使用的容器镜像格式为 [host/]image[:version]')
   }
   stages {
      stage('Compile') {
         agent {
            docker {
               image "${params.IMAGE_NAME}"  // 替换为双引号
            }
         }
         steps {
            sh 'ls -l'
            sh './compile.sh'
         }
         post {
            always {
               cleanWs()
            }
         }
      }
   }
}

额外优化(可选)

如果需要限制用户输入的镜像名格式,可以给string参数添加正则验证:

string(name: 'IMAGE_NAME', 
       defaultValue: 'registry.internal.mycompany.com/myplatform:myversion', 
       description: '定义构建使用的容器镜像格式为 [host/]image[:version]',
       regex: '^([a-zA-Z0-9.-]+/)?[a-zA-Z0-9._-]+(:[a-zA-Z0-9._-]+)?$',
       message: '镜像名称格式不符合要求,需遵循 [host/]image[:version] 格式')

内容的提问来源于stack exchange,提问作者Absent Link

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 21:01:05