I wanted to use an ECR prebuilt image as a Jenkins pipeline agent. The motivation was simple — stop running docker build every time and just pull a pre-built image to speed up the pipeline.

So I had Claude Code draft a plan, and the proposal that came back was more complex than I expected.

I rejected it.

The Initial Proposal

The current Jenkinsfile has this structure:

pipeline {
    agent {
        dockerfile {
            label 'ec2-fleet-small'
            dir '.'
            filename 'Dockerfile'
            args "-v \${WORKSPACE}:/workspace -w /workspace"
        }
    }
    stages { ... }
    post { /* archiveArtifacts, cleanWs, webhook */ }
}

To switch this to an ECR image, the AI proposed the following structure:

pipeline {
    agent { label 'ec2-fleet-small' }  // bare host first
    stages {
        stage('ECR Login') { ... }     // authenticate here
        stage('Run in Docker') {
            agent { docker { image ECR_IMAGE, reuseNode true } }
            stages { all existing stages }
            post { archiveArtifacts, cleanup }
        }
    }
    post { cleanWs, webhook }
}

The reasoning made sense. Run the ECR Login on the bare host, then use those credentials to launch the Docker agent. With reuseNode true, the same node is reused, so the authenticated state carries over.

The split post blocks were logical too. Steps that need access to files in the Docker container's /tmp/ must run in the Docker stage's post before the container dies. cleanWs and the webhook stay in the pipeline-level post.

But it required restructuring the entire pipeline — nested stages, split post blocks, script-scoped variable management...

The amount of change felt disproportionate to what I was trying to achieve.

"Isn't There an Easier Way?"

I rejected the plan and asked.

Two alternatives came up:

Option 1: amazon-ecr-credential-helper (EC2 OS level)
Option 2: Jenkins Amazon ECR Plugin (Jenkins side)

Comparing the Two Approaches

Both aim to let Docker automatically pull images from ECR. The difference is in the mechanism and where it's configured.

credential-helper Jenkins ECR Plugin
Where it lives EC2 instance (OS level) Jenkins (plugin)
Auth method IAM instance profile Jenkins Credentials
Jenkinsfile changes agent block only registryUrl + credentialsId
Scope All Docker on instance Target job only
Scaling to other jobs No Jenkinsfile changes Must add to each file
EC2 changes needed AMI/user data update None

In terms of Jenkinsfile changes, credential-helper wins by a wide margin.

// Using the ECR Plugin
agent {
    docker {
        image '<ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/your-image:latest'
        registryUrl 'https://<ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/'
        registryCredentialsId 'ecr:ap-northeast-1:<Jenkins Credential ID>'
        label 'ec2-fleet-small'
    }
}

// Using credential-helper
agent {
    docker {
        image '<ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/your-image:latest'
        label 'ec2-fleet-small'
        alwaysPull true
    }
}

With credential-helper installed, the Jenkinsfile needs zero authentication configuration. Docker handles ECR auth automatically using the EC2's IAM instance profile.

Why I Chose credential-helper

I went with credential-helper for two main reasons.

I don't want authentication config scattered across Jenkinsfiles.
This isn't just about one job. Other pipelines will be switching to ECR images too. With the ECR plugin, every Jenkinsfile would need registryUrl and registryCredentialsId added. With credential-helper, none of them need anything.

No impact on other registries like Docker Hub.
I checked this first. credential-helper uses a credHelpers mechanism that works on a per-domain basis:

{
  "credHelpers": {
    "<ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com": "ecr-login"
  }
}

It doesn't touch any registry not listed here. Docker Hub pulls continue to work as before.

The trade-off is that the EC2 AMI or user data needs to be updated. It's an infrastructure-layer change, so the blast radius is wider than a Jenkinsfile change. But given that it's a one-time setup that benefits all jobs, I judged it an acceptable cost.

So, Infrastructure First

This is where I realized the sequencing matters.

If credential-helper isn't installed on the EC2 instances, switching the Jenkinsfile to an ECR image simply won't work. The prerequisite isn't met.

What's needed:

  1. Install amazon-ecr-credential-helper on EC2 fleet instances
  2. Configure credHelpers in ~/.docker/config.json for the Docker user
  3. Verify the EC2 IAM role has the required ECR permissions (ecr:GetAuthorizationToken, ecr:BatchGetImage, ecr:GetDownloadUrlForLayer)

This is an infrastructure code change, not a Jenkinsfile change.

So rather than touching the Jenkinsfile first, I filed an IaC issue to update the infrastructure. Once that's done, the Jenkinsfile change is just a few lines in the agent block.

Current Status

The Jenkinsfile hasn't been changed yet.

I created the infrastructure issue and prioritized that work first. Once it's done, I'll submit the Jenkinsfile PR.

Documenting the decision process here while it's still fresh.

Recommended Resources

The following books are helpful for understanding Jenkins pipeline design and AWS infrastructure operations.

[📦 商品リンク: moshimo-book-jenkins-jissen]

[📦 商品リンク: moshimo-book-jenkins-blue]

[📦 商品リンク: moshimo-book-aws-operations]