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
相关产品推荐
相关产品推荐

