A CI/CD pipeline turns a reviewed change into a verifiable artifact and an observable execution. Its responsibility includes checking what is built, preserving artifact identity, and bounding how it reaches an environment. A green pipeline run does not by itself prove that product behavior is correct after deployment.
Blue-green retains the current version, blue, and prepares another, green, to receive traffic after it satisfies its conditions. It offers a route back to the previous application while that application remains compatible with shared state. Design that compatibility before the transition.
Build once and promote
The chain starts with review, tests, and validation of the change. Unit and integration tests protect different contracts; migration and compatibility tests should cover versions that will coexist. Dependency, secret, and image scans provide signals evaluated under a defined policy. A scan with no findings does not prove an absence of vulnerabilities.
Build the image and identify it by digest. A tag can move to other bytes; a digest lets deployment use the specific content that was evaluated. Promote the same image across environments and bind it to its commit, test results, and, where applicable, verifiable provenance and signatures. The container image defines packaging; environment configuration needs its own controls.
Rebuilding an image after review may introduce different dependencies while keeping the same name. Also protect the registry and retain the prior artifact through the rollback window. An immutable reference does not preserve an object that has been deleted.
Deployment identity
The deployment job can use OIDC to obtain temporary permissions, avoiding long-lived keys stored in the pipeline. Its trust policy validates the issuer, audience, and actual subject corresponding to the authorized repository or environment. GitHub’s format can vary; do not assume every repository uses a subject based only on names.
When using an environment, its protection rules should restrict which branches or tags may reach that identity. Policy should limit actions and resources to the intended environment. Build steps do not automatically need to inherit production permissions. IAM and KMS explains that identity’s boundaries and secret access.
This partial GitHub Actions YAML expresses the contract: a validated environment, a concurrency group per environment, and a reviewed image digest. id-token: write permits requesting the JWT; it grants no AWS permissions. The role and its trust policy still limit the session. Validate inputs.environment against permitted environments and replace <REVIEWED_DIGEST> with the verified digest.
concurrency:
group: deploy-${{ inputs.environment }}
cancel-in-progress: false
jobs:
deploy:
environment: ${{ inputs.environment }}
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
env:
IMAGE: "registry.example.invalid/app@sha256:<REVIEWED_DIGEST>"
steps: []Triggers, input declaration and validation, checkout, tests, build, artifact verification, OIDC role assumption, and deployment with observation are deliberately omitted. steps: [] makes clear that this is not a complete executable workflow. Concurrency limits jobs in the same group; it does not guarantee FIFO order, stopping a remote operation, or rollback.
Prepare green and switch traffic
--- config: look: handDrawn --- flowchart TD change["Reviewed change"] --> tests["Tests and security policy"] tests --> artifact["Build once<br/>Immutable image digest"] artifact --> green["Deploy green<br/>Bounded test traffic"] green --> verify["Health, compatibility and SLO checks"] verify --> switch["Traffic transition"] switch --> active["Green serves users"] blue["Blue retained for rollback"] --> switch active --> observe["Observe release window"] observe -->|"Compatible rollback"| blue blue --> shared[("Shared data and queues")] active --> shared
Green should demonstrate readiness with its dependencies, receive appropriate tests, and have capacity for expected traffic. A health endpoint may pass while the main route fails. Transition may be complete or gradual depending on the service; health checks, distribution, and routing propagation need observation.
AWS recommends native ECS blue-green in current documentation; CodeDeploy also exists in architectures using it. Their controllers and configuration are distinct paths; a CodeDeploy AppSpec does not configure the native controller. Selection should match the service’s current capabilities and constraints. This note describes the operational contract without adding a workflow or executing a deployment.
Load balancers and draining coordinate new traffic and in-flight requests. A routing change does not atomically finish existing connections. Processes need shutdown deadlines and clients capable of resolving uncertain outcomes. A timed-out write request may have committed before the transition.
Data and consumers
An expand–migrate–contract migration first adds a compatible schema, then migrates data or behavior, and finally removes the old form when it is no longer needed. Before switching traffic, blue and green should be able to read each other’s writes throughout coexistence and the rollback window.
Adding a column may be compatible; renaming or deleting the only column blue uses may prevent a return. Defaults, constraints, and semantic changes also matter. Returning to the previous digest does not undo writes or a destructive migration. Data recovery needs a separate procedure and explicit recovery objectives.
Queue consumers do not necessarily follow the HTTP switch. If both versions read the same queue, they may process messages before or after the transition. Decide which consumers are active, how they drain, which message versions they accept, and how they deduplicate effects. Duplicating processing against real systems to test green may repeat effects; testing needs isolation or a safe contract.
Rollback and failures
Rollback requires blue to retain its image, configuration, capacity, and compatibility. Define which signal triggers it, who can perform it, and how long the option remains available. Blue-green also occupies additional capacity; the cost of coexistence is part of the decision.
A canceled pipeline does not imply that a remote change stopped or rolled back. If the deployment service’s response is lost, query its state before starting another change. Concurrent releases need coordination per environment to prevent an earlier transition from removing resources needed by the next one.
Verification should simulate a healthy green version with functional errors, blue reading green’s writes, repeated messages, long connections, and interruption during the switch. Observe errors, latency, saturation, business outcomes, and backlog against criteria defined before deployment. The result is an identifiable release and a verified failure response, including the situation where returning to blue is no longer sufficient.