services: localstack: container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}" image: localstack/localstack ports: - "127.0.0.1:4566:4566" # LocalStack Gateway - "127.0.0.1:4510-4559:4510-4559" # external services port range - "127.0.0.1:443:443" # LocalStack HTTPS Gateway environment: # Activate LocalStack for AWS: https://docs.localstack.cloud/getting-started/auth-token/ - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:?} # required for Pro # LocalStack configuration: https://docs.localstack.cloud/references/configuration/ - DEBUG=${DEBUG:-0} - PERSISTENCE=${PERSISTENCE:-0} # Queue URLs are handed out by LocalStack and then connected to by the # cms container. The default "standard" strategy builds them on # sqs..localhost.localstack.cloud, which public DNS points at # 127.0.0.1 and which this network has no alias for — so cms would fail # to resolve its own queue. "off" keeps them on the gateway host, the # one name that resolves from the host and from inside the network. - SQS_ENDPOINT_STRATEGY=off volumes: - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack" - "/var/run/docker.sock:/var/run/docker.sock" networks: default: aliases: # Publicly this name resolves to 127.0.0.1, so the endpoint in # infrastructure/Pulumi.local.yaml works from the host; the alias # makes the same name resolve here from inside the network. - localhost.localstack.cloud # S3 Control prefixes its endpoint host with the caller's account id # — the SDK does this even for a custom endpoint — so the bucket-tag # read goes to .localhost.localstack.cloud. The public # wildcard points that at 127.0.0.1, which inside the network is the # calling container, not this one. LocalStack's account is always # 000000000000, so one more alias covers it. - 000000000000.localhost.localstack.cloud # Provisions the buckets, the Postgres instance and the IAM roles inside # LocalStack, by running infrastructure/ — the same program that deploys # production, on its "local" stack. Runs to completion before cms starts. # Equivalent to `pulumi stack select local && pulumi up` from the host. infra: image: pulumi/pulumi-go:latest working_dir: /infra entrypoint: ["/bin/sh", "-c"] # One list element on purpose: a string command is split on whitespace, and # `sh -c` would then take just the first word as its script. command: - > pulumi login file:///state && pulumi stack select local --create && pulumi up --yes --non-interactive environment: - PULUMI_CONFIG_PASSPHRASE=${PULUMI_CONFIG_PASSPHRASE:-local} - PULUMI_SKIP_UPDATE_CHECK=true - DB_PASSWORD=${DB_PASSWORD:?} volumes: - "./infrastructure:/infra" - "pulumi-state:/state" # stack state, kept out of the repo - "pulumi-home:/root/.pulumi" # provider plugins, downloaded once - "go-mod-cache:/go/pkg/mod" depends_on: localstack: condition: service_healthy develop: watch: # The program is bind-mounted, not baked into the image, so there is # nothing to rebuild — the restart is what re-runs `pulumi up`. - action: sync+restart path: ./infrastructure target: /infra ignore: - README.md cms: container_name: "${CMS_DOCKER_NAME:-cms}" build: context: ./cms dockerfile: Dockerfile ports: - "127.0.0.1:8081:8081" # JSON API + Swagger UI at /swagger/ environment: # AWS: point the SDK at LocalStack instead of the real endpoints. This # host is deliberately not "localstack": it is baked into the presigned # upload URLs this service hands out, so it has to resolve for whoever # PUTs the file — on the host as well as inside this network. - AWS_REGION=${AWS_REGION:-us-east-1} - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-test} - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-test} - AWS_ENDPOINT_URL=${AWS_ENDPOINT_URL:-http://localhost.localstack.cloud:4566} # Bucket and role wiring — see main.go, which panics if any is empty. The # bucket names are pinned by the localstack branch in infrastructure/main.go. - S3_BUCKET=${S3_BUCKET:-raw-uploads-bucket} - MEDIACONVERT_INPUT_BUCKET=${MEDIACONVERT_INPUT_BUCKET:-raw-uploads-bucket} - MEDIACONVERT_OUTPUT_BUCKET=${MEDIACONVERT_OUTPUT_BUCKET:-encoded-bucket} - MEDIACONVERT_ROLE_ARN=${MEDIACONVERT_ROLE_ARN:-arn:aws:iam::000000000000:role/mediaconvert-service-role} # The queue the job-events topic fans out to, consumed for the lifetime # of the process. Pinned by the localstack branch in infrastructure/main.go; # LocalStack always uses account 000000000000. - MEDIACONVERT_EVENTS_QUEUE_URL=${MEDIACONVERT_EVENTS_QUEUE_URL:-http://localhost.localstack.cloud:4566/000000000000/cms-mediaconvert-events} # Where finished HLS output is served from. In AWS this is the CloudFront # distribution; there is none under LocalStack, so the encoded bucket is # addressed directly — path-style, for the same reason S3 is elsewhere. - PLAYBACK_BASE_URL=${PLAYBACK_BASE_URL:-http://localhost.localstack.cloud:4566/encoded-bucket} # Postgres: the RDS instance LocalStack provisions, which runs inside the # localstack container and speaks plain TCP — hence sslmode=disable. - DB_HOST=${DB_HOST:-localhost.localstack.cloud} - DB_PORT=${DB_PORT:-4510} - DB_NAME=${DB_NAME:-cms} - DB_USER=${DB_USER:-cms} - DB_PASSWORD=${DB_PASSWORD:?} - DB_SSLMODE=${DB_SSLMODE:-disable} depends_on: infra: condition: service_completed_successfully develop: watch: # cms is a compiled binary, so there is nothing useful to sync into the # running container — every change means a new image. Needs # `docker compose up --watch` (or `docker compose watch`) to take effect. - action: rebuild path: ./cms discovery: container_name: "${DISCOVERY_DOCKER_NAME:-discovery}" build: context: ./discovery dockerfile: Dockerfile ports: - "127.0.0.1:8080:8080" # JSON API + Swagger UI at /swagger/ environment: # Postgres only — discovery touches no AWS service, which is why it has # no task role in infrastructure/main.go and no AWS_* wiring here. Its # own role and database, provisioned alongside the cms ones by # newServiceDatabase, so the two services share no credentials. - DB_HOST=${DISCOVERY_DB_HOST:-localhost.localstack.cloud} - DB_PORT=${DISCOVERY_DB_PORT:-4510} - DB_NAME=${DISCOVERY_DB_NAME:-discovery} - DB_USER=${DISCOVERY_DB_USER:-discovery} - DB_PASSWORD=${DB_PASSWORD:?} - DB_SSLMODE=${DISCOVERY_DB_SSLMODE:-disable} depends_on: infra: condition: service_completed_successfully develop: watch: # Same as cms: a compiled binary, so every change means a new image. # Needs `docker compose up --watch` (or `docker compose watch`). - action: rebuild path: ./discovery volumes: pulumi-state: pulumi-home: go-mod-cache: