pipeline { // Declarative Jenkins pipeline start agent any // Run on any available Jenkins agent environment { // Global environment variables APP_NAME = 'demo-nginx' // Application name (Docker, K8s, logs) NAMESPACE = 'demo-app' // Kubernetes namespace DOCKER_REGISTRY = 'docker.io' // Docker registry hostname DOCKER_REPO = 'vladcrypto' // Docker Hub repository / namespace GITEA_URL = 'http://gitea-http.gitea.svc.cluster.local:3000' // Internal Gitea URL GITEA_REPO = 'admin/k3s-gitops' // GitOps repository path GITEA_BRANCH = 'main' // Git branch for GitOps updates BUILD_TAG = "${env.BUILD_NUMBER}" // Jenkins build number IMAGE_TAG = "${env.BRANCH_NAME}-${env.BUILD_NUMBER}" // Image version tag } stages { // Pipeline stages definition stage('Checkout Source') { // Stage: prepare application source steps { // Steps executed in this stage echo "Checking out application source code..." // Log message sh ''' // Execute shell script cat > Dockerfile << 'EOF' # Create Dockerfile FROM nginx:1.25.3-alpine # Base Nginx Alpine image RUN echo "
Environment: Production
Version: ${IMAGE_TAG}
" > /usr/share/nginx/html/index.html # Inject build metadata into HTML COPY nginx.conf /etc/nginx/nginx.conf # Copy custom nginx configuration EXPOSE 80 # Expose HTTP port CMD ["nginx", "-g", "daemon off;"] # Run nginx in foreground EOF ''' sh ''' // Generate nginx configuration cat > nginx.conf << 'EOF' # Create nginx.conf user nginx; # Run workers as nginx user worker_processes auto; # Scale workers to CPU cores error_log /var/log/nginx/error.log warn; # Error log level and path pid /var/run/nginx.pid; # PID file location events { worker_connections 1024; } # Max connections per worker http { # HTTP configuration block include /etc/nginx/mime.types; # Load MIME types default_type application/octet-stream; # Default content type log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # Access log format access_log /var/log/nginx/access.log main; # Enable access logging sendfile on; # Enable zero-copy file transfer keepalive_timeout 65; # Keepalive timeout server { # Server definition listen 80; # Listen on port 80 server_name _; # Catch-all server location / { # Root location root /usr/share/nginx/html; # Serve static files index index.html; # Default index file } location /health { # Health check endpoint access_log off; # Disable logging for health checks return 200 "healthy\n"; # Always return HTTP 200 add_header Content-Type text/plain; # Explicit content type } } } EOF ''' } } stage('Build Docker Image') { // Stage: build Docker image steps { script { // Scripted block echo "Building Docker image: ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:${IMAGE_TAG}" // Log image name sh """ // Execute Docker build docker build \ -t ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:${IMAGE_TAG} \ // Versioned image -t ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:latest \ // Latest tag . // Build context """ echo "✅ Image built successfully!" // Success message } } } stage('Push to Registry') { // Stage: push image to registry when { branch 'main' } // Execute only on main branch steps { script { echo "Pushing image to registry..." // Log push start withCredentials([usernamePassword( // Inject Docker credentials credentialsId: 'docker-registry-credentials', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS' )]) { sh """ // Authenticate and push image echo "\${DOCKER_PASS}" | docker login ${DOCKER_REGISTRY} -u "\${DOCKER_USER}" --password-stdin // Login securely docker push ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:${IMAGE_TAG} // Push versioned image docker push ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:latest // Push latest image docker logout ${DOCKER_REGISTRY} // Logout """ } echo "✅ Image pushed successfully!" // Push success } } } stage('Update GitOps Manifests') { // Stage: update GitOps repository when { branch 'main' } // Only from main branch steps { script { echo "Updating Kubernetes manifests..." // Log GitOps update withCredentials([usernamePassword( // Inject Gitea credentials credentialsId: 'gitea-credentials', usernameVariable: 'GIT_USER', passwordVariable: 'GIT_PASS' )]) { sh """ // Clone and update manifests rm -rf k3s-gitops || true // Remove old repo git clone http://\${GIT_USER}:\${GIT_PASS}@gitea-http.gitea.svc.cluster.local:3000/admin/k3s-gitops.git // Clone repo cd k3s-gitops // Enter repo git config user.name "Jenkins" // Git author name git config user.email "jenkins@thedevops.dev" // Git author email sed -i 's|image: .*|image: ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:${IMAGE_TAG}|' apps/demo-nginx/deployment.yaml // Update image git add apps/demo-nginx/deployment.yaml // Stage change git commit -m "chore(demo-nginx): Update image to ${IMAGE_TAG}" || echo "No changes" // Commit if needed git push origin main // Push to main """ } echo "✅ Manifests updated!" // GitOps success } } } stage('Verify Deployment') { // Stage: verify Kubernetes deployment when { branch 'main' } // Only on main steps { script { echo "Verifying deployment..." // Log verification start sh """ // Check deployment status sleep 30 // Wait for rollout start kubectl rollout status deployment/${APP_NAME} -n ${NAMESPACE} --timeout=300s || true // Rollout status kubectl get pods -n ${NAMESPACE} -l app=${APP_NAME} // List pods """ echo "✅ Deployment completed!" // Verification success } } } } post { // Post-pipeline actions success { // On success echo """ // Success summary ✅ Pipeline SUCCESS! Image: ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:${IMAGE_TAG} Namespace: ${NAMESPACE} """ } failure { // On failure echo "❌ Pipeline failed!" // Failure message } always { // Always execute cleanup sh """ // Cleanup Docker artifacts docker rmi ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:${IMAGE_TAG} || true // Remove versioned image docker rmi ${DOCKER_REGISTRY}/${DOCKER_REPO}/${APP_NAME}:latest || true // Remove latest image docker stop test-${BUILD_NUMBER} 2>/dev/null || true // Stop test container docker rm test-${BUILD_NUMBER} 2>/dev/null || true // Remove test container """ cleanWs() // Clean Jenkins workspace } } }