UNPKG

@povio/ecs-deploy-cli

Version:

Use this tool to deploy a Docker image to ECR and ECS with CI or manually.

286 lines (210 loc) 7.61 kB
# ECS Deploy CLI Use this tool to deploy a Docker image to ECR and ECS with CI or manually. Features: - Environment and SSM credentials storage conventions - GitHub Actions pipeline example - Cross-platform (made with TypeScript/Javascript, external requirements: `git`, `docker`) Examples: - [NestJs](./examples/nestjs) Docker and Pipeline # Usage ```bash yarn add @povio/ecs-deploy-cli ``` ## Configure ### .config/${STAGE}.ecs-deploy.yaml ```yaml accountId: "000000000000" region: us-east-1 taskFamily: myapp-dev-backend serviceName: myapp-dev-backend clusterName: myapp-dev # build and upload to ecr with `ecs-deploy build backend --stage dev` build: - name: backend repoName: myapp-backend #context: ./test #dockerfile: Dockerfile platform: linux/amd64 # Docker Buildx Bake support #bakeFile: "./docker-bake.hcl" #bakeTarget: "backend" # optional: specific target environmentValues: # resolved at build time - name: RELEASE valueFrom: "func:release" - name: BUILD_TIMESTAMP valueFrom: "func:timestamp" - name: BUILD_ENV_VAR_1 value: "static value" # deploy to ecs with `ecs-deploy deploy --stage dev` taskDefinition: - name: default # resolved at deploy time, requires SSM access template: arn:aws:ssm:::parameter/myapp-dev/backend/task-definition containerDefinitions: - name: backend # name of build above or any other docker path image: backend # inserted into task definition and resolved at deploy time environmentValues: - name: DEPLOY_TIMESTAMP valueFrom: "func:timestamp" - name: TASK_ENV_VAR_1 value: "static value" # inserted into task definition and resolved at task init secrets: STAGE2: arn:aws:ssm:::parameter/myapp-dev/backend/task-definition # resolved at runtime using `ecs-deploy config backend --stage dev` configs: - name: backend destination: ./.config/myapp-dev.backend.yml # optional template, to diff the resolved data from template: values: # load config from ./.config/${stage}.backend.template.yml # and interpolate ${arn:aws:ssm..} and ${env:ENV_VALUE} values # load them onto the root - name: "@" configFrom: backend.template - name: "@" configFrom: backend.override optional: true # simple value mapping - name: database__password valueFrom: arn:aws:ssm:::parameter/myapp-dev/database/password # JSON object mapping - name: database valueFrom: arn:aws:ssm:::parameter/myapp-dev/database - name: database__host valueFrom: env:DATABASE_HOST ``` ### Example Where `configFrom: backend.template` and the config file is `.config/${stage}.backend.template.yml`: ```yaml stage: ${func:stage} release: ${func:release} database: username: myapp2 password: ${arn:aws:ssm:::parameter/myapp-dev/database/password} debug: ${env:DEBUG} ``` the output will be at the set destination, for example `./.config/myapp-dev.backend.yml`: ```yaml database: username: myapp2 password: the-password-from-ssm debug: the-value-from-the-environment ``` ## Run ```bash yarn ecs-deploy --help # Build a new image from the current git commit and push to ECR yarn ecs-deploy build <name> --stage my-stage # Push an existing image to ECR (tag of image needs to be the same as RELEASE or the git commit hash ) # yarn ecs-deploy push <name> --stage my-stage # Deploy the task definition to ECS yarn ecs-deploy deploy [name] --stage my-stage # Deploy and clean up old unused image tags older than 30 days yarn ecs-deploy deploy [name] --stage my-stage --untagUnused --days 30 # Generate a config script yarn ecs-deploy bootstrap [name] --stage my-stage ``` ## Run Options Descriptions for useful flags. Use `--help` for a comprehensive list. #### --ignoreGitChanges Use this flag while debugging the build. This might have unintended consequences - never deploy a build made using this flag. (build only) #### --skipEcrExistsCheck Speed up builds if you know the ECR image does not exist. (build only) #### --skipPush Only build the image. Useful for testing. #### --buildx Use [docker buildx](https://docs.docker.com/buildx/working-with-buildx/) to build on ARM / Apple M1. #### Docker Buildx Bake Support Enable Docker Buildx Bake by adding `bake-file` to your build configuration: ```yaml build: - name: backend repoName: myapp-backend bake-file: "./docker-bake.hcl" bake-target: "api-final" # optional: specific target, otherwise builds all ``` When `bake-file` is present, the CLI automatically: - Uses `docker buildx bake` instead of standard Docker build - Sets `--set "*.tags=<generated-tag>"` to override all image tags - Supports HCL, JSON, and YAML bake files - Optionally targets specific bake targets #### --watch In CI, wait for ecs-deploy to complete. This could take a while so set a timeout on the CI. #### --untagUnused Clean up old unused image tags from ECR repositories after deployment. This will remove tags that are older than the specified number of days (default: 30) while preserving the currently deployed image and the newly deployed image. #### --days Specify the number of days to keep image tags when using `--untagUnused`. Tags older than this number of days will be removed (default: 30). #### --untagPrefix Only untag images whose tags start with this prefix. Providing this argument overrides `build.prefix` property in config. #### untag Standalone command to untag images. ## Required AWS IAM Permissions To use all features of this CLI (build, push, deploy, untag, describe, etc.), your IAM user/role needs the following permissions: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:GetRepositoryPolicy", "ecr:DescribeRepositories", "ecr:ListImages", "ecr:DescribeImages", "ecr:BatchGetImage", "ecr:InitiateLayerUpload", "ecr:UploadLayerPart", "ecr:CompleteLayerUpload", "ecr:PutImage", "ecr:BatchDeleteImage", "ecs:DescribeServices", "ecs:UpdateService", "ecs:DescribeTaskDefinition", "ecs:RegisterTaskDefinition", "ecs:ListTasks", "ecs:DescribeTasks" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ssm:GetParameter", "ssm:GetParameters", "ssm:GetParametersByPath" ], "Resource": "*" } ] } ``` **Notes:** - You may scope `Resource` to specific ARNs for tighter security. - If you use SSM for secrets or task definitions, SSM permissions are required. ## How it works The build script builds and pushes a Docker image to ECR. The deploy script generates a ECS task definition using a template stored on SSM and deploys it to ECS. The bootstrap script generates a config script with resolved values from SSM and environment variables. <img src="./docs/arch-overview.svg"> ## Development ### Test locally Set up `./test/.config/myapp-dev.ecs-deploy.yml` with credentials to do a E2E test. ```bash # alias for `ecs-deploy` while developing yarn start build backend --cwd ./test --stage myapp-dev yarn start bootstrap --stage myapp-dev --verbose --pwd ./test yarn test:watch ``` ### Release Set new version in `package.json`. ```bash yarn build ```