Ravindra BagaleCourses & study guides मराठी

Chapter 28: Registries, Kubernetes, Terraform and Ansible from Jenkins

28.1 Registries

Why: the problem

Think of Myntra. Its Jenkins builds a new Docker image for the catalog service twenty times a day. Where do those images go? Not on the Jenkins disk. They go to a registry: a store for images, like Docker Hub, Amazon ECR, GitHub Container Registry, or a private Harbor or Nexus server. Kubernetes and servers pull images from the registry when they deploy. If Jenkins pushes a tag called latest every time, nobody knows which code is running. If Jenkins puts the registry password inside the Jenkinsfile, it leaks to everyone who can read Git. So pushing images looks simple but has three rules: log in with a saved credential, tag every image with something traceable like the build number or Git commit, and never overwrite a release tag. In this lesson you will push the same image to Docker Hub, Amazon ECR and a private registry from Jenkins.

What we will build

You will build a small Node.js image in Jenkins. You will tag it with the Git short commit and the build number. You will push it to Docker Hub using docker.withRegistry, to Amazon ECR using the AWS CLI login, and to a self-hosted registry. Then you will check the tags with the registry API and clean up dangling images on the agent.

What: every term in plain English

  • Registry — A server that stores Docker images, like Docker Hub, Amazon ECR, Harbor or Nexus.
  • Repository — One image name inside a registry, like ravilab/shop-api. It holds many tags.
  • Tag — A label on an image version, like 1.4.0 or 42-a1b2c3d.
  • Digest — A sha256 ID of the exact image content. It never changes for the same content.
  • docker login — Gives Docker a token to push or pull from a registry.
  • ECR — Amazon Elastic Container Registry. AWS private registry, login with the AWS CLI.
  • Immutable tag — A setting that blocks pushing the same tag twice. Protects releases.
  • Dangling image — An old image with no tag left, taking disk space on the agent.
Add Docker Hub token Get the short commit Build with two tags Create an ECR repository Log in to ECR Push Check tags
Build, tag, login, push, top to bottom

How: step by step

  1. Add Docker Hub token

    Manage Jenkins > Credentials > Global > Add > Username with password > ID dockerhub > password: a Docker Hub access token
    

    What it does: Token, not your Docker Hub password.

    Output

    Credential dockerhub created
    
  2. Get the short commit

    git rev-parse --short HEAD
    

    What it does: A 7 letter ID of the code version.

    Output

    a1b2c3d
    
  3. Build with two tags

    docker build -t ravilab/shop-api:42-a1b2c3d -t ravilab/shop-api:42 .
    

    What it does: One image, two names.

    Output

    Successfully tagged ravilab/shop-api:42-a1b2c3d
    
  4. Create an ECR repository

    aws ecr create-repository --repository-name shop-api --image-tag-mutability IMMUTABLE --region ap-south-1
    

    What it does: A private repo in Mumbai region that refuses tag overwrite.

    Output

    "repositoryUri": "123456789012.dkr.ecr.ap-south-1.amazonaws.com/shop-api"
    
  5. Log in to ECR

    aws ecr get-login-password --region ap-south-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-south-1.amazonaws.com
    

    What it does: A 12 hour login token from AWS.

    Output

    Login Succeeded
    
  6. Push

    docker push 123456789012.dkr.ecr.ap-south-1.amazonaws.com/shop-api:42-a1b2c3d
    

    What it does: Uploads the layers.

    Output

    42-a1b2c3d: digest: sha256:9f8e... size: 1784
    
  7. Check tags

    aws ecr list-images --repository-name shop-api --region ap-south-1
    

    What it does: Lists the image tags in ECR.

    Output

    "imageTag": "42-a1b2c3d"
    

Example 1: Push to Docker Hub with docker

Stack. Jenkins, Docker Pipeline plugin, Docker Hub

Goal. Push to Docker Hub with docker.withRegistry.

Jenkinsfile

