Skip to content

Multi-env CI/CD: ECR build-push + ECS deploy - #144

Open
arvsa wants to merge 3 commits into
mainfrom
feature/ec2-multi-env-cicd
Open

Multi-env CI/CD: ECR build-push + ECS deploy#144
arvsa wants to merge 3 commits into
mainfrom
feature/ec2-multi-env-cicd

Conversation

@arvsa

@arvsa arvsa commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Stacked on Migrate database engine from MySQL back to PostgreSQL #143 (Postgres migration) — this PR's task definitions reference POSTGRES_* naming, so it should merge after/into that one.
  • Build: a GitHub-hosted ubuntu-24.04-arm runner runs docker compose build backend frontend pingsvc (reusing compose.yml's own Dockerfile/context/target definitions rather than duplicating them in the workflow), then tags/pushes the results into two ECR repos as separate tags instead of one repo per service: argus-client holds backend-<sha>/frontend-<sha>/pingsvc-<sha> (a full zone needs all three), argus-server holds backend-<sha>/frontend-<sha> only (the central dashboard never runs pingsvc — see CLAUDE.md). backend/frontend are role-agnostic at runtime (ROLE/S3_BUCKET pick client vs server), so the same build lands in both repos — only argus-client's tags are actually consumed by these two workflows' deploy step since staging/production are both client-role zones; argus-server's tags are pushed for a future server deployment, not deployed by anything yet. Auth to ECR is via OIDC (AWS_DEPLOY_ROLE_ARN, no static AWS keys as secrets).
  • Deploy: fully AWS-managed ECS (EC2 launch type, reusing the existing argus-staging cluster). The deploy step renders the new image tag into a checked-in task definition (aws-actions/amazon-ecs-render-task-definition) and calls register-task-definition + update-service (aws-actions/amazon-ecs-deploy-task-definition) — no SSH, no self-hosted runner, nothing to reach into on a routine deploy.
  • Both environments run as a single ECS task with all 7 services as sidecar containers (same topology compose.yml runs locally): classic Docker links give inter-container DNS the way compose's default network does, and Traefik uses its file provider (ecs/traefik-dynamic.{staging,production}.yml) instead of the docker-label provider, since routing shouldn't require giving a container access to the host's docker.sock.
  • App secrets live in SSM Parameter Store (SecureString), read directly by the task definition's secrets blocks. Non-sensitive config (domain, environment name, CORS origins, admin email) is baked into the checked-in per-environment task-def JSON. This shrinks the GitHub Actions secrets surface for deploy down to just two: AWS_DEPLOY_ROLE_ARN and the AWS_REGION variable.
  • Adds ecs/README.md (full provisioning runbook), ecs/{staging,production}-taskdef.json, ecs/traefik-dynamic.{staging,production}.yml.
  • Rewrites deployment.md's Continuous Deployment section to match.

Test plan

  • All workflow YAML and task-definition JSON validated for syntax (yaml.safe_load / json.load)
  • Container names in both task definitions verified to match what the workflows reference (prestart, backend, frontend, pingsvc)
  • Not yet exercised against real AWS infra — first real verification is provisioning per ecs/README.md (staging first, reusing the existing argus-staging cluster, creating the argus-client/argus-server ECR repos), then confirming a push to main flows all the way through: images land in both ECR repos → task definition registers → service updates and stabilizes → https://api.staging.<domain>/api/v1/utils/health-check/ responds. Production only gets provisioned/deployed after staging is confirmed working.

🤖 Generated with Claude Code

deploy-staging.yml and deploy-production.yml now build all three service
images on a GitHub-hosted arm64 runner, push them to AWS ECR (OIDC role,
no static AWS keys), then SSH into that environment's plain EC2 box and
docker compose pull && up -d. Only the image tag/registry flow through CI
on each deploy; app secrets stay in a persistent .env bootstrapped once
per box. Removes the ecs/ directory (untracked, superseded ECS-cluster
approach) and rewrites deployment.md's CD section into a provisioning
runbook for the new flow, with an updated secrets/variables table.

No self-hosted runner install is needed anywhere anymore.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Base automatically changed from feature/postgres-migration to main July 29, 2026 00:40
Replaces the SSH-into-EC2 docker-compose deploy with ECS (EC2 launch
type, reusing the existing argus-staging cluster): CI still builds and
pushes images to ECR, but the deploy step now renders the new image tag
into a checked-in task definition and calls register-task-definition +
update-service via aws-actions/amazon-ecs-deploy-task-definition -- no
SSH, no self-hosted runner, nothing to reach into on a routine deploy.

Both environments run as a single ECS task with all 7 services as
sidecar containers (same topology compose.yml runs locally), using
classic Docker links for inter-container DNS and Traefik's file
provider (ecs/traefik-dynamic.*.yml) instead of the docker-label
provider, since routing shouldn't depend on giving a container access
to the host's docker.sock. App secrets move from a persistent .env
file to SSM Parameter Store (SecureString), referenced directly by the
task definition's `secrets` blocks -- non-sensitive config (domain,
environment name, CORS origins) is baked into the checked-in
per-environment task-def JSON instead. This shrinks the GitHub Actions
secrets surface for deploy down to just two: AWS_DEPLOY_ROLE_ARN and
the AWS_REGION variable.

Adds ecs/README.md (provisioning runbook), ecs/{staging,production}-
taskdef.json, and ecs/traefik-dynamic.{staging,production}.yml.
Rewrites deployment.md's Continuous Deployment section to match.

Not yet exercised against real AWS infra -- workflow YAML and task
definition JSON validated for syntax only, per the existing caveat
that this needs a real provisioning pass to fully verify.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@arvsa arvsa changed the title Multi-env CI/CD: ECR build-push + SSH-to-EC2 deploys Multi-env CI/CD: ECR build-push + ECS deploy Jul 29, 2026
Replaces the 3x docker/build-push-action calls (one ECR repo per
service) with a single `docker compose build` invocation -- reusing
compose.yml's own Dockerfile/context/target definitions rather than
duplicating them in the workflow -- followed by tagging/pushing into
two repos as separate tags: argus-client (backend-<sha>,
frontend-<sha>, pingsvc-<sha> -- a full zone) and argus-server
(backend-<sha>, frontend-<sha> only, since the central dashboard never
runs pingsvc). backend/frontend are role-agnostic at runtime (ROLE/
S3_BUCKET pick client vs server, see CLAUDE.md), so the same build
lands in both repos; only argus-client's tags are actually consumed by
these two workflows' ECS deploy step, since staging and production are
both client-role zones -- argus-server's tags are pushed for future use
by a server deployment, not deployed by anything yet.

Updates ecs/README.md's ECR/IAM sections and both task definitions'
placeholder image strings to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant