name: Shared - Deploy to EKS
on: workflow_call: inputs: runner: description: 'Runner type' required: false type: string default: 'ubuntu-latest' image_tag: description: 'Docker image tag to deploy' required: true type: string environment: description: 'GitHub environment (develop, prod)' required: false type: string default: 'develop' cluster_name: description: 'EKS cluster name' required: true type: string namespace: description: 'Kubernetes namespace' required: false type: string default: 'default' deployment_name: description: 'Kubernetes deployment name (defaults to repo name)' required: false type: string default: '' container_name: description: 'Container name inside the deployment (defaults to repo name)' required: false type: string default: '' container_port: description: 'Container port' required: false type: number default: 8080 replicas: description: 'Number of replicas' required: false type: number default: 1 health_check_path: description: 'Health check endpoint path' required: false type: string default: '/actuator/health' rollout_timeout: description: 'Rollout timeout (e.g., 300s, 5m)' required: false type: string default: '300s' memory_limit: description: 'Container memory limit (e.g., 512Mi, 1Gi)' required: false type: string default: '512Mi' memory_request: description: 'Container memory request (e.g., 256Mi, 512Mi)' required: false type: string default: '256Mi' cpu_limit: description: 'Container CPU limit (e.g., 500m, 1)' required: false type: string default: '500m' cpu_request: description: 'Container CPU request (e.g., 250m, 500m)' required: false type: string default: '250m'
# Helm options (alternative to kubectl) use_helm: description: 'Use Helm for deployment instead of kubectl' required: false type: boolean default: false helm_chart_path: description: 'Path to Helm chart' required: false type: string default: './helm' helm_values_file: description: 'Path to Helm values file' required: false type: string default: '' helm_set_values: description: 'Additional --set arguments (comma-separated key=value)' required: false type: string default: ''
# Extra env vars for the container container_env_vars: description: 'Environment variables as KEY=VALUE pairs (one per line)' required: false type: string default: ''
secrets: AWS_ECR_URL: required: true AWS_ACCESS_KEY_ID: required: true AWS_SECRET_ACCESS_KEY: required: true AWS_REGION: required: true
outputs: deploy_status: description: 'Deployment status' value: ${{ jobs.deploy.outputs.status }} deployed_image: description: 'Deployed image URI' value: ${{ jobs.deploy.outputs.image }}
jobs: deploy: name: Deploy to EKS runs-on: ${{ inputs.runner }} environment: ${{ inputs.environment }} timeout-minutes: 15
outputs: status: ${{ steps.deploy.outputs.status }} image: ${{ steps.setup.outputs.image_uri }}
steps: - name: Checkout uses: actions/checkout@v5
- name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ${{ secrets.AWS_REGION }}
- name: Setup deployment vars id: setup env: AWS_ECR_URL: ${{ secrets.AWS_ECR_URL }} run: | REPO_NAME="${{ github.repository }}" REPO_NAME="${REPO_NAME##*/}"
DEPLOY_NAME="${{ inputs.deployment_name }}" if [ -z "$DEPLOY_NAME" ]; then DEPLOY_NAME="$REPO_NAME" fi
CTR_NAME="${{ inputs.container_name }}" if [ -z "$CTR_NAME" ]; then CTR_NAME="$REPO_NAME" fi
IMAGE_URI="${AWS_ECR_URL}/${REPO_NAME}:${{ inputs.image_tag }}"
echo "repo_name=$REPO_NAME" >> $GITHUB_OUTPUT echo "deploy_name=$DEPLOY_NAME" >> $GITHUB_OUTPUT echo "container_name=$CTR_NAME" >> $GITHUB_OUTPUT echo "image_uri=$IMAGE_URI" >> $GITHUB_OUTPUT
- name: Update kubeconfig run: | aws eks update-kubeconfig \ --name ${{ inputs.cluster_name }} \ --region ${{ secrets.AWS_REGION }}
# ============================================ # HELM DEPLOYMENT # ============================================ - name: Deploy with Helm if: inputs.use_helm id: helm-deploy env: DEPLOY_NAME: ${{ steps.setup.outputs.deploy_name }} IMAGE_URI: ${{ steps.setup.outputs.image_uri }} run: | HELM_CMD="helm upgrade --install $DEPLOY_NAME ${{ inputs.helm_chart_path }}" HELM_CMD="$HELM_CMD --namespace ${{ inputs.namespace }} --create-namespace" HELM_CMD="$HELM_CMD --set image.repository=${IMAGE_URI%:*}" HELM_CMD="$HELM_CMD --set image.tag=${{ inputs.image_tag }}" HELM_CMD="$HELM_CMD --set replicaCount=${{ inputs.replicas }}" HELM_CMD="$HELM_CMD --wait --timeout ${{ inputs.rollout_timeout }}"
if [ -n "${{ inputs.helm_values_file }}" ]; then HELM_CMD="$HELM_CMD -f ${{ inputs.helm_values_file }}" fi
if [ -n "${{ inputs.helm_set_values }}" ]; then IFS=',' read -ra SETS <<< "${{ inputs.helm_set_values }}" for s in "${SETS[@]}"; do HELM_CMD="$HELM_CMD --set $s" done fi
echo "Running: $HELM_CMD" eval $HELM_CMD
# ============================================ # KUBECTL DEPLOYMENT # ============================================ - name: Check if deployment exists if: "!inputs.use_helm" id: check-deploy run: | if kubectl get deployment ${{ steps.setup.outputs.deploy_name }} \ -n ${{ inputs.namespace }} >/dev/null 2>&1; then echo "exists=true" >> $GITHUB_OUTPUT else echo "exists=false" >> $GITHUB_OUTPUT fi
- name: Update existing deployment if: "!inputs.use_helm && steps.check-deploy.outputs.exists == 'true'" run: | kubectl set image deployment/${{ steps.setup.outputs.deploy_name }} \ ${{ steps.setup.outputs.container_name }}=${{ steps.setup.outputs.image_uri }} \ -n ${{ inputs.namespace }}
- name: Create new deployment if: "!inputs.use_helm && steps.check-deploy.outputs.exists == 'false'" env: DEPLOY_NAME: ${{ steps.setup.outputs.deploy_name }} CTR_NAME: ${{ steps.setup.outputs.container_name }} IMAGE_URI: ${{ steps.setup.outputs.image_uri }} NAMESPACE: ${{ inputs.namespace }} CONTAINER_ENV_VARS: ${{ inputs.container_env_vars }} run: | # Build env vars YAML block ENV_YAML="" if [ -n "$CONTAINER_ENV_VARS" ]; then ENV_YAML=" env:" while IFS= read -r line; do if [ -n "$line" ]; then KEY="${line%%=*}" VALUE="${line#*=}" ENV_YAML="$ENV_YAML - name: $KEY value: \"$VALUE\"" fi done <<< "$CONTAINER_ENV_VARS" fi
cat <<MANIFEST | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: ${DEPLOY_NAME} namespace: ${NAMESPACE} labels: app: ${DEPLOY_NAME} spec: replicas: ${{ inputs.replicas }} selector: matchLabels: app: ${DEPLOY_NAME} template: metadata: labels: app: ${DEPLOY_NAME} spec: containers: - name: ${CTR_NAME} image: ${IMAGE_URI} ports: - containerPort: ${{ inputs.container_port }} resources: requests: memory: "${{ inputs.memory_request }}" cpu: "${{ inputs.cpu_request }}" limits: memory: "${{ inputs.memory_limit }}" cpu: "${{ inputs.cpu_limit }}" readinessProbe: httpGet: path: ${{ inputs.health_check_path }} port: ${{ inputs.container_port }} initialDelaySeconds: 30 periodSeconds: 10 livenessProbe: httpGet: path: ${{ inputs.health_check_path }} port: ${{ inputs.container_port }} initialDelaySeconds: 60 periodSeconds: 30 ${ENV_YAML} --- apiVersion: v1 kind: Service metadata: name: ${DEPLOY_NAME} namespace: ${NAMESPACE} spec: selector: app: ${DEPLOY_NAME} ports: - port: 80 targetPort: ${{ inputs.container_port }} type: ClusterIP MANIFEST
kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -
- name: Wait for rollout if: "!inputs.use_helm" run: | kubectl rollout status deployment/${{ steps.setup.outputs.deploy_name }} \ -n ${{ inputs.namespace }} \ --timeout=${{ inputs.rollout_timeout }}
# ============================================ # STATUS & SUMMARY # ============================================ - name: Set deploy status id: deploy if: always() run: | if kubectl get deployment ${{ steps.setup.outputs.deploy_name }} \ -n ${{ inputs.namespace }} -o jsonpath='{.status.readyReplicas}' 2>/dev/null | grep -q "[1-9]"; then echo "status=success" >> $GITHUB_OUTPUT else echo "status=failure" >> $GITHUB_OUTPUT fi
echo "### EKS Deployment" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY echo "| **Cluster** | ${{ inputs.cluster_name }} |" >> $GITHUB_STEP_SUMMARY echo "| **Namespace** | ${{ inputs.namespace }} |" >> $GITHUB_STEP_SUMMARY echo "| **Deployment** | ${{ steps.setup.outputs.deploy_name }} |" >> $GITHUB_STEP_SUMMARY echo "| **Image** | ${{ steps.setup.outputs.image_uri }} |" >> $GITHUB_STEP_SUMMARY echo "| **Replicas** | ${{ inputs.replicas }} |" >> $GITHUB_STEP_SUMMARY echo "| **Environment** | ${{ inputs.environment }} |" >> $GITHUB_STEP_SUMMARY Shared (cross-cutting)· Reusable workflow ·on: workflow_call
Shared Deploy Eks
Shared - Deploy to EKS
.github/workflows/shared-deploy-eks.yml