将 Amazon Elastic Container Registry 与 Jenkins 集成

Gus*_*uss 10 amazon-web-services jenkins docker amazon-ecr

我正在尝试将 Amazon 新的 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 登录令牌,或者以某种方式自动生成令牌?

小智 6

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

它的短处是:

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


Gus*_*uss 4

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

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

脚步:

  1. 确保您的 Jenkins master 可以访问所需的 AWS API。在我的设置中,Jenkins master 在具有 IAM 角色的 EC2 上运行,因此我只需ecr:GetAuthorizationToken向服务器角色添加权限。[更新] 要成功完成任何推送,您还需要授予以下权限:ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage。Amazon 有一个提供这些功能的内置策略,称为AmazonEC2ContainerRegistryPowerUser.
  2. 确保主服务器上安装了 AWS CLI。在我的设置中,当 master 在 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)
}
Run Code Online (Sandbox Code Playgroud)

请注意:

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

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