Continuous Integration and Continuous Deployment (CI/CD) are essential practices for modern Java development. This guide covers everything you need to know about implementing CI/CD for Java applications.
Key areas covered:
name: Java CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'
- name: Cache Maven packages
uses: actions/cache@v2
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Run Tests
run: mvn test
- name: Generate Test Report
run: mvn surefire-report:report
- name: Upload Test Results
uses: actions/upload-artifact@v2
with:
name: test-results
path: target/site/surefire-report.html
name: Quality Gates
on:
push:
branches: [ main ]
jobs:
sonarcloud:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
-Dsonar.projectKey=my-project
-Dsonar.organization=my-org
-Dsonar.java.binaries=target/classes
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
- name: Check Quality Gate
run: |
QUALITY_GATE=$(curl -s -u ${{ secrets.SONAR_TOKEN }}: \
"https://sonarcloud.io/api/qualitygates/project_status?projectKey=my-project" \
| jq -r '.projectStatus.status')
if [ "$QUALITY_GATE" != "OK" ]; then
echo "Quality Gate failed"
exit 1
fi
pipeline {
agent any
tools {
maven 'Maven 3.8.4'
jdk 'JDK 17'
}
stages {
stage('Checkout') {
steps {
git 'https://github.com/user/repo.git'
}
}
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}
stage('Code Analysis') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Deploy to Staging') {
when {
branch 'develop'
}
steps {
sh '''
docker build -t myapp:${BUILD_NUMBER} .
docker push myapp:${BUILD_NUMBER}
kubectl apply -f k8s/staging/
'''
}
}
stage('Deploy to Production') {
when {
branch 'main'
}
steps {
input 'Deploy to production?'
sh '''
docker build -t myapp:${BUILD_NUMBER} .
docker push myapp:${BUILD_NUMBER}
kubectl apply -f k8s/production/
'''
}
}
}
post {
always {
cleanWs()
}
success {
slackSend channel: '#deployments',
color: 'good',
message: "Build successful: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
}
failure {
slackSend channel: '#deployments',
color: 'danger',
message: "Build failed: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
}
}
}
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: java-app
template:
metadata:
labels:
app: java-app
spec:
containers:
- name: java-app
image: myapp:latest
ports:
- containerPort: 8080
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1"
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
name: java-app-service
namespace: production
spec:
selector:
app: java-app
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
apiVersion: v2
name: java-app
description: A Helm chart for Java application
version: 0.1.0
dependencies:
- name: postgresql
version: 11.6.3
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
values:yaml:
replicaCount: 3
image:
repository: myapp
tag: latest
pullPolicy: Always
service:
type: LoadBalancer
port: 80
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
hosts:
- host: app.example.com
paths:
- path: /
pathType: Prefix
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1
memory: 1Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'java-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['java-app:8080']
- job_name: 'jenkins'
metrics_path: '/prometheus'
static_configs:
- targets: ['jenkins:8080']
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
rule_files:
- 'alert.rules'
Implementing a robust CI/CD pipeline is crucial for modern Java applications. By following the patterns and practices outlined in this guide, you can create reliable and efficient deployment pipelines.
Remember to focus on automation, testing, monitoring, and continuous improvement of your CI/CD processes.