With the use of the Jenkins Docker Pipeline plugin, it’s easy to build and push Docker images.
For example, building in a Jenkinsfile:
script { dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}", "${args}") }
And push:
script { docker.withRegistry("${env.DOCKER_PRIVATE_REGISTRY_URL}", "docker-private-registry-${env.DEPLOY_ENVIRONMENT}") { dockerImage.push("${env.DOCKER_IMAGE_SHORT_PUSH_TAG}") } }
The Docker registry username and password are provided by the credential ID “docker-private-registry-${env.DEPLOY_ENVIRONMENT}”. However Amazon ECR uses tokens that are only valid for 12 hours. So the password that you specify when creating the credential will only work in the example above for a short period of time.
With the following script it’s easy to update the password / token periodically. It’s tested on Jenkins version 2.138.2.
AWS CLI installation
Make sure your AWS credentials are in $JENKINS_HOME/.aws/credentials and the region is in $JENKINS_HOME/.aws/config.
Example $JENKINS_HOME/.aws/credentials file:
[default] aws_access_key_id = MyAccessKey2I2JA aws_secret_access_key = ksdfm3N2o1wnwnsbaqqadummy982
Example $JENKINS_HOME/.aws/config file:
[default] region = eu-west-1
Install it with the Jenkins update center / manage plugins page. The plugin page is at https://plugins.jenkins.io/groovy.
Build every 10 hours with “H H/10 * * *”.
// Add the content of this script as inline script of a "Execute system Groovy script" build step. // That build step also has the option to execute from a script file, but that has too much security restrictions. // The job must have a job parameter "CREDENTIAL_ID" and "REGION". import jenkins.model.* import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl def changePassword = { id, new_password -> def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials( com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class, Jenkins.instance) def c = creds.findResult { it.id == id ? it : null } if (c) { println "Found credential with ID \"${c.id}\"" 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, id, c.description, c.username, new_password)) if (result) { println "Changed password of credential \"${id}\"" } else { println "Failed to change password of credential \"${id}\"" } } else { println "Could not find credential ID \"${id}\"" } } // Get job parameters def credentialId = build.buildVariableResolver.resolve('CREDENTIAL_ID') def region = build.buildVariableResolver.resolve('REGION') println "Credential ID \"${credentialId}\"" println "Region \"${region}\"" println "Calling AWS for docker login" def prs = "/usr/bin/aws ecr get-login --no-include-email --region ${region}".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(credentialId, password) }
If a Docker image is pushed to a regular Docker registry, the repository is created on first time push if it doesn’t exist yet. This is not the case with Amazon ECR. You have to make sure the repository exists before push.
Create in your Jenkinsfile something like:
if (env.DOCKER_PRIVATE_REGISTRY_URL.contains('.ecr.')) { // Docker registry automatically creates a repository on first time push, but Amazon ECR // requires a separate creation step first sh "${env.JENKINS_HOME}/custom/aws/ecr-ensure-repository.sh ${env.DOCKER_IMAGE}" }
The content from ecr-ensure-repository.sh:
#!/usr/bin/env bash repository_name=$1 if [ -z "$repository_name" ]; then echo 'Repository name is required as first argument' exit 1 fi aws ecr describe-repositories | grep repositoryName | grep "\"$repository_name\"" > /dev/null exit_code=$? if [ ${exit_code} -gt 0 ]; then echo "Repository $repository_name not found, creating..." aws ecr create-repository --repository-name ${repository_name} fi