我正在尝试将亚马逊的新 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 凭证。这基于这个非常详细的答案,尽管我做了一些不同的事情,而且我不得不修改脚本。
脚步:
- 确保您的 Jenkins 主服务器可以访问所需的 AWS API。在我的设置中,Jenkins 主服务器在具有 IAM 角色的 EC2 上运行,因此我只需将权限添加
ecr:GetAuthorizationToken
到服务器角色即可。[更新] 要成功完成任何推送,您还需要授予以下权限:ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage
。Amazon 有一个提供这些功能的内置策略,称为AmazonEC2ContainerRegistryPowerUser
。 - 确保主服务器上安装了 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
- 安装Groovy 插件它允许您将 Groovy 脚本作为 Jenkins 系统的一部分运行。
- 在凭证屏幕中,查找您的 AWS ECR 密钥,单击“高级”并记录其“ID”。在这个例子中,我假设它是“12345”。
- 创建一个新的作业,定期启动 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 进行的。如果您使用 ID
null
的值(如我之前链接的答案中所述),那么将创建一个新的 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 插件就可以正常工作。