This is a simple Sales Manager Java App that stores sales items in a table presented in a web app. This demo repo is designed to help understand some of CI/CD (Continuous Integration/Continuous Delivery) principles and best practices.
- Language: Java (Spring Boot framework)
- Design Patterns: MVC (Model View Controller) and OOP (Object Oriented Programming)
- Database: PostreSQL 10.4 (compatible with other versions)
- CI/CD Pipeline: GitHub Actions
The pipeline is optimized using various tools. See the .github/workflows/ci.yml
and .github/workflows/cd.yml
for more detailed configuration.
- Caching Dependencies to Speed Up Workflows
- Docker Layer Caching with action-docker-layer-caching or build-push-action actions.
- Metrix Strategy for parallel unit testing.
- Split Test Action for splitting tests across multiple runners.
- GitHub Advanced Security with CodeQL analysis.
- Liquibase Quality Checks for enforcing database schema changes best practices.
- Environments with an approval step review prior to deployments
- azure/login action for OIDC (OpenID Connect) functionality.
- Canary or Blue-Green deployments in an AKS (Azure Kubernetes) Cluster.
stateDiagram
state Developer-Workflow {
Commits --> PR: Developers Commit new changes in a Pull Request
PR --> Build: Build & Unit Test Suite
}
state Continuous-Integration {
state Security-Scans {
Build --> App: CodeQL Analysis
Build --> Database: Liquibase Quality Checks
Build --> Package: Compile
}
Build --> JunitTests: Storing Artifacts
state Parallel-Testing {
JunitTests --> JunitTest1: Each test runs in \na containerized environment
JunitTests --> JunitTest2
JunitTests --> JunitTest3
JunitTests --> JunitTest4
JunitTests --> JunitTest..N
}
JunitTests --> Publish: If CI passes, \nmerging to main branch \nand publishing Containerised\n App to GitHub\n Container Registry
}
state Continuous-Delivery {
Publish --> SystemTesting: Pulling Image from GHCR
SystemTesting --> IntegrationTesting: [staging]
IntegrationTesting --> AccepetanceTesting: [staging]
}
AccepetanceTesting --> Deploy: Login with OpenID Connect and \nDeploy the app to K8s
Deploy --> [ProdInstance1]: Blue
Deploy --> [ProdInstance2]: Green
sequenceDiagram
participant C as Commit
participant G as GitHub Actions
participant H as Helm
participant K as Kubernetes
C->>G: Developer pushes a commit
G->>G: GitHub Actions extracts the commit message
Note over G: GitHub Actions checks if the commit message starts with [v1]
alt Commit message starts with [v1]
G->>H: GitHub Actions tells Helm to update the app without changing the v2 image
Note over G: The v2 image remains the same
else Commit message does not start with [v1]
G->>H: GitHub Actions tells Helm to update the app and change the v2 image
Note over G: The v2 image is updated to the new version
end
H->>K: Helm deploys or updates the Kubernetes resources
G->>K: GitHub Actions checks the status of the deployments
- User sends a request to the Load Balancer.
- Load Balancer routes the request to the Kubernetes Service.
- Kubernetes Service routes the request to the Spring Boot App.
- Spring Boot App queries the Database.
- Database returns data to the Spring Boot App.
- Spring Boot App checks the Feature Flag.
- Feature Flag returns the flag status to the Spring Boot App.
- Spring Boot App checks the Redis Cache.
- Redis Cache returns the session data to the Spring Boot App.
- Spring Boot App returns the response to the User.
- App Startup deploys the Database.
- Canary Deployment spins up new pods.
- Rollback triggers a Canary Deployment.
- Canary Deployment deploys the previous stable Docker image.
- Canary Deployment reverts database changes.
- Promote deploys to all pods.
- Monitoring alerts the Ops Team.
- Ops Team fixes issues.
- Rollback/Canary Deployment deploys the fix.
- New Pods verifies the fix.
- Monitoring verifies the fix.
graph LR
A[User] -->|Sends Request| B[Load Balancer]
B -->|Routes Request| C[Kubernetes Service]
C -->|Routes to Pod| D[Spring Boot App]
D -->|Queries| E[Database]
E -->|Returns Data| D
D -->|Checks| F[Feature Flag]
F -->|Returns Flag Status| D
D -->|Checks| G[Redis Cache]
G -->|Returns Session Data| D
D -->|Returns Response| A
H[App Startup] -->|Deploys Database| E
I[Canary Deployment] -->|Spins Up New Pods| C
J[Rollback] -->|Triggers Canary Deployment| K[Canary Deployment]
K -->|Deploys Previous Stable Docker Image| L[New Pods]
K -->|Reverts Database Changes| M[Database Deployment]
N[Promote] -->|Deploys to All Pods| C
O[Monitoring] -->|Alerts| P[Ops Team]
P -->|Fixes Issues| Q[Rollback/Canary Deployment]
Q -->|Deploys Fix| R[New Pods]
R -->|Verifies Fix| S[Monitoring]
style A fill:#f9d,stroke:#333,stroke-width:4px
style B fill:#ccf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style C fill:#ff9,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style D fill:#9f6,stroke:#333,stroke-width:2px,stroke-dasharray: 5, 5
style E fill:#9f6,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style F fill:#cfc,stroke:#333,stroke-width:2px
style G fill:#6cf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style H fill:#f6c,stroke:#333,stroke-width:2px
style I fill:#6fc,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style J fill:#cf6,stroke:#333,stroke-width:2px
style K fill:#6cf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style L fill:#f6c,stroke:#333,stroke-width:2px
style M fill:#6fc,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style N fill:#cf6,stroke:#333,stroke-width:2px
style O fill:#6cf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style P fill:#f6c,stroke:#333,stroke-width:2px
style Q fill:#6fc,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style R fill:#cf6,stroke:#333,stroke-width:2px
style S fill:#6cf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
graph TB
A[Local Branch] -->|pull request| B((Main Branch))
B --> C{GitHub Actions Workflow}
C -->|Build| D[GitHub Artifacts/Container Registry]
C -->|Infrastructure Build| E[K8s Configuration]
D --> F{GitHub Actions Test Job}
E --> F
F -->|tests pass| G[Unit Tests]
G -->|tests pass| H[Merge to Main Branch]
H --> I[Deployment Approval]
I --> J[Canary Deployment]
J -->|monitoring| K{Decision Point}
K -->|rollback| L[Revert Commit]
K -->|promote| M[Full Deployment]
style A fill:#f9d,stroke:#333,stroke-width:4px
style B fill:#ccf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style C fill:#ff9,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style D fill:#9f6,stroke:#333,stroke-width:2px,stroke-dasharray: 5, 5
style E fill:#9f6,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style F fill:#cfc,stroke:#333,stroke-width:2px
style G fill:#6cf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style H fill:#f6c,stroke:#333,stroke-width:2px
style I fill:#6fc,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style J fill:#cf6,stroke:#333,stroke-width:2px
style K fill:#6cf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style L fill:#f6c,stroke:#333,stroke-width:2px
style M fill:#6fc,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5