整合Amazon弹性容器registry与Jenkins

我试图将亚马逊的新弹性容器registry(ECR)与我的Jenkins构build服务相集成。 我正在使用Cloudbees Docker Build&Publish插件来构build容器映像并将其发布到registry中。

要使用ECR而不是我的私人registry,我已经运行了AWS CLI命令aws --region us-east-1 ecr get-login这会发出一个docker login命令来运行 – 但是我只是复制出密码并创build了一个Jenkins从该密码(用户名始终为“AWS”)键入“用户名和密码”凭据。

那工作正常! 问题是由AWS CLI生成的ECR密码只有12小时有效。 所以现在,我必须每天手动重新生成密码两次,并手动更新Jenkins凭据屏幕,否则我的构build开始失败。

有没有办法生成永久的ECRlogin令牌,或以某种方式自动化令牌生成?

现在可以使用amazon-ecr-credential-helper ,如https://aws.amazon.com/blogs/compute/authenticating-amazon-ecr-repositories-for-docker-cli-with-credential-helper/中所述 。

它的缺点是:

  • 确保您的Jenkins实例具有正确的AWS凭证,以便用您的ECR存储库进行推送/推送。 这些可以是环境variables,共享凭据文件或实例configuration文件的forms。
  • 将docker-credential-ecr-login二进制文件放置在$ PATH中的某个目录中。
  • 在Jenkins用户的主目录下写入Dockerconfiguration文件,例如/var/lib/jenkins/.docker/config.json。 内容{"credsStore": "ecr-login"}
  • 安装Docker Build和Publish插件,并确保jenkins用户可以联系Docker守护进程。
  • 最后,创build一个发布Docker镜像的构build步骤的项目

正如康纳·麦卡锡(@Connor McCarthy)所说,在等待亚马逊为更多永久密钥提出更好的解决scheme的同时,我们还需要自己在Jenkins服务器上自行生成密钥。

我的解决scheme是定期使用Groovy API,每12小时自动更新ECR的Jenkins凭证。 这是基于这个非常详细的答案 ,但我做了一些不同的事情,我不得不修改脚本。

脚步:

  1. 确保您的Jenkins master可以访问所需的AWS API。 在我的设置中,Jenkins主服务器在IAMangular色的EC2上运行,所以我只需将权限ecr:GetAuthorizationToken添加到服务器angular色。 [ 更新 ]要成功推送完成,您还需要授予这些权限ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage 。 亚马逊有一个内置的策略,提供这些function,称为AmazonEC2ContainerRegistryPowerUser
  2. 确保AWS CLI安装在主服务器上。 在我的设置中,使用在debian docker容器中运行的master,我刚刚将这个shell构build步骤添加到密钥生成作业: dpkg -l python-pip >/dev/null 2>&1 || sudo apt-get install python-pip -y; pip list 2>/dev/null | grep -q awscli || pip install awscli dpkg -l python-pip >/dev/null 2>&1 || sudo apt-get install python-pip -y; pip list 2>/dev/null | grep -q awscli || pip install awscli
  3. 安装Groovy插件 ,它允许您运行Groovy脚本作为Jenkins系统的一部分。
  4. 在凭证屏幕上,查找您的AWS ECR密钥,单击“高级”并logging其“ID”。 对于这个例子,我将假设它是“12345”。
  5. 创build一个新的工作,定期启动12个小时,然后使用以下脚本添加“系统Groovy脚本”构build步骤:

 import jenkins.model.* import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl def changePassword = { username, new_password -> def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials( com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class, Jenkins.instance) def c = creds.findResult { it.username == username ? it : null } if ( c ) { println "found credential ${c.id} for username ${c.username}" def credentials_store = Jenkins.instance.getExtensionList( 'com.cloudbees.plugins.credentials.SystemCredentialsProvider' )[0].getStore() def result = credentials_store.updateCredentials( com.cloudbees.plugins.credentials.domains.Domain.global(), c, new UsernamePasswordCredentialsImpl(c.scope, "12345", c.description, c.username, new_password)) if (result) { println "password changed for ${username}" } else { println "failed to change password for ${username}" } } else { println "could not find credential for ${username}" } } println "calling AWS for docker login" def prs = "/usr/local/bin/aws --region us-east-1 ecr get-login".execute() prs.waitFor() def logintext = prs.text if (prs.exitValue()) { println "Got error from aws cli" throw new Exception() } else { def password = logintext.split(" ")[5] println "Updating password" changePassword('AWS', password) } 

请注意:

  • 使用硬编码的string"AWS"作为ECR凭证的用户名 – 这就是ECR的工作原理,但是如果你有多个用户名为“AWS”的凭证,那么你需要更新脚本以find凭证基于描述字段或其他内容。
  • 您必须在脚本中使用真正的ECR密钥的ID,因为凭证的API将使用新对象replace凭证对象,而不是仅更新凭证对象,并且Docker构build步骤和密钥之间的绑定由ID组成。 如果您使用的值为null (如在之前链接的答案中),则会创build一个新的ID,并且Docker构build步骤中凭据的设置将丢失。

就是这样 – 脚本应该能够每12小时运行一次并刷新ECR凭据,并且我们可以继续使用Docker插件。

我也在研究这个完全相同的问题。 我没有拿出我们正在寻找的答案,但是我能够用shell脚本创build一个解决方法。 在AWS出现更好的ECR凭证解决scheme之前,我计划按照这些方法做一些事情。

我将Jenkins作业的Docker Build和Publish步骤replace为Execute Shell步骤。 我使用下面的脚本(可能写得更好)来构build和发布我的容器到ECR。 根据需要replace<>括号中的variables:

 #!/bin/bash #Variables REG_ADDRESS="<your ECR Registry Address>" REPO="<your ECR Repository>" IMAGE_VERSION="v_"${BUILD_NUMBER} WORKSPACE_PATH="<path to the workspace directory of the Jenkins job>" #Login to ECR Repository LOGIN_STRING=`aws ecr get-login --region us-east-1` ${LOGIN_STRING} #Build the containerexit cd ${WORKSPACE_PATH} docker build -t ${REPO}:${IMAGE_VERSION} . #Tag the build with BUILD_NUMBER version and Latests docker tag ${REPO}:${IMAGE_VERSION} ${REPO_ADDRESS}/${REPO}:${IMAGE_VERSION} #Push builds docker push ${REG_ADDRESS}/${REPO}:${IMAGE_VERSION}