pipeline {
  agent { label 'linux-docker' }
  environment { REPO = 'ravilab/shop-api' }
  stages {
    stage('Checkout') { steps { checkout scm } }
    stage('Build') {
      steps {
        script {
          env.SHORT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
          env.TAG = "${BUILD_NUMBER}-${env.SHORT}"
          img = docker.build("${REPO}:${env.TAG}")
        }
      }
    }
    stage('Push') {
      steps {
        script {
          docker.withRegistry('https://index.docker.io/v1/', 'dockerhub') {
            img.push()
            img.push("${BUILD_NUMBER}")
          }
        }
      }
    }
  }
  post { always { sh 'docker image prune -f' } }
}

What each line does

  • checkout scm — Checks out the same commit the job was started for.
  • sh(script: ..., returnStdout: true).trim() — Runs a command and keeps its output in a variable.
  • env.TAG = "${BUILD_NUMBER}-${env.SHORT}" — Tag like 42-a1b2c3d: build number plus commit.
  • docker.build(...) — Docker Pipeline plugin step that runs docker build and returns an image object.
  • docker.withRegistry(url, 'dockerhub') — Logs in with the saved credential only inside the block, and logs out after.
  • img.push() — Pushes the main tag. push("42") adds a second tag.
  • docker image prune -f — Deletes dangling images so the agent disk stays healthy.

Green output

[Pipeline] stage (Build)
+ git rev-parse --short HEAD
+ docker build -t ravilab/shop-api:42-a1b2c3d .
Successfully tagged ravilab/shop-api:42-a1b2c3d
[Pipeline] stage (Push)
+ docker login -u ravilab -p ******** https://index.docker.io/v1/
Login Succeeded
+ docker push ravilab/shop-api:42-a1b2c3d
42-a1b2c3d: digest: sha256:4c5d... size: 1784
+ docker push ravilab/shop-api:42
Total reclaimed space: 211MB

Expected result. Docker Hub shows two tags for the same digest. From any tag you can find the build and the commit.

Example 2: Push to Amazon ECR with the agent IAM role

Stack. Jenkins agent on EC2 with IAM role, AWS CLI v2, ECR

Goal. Push to Amazon ECR with the agent IAM role.

Jenkinsfile

pipeline {
  agent { label 'linux-docker' }
  environment {
    AWS_REGION = 'ap-south-1'
    REGISTRY   = '123456789012.dkr.ecr.ap-south-1.amazonaws.com'
    REPO       = 'shop-api'
  }
  stages {
    stage('Build') {
      steps { sh 'docker build -t $REGISTRY/$REPO:$BUILD_NUMBER .' }
    }
    stage('Login and push') {
      steps {
        sh 'aws sts get-caller-identity --query Arn --output text'
        sh 'aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $REGISTRY'
        sh 'docker push $REGISTRY/$REPO:$BUILD_NUMBER'
      }
    }
    stage('Scan result') {
      steps {
        sh 'sleep 20; aws ecr describe-image-scan-findings --repository-name $REPO --image-id imageTag=$BUILD_NUMBER --region $AWS_REGION --query imageScanFindings.findingSeverityCounts || true'
      }
    }
  }
}

What each line does

  • REGISTRY = 123456789012.dkr.ecr... — Your account ID and region. 123456789012 is the standard AWS example number.
  • aws sts get-caller-identity — Prints which IAM role Jenkins uses. Here the agent EC2 instance role, no keys stored.
  • get-login-password | docker login — Gets a temporary password and pipes it to docker login.
  • docker push $REGISTRY/$REPO:$BUILD_NUMBER — Pushes to the private ECR repo.
  • describe-image-scan-findings — If scan on push is on, shows counts of HIGH and CRITICAL problems.
  • || true — Do not fail the build if the scan is not ready yet.

Green output

+ aws sts get-caller-identity --query Arn --output text
arn:aws:sts::123456789012:assumed-role/jenkins-agent-role/i-0abc123def4567890
+ docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-south-1.amazonaws.com
Login Succeeded
+ docker push 123456789012.dkr.ecr.ap-south-1.amazonaws.com/shop-api:43
43: digest: sha256:7a6b... size: 1784
{
    "HIGH": 1,
    "MEDIUM": 4
}

Expected result. The image is in ECR, pushed with a role, not a key. Lesson 28.2 explains the role.

Example 3: Push to a private self-hosted registry and read tags by API

Stack. Docker registry:2, Jenkins

Goal. Push to a private self-hosted registry and read tags by API.

run-registry.sh

