将 Amazon Elastic Container Registry 与 Jenkins 集成

将 Amazon Elastic Container Registry 与 Jenkins 集成

我正在尝试将亚马逊的新 Elastic Container Registry (ECR) 与我的 Jenkins 构建服务集成。我正在使用 Cloudbees Docker Build & Publish 插件来构建容器映像并将其发布到注册表。

为了使用 ECR 而不是我的私人注册表,我运行了 AWS CLI 命令aws --region us-east-1 ecr get-login,它会发出一个docker login要运行的命令 - 但我只是复制了密码并根据该密码创建了类型为“带密码的用户名”的 Jenkins 凭证(用户名始终为“AWS”)。

一切正常!问题是 AWS CLI 生成的 ECR 密码仅在 12 小时内有效。所以现在,我必须每天手动重新生成两次密码并手动更新 Jenkins 凭证屏幕,否则我的构建就会开始失败。

有没有办法生成永久的 ECR 登录令牌,或者以某种方式自动生成令牌?

答案1

现在可以使用amazon-ecr-凭证助手如下所述https://aws.amazon.com/blogs/compute/authenticating-amazon-ecr-repositories-for-docker-cli-with-credential-helper/

简而言之:

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

答案2

正如 @Connor McCarthy 所说,在等待亚马逊提出更好的解决方案以获得更永久的密钥的同时,我们需要以某种方式自己在 Jenkins 服务器上生成密钥。

我的解决方案是使用 Groovy API 定期执行一项任务,每 12 小时自动更新一次 ECR 的 Jenkins 凭证。这基于这个非常详细的答案,尽管我做了一些不同的事情,而且我不得不修改脚本。

脚步:

  1. 确保您的 Jenkins 主服务器可以访问所需的 AWS API。在我的设置中,Jenkins 主服务器在具有 IAM 角色的 EC2 上运行,因此我只需将权限添加ecr:GetAuthorizationToken到服务器角色即可。[更新] 要成功完成任何推送,您还需要授予以下权限:ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage。Amazon 有一个提供这些功能的内置策略,称为AmazonEC2ContainerRegistryPowerUser
  2. 确保主服务器上安装了 AWS CLI。在我的设置中,主服务器在 Debian Docker 容器中运行,我刚刚将此 shell 构建步骤添加到密钥生成作业中: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 密钥,单击“高级”并记录其“ID”。在这个例子中,我假设它是“12345”。
  5. 创建一个新的作业,定期启动 12 小时,并使用以下脚本添加“系统 Groovy 脚本”构建步骤:

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)
}

请注意:

  • 使用硬编码字符串"AWS"作为 ECR 凭证的用户名 - 这是 ECR 的工作方式,但如果您有多个用户名为“AWS”的凭证,那么您需要更新脚本以根据描述字段或其他内容来定位凭证。
  • 您必须在脚本中使用真实 ECR 密钥的真实 ID,因为凭证 API 会用新对象替换凭证对象,而不仅仅是更新它,并且 Docker 构建步骤和密钥之间的绑定是通过 ID 进行的。如果您使用 IDnull的值(如我之前链接的答案中所述),那么将创建一个新的 ID,并且 docker 构建步骤中的凭证设置将丢失。

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

答案3

我也在研究这个完全相同的问题。我没有找到我们想要的答案,但我能够使用 shell 脚本创建一个解决方法。在 AWS 推出更好的 ECR 凭证解决方案之前,我计划采取类似的措施。

我将 Jenkins 作业的 Docker Build and Publish 步骤替换为 Execute Shell 步骤。我使用以下脚本(可能写得更好)来构建并将我的容器发布到 ECR。根据需要替换 < > 括号中的变量:

#!/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}

答案4

使用https://wiki.jenkins-ci.org/display/JENKINS/Amazon+ECR使用 Docker Build 和 Publish 插件就可以正常工作。

相关内容