Source-to-Image (S2I) for Spring Boot

Learn how Source-to-Image (S2I) builds Spring Boot applications directly from source code in OpenShift. Understand S2I architecture, build lifecycle, builder images, implementation, and enterprise best practices.


Introduction

One of the unique features that makes OpenShift different from standard Kubernetes is Source-to-Image (S2I).

Instead of requiring developers to write Dockerfiles and build container images manually, S2I allows OpenShift to:

  • Clone source code from Git
  • Compile the application
  • Package the application
  • Create a container image
  • Push the image to the internal registry
  • Deploy the application automatically

For Java developers, this significantly simplifies the deployment process.


Learning Objectives

By the end of this article, you will understand:

  • What is Source-to-Image (S2I)?
  • How S2I works
  • S2I architecture
  • Builder Images
  • BuildConfig integration
  • Spring Boot implementation
  • S2I vs Docker Build
  • Enterprise use cases
  • Best practices

What is Source-to-Image?

Source-to-Image (S2I) is an OpenShift build strategy that creates container images directly from application source code.

Instead of writing a Dockerfile, developers simply provide:

  • Git Repository
  • Builder Image
  • BuildConfig

OpenShift performs the rest automatically.


Traditional Docker Build

flowchart LR
    DEV["Developer"]
    GIT["Git Repository"]
    CI["CI/CD Pipeline"]
    MAVEN["Maven Package"]
    DOCKER["Docker Build"]
    IMAGE["Container Image"]
    REG["Container Registry"]

    subgraph OCP["OpenShift Cluster"]
        DEPLOY["Deployment"]
        POD["Application Pod"]
    end

    DEV --> GIT
    GIT --> CI
    CI --> MAVEN
    MAVEN --> DOCKER
    DOCKER --> IMAGE
    IMAGE --> REG
    REG --> DEPLOY
    DEPLOY --> POD

Developers are responsible for building and maintaining Docker images.


Source-to-Image Workflow

flowchart LR
    DEV["Developer"]
    GIT["Git Repository"]
    BC["BuildConfig"]
    S2I["S2I Builder"]
    MAVEN["Maven Build"]
    IMAGE["Container Image"]
    IS["ImageStream"]
    DEPLOY["Deployment"]
    PODS["Running Pods"]

    DEV --> GIT
    GIT --> BC
    BC --> S2I
    S2I --> MAVEN
    MAVEN --> IMAGE
    IMAGE --> IS
    IS --> DEPLOY
    DEPLOY --> PODS

OpenShift handles the entire build process.


S2I Architecture

flowchart TD
    GIT["Git Repository"]
    BC["BuildConfig"]
    BUILDPOD["Build Pod"]
    BUILDER["Builder Image"]
    MAVEN["Maven Package"]
    RUNTIME["Runtime Image"]
    IS["ImageStream"]
    DEPLOY["Deployment"]

    GIT --> BC
    BC --> BUILDPOD
    BUILDPOD --> BUILDER
    BUILDER --> MAVEN
    MAVEN --> RUNTIME
    RUNTIME --> IS
    IS --> DEPLOY

How S2I Works

The build process consists of several stages.

sequenceDiagram

participant Developer

participant Git

participant BuildConfig

participant Build Pod

participant ImageStream

participant Deployment

Developer->>Git: Push Code

Git->>BuildConfig: Trigger Build

BuildConfig->>Build Pod: Create Build Pod

Build Pod->>Build Pod: Maven Build

Build Pod->>ImageStream: Push Image

ImageStream->>Deployment: Deploy Image

What is a Builder Image?

A Builder Image is a preconfigured container image that contains everything needed to build an application.

For Java applications, it typically includes:

  • Java
  • Maven
  • Linux
  • Build scripts
  • S2I tooling

Examples:

  • OpenJDK 17
  • OpenJDK 21
  • Red Hat UBI Java

Builder Image Architecture

flowchart TD
    BUILDER["Builder Image"]
    LINUX["Linux Base"]
    JAVA["Java Runtime"]
    MAVEN["Maven"]
    S2I["S2I Scripts"]

    BUILDER --> LINUX
    BUILDER --> JAVA
    BUILDER --> MAVEN
    BUILDER --> S2I

Developers don't need to install these tools locally.


Spring Boot Project

Example structure:

springboot-demo/

├── src/
├── pom.xml
├── mvnw
├── .mvn/
└── README.md

Notice that no Dockerfile is required.


BuildConfig Example

apiVersion: build.openshift.io/v1
kind: BuildConfig

metadata:
  name: springboot-demo

spec:

  source:
    git:
      uri: https://github.com/codewithvenu/springboot-demo.git

  strategy:
    sourceStrategy:
      from:
        kind: ImageStreamTag
        name: openjdk-21:latest

  output:
    to:
      kind: ImageStreamTag
      name: springboot-demo:latest

Create BuildConfig