docker run -d --name registry -p 5000:5000 --restart unless-stopped -v registry-data:/var/lib/registry registry:2
curl -s http://localhost:5000/v2/

Jenkinsfile stage

stage('Push to lab registry') {
  steps {
    sh 'docker tag ravilab/shop-api:$BUILD_NUMBER localhost:5000/shop-api:$BUILD_NUMBER'
    sh 'docker push localhost:5000/shop-api:$BUILD_NUMBER'
    sh 'curl -s http://localhost:5000/v2/shop-api/tags/list'
  }
}

What each line does

  • registry:2 — The official open source registry image.
  • -v registry-data:/var/lib/registry — Images stay after the container restarts.
  • /v2/ — The registry API root. It answers {} when healthy.
  • localhost:5000/shop-api — Image names start with the registry host to push there.
  • /v2/shop-api/tags/list — Lists tags of one repository.
  • Lab only — Without TLS and login, use this only on localhost. For teams use Harbor or Nexus with HTTPS.

Green output

{}
+ docker push localhost:5000/shop-api:44
44: digest: sha256:1b2c... size: 1784
+ curl -s http://localhost:5000/v2/shop-api/tags/list
{"name":"shop-api","tags":["44"]}

Expected result. Your own registry holds the image. Companies use Harbor, Nexus or JFrog Artifactory the same way, with HTTPS and users.

Verify: did it work?

  1. Pull by tag on another machine

    docker pull ravilab/shop-api:42-a1b2c3d && docker inspect --format "{{index .RepoDigests 0}}" ravilab/shop-api:42-a1b2c3d
    

    What it does: Same digest as the push log.

    Output

    ravilab/shop-api@sha256:4c5d...
    
  2. ECR tag is immutable

    docker push 123456789012.dkr.ecr.ap-south-1.amazonaws.com/shop-api:43
    

    What it does: Push the same tag again; it must be refused.

    Output

    tag invalid: The image tag 43 already exists ... cannot be overwritten because the repository is immutable.
    

When it is red 1

denied: requested access to the resource is denied

Cause. Wrong repo name, or the token has no write right.

Fix, step by step

  1. Name must be yourname/repo on Docker Hub.
  2. Give the access token Read and Write scope.
  3. Check the credential ID.

When it is red 2

no basic auth credentials

Cause. Docker was not logged in to ECR, or the 12 hour token expired.

Fix, step by step

  1. Run the get-login-password step in the same stage, right before push.
  2. Check the IAM role has ecr:GetAuthorizationToken and ecr push actions.

When it is red 3

http: server gave HTTP response to HTTPS client

Cause. Docker wants HTTPS for any registry that is not localhost.

Fix, step by step

  1. Use HTTPS with a real certificate.
  2. For a lab only, add the host to insecure-registries in /etc/docker/daemon.json and restart Docker.

Cleanup

  1. Remove lab registry

    docker rm -f registry && docker volume rm registry-data
    

    What it does: Deletes the lab registry and its images.

    Output

    registry
    registry-data
    
  2. Delete an ECR test image

    aws ecr batch-delete-image --repository-name shop-api --image-ids imageTag=43 --region ap-south-1
    

    What it does: Removes one tag from ECR.

    Output

    "imageDigest": "sha256:7a6b..."
    

Ravindra Bagale's Tip

Fakt latest tag nako; build number ani commit vapra. Password Jenkinsfile madhe kadhich nako. Lakshat theva!

Practice tasks

Easy Tag with commit

Why: Traceability starts with the tag.

What to do: Add the short commit to your image tag.

How:
  1. git rev-parse --short HEAD.
  2. Use it in docker build -t.

Check: The tag shows the commit.

Medium Lifecycle policy

Why: Registries cost money.

What to do: Keep only 30 images in ECR.

How:
  1. ECR > Lifecycle policy > rule.

Check: Old images expire.

Hard Sign images

Why: Prove who built an image.

What to do: Sign the image with cosign after push.

How:
  1. Install cosign.
  2. cosign sign the digest.
  3. cosign verify.

Check: Verify passes.

Easy Say pushing images to a registry in two lines

Why: If you can say it simply, you understand it. Juniors and interviewers want the short version first.

