🚀 Complete CI/CD + Docker Deployment Flow

🚀 Complete CI/CD + Docker Deployment Flow

The big picture is:

Developer writes code
        ↓
Git commit
        ↓
Push to GitHub / GitLab / Bitbucket
        ↓
CI/CD pipeline starts
        ↓
        BUILD
        ↓
       TEST
        ↓
Create Docker Image
        ↓
Push Image to Registry
        ↓
       DEPLOY
        ↓
Server / Cloud / Kubernetes / Cloud Run
        ↓
Container starts
        ↓
Application starts listening on PORT
        ↓
User sends HTTP request
        ↓
Application responds

Let's understand every step.


1. Developer writes code

Suppose you're developing a Java Spring Boot application:

payment-service/
│
├── src/
│   ├── main/
│   │   └── java/
│   └── test/
│
├── pom.xml
├── Dockerfile
└── application.properties

Your code could contain:

@RestController
public class PaymentController {

    @GetMapping("/payment")
    public String payment() {
        return "Payment successful";
    }
}

Your application needs:

Java
Spring Boot
Dependencies
Configuration
Your code

2. Developer commits code

You make changes:

git add .
git commit -m "Add payment API"

Now Git records your changes.

Then:

git push origin main

Your code goes to:

GitHub / GitLab / Bitbucket

For example:

Developer Laptop
       ↓
      Git
       ↓
GitHub repository

3. What happens after PUSH?

This is where CI/CD starts.

Your Git repository can be connected to a CI/CD system.

Examples:

  • Jenkins
  • GitHub Actions
  • GitLab CI/CD
  • Bitbucket Pipelines
  • Azure DevOps
  • Google Cloud Build

The repository/pipeline configuration tells the CI/CD system:

"When code is pushed to this branch, start this pipeline."

For example:

Developer
    ↓
git push
    ↓
GitHub
    ↓
Webhook / trigger
    ↓
Jenkins
    ↓
Pipeline starts

4. What is CI?

CI = Continuous Integration

The main idea:

Whenever developers push code, automatically build and test it.

For your Java application:

Git Push
   ↓
CI
   ↓
Checkout code
   ↓
Build
   ↓
Test
   ↓
Quality/Security checks

The purpose is to catch problems early.


5. CI pipeline checks out the code

The CI server needs your source code.

So it does something equivalent to:

git clone <repository>

Now the CI machine has:

src/
pom.xml
Dockerfile
...

The CI server is basically another machine/environment where your pipeline commands execute.


6. BUILD

Now the pipeline builds your application.

For Maven:

mvn clean package

Maven performs things such as:

Read pom.xml
      ↓
Download dependencies
      ↓
Compile Java code
      ↓
Run tests
      ↓
Package application
      ↓
Generate JAR

For example:

payment-service.jar

gets created.


7. What does Maven actually do?

Suppose:

src/main/java

contains:

PaymentController.java
PaymentService.java
PaymentRepository.java

Maven compiles them:

.java
  ↓
.class

Then packages the application:

.class + dependencies + resources
             ↓
        application.jar

So:

Source Code
     ↓
 Maven Build
     ↓
 JAR

8. TEST

The pipeline then runs tests.

For example:

mvn test

or the build command may already execute tests.

Tests could include:

Unit tests
Integration tests
API tests
Security checks
Code quality checks

For example:

Test PaymentService
       ↓
Expected = SUCCESS
Actual   = SUCCESS
       ↓
PASS

If tests fail:

Build
  ↓
Test
  ↓
FAILED ❌
  ↓
Pipeline stops
  ↓
No deployment

This is very important.

Normally you don't want broken code to reach production.


9. If everything passes → Docker build

Now comes Docker.

Your repository may contain:

Dockerfile

Example:

FROM eclipse-temurin:17

COPY target/payment-service.jar app.jar

ENTRYPOINT ["java", "-jar", "app.jar"]

This Dockerfile tells Docker:

"Take this Java application and create an image containing the environment and instructions required to run it."


10. What is Dockerfile?

A Dockerfile is a set of instructions for building a container image.

For example:

FROM eclipse-temurin:17

Means:

Start with a Java 17 runtime/base image.

Then:

COPY target/payment-service.jar app.jar

Means:

Copy my generated JAR into the image.

Then:

ENTRYPOINT ["java", "-jar", "app.jar"]

Means:

When the container starts, execute this command.


11. Docker builds the image

Pipeline runs something like:

docker build -t payment-service:1.0 .

Docker reads:

Dockerfile

and creates:

Container Image

Conceptually:

Dockerfile
     +
JAR
     +
Java runtime
     +
required files
     ↓
Docker Image

12. Image vs Container — VERY IMPORTANT

This is one of the most important Docker concepts.

Image

An image is a packaged template/blueprint.

payment-service:1.0

It is not necessarily running.

Container

A container is a running instance of an image.

Image
  ↓
docker run
  ↓
Container

For example:

payment-service:1.0
        ↓
   Container 1

You can create multiple containers from the same image:

             Image
               ↓
      ┌────────┼────────┐
      ↓        ↓        ↓
 Container  Container  Container
    1          2          3

13. Where is the image stored?

Usually, you don't leave the image only on the CI machine.

You push it to a Container Registry.

Examples:

Google Artifact Registry
Docker Hub
Amazon ECR
Azure Container Registry
GitHub Container Registry

For Google Cloud:

Docker Image
     ↓
Artifact Registry

Example conceptually:

Artifact Registry
└── payment-service
      ├── 1.0
      ├── 1.1
      └── 1.2

14. Why do we need a Registry?

Because your production server needs to obtain the image.

Think:

CI/CD machine
     ↓
Build image
     ↓
Registry
     ↓
Production server
     ↓
Pull image
     ↓
Run container

The registry acts like a central warehouse for container images.


15. CD starts

Now we move from:

CI → CD

CD generally means Continuous Delivery/Continuous Deployment, depending on the setup.

The deployment pipeline might say:

Image successfully created
       ↓
Push image to registry
       ↓
Deploy image
       ↓
Production

16. Where can we deploy?

There are several possibilities.

Option 1 — VM/server

Linux Server
     ↓
Docker
     ↓
Container

Option 2 — Kubernetes

Kubernetes Cluster
       ↓
Pod
       ↓
Container

Option 3 — Cloud Run

Cloud Run
    ↓
Container instance

The fundamental idea remains:

Container Image
       ↓
Runtime platform
       ↓
Running Container

17. Let's understand the traditional SERVER setup

Suppose your company has a Linux production server.

It could look something like:

Production Server
│
├── OS
│   └── Linux
│
├── Docker
│
├── Application
│   └── Container
│
├── Configuration
│
├── Logs
│
└── Networking

The server could be:

Physical server

or:

Virtual Machine

or:

Cloud VM

18. What files are generally present on the server?

This depends heavily on the company's deployment architecture.

A traditional non-containerized Java server might have things like:

/opt/application/
    ├── app.jar
    ├── config/
    ├── logs/
    └── scripts/

Configuration might be stored separately:

/etc/application/
    └── application.properties

But modern containerized deployments often don't copy the application JAR manually into a random server directory.

Instead:

Server
   ↓
Docker
   ↓
Pull image
   ↓
Run container

The JAR is already inside the image.


19. Containerized server setup

Suppose the image is:

payment-service:1.5

The server does:

docker pull payment-service:1.5

Then:

docker run payment-service:1.5

Docker creates a container:

Docker
  ↓
Container
  ↓
Java
  ↓
Spring Boot

20. What happens when the container starts?

This is VERY important.

Docker starts the container.

The Dockerfile says:

ENTRYPOINT ["java", "-jar", "app.jar"]

Therefore Docker executes:

java -jar app.jar

Spring Boot starts.

Then the embedded server starts.

Usually Spring Boot uses an embedded server such as Tomcat, Jetty, or Undertow depending on configuration/dependencies.

Conceptually:

Container starts
      ↓
java -jar app.jar
      ↓
Spring Boot starts
      ↓
Embedded web server starts
      ↓
Application listens on PORT

21. What does "listening on port" mean?

Yes 👍 you are thinking in the right direction, but there is one important distinction.

Docker

IMAGE
  ↓
Container

A container is the running instance of an image.

Kubernetes

Kubernetes adds another layer:

IMAGE
  ↓
CONTAINER
  ↓
POD

Actually, more precisely:

              Docker Image
                   ↓
                 Pod
            ┌──────┴──────┐
            ↓             ↓
       Container A   Container B

A Pod is the Kubernetes unit that runs one or more containers.

Most commonly:

Pod
 └── Container

So you can think:

TermMeaning
ImageBlueprint/package
ContainerRunning instance of image
PodKubernetes wrapper/unit containing one or more containers
VM/NodeMachine where Pods run

Example

Docker Image
payment:v1
     ↓
Kubernetes Pod
     ↓
Container
     ↓
Java Spring Boot running
     ↓
Listening on :8080

If Kubernetes needs 3 replicas:

Image: payment:v1
        ↓
 ┌──────┼──────┐
 ↓      ↓      ↓
Pod 1   Pod 2   Pod 3
 ↓      ↓      ↓
C1      C2      C3

So don't say "Pod = Container".

Better remember:

Container = the application running from an image.
Pod = Kubernetes' unit that contains the running container(s).

And yes, when someone says "instance", they often mean a running copy of something, but the exact meaning depends on context.

QUESTION: means run multiple containers but image run 1 container like that????

Almost exactly — just one correction. 👍

Docker

IMAGE
  ↓
Container

One image can be used to create one or many containers:

             IMAGE
          payment:v1
        /      |      \
       ↓       ↓       ↓
   Container Container Container

So an image is not limited to one container.

Kubernetes

A Pod can contain one or multiple containers:

             IMAGE
               ↓
              POD
        ┌──────┴──────┐
        ↓             ↓
   Container 1   Container 2

But in real-world Kubernetes applications, one Pod usually contains one main application container. Multiple containers in one Pod are commonly used when they need to work very closely together, such as a sidecar.

🧠 Remember

IMAGE
  ↓
can create many CONTAINERS

POD
  ↓
contains one or more CONTAINERS

So:

Image → Container
Pod → Container(s)

And Kubernetes Pods themselves run on Nodes (VMs/machines).

use of pod ?

Yes. Think of a Pod as the basic running unit in Kubernetes.

Why do we need a Pod?

Kubernetes needs something to manage your running application. Instead of directly managing individual containers, Kubernetes manages Pods.

Kubernetes
    ↓
  Pod
    ↓
Container
    ↓
Your Application

Main uses of a Pod

1. Run your application

For example:

Pod
 └── Spring Boot Container
       └── Java Application

Kubernetes can start, stop, restart, and replace the Pod.


2. Give the application a network identity

A Pod gets an IP address inside the Kubernetes cluster.

Other Service
      ↓
   Pod IP
      ↓
Container

Kubernetes Services can then route traffic to Pods.


3. Run multiple tightly coupled containers together

Sometimes two containers need to work together:

Pod
├── Main application container
└── Sidecar container

They share things such as:

  • Network
  • Storage volumes
  • Pod lifecycle

Example:

Pod
├── Java application
└── Logging sidecar

4. Kubernetes can scale Pods

Suppose you need 3 copies of your application:

        Kubernetes
             ↓
     ┌───────┼───────┐
     ↓       ↓       ↓
   Pod 1   Pod 2   Pod 3
     ↓       ↓       ↓
 Container Container Container

If one Pod fails:

Pod 1 ❌

Kubernetes can create a replacement:

Pod 1 ❌
   ↓
New Pod ✅

⭐ Most important

Don't think:

Pod = container

Think:

Pod = Kubernetes' wrapper/management unit around one or more containers.

And the hierarchy is:

Kubernetes Cluster
       ↓
      Node
       ↓
      Pod
       ↓
Container
       ↓
Application

For a normal Spring Boot application, you will very commonly see:

Node
 └── Pod
      └── Spring Boot Container
           └── Java Application

Why Pod exists: Kubernetes uses the Pod as the unit for running, networking, scaling, restarting, and managing your application containers.

 

Comments

Popular posts from this blog

Async/await

First negative in every window of size k

Valid Parentheses