Назад | Перейти на главную страницу

Интегрируйте реестр Amazon Elastic Container Registry с Jenkins

Я пытаюсь интегрировать новый Elastic Container Registry (ECR) Amazon с моей службой сборки Jenkins. Я использую плагин Cloudbees Docker Build & Publish для создания образов контейнеров и их публикации в реестре.

Чтобы использовать ECR вместо моего частного реестра, я выполнил команду AWS CLI aws --region us-east-1 ecr get-login который извергает docker login команду для запуска, но я просто скопировал пароль и создал учетные данные Jenkins типа «Имя пользователя с паролем» из этого пароля (имя пользователя всегда «AWS»).

И это прекрасно работает! Проблема в том, что пароль ECR, созданный с помощью интерфейса командной строки AWS, действителен только в течение 12 часов. Итак, прямо сейчас мне нужно вручную повторно создавать пароль два раза в день и вручную обновлять экран учетных данных Jenkins, иначе мои сборки начнут давать сбой.

Есть ли способ сгенерировать постоянные токены входа в систему ECR или как-то автоматизировать генерацию токенов?

Теперь это возможно с помощью 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.
  • Напишите файл конфигурации Docker в домашнем каталоге пользователя Jenkins, например, /var/lib/jenkins/.docker/config.json. с содержанием {"credsStore": "ecr-login"}
  • Установите плагин Docker Build and Publish и убедитесь, что пользователь jenkins может связаться с демоном Docker.
  • Наконец, создайте проект с этапом сборки, который публикует образ докера.

Как сказал @Connor McCarthy, ожидая, пока Amazon предложит лучшее решение для более постоянных ключей, тем временем нам нужно было бы каким-то образом сгенерировать ключи на сервере Jenkins.

Мое решение состоит в том, чтобы периодически выполнять задание, которое автоматически обновляет учетные данные Jenkins для ECR каждые 12 часов с помощью Groovy API. Это основано на этот очень подробный ответ, хотя я сделал несколько вещей по-другому, и мне пришлось изменить сценарий.

Шаги:

  1. Убедитесь, что ваш мастер Jenkins имеет доступ к необходимому API AWS. В моей настройке мастер Jenkins работает на EC2 с ролью IAM, поэтому мне просто нужно было добавить разрешение ecr:GetAuthorizationToken к роли сервера. [Обновить] Для успешного завершения любых push-уведомлений вам также необходимо предоставить следующие разрешения: ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage. У Amazon есть встроенная политика, которая предлагает эти возможности, которая называется AmazonEC2ContainerRegistryPowerUser.
  2. Убедитесь, что на главном сервере установлен AWS CLI. В моей настройке, когда мастер запущен в контейнере docker debian, я только что добавил этот шаг сборки оболочки в задание генерации ключей: 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, потому что API для учетных данных заменяет объект учетных данных новым объектом, а не просто обновляет его, а привязка между этапом сборки Docker и ключом осуществляется по идентификатору. Если вы используете значение null для идентификатора (как в ответе, который я связал ранее), тогда будет создан новый идентификатор, и настройка учетных данных на этапе сборки докера будет потеряна.

И все - скрипт должен запускаться каждые 12 часов и обновлять учетные данные ECR, и мы можем продолжать использовать плагины Docker.

Я тоже занимался этой же проблемой. Я не нашел ответа, который искал кто-либо из нас, но я смог создать обходной путь с помощью сценариев оболочки. Пока AWS не предложит лучшее решение для учетных данных ECR, я планирую делать что-то в этом направлении.

Я заменил этап Docker Build and Publish задания Jenkins на этап 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}

С помощью https://wiki.jenkins-ci.org/display/JENKINS/Amazon+ECR с плагином Docker Build and Publish работает нормально.