What to do: Write two short lines about pushing images to a registry for a fresher who knows only Linux basics.

How:
  1. Write what problem it solves.
  2. Write the one command or menu you use for it.
  3. Read it aloud to a friend.

Check: A fresher understands it without asking a question.

Easy Start a fresh lab Jenkins

Why: Practice needs a throwaway Jenkins. If you break it, you delete it and start again.

What to do: Run Jenkins LTS in Docker with a named volume.

How:
  1. docker volume create jenkins_home
  2. docker run -d --name jenkins -p 8080:8080 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts-jdk17
  3. docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

Check: The Jenkins unlock page opens on localhost:8080.

Medium Break it on purpose

Why: You must know the red message by face. During an outage there is no time to read slowly.

What to do: Cause one error from the "When it is red" part of this lesson and fix it.

How:
  1. Follow the error section.
  2. Copy the exact message into your notes.
  3. Write the fix in one line.

Check: You fixed it using only the steps, without searching the web.

Medium Write a one-page runbook

Why: At 2 a.m. nobody remembers where a file lives. A short page saves the on-call person.

What to do: Write a runbook page for this lesson.

How:
  1. Title, when to use, exact command, how to check, how to undo.

Check: A teammate can follow it alone.

Medium Repeat it on a cloud VM

Why: A laptop is not a server. Real Jenkins runs on EC2 or a company VM.

What to do: Do the main steps of this lesson again on a small Ubuntu 22.04 EC2 instance.

How:
  1. Launch t3.small with 20 GB disk.
  2. Open port 22 only to your IP.
  3. Repeat the steps and compare the output.

Check: Same green output on the VM as on your laptop.

Hard Explain it like an interview

Why: Interviewers want real stories, not definitions.

What to do: Record a 60 second answer about this lesson.

How:
  1. Say the problem, the command you ran, and one error you hit.

Check: Your answer has a real command and a real error message.

Hard Draw the flow top to bottom

Why: A drawing shows who talks to whom and in what order.

What to do: Draw this lesson as boxes from top to bottom.

How:
  1. Start at the developer push, go through the controller and agent, end at the result.

Check: Each box matches a real thing you saw on screen.

Homework: try at home

Try at home

At home, push one image to Docker Hub from Jenkins with tag BUILD-COMMIT. Then add an ECR lifecycle policy that keeps only the last 30 images, and check it in the ECR console.

Recap

  • Images go to a registry, not the Jenkins disk.
  • Tag with build number and commit; avoid only latest.
  • Log in with saved credentials or an IAM role, never a password in the Jenkinsfile.
  • Use immutable tags for releases.
  • Prune dangling images on agents.

FAQ

Docker Hub or ECR?

Docker Hub for public images; ECR for private images on AWS, with IAM and scanning.

Does Docker Hub limit pulls?

Yes, anonymous and free accounts have pull limits. Log in or use a mirror.

Should Jenkins push to production registry directly?

Usually it pushes to one registry; deploys use the digest or tag from it.

What is Harbor?

A free self-hosted registry with users, scanning and replication.

Do I need to log out?

withRegistry logs out after the block. For plain sh, run docker logout in post.

Interview questions

  1. How do you push Docker images from Jenkins?

    Build with docker.build or sh, then push inside docker.withRegistry with a credential ID, or log in to ECR with the AWS CLI using an IAM role.

  2. How do you tag images in CI?

    With build number and short Git commit, plus a semantic version for releases. Avoid relying on latest.

  3. How do you avoid storing registry passwords?

    Jenkins credentials with masking, or IAM roles for ECR with temporary tokens.

  4. What is the difference between a tag and a digest?

    A tag is a movable label; a digest is the content hash. Deploy by digest for exact versions.

  5. How do you stop agent disks filling with images?

    docker image prune in post, scheduled docker system prune, and ephemeral agents.

Quick quiz

Q1. Why not use only the latest tag?

You cannot tell which code runs, and rollbacks become guesswork.

Q2. Which step logs in with a credential ID?

docker.withRegistry.

Q3. How long is an ECR login valid?

12 hours.

Q4. What blocks overwriting a tag in ECR?

Tag immutability.

Q5. What is a digest?

The sha256 ID of the exact image content.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards