Przejdź do treści

🚀 Release and Deploy Recipes

Reliable release and deployment processes are crucial for delivering software consistently and safely. This recipe provides patterns for automated deployments, version management, and rollback strategies.


🎯 Core Principles

Automated Deployment Pipeline

Build repeatable, automated deployment workflows with proper validation.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
#!/bin/bash
# deployment-pipeline.sh - Structured deployment framework

# Deployment configuration
DEPLOYMENT_CONFIG_DIR="/etc/deployments"
DEPLOYMENT_LOG_DIR="/var/log/deployments"
DEPLOYMENT_STATE_DIR="/var/lib/deployments"
DEPLOYMENT_LOCK_FILE="/var/run/deployment.lock"

# Deployment states
STATE_PENDING="pending"
STATE_DEPLOYING="deploying"
STATE_VERifying="verifying"
STATE_COMPLETED="completed"
STATE_FAILED="failed"
STATE_ROLLED_BACK="rolled_back"

# Initialize deployment environment
init_deployment() {
    local deployment_name="$1"

    # Create directories
    mkdir -p "$DEPLOYMENT_LOG_DIR"
    mkdir -p "$DEPLOYMENT_STATE_DIR"

    # Set up logging
    exec 3>&1 4>&2
    exec 1>>"$DEPLOYMENT_LOG_DIR/${deployment_name}.log"
    exec 2>&1

    echo "[$(date)] Initializing deployment: $deployment_name"
}

# Deployment state management
get_deployment_state() {
    local deployment_name="$1"
    local state_file="$DEPLOYMENT_STATE_DIR/${deployment_name}.state"

    if [ -f "$state_file" ]; then
        cat "$state_file"
    else
        echo "$STATE_PENDING"
    fi
}

set_deployment_state() {
    local deployment_name="$1"
    local state="$2"
    local state_file="$DEPLOYMENT_STATE_DIR/${deployment_name}.state"

    echo "$state" > "$state_file"
    echo "[$(date)] Deployment $deployment_name state set to: $state"
}

# Lock management for concurrent execution prevention
acquire_deployment_lock() {
    local deployment_name="$1"

    if [ -f "$DEPLOYMENT_LOCK_FILE" ]; then
        local existing_lock
        existing_lock=$(cat "$DEPLOYMENT_LOCK_FILE")
        echo "[$(date)] Deployment lock held by: $existing_lock" >&2
        return 1
    fi

    echo "$deployment_name" > "$DEPLOYMENT_LOCK_FILE"
    echo "[$(date)] Acquired deployment lock for: $deployment_name"
    return 0
}

release_deployment_lock() {
    local deployment_name="$1"

    if [ -f "$DEPLOYMENT_LOCK_FILE" ]; then
        local lock_holder
        lock_holder=$(cat "$DEPLOYMENT_LOCK_FILE")

        if [ "$lock_holder" = "$deployment_name" ]; then
            rm -f "$DEPLOYMENT_LOCK_FILE"
            echo "[$(date)] Released deployment lock for: $deployment_name"
        else
            echo "[$(date)] Warning: Attempted to release lock held by $lock_holder" >&2
        fi
    fi
}

# Version management
get_current_version() {
    local service_name="$1"
    local version_file="${2:-/etc/${service_name}/VERSION}"

    if [ -f "$version_file" ]; then
        cat "$version_file"
    else
        echo "0.0.0"
    fi
}

set_current_version() {
    local service_name="$1"
    local version="$2"
    local version_file="${3:-/etc/${service_name}/VERSION}"

    echo "$version" > "$version_file"
    echo "[$(date)] Set version for $service_name to: $version"
}

🔧 Application Deployment Patterns

Container-Based Deployment

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# container-deployment.sh - Container deployment utilities

# Deploy Docker container with health checks
deploy_docker_container() {
    local service_name="$1"
    local image_name="$2"
    local tag="$3"
    local port_mapping="$4"
    local env_file="$5"

    local full_image="${image_name}:${tag}"
    local container_name="${service_name}-${tag}-$(date +%s)"

    echo "[$(date)] Deploying container: $container_name"
    echo "[$(date)] Image: $full_image"

    # Pull latest image
    if ! docker pull "$full_image"; then
        echo "[$(date)] Failed to pull image: $full_image" >&2
        return 1
    fi

    # Stop existing container if running
    if docker ps -q -f name="$service_name" | grep -q .; then
        echo "[$(date)] Stopping existing container for $service_name"
        docker stop "$service_name" 2>/dev/null || true
        docker rm "$service_name" 2>/dev/null || true
    fi

    # Run new container
    local docker_run_cmd="docker run -d --name $service_name"

    # Add port mappings
    if [ -n "$port_mapping" ]; then
        IFS=',' read -ra ports <<< "$port_mapping"
        for port in "${ports[@]}"; do
            docker_run_cmd="$docker_run_cmd -p $port"
        done
    fi

    # Add environment file
    if [ -n "$env_file" ] && [ -f "$env_file" ]; then
        docker_run_cmd="$docker_run_cmd --env-file $env_file"
    fi

    # Add health check
    docker_run_cmd="$docker_run_cmd --health-cmd='curl -f http://localhost:8080/health || exit 1' --health-interval=30s --health-timeout=10s --health-retries=3"

    # Add restart policy
    docker_run_cmd="$docker_run_cmd --restart=unless-stopped"

    # Add image
    docker_run_cmd="$docker_run_cmd $full_image"

    # Execute docker run
    if eval "$docker_run_cmd"; then
        echo "[$(date)] Container deployed successfully: $container_name"

        # Wait for container to be healthy
        if wait_for_container_healthy "$service_name" 300; then
            echo "[$(date)] Container is healthy: $service_name"
            return 0
        else
            echo "[$(date)] Container failed health check: $service_name" >&2
            docker logs "$service_name" >&2
            return 1
        fi
    else
        echo "[$(date)] Failed to deploy container: $container_name" >&2
        return 1
    fi
}

# Wait for container to become healthy
wait_for_container_healthy() {
    local container_name="$1"
    local timeout="${2:-300}"

    local count=0
    while [ $count -lt $timeout ]; do
        local status
        status=$(docker inspect --format='{{.State.Health.Status}}' "$container_name" 2>/dev/null || echo "unknown")

        case "$status" in
            healthy)
                return 0
                ;;
            unhealthy)
                return 1
                ;;
            *)
                # Still starting or unknown
                sleep 1
                count=$((count + 1))
                ;;
        esac
    done

    echo "[$(date)] Timeout waiting for container to become healthy: $container_name" >&2
    return 1
}

# Rolling update for container services
rolling_update_containers() {
    local service_name="$1"
    local image_name="$2"
    local new_tag="$3"
    local replicas="${4:-3}"
    local delay="${5:-30}"

    echo "[$(date)] Starting rolling update for $service_name"
    echo "[$(date)] New image: ${image_name}:${new_tag}"
    echo "[$(date)] Replicas: $replicas"

    # Pull new image
    if ! docker pull "${image_name}:${new_tag}"; then
        echo "[$(date)] Failed to pull new image" >&2
        return 1
    fi

    # Update containers one by one
    for i in $(seq 1 $replicas); do
        echo "[$(date)] Updating replica $i/$replicas"

        # Stop and remove current container
        if docker ps -q -f name="${service_name}-$i" | grep -q .; then
            docker stop "${service_name}-$i" 2>/dev/null || true
            docker rm "${service_name}-$i" 2>/dev/null || true
        fi

        # Start new container
        if ! docker run -d \
            --name "${service_name}-$i" \
            --health-cmd='curl -f http://localhost:8080/health || exit 1' \
            --health-interval=30s \
            --health-timeout=10s \
            --health-retries=3 \
            --restart=unless-stopped \
            -p "808$i:8080" \
            "${image_name}:${new_tag}"; then

            echo "[$(date)] Failed to start new container for replica $i" >&2
            return 1
        fi

        # Wait for container to be healthy
        if ! wait_for_container_healthy "${service_name}-$i" 120; then
            echo "[$(date)] New container failed health check for replica $i" >&2
            docker logs "${service_name}-$i" >&2
            return 1
        fi

        echo "[$(date)] Replica $i updated successfully"

        # Delay before updating next replica (unless it's the last one)
        if [ $i -lt $replicas ]; then
            echo "[$(date)] Waiting $delay seconds before updating next replica"
            sleep $delay
        fi
    done

    echo "[$(date)] Rolling update completed successfully"
    return 0
}

📦 Package-Based Deployment

System Package Deployment

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# package-deployment.sh - System package deployment utilities

# Deploy RPM/DEB packages with dependency management
deploy_system_packages() {
    local packages=("$@")

    echo "[$(date)] Deploying system packages: ${packages[*]}"

    # Detect package manager
    if command -v apt-get >/dev/null 2>&1; then
        deploy_debian_packages "${packages[@]}"
    elif command -v yum >/dev/null 2>&1; then
        deploy_redhat_packages "${packages[@]}"
    elif command -v pacman >/dev/null 2>&1; then
        deploy_arch_packages "${packages[@]}"
    else
        echo "[$(date)] Unsupported package manager" >&2
        return 1
    fi
}

deploy_debian_packages() {
    local packages=("$@")

    # Update package cache
    if ! apt-get update; then
        echo "[$(date)] Failed to update package cache" >&2
        return 1
    fi

    # Install packages with automatic dependency resolution
    if ! apt-get install -y "${packages[@]}"; then
        echo "[$(date)] Failed to install packages: ${packages[*]}" >&2
        return 1
    fi

    echo "[$(date)] Debian packages deployed successfully"
    return 0
}

deploy_redhat_packages() {
    local packages=("$@")

    # Update package cache
    if ! yum makecache; then
        echo "[$(date)] Failed to update package cache" >&2
        return 1
    fi

    # Install packages with automatic dependency resolution
    if ! yum install -y "${packages[@]}"; then
        echo "[$(date)] Failed to install packages: ${packages[*]}" >&2
        return 1
    fi

    echo "[$(date)] RedHat packages deployed successfully"
    return 0
}

deploy_arch_packages() {
    local packages=("$@")

    # Update package cache
    if ! pacman -Sy; then
        echo "[$(date)] Failed to update package cache" >&2
        return 1
    fi

    # Install packages with automatic dependency resolution
    if ! pacman -S --noconfirm "${packages[@]}"; then
        echo "[$(date)] Failed to install packages: ${packages[*]}" >&2
        return 1
    fi

    echo "[$(date)] Arch packages deployed successfully"
    return 0
}

# Deploy application packages with configuration management
deploy_application_package() {
    local package_file="$1"
    local config_dir="$2"
    local service_name="$3"

    echo "[$(date)] Deploying application package: $package_file"

    # Backup current configuration
    local backup_dir="/tmp/config_backup_$(date +%s)"
    if [ -d "$config_dir" ]; then
        echo "[$(date)] Backing up current configuration"
        cp -r "$config_dir" "$backup_dir"
    fi

    # Install package
    if [[ "$package_file" == *.deb ]]; then
        if ! dpkg -i "$package_file"; then
            echo "[$(date)] Failed to install DEB package" >&2
            # Restore configuration backup
            if [ -d "$backup_dir" ]; then
                cp -r "$backup_dir"/* "$config_dir"/
            fi
            return 1
        fi
    elif [[ "$package_file" == *.rpm ]]; then
        if ! rpm -Uvh "$package_file"; then
            echo "[$(date)] Failed to install RPM package" >&2
            # Restore configuration backup
            if [ -d "$backup_dir" ]; then
                cp -r "$backup_dir"/* "$config_dir"/
            fi
            return 1
        fi
    else
        echo "[$(date)] Unsupported package format: $package_file" >&2
        return 1
    fi

    # Post-installation configuration
    if [ -n "$config_dir" ] && [ -d "$config_dir" ]; then
        echo "[$(date)] Applying post-installation configuration"
        apply_post_install_config "$config_dir" "$service_name"
    fi

    # Start service
    if [ -n "$service_name" ]; then
        echo "[$(date)] Starting service: $service_name"
        if ! systemctl restart "$service_name"; then
            echo "[$(date)] Failed to start service: $service_name" >&2
            return 1
        fi

        # Wait for service to be ready
        if ! wait_for_service_ready "$service_name" 120; then
            echo "[$(date)] Service failed to become ready: $service_name" >&2
            return 1
        fi
    fi

    echo "[$(date)] Application package deployed successfully"
    return 0
}

# Apply post-installation configuration
apply_post_install_config() {
    local config_dir="$1"
    local service_name="$2"

    # Apply configuration templates
    find "$config_dir" -name "*.template" | while read -r template; do
        local config_file
        config_file="${template%.template}"

        echo "[$(date)] Applying configuration template: $template"

        # Process template with environment variables
        envsubst < "$template" > "$config_file"

        # Set appropriate permissions
        chmod 644 "$config_file"
    done

    # Reload service configuration
    if [ -n "$service_name" ]; then
        systemctl reload "$service_name" 2>/dev/null || true
    fi
}

# Wait for service to be ready
wait_for_service_ready() {
    local service_name="$1"
    local timeout="${2:-120}"

    local count=0
    while [ $count -lt $timeout ]; do
        if systemctl is-active --quiet "$service_name"; then
            # Service is active, check if it's responding
            if check_service_health "$service_name"; then
                return 0
            fi
        fi

        sleep 1
        count=$((count + 1))
    done

    echo "[$(date)] Timeout waiting for service to be ready: $service_name" >&2
    return 1
}

# Check service health
check_service_health() {
    local service_name="$1"

    # Check service-specific health endpoint or status
    case "$service_name" in
        nginx)
            curl -sf http://localhost/nginx_status >/dev/null 2>&1
            ;;
        postgresql)
            pg_isready >/dev/null 2>&1
            ;;
        redis)
            redis-cli ping >/dev/null 2>&1
            ;;
        *)
            # Generic health check
            systemctl is-active --quiet "$service_name"
            ;;
    esac
}

🔄 Deployment Verification

Post-Deployment Validation

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# deployment-validation.sh - Deployment verification utilities

# Comprehensive deployment verification
verify_deployment() {
    local service_name="$1"
    local expected_version="$2"

    echo "[$(date)] Starting deployment verification for: $service_name"

    local errors=()

    # Verify service is running
    if ! verify_service_running "$service_name"; then
        errors+=("Service not running")
    fi

    # Verify correct version deployed
    if [ -n "$expected_version" ]; then
        if ! verify_service_version "$service_name" "$expected_version"; then
            errors+=("Incorrect version deployed")
        fi
    fi

    # Verify service health
    if ! verify_service_health "$service_name"; then
        errors+=("Service health check failed")
    fi

    # Verify dependencies
    if ! verify_service_dependencies "$service_name"; then
        errors+=("Service dependencies not met")
    fi

    # Verify performance metrics
    if ! verify_service_performance "$service_name"; then
        errors+=("Service performance below threshold")
    fi

    # Report results
    if [ ${#errors[@]} -eq 0 ]; then
        echo "[$(date)] Deployment verification PASSED"
        return 0
    else
        echo "[$(date)] Deployment verification FAILED:" >&2
        for error in "${errors[@]}"; do
            echo "  - $error" >&2
        done
        return 1
    fi
}

# Verify service is running
verify_service_running() {
    local service_name="$1"

    if systemctl is-active --quiet "$service_name"; then
        echo "[$(date)] Service $service_name is running"
        return 0
    else
        echo "[$(date)] Service $service_name is not running" >&2
        return 1
    fi
}

# Verify service version
verify_service_version() {
    local service_name="$1"
    local expected_version="$2"

    local current_version
    current_version=$(get_current_version "$service_name")

    if [ "$current_version" = "$expected_version" ]; then
        echo "[$(date)] Service $service_name version verified: $current_version"
        return 0
    else
        echo "[$(date)] Service $service_name version mismatch. Expected: $expected_version, Actual: $current_version" >&2
        return 1
    fi
}

# Verify service health
verify_service_health() {
    local service_name="$1"

    # Service-specific health checks
    case "$service_name" in
        web-app)
            if curl -sf http://localhost:8080/health >/dev/null 2>&1; then
                echo "[$(date)] Web application health check passed"
                return 0
            else
                echo "[$(date)] Web application health check failed" >&2
                return 1
            fi
            ;;
        database)
            if pg_isready >/dev/null 2>&1; then
                echo "[$(date)] Database health check passed"
                return 0
            else
                echo "[$(date)] Database health check failed" >&2
                return 1
            fi
            ;;
        cache)
            if redis-cli ping | grep -q "PONG"; then
                echo "[$(date)] Cache health check passed"
                return 0
            else
                echo "[$(date)] Cache health check failed" >&2
                return 1
            fi
            ;;
        *)
            # Generic health check
            if systemctl is-active --quiet "$service_name"; then
                echo "[$(date)] Generic service health check passed"
                return 0
            else
                echo "[$(date)] Generic service health check failed" >&2
                return 1
            fi
            ;;
    esac
}

# Verify service dependencies
verify_service_dependencies() {
    local service_name="$1"

    # Load dependency configuration
    local deps_file="/etc/${service_name}/dependencies.conf"

    if [ ! -f "$deps_file" ]; then
        echo "[$(date)] No dependencies file found for $service_name"
        return 0
    fi

    local failed_deps=()

    while IFS='=' read -r dep_name dep_check || [ -n "$dep_name" ]; do
        if [ -n "$dep_name" ]; then
            echo "[$(date)] Checking dependency: $dep_name"

            if ! eval "$dep_check"; then
                echo "[$(date)] Dependency check failed: $dep_name" >&2
                failed_deps+=("$dep_name")
            fi
        fi
    done < "$deps_file"

    if [ ${#failed_deps[@]} -eq 0 ]; then
        echo "[$(date)] All dependencies verified for $service_name"
        return 0
    else
        echo "[$(date)] Failed dependencies for $service_name: ${failed_deps[*]}" >&2
        return 1
    fi
}

# Verify service performance
verify_service_performance() {
    local service_name="$1"
    local response_time_threshold="${2:-2000}"  # milliseconds

    # Service-specific performance checks
    case "$service_name" in
        web-app)
            local response_time
            response_time=$(curl -w "%{time_total}" -o /dev/null -s http://localhost:8080/)
            response_time=$(echo "$response_time * 1000" | bc | cut -d'.' -f1)

            if [ "$response_time" -lt "$response_time_threshold" ]; then
                echo "[$(date)] Web app response time acceptable: ${response_time}ms"
                return 0
            else
                echo "[$(date)] Web app response time too slow: ${response_time}ms (threshold: ${response_time_threshold}ms)" >&2
                return 1
            fi
            ;;
        *)
            echo "[$(date)] Performance verification not implemented for $service_name"
            return 0
            ;;
    esac
}

🎨 Advanced Deployment Features

Blue-Green Deployment

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# blue-green-deployment.sh - Blue-green deployment utilities

# Perform blue-green deployment
perform_blue_green_deployment() {
    local service_name="$1"
    local new_version="$2"
    local blue_env="$3"
    local green_env="$4"
    local current_active_env="$5"

    local new_active_env
    if [ "$current_active_env" = "blue" ]; then
        new_active_env="green"
        local new_env_config="$green_env"
        local old_env_config="$blue_env"
    else
        new_active_env="blue"
        local new_env_config="$blue_env"
        local old_env_config="$green_env"
    fi

    echo "[$(date)] Starting blue-green deployment for $service_name"
    echo "[$(date)] Current active environment: $current_active_env"
    echo "[$(date)] Deploying to: $new_active_env"

    # Step 1: Deploy to inactive environment
    echo "[$(date)] Deploying new version to $new_active_env environment"
    if ! deploy_to_environment "$service_name" "$new_version" "$new_env_config"; then
        echo "[$(date)] Deployment to $new_active_env failed" >&2
        return 1
    fi

    # Step 2: Validate new environment
    echo "[$(date)] Validating $new_active_env environment"
    if ! validate_environment "$new_active_env" "$service_name" "$new_version"; then
        echo "[$(date)] Validation of $new_active_env failed" >&2
        rollback_environment "$old_env_config" "$service_name"
        return 1
    fi

    # Step 3: Switch traffic
    echo "[$(date)] Switching traffic to $new_active_env environment"
    if ! switch_traffic "$service_name" "$new_active_env"; then
        echo "[$(date)] Traffic switch failed, rolling back" >&2
        switch_traffic "$service_name" "$current_active_env"
        rollback_environment "$old_env_config" "$service_name"
        return 1
    fi

    # Step 4: Decommission old environment
    echo "[$(date)] Decommissioning $current_active_env environment"
    decommission_environment "$old_env_config" "$service_name"

    echo "[$(date)] Blue-green deployment completed successfully"
    echo "[$(date)] New active environment: $new_active_env"

    return 0
}

# Deploy to specific environment
deploy_to_environment() {
    local service_name="$1"
    local version="$2"
    local env_config="$3"

    # Source environment configuration
    if [ -f "$env_config" ]; then
        source "$env_config"
    fi

    # Deploy application
    if ! deploy_application_package "/tmp/${service_name}-${version}.deb" "/etc/$service_name" "$service_name"; then
        echo "[$(date)] Failed to deploy to environment" >&2
        return 1
    fi

    return 0
}

# Validate environment
validate_environment() {
    local environment="$1"
    local service_name="$2"
    local expected_version="$3"

    # Set environment-specific variables
    export DEPLOYMENT_ENVIRONMENT="$environment"

    # Perform validation
    if ! verify_deployment "$service_name" "$expected_version"; then
        echo "[$(date)] Environment validation failed: $environment" >&2
        return 1
    fi

    return 0
}

# Switch traffic to environment
switch_traffic() {
    local service_name="$1"
    local target_environment="$2"

    # Update load balancer configuration
    local lb_config="/etc/haproxy/haproxy.cfg"

    if [ -f "$lb_config" ]; then
        # Update backend servers
        sed -i "s/backend $service_name.*/backend $service_name-$target_environment/" "$lb_config"

        # Reload haproxy
        if ! systemctl reload haproxy; then
            echo "[$(date)] Failed to reload haproxy" >&2
            return 1
        fi
    fi

    echo "[$(date)] Traffic switched to $target_environment environment"
    return 0
}

# Rollback environment
rollback_environment() {
    local env_config="$1"
    local service_name="$2"

    echo "[$(date)] Rolling back environment using config: $env_config"

    # Deploy previous version
    if [ -f "$env_config" ]; then
        local prev_version
        prev_version=$(grep "SERVICE_VERSION=" "$env_config" | cut -d'=' -f2)

        if [ -n "$prev_version" ]; then
            deploy_to_environment "$service_name" "$prev_version" "$env_config"
        fi
    fi

    return 0
}

# Decommission environment
decommission_environment() {
    local env_config="$1"
    local service_name="$2"

    echo "[$(date)] Decommissioning environment: $env_config"

    # Stop services
    systemctl stop "$service_name-blue" 2>/dev/null || true
    systemctl stop "$service_name-green" 2>/dev/null || true

    # Clean up resources
    # Implementation depends on infrastructure (containers, VMs, etc.)

    return 0
}

🧾 Summary Best Practices

Deployment Guidelines

  1. Automated Pipelines: Use automated deployment pipelines to reduce human error
  2. Version Control: Maintain strict version control for all deployment artifacts
  3. Rollback Planning: Always have a rollback plan before deploying
  4. Gradual Rollout: Use blue-green or canary deployments for critical services
  5. Health Checks: Implement comprehensive health checks for all services
  6. Monitoring: Monitor deployments closely and have alerting in place
  7. Validation: Validate deployments with automated tests
  8. Documentation: Document deployment procedures and rollback steps
  9. Security: Follow security best practices for deployment processes
  10. Testing: Test deployments in staging environments first

Sample Deployment Configuration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# deployment-config-example.sh - Deployment configuration template

# General deployment settings
export DEPLOYMENT_TIMEOUT=3600
export HEALTH_CHECK_TIMEOUT=300
export ROLLBACK_ON_FAILURE=true

# Container deployment settings
export DOCKER_REGISTRY="registry.example.com"
export DOCKER_USERNAME="deploy-user"
export DOCKER_PASSWORD_FILE="/etc/docker/password"

# Package deployment settings
export PACKAGE_REPOSITORY="https://packages.example.com"
export PACKAGE_GPG_KEY="/etc/apt/trusted.gpg.d/example.gpg"

# Blue-green deployment settings
export BLUE_ENV_CONFIG="/etc/deploy/blue.env"
export GREEN_ENV_CONFIG="/etc/deploy/green.env"
export TRAFFIC_SWITCH_DELAY=30

# Service health check settings
export DEFAULT_HEALTH_ENDPOINT="/health"
export DEFAULT_HEALTH_PORT=8080
export HEALTH_CHECK_RETRIES=3
export HEALTH_CHECK_INTERVAL=10

🧠 Complete Deployment Script

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/bin/bash
# complete-deployment-system.sh - Production-ready deployment framework

set -euo pipefail

# Source deployment modules
source deployment-pipeline.sh
source container-deployment.sh
source package-deployment.sh
source deployment-validation.sh
source blue-green-deployment.sh

# Main deployment controller
main() {
    local deployment_type="$1"
    shift

    case "$deployment_type" in
        container)
            execute_container_deployment "$@"
            ;;
        package)
            execute_package_deployment "$@"
            ;;
        blue-green)
            execute_blue_green_deployment "$@"
            ;;
        rolling-update)
            execute_rolling_update "$@"
            ;;
        verify)
            execute_deployment_verification "$@"
            ;;
        *)
            echo "Usage: $0 {container|package|blue-green|rolling-update|verify} [options]" >&2
            return 1
            ;;
    esac
}

# Execute container deployment
execute_container_deployment() {
    local service_name="$1"
    local image_name="$2"
    local tag="$3"
    local port_mapping="$4"
    local env_file="$5"

    init_deployment "${service_name}_${tag}"

    if acquire_deployment_lock "$service_name"; then
        if deploy_docker_container "$service_name" "$image_name" "$tag" "$port_mapping" "$env_file"; then
            if verify_deployment "$service_name" "$tag"; then
                set_deployment_state "${service_name}_${tag}" "$STATE_COMPLETED"
                echo "[$(date)] Container deployment completed successfully"
            else
                set_deployment_state "${service_name}_${tag}" "$STATE_FAILED"
                echo "[$(date)] Container deployment verification failed" >&2
                release_deployment_lock "$service_name"
                return 1
            fi
        else
            set_deployment_state "${service_name}_${tag}" "$STATE_FAILED"
            echo "[$(date)] Container deployment failed" >&2
            release_deployment_lock "$service_name"
            return 1
        fi
        release_deployment_lock "$service_name"
    else
        echo "[$(date)] Deployment already in progress" >&2
        return 1
    fi
}

# Run main function
main "$@"

🧾 See Also