Integrar o Amazon Elastic Container Registry ao Jenkins

10

Estou tentando integrar o novo Elastic Container Registry (ECR) da Amazon ao meu serviço de compilação Jenkins. Estou usando o plug-in Cloudbees Docker Build & Publish para criar imagens de contêiner e publicá-las em um registro.

Para usar o ECR em vez do meu registro privado, executei o comando AWS CLI aws --region us-east-1 ecr get-loginque envia um docker logincomando para execução - mas apenas copiei a senha e criei credenciais Jenkins do tipo "Nome de usuário com senha" a partir dessa senha (o nome de usuário é sempre "AWS").

E isso funciona bem! O problema é que a senha do ECR gerada pela AWS CLI é válida apenas por 12 horas. Portanto, agora, preciso gerar novamente a senha manualmente duas vezes por dia e atualizar a tela de credenciais do Jenkins manualmente, caso contrário minhas compilações começarão a falhar.

Existe uma maneira de gerar tokens de login ECR permanentes ou de alguma forma automatizar a geração de tokens?

Guss
fonte

Respostas:

6

Agora isso é possível usando o amazon-ecr-credential-helper, conforme descrito em https://aws.amazon.com/blogs/compute/authenticating-amazon-ecr-repositories-for-docker-cli-with-credential-helper/ .

O resumo é:

  • Verifique se sua instância do Jenkins possui as credenciais da AWS adequadas para puxar / enviar com seu repositório de ECR. Elas podem estar na forma de variáveis ​​de ambiente, um arquivo de credencial compartilhado ou um perfil de instância.
  • Coloque o binário docker-credential-ecr-login em um dos diretórios em $ PATH.
  • Escreva o arquivo de configuração do Docker no diretório inicial do usuário Jenkins, por exemplo, /var/lib/jenkins/.docker/config.json. com o conteúdo{"credsStore": "ecr-login"}
  • Instale o plug-in Build and Publish do Docker e verifique se o usuário jenkins pode entrar em contato com o daemon do Docker.
  • Por fim, crie um projeto com uma etapa de construção que publique a imagem do docker
Klugscheißer
fonte
4

Como @Connor McCarthy disse, enquanto esperava a Amazon encontrar uma solução melhor para chaves mais permanentes, nesse meio tempo precisaríamos gerar as chaves no servidor Jenkins de alguma forma.

Minha solução é ter um trabalho periódico que atualize as credenciais Jenkins para ECR a cada 12 horas automaticamente, usando a API do Groovy. Isso se baseia nesta resposta muito detalhada , embora eu tenha feito algumas coisas de maneira diferente e precisei modificar o script.

Passos:

  1. Verifique se o seu mestre Jenkins pode acessar a API da AWS necessária. Na minha configuração, o mestre Jenkins está sendo executado no EC2 com uma função do IAM, então tive que adicionar a permissão ecr:GetAuthorizationTokenà função de servidor. [ Atualização ] para obter qualquer empurra concluída com êxito, você também precisaria conceder essas permissões: ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage. A Amazon possui uma política interna que oferece esses recursos, chamados AmazonEC2ContainerRegistryPowerUser.
  2. Verifique se a AWS CLI está instalada no mestre. Na minha configuração, com o mestre sendo executado em um contêiner do docker debian, acabei de adicionar esta etapa de construção do shell ao trabalho de geração de chaves: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. Instale o plug-in Groovy, que permite executar o script Groovy como parte do sistema Jenkins.
  4. Na tela de credenciais, procure sua chave ECR da AWS, clique em "Avançado" e registre seu "ID". Neste exemplo, vou assumir que é "12345".
  5. Crie um novo trabalho, com um lançamento periódico de 12 horas, e adicione uma etapa de criação "script do Groovy do sistema" com o seguinte script:

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

Observe:

  • o uso da string codificada "AWS"como o nome de usuário das credenciais de ECR - é assim que a ECR funciona, mas se você tiver várias credenciais com o nome de usuário "AWS", será necessário atualizar o script para localizar as credenciais com base no campo de descrição ou algo assim.
  • Você deve usar o ID real da sua chave ECR real no script, porque a API para credenciais substitui o objeto de credenciais por um novo objeto em vez de apenas atualizá-lo, e a ligação entre a etapa de construção do Docker e a chave é pelo ID. Se você usar o valor nulldo ID (como na resposta que eu vinculei antes), um novo ID será criado e a configuração das credenciais na etapa de construção do docker será perdida.

E é isso: o script deve ser executado a cada 12 horas e atualizar as credenciais de ECR, e podemos continuar usando os plug-ins do Docker.

Guss
fonte
3

Eu também estava investigando esse mesmo problema. Não encontrei a resposta que estávamos procurando, mas consegui criar uma solução alternativa com scripts de shell. Até que a AWS saia com uma solução melhor para as credenciais de ECR, pretendo fazer algo nesse sentido.

Substituí a etapa Docker Build and Publish da tarefa Jenkins pela etapa Execute Shell. Usei o seguinte script (provavelmente poderia ser melhor escrito) para criar e publicar meu contêiner no ECR. Substitua as variáveis ​​entre colchetes, conforme necessário:

#!/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}
Connor McCarthy
fonte
Parece muito razoável. o problema é que eu gosto do Docker Build and Publish e continuo a usá-lo, pois simplifica minha vida. Eu tenho várias compilações de contêiner no sistema e quero adicionar mais, e integrar esse script a cada compilação é mais complicado do que estou disposto a conviver. Eu tenho uma solução alternativa que estou adicionando como resposta.
Guss
2

O uso de https://wiki.jenkins-ci.org/display/JENKINS/Amazon+ECR com o plug-in Docker Build and Publish funciona perfeitamente.

Danilo
fonte
Eu o instalei - mas não consegui descobrir o que fazer com ele: ele não tem configuração nem interface do usuário.
Guss
Instale o plugin. Na etapa Docker Build and Publish, você tem uma lista suspensa chamada "Credenciais do Registro". Clique em "Adicionar" ao lado, selecione como tipo "Credenciais da AWS" na caixa de diálogo. Digite a chave de acesso / chave secreta.
Danilo
Agora eu vejo. Pena que não suporta perfis de instância.
Guss
Sim. Mas por enquanto eu prefiro esta solução.
Danilo