oc apply -f buildconfig.yaml

Verify:

oc get buildconfigs

Start S2I Build

oc start-build springboot-demo

Follow logs:

oc logs -f build/springboot-demo-1

Build Lifecycle

flowchart LR
    CLONE["Clone Source"]
    DEPS["Download Dependencies"]
    MAVEN["Maven Package"]
    IMAGE["Create Image"]
    PUSH["Push Image"]
    DEPLOY["Deploy"]

    CLONE --> DEPS
    DEPS --> MAVEN
    MAVEN --> IMAGE
    IMAGE --> PUSH
    PUSH --> DEPLOY

Every stage executes automatically.


Build Pod

OpenShift creates a temporary Build Pod.

Responsibilities:

  • Clone Git repository
  • Download Maven dependencies
  • Compile source code
  • Package JAR
  • Build image
  • Push image

After completion, the Build Pod is removed.


Build Pod Architecture

graph TD
    A["Build Pod"]
    B["Git Clone"]
    C["Maven Build"]
    D["Package Application"]
    E["Create Container Image"]

    A --> B
    A --> C
    A --> D
    A --> E

ImageStream Integration

The generated image is stored inside an ImageStream.

flowchart LR
    S2I["S2I Build"]
    IS["ImageStream"]
    DEPLOY["Deployment"]
    PODS["Pods"]

    S2I --> IS
    IS --> DEPLOY
    DEPLOY --> PODS

Deployments can automatically react to new images.


Enterprise Banking Example

Suppose the Payment Service is updated.

flowchart LR
    DEV["Developer"]
    GIT["GitHub Repository"]
    BC["BuildConfig"]
    BUILDPOD["Build Pod"]
    IS["ImageStream"]
    DC["DeploymentConfig"]
    POD["Payment Pods"]
    ROUTE["OpenShift Route"]
    USER["Customers"]

    DEV --> GIT
    GIT --> BC
    BC --> BUILDPOD
    BUILDPOD --> IS
    IS --> DC
    DC --> POD
    POD --> ROUTE
    ROUTE --> USER

A simple Git push triggers a complete deployment.


Binary Build vs S2I

Binary Build S2I
Upload JAR Upload Source Code
Maven outside OpenShift Maven inside OpenShift
Manual Packaging Automatic Packaging
Useful for offline builds Best for CI/CD

Docker Build vs S2I

Docker Build S2I
Requires Dockerfile No Dockerfile
Manual image creation Automatic image creation
Full image control Standardized builds
Flexible Faster development

Advantages of S2I

  • No Docker knowledge required
  • Faster developer onboarding
  • Standardized builds
  • Secure build environment
  • Integrated with BuildConfig
  • Automatic deployments
  • Ideal for Java applications

Common S2I Commands

Create Build:

oc start-build springboot-demo

List Builds:

oc get builds

View Logs:

oc logs build/springboot-demo-1

Cancel Build:

oc cancel-build springboot-demo-2

Delete Build:

oc delete build springboot-demo-1

Build Logs

Typical output:

Cloning repository...

Downloading Maven dependencies...

Compiling Java sources...

Packaging Spring Boot application...

Creating container image...

Pushing image...

Build completed successfully.

Best Practices

  • Keep Git repositories clean.
  • Use Maven Wrapper (mvnw).
  • Enable Git webhooks.
  • Use immutable image tags.
  • Keep BuildConfigs in source control.
  • Monitor build logs.
  • Separate Dev, QA, and Production builds.
  • Use ImageStreams for version management.

Common Mistakes

❌ Building Docker images manually for every change.

❌ Using latest image tags.

❌ Ignoring build failures.

❌ Hardcoding credentials.

❌ Not using BuildConfig triggers.


S2I vs Docker Decision Matrix

Requirement Recommended
Standard Spring Boot App S2I
Custom OS Packages Docker Build
Simple Git Deployment S2I
Full Image Customization Docker Build
Enterprise CI/CD S2I

Summary

Source-to-Image (S2I) is one of OpenShift's most powerful features for Java developers.

Key takeaways:

  • S2I builds container images directly from source code.
  • No Dockerfile is required for standard Spring Boot applications.
  • BuildConfig defines how the application is built.
  • Builder Images provide Java, Maven, and build tools.
  • ImageStreams store generated images.
  • Git pushes can automatically trigger new deployments.
  • S2I simplifies enterprise CI/CD while enforcing consistent build practices.

Interview Questions

  1. What is Source-to-Image (S2I)?
  2. How does S2I differ from Docker Build?
  3. What is a Builder Image?
  4. What is the purpose of BuildConfig?
  5. Does S2I require a Dockerfile?
  6. What happens inside the Build Pod?
  7. How does S2I integrate with ImageStreams?
  8. What triggers an S2I build?
  9. When should you choose S2I over Docker Build?
  10. Why is S2I commonly used for Spring Boot applications?