DevOps Practices trong Java

1. Lý thuyết và Khái niệm Cơ bản

1.1 DevOps Principles

  • Continuous Integration (CI)
  • Continuous Delivery (CD)
  • Infrastructure as Code (IaC)
  • Monitoring và Logging
  • Automated Testing
  • Security Integration (DevSecOps)
  • Collaboration và Communication

1.2 DevOps Pipeline

  • Source Control
  • Build Automation
  • Test Automation
  • Deployment Automation
  • Infrastructure Automation
  • Monitoring và Feedback

2. Best Practices và Design Patterns

2.1 CI/CD Configuration

# .github/workflows/ci-cd.yml
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: Build with Maven
      run: mvn -B package --file pom.xml

    - name: Run Tests
      run: mvn test

    - name: Build Docker image
      run: docker build -t myapp:${{ github.sha }} .

    - name: Push to Registry
      run: |
        docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
        docker push myapp:${{ github.sha }}

2.2 Docker Configuration

# Dockerfile
FROM openjdk:17-jdk-slim

WORKDIR /app

COPY target/*.jar app.jar

EXPOSE 8080

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

3. Anti-patterns và Common Pitfalls

3.1 DevOps Anti-patterns

  • Manual Deployment Steps
  • No Version Control
  • Inconsistent Environments
  • No Automated Testing
  • Poor Monitoring
  • Lack of Documentation

3.2 Security Anti-patterns

# Bad Practice: Hardcoded Credentials
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mydb
    username: admin
    password: secretpassword  # Never hardcode passwords

# Good Practice: Use Environment Variables
spring:
  datasource:
    url: ${DB_URL}
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

4. Ví dụ Code Thực tế

4.1 Kubernetes Configuration

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-app
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: "256Mi"
            cpu: "200m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        readinessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 20

4.2 Monitoring Configuration

# prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'spring-actuator'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']

# grafana-dashboard.json
{
  "annotations": {
    "list": []
  },
  "panels": [
    {
      "title": "JVM Memory Usage",
      "type": "graph",
      "datasource": "Prometheus",
      "targets": [
        {
          "expr": "jvm_memory_used_bytes",
          "legendFormat": "{{area}}"
        }
      ]
    }
  ]
}

5. Use Cases và Scenarios

5.1 Microservices Deployment

# docker-compose.yml
version: '3.8'

services:
  api-gateway:
    build: ./api-gateway
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    depends_on:
      - service-registry

  service-registry:
    build: ./service-registry
    ports:
      - "8761:8761"

  order-service:
    build: ./order-service
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://service-registry:8761/eureka/
    depends_on:
      - service-registry
      - order-db

  order-db:
    image: postgres:13
    environment:
      - POSTGRES_DB=orderdb
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
    volumes:
      - order-data:/var/lib/postgresql/data
    secrets:
      - db_password

volumes:
  order-data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

5.2 CI/CD Pipeline

// Jenkinsfile
pipeline {
    agent any

    environment {
        DOCKER_REGISTRY = 'registry.example.com'
        APP_NAME = 'java-app'
    }

    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }

        stage('Test') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    junit '**/target/surefire-reports/*.xml'
                }
            }
        }

        stage('SonarQube Analysis') {
            steps {
                withSonarQubeEnv('SonarQube') {
                    sh 'mvn sonar:sonar'
                }
            }
        }

        stage('Build Docker Image') {
            steps {
                script {
                    docker.build("${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER}")
                }
            }
        }

        stage('Deploy to Staging') {
            when {
                branch 'develop'
            }
            steps {
                sh "kubectl apply -f k8s/staging/"
            }
        }

        stage('Deploy to Production') {
            when {
                branch 'main'
            }
            steps {
                timeout(time: 1, unit: 'HOURS') {
                    input message: 'Approve production deployment?'
                }
                sh "kubectl apply -f k8s/production/"
            }
        }
    }

    post {
        always {
            cleanWs()
        }
        success {
            slackSend channel: '#deployments',
                      color: 'good',
                      message: "Deployment successful: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
        }
        failure {
            slackSend channel: '#deployments',
                      color: 'danger',
                      message: "Deployment failed: ${env.JOB_NAME} ${env.BUILD_NUMBER}"
        }
    }
}

6. Performance Considerations

6.1 Resource Management

# kubernetes-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi

---
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-limit-range
spec:
  limits:
  - default:
      cpu: 500m
      memory: 512Mi
    defaultRequest:
      cpu: 200m
      memory: 256Mi
    type: Container

6.2 Scaling Configuration

# autoscaling.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: java-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: java-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 80
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

7. Security Considerations

7.1 Security Scanning

# security-scan.yml
name: Security Scan

on:
  push:
    branches: [ main ]
  schedule:
    - cron: '0 0 * * *'

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Run OWASP Dependency Check
      uses: dependency-check/Dependency-Check_Action@main
      with:
        project: 'MyApp'
        path: '.'
        format: 'HTML'

    - name: Run Container Scan
      uses: azure/container-scan@v0
      with:
        image-name: myapp:latest

7.2 Network Policies

# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-network-policy
spec:
  podSelector:
    matchLabels:
      app: java-app
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          role: database
    ports:
    - protocol: TCP
      port: 5432

8. Testing Strategies

8.1 Integration Testing

@SpringBootTest
public class DeploymentTest {
    @Test
    public void testDeploymentConfiguration() {
        // Test environment variables
        assertNotNull(System.getenv("DB_URL"));
        assertNotNull(System.getenv("DB_USERNAME"));

        // Test application properties
        @Value("${spring.datasource.url}")
        String dbUrl;
        assertEquals(System.getenv("DB_URL"), dbUrl);
    }
}

8.2 Infrastructure Testing

# infrastructure-test.yml
name: Infrastructure Tests

on:
  pull_request:
    paths:
      - 'terraform/**'
      - 'kubernetes/**'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1

    - name: Terraform Format
      run: terraform fmt -check

    - name: Terraform Init
      run: terraform init

    - name: Terraform Validate
      run: terraform validate

    - name: Run tfsec
      uses: aquasecurity/tfsec-action@v1.0.0

9. Monitoring và Troubleshooting

9.1 Logging Configuration

# fluentd-config.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
data:
  fluent.conf: |
    <source>
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/fluentd-containers.log.pos
      tag kubernetes.*
      read_from_head true
      <parse>
        @type json
        time_key time
        time_format %Y-%m-%dT%H:%M:%S.%NZ
      </parse>
    </source>

    <match kubernetes.**>
      @type elasticsearch
      host elasticsearch-logging
      port 9200
      logstash_format true
      logstash_prefix k8s
      <buffer>
        @type file
        path /var/log/fluentd-buffers/kubernetes.system.buffer
        flush_mode interval
        retry_type exponential_backoff
        flush_interval 5s
        retry_forever false
        retry_max_interval 30
        chunk_limit_size 2M
        queue_limit_length 8
        overflow_action block
      </buffer>
    </match>

9.2 Alerting Rules

# alerting-rules.yml
groups:
- name: JavaAppAlerts
  rules:
  - alert: HighCPUUsage
    expr: container_cpu_usage_seconds_total{container="java-app"} > 0.8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: High CPU usage detected
      description: Container {{ $labels.container }} has high CPU usage

  - alert: HighMemoryUsage
    expr: container_memory_usage_bytes{container="java-app"} > 1e9
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: High memory usage detected
      description: Container {{ $labels.container }} has high memory usage

10. References và Further Reading

10.1 DevOps Resources

  • The DevOps Handbook
  • Continuous Delivery by Jez Humble
  • Site Reliability Engineering (Google)
  • Infrastructure as Code by Kief Morris
  • The Phoenix Project

10.2 Tools và Platforms

  • Jenkins/GitHub Actions for CI/CD
  • Docker/Kubernetes for Containerization
  • Terraform for Infrastructure as Code
  • Prometheus/Grafana for Monitoring
  • ELK Stack for Logging
  • SonarQube for Code Quality