diff --git a/docs/layers/github-actions/github-oidc-with-aws.mdx b/docs/layers/github-actions/github-oidc-with-aws.mdx index 4b6787357..4e20355c8 100644 --- a/docs/layers/github-actions/github-oidc-with-aws.mdx +++ b/docs/layers/github-actions/github-oidc-with-aws.mdx @@ -88,10 +88,18 @@ sequenceDiagram ### Deploy GitHub OIDC Provider Component After deploying the [GitHub OIDC Provider component](/components/library/aws/github-oidc-provider/) into an account, you should see the Identity Provider in IAM in the AWS Web Console. + + Deploy this component in each account where GitHub Actions need to assume a role. + + + - Import `catalog/github-oidc-provider` in the `gbl` stack for the given account + - Deploy the `github-oidc-provider` component: `atmos terraform apply github-oidc-provider -s plat-gbl-dev` + + - ### Configure GitHub OIDC Mixin Role and Policy + ### Option 1: Configure GitHub OIDC Mixin Role and Policy Use the mixin to grant GitHub the ability to assume a role for a specific component. @@ -100,7 +108,7 @@ sequenceDiagram - ### Deploy GitHub OIDC Role Component + ### Option 2: Deploy GitHub OIDC Role Component Deploy the [GitHub OIDC Role component](/components/library/aws/github-oidc-role/) to create a generalized role for GitHub to access several resources in AWS. diff --git a/docs/layers/software-delivery/ecs-ecspresso/ecs-partial-task-definitions.mdx b/docs/layers/software-delivery/ecs-ecspresso/ecs-partial-task-definitions.mdx new file mode 100644 index 000000000..f360e0eef --- /dev/null +++ b/docs/layers/software-delivery/ecs-ecspresso/ecs-partial-task-definitions.mdx @@ -0,0 +1,221 @@ +--- +title: "ECS Partial Task Definitions" +sidebar_label: "Partial Task Definitions" +sidebar_position: 20 +--- + +import Intro from '@site/src/components/Intro'; +import Steps from '@site/src/components/Steps'; + + + This document describes what partial task definitions are and how we can use them to set up ECS services using Terraform and GitHub Actions. + + +## The Problem + +Managing ECS Services is challenging. Ideally, we want our services to be managed by Terraform so everything is living +in code. However, we also want to update the task definition via GitOps as through the GitHub release lifecycle. This is +challenging because Terraform can create the task definition, but if updated by the application repository, the task +definition will be out of sync with the Terraform state. + +Managing it entirely through Terraform means we cannot easily update the newly built image by the application repository +unless we directly commit to the infrastructure repository, which is not ideal. + +Managing it entirely through the application repository means we cannot codify the infrastructure and have to hardcode +ARNs, secrets, and other infrastructure-specific configurations. + +## Introduction + +ECS Partial task definitions is the idea of breaking the task definition into smaller parts. This allows for easier +management of the task definition and makes it easier to update the task definition. + +We do this by setting up Terraform to manage a portion of the task definition, and the application repository to manage +another portion. + +The Terraform (infrastructure) portion is created first. It will create an ECS Service in ECS, and then upload the task +definition JSON to S3 as `task-template.json`.The application repository will have a `task-definition.json` git +controlled, during the development lifecycle, the application repository will download the task definition from S3, +merge the task definitions, then update the ECS Service with the new task definition. Finally, GitHub actions will +update the S3 bucket with the deployed task definition under `task-definition.json`. If Terraform is planned again, it +will use the new task definition as the base for the next deployment, thus not resetting the image or application +configuration. + +
+ +### Pros + +The **benefit** to using this approach is that we can manage the task definition portion in Terraform with the +infrastructure, meaning secrets, volumes, and other ARNs can be managed in Terraform. If a filesystem ID updates we can +re-apply Terraform to update the task definition with the new filesystem ID. The application repository can manage the +container definitions, environment variables, and other application-specific configurations. This allows developers who +are closer to the application to quickly update the environment variables or other configuration. + +### Cons + +The drawback to this approach is that it is more complex than managing the task definition entirely in Terraform or the +application repository. It requires more setup and more moving parts. It can be confusing for a developer who is not +familiar with the setup to understand how the task definition is being managed and deployed. + +This also means that when something goes wrong, it becomes harder to troubleshoot as there are more moving parts. + +### Getting Setup + +#### Pre-requisites + +- Application Repository - [Cloud Posse Example ECS Application](https://github.com/cloudposse-examples/app-on-ecs) +- Infrastructure Repository +- ECS Cluster - [Cloud Posse Docs](https://docs.cloudposse.com/components/library/aws/ecs/) - + [Component](https://github.com/cloudposse/Terraform-aws-components/tree/main/modules/ecs). +- `ecs-service` - [Cloud Posse Docs](https://docs.cloudposse.com/components/library/aws/ecs-service/) - + [Component](https://github.com/cloudposse/Terraform-aws-components/tree/main/modules/ecs-service). + - **Must** use the Cloud Posse Component. + - [`v1.416.0`](https://github.com/cloudposse/Terraform-aws-components/releases/tag/1.416.0) or later. +- S3 Bucket - [Cloud Posse Docs](https://docs.cloudposse.com/components/library/aws/s3-bucket/) - + [Component](https://github.com/cloudposse/Terraform-aws-components/tree/main/modules/s3-bucket). + +#### Steps + + + +1. Set up the S3 Bucket that will store the task definition. + +
This bucket should be in the same account as the ECS Cluster. + +
+
+ S3 Bucket Default Definition + + ```yaml + components: + terraform: + s3-bucket/defaults: + metadata: + type: abstract + vars: + enabled: true + account_map_tenant_name: core + # Suggested configuration for all buckets + user_enabled: false + acl: "private" + grants: null + force_destroy: false + versioning_enabled: false + allow_encrypted_uploads_only: true + block_public_acls: true + block_public_policy: true + ignore_public_acls: true + restrict_public_buckets: true + allow_ssl_requests_only: true + lifecycle_configuration_rules: + - id: default + enabled: true + abort_incomplete_multipart_upload_days: 90 + filter_and: + prefix: "" + tags: {} + # Move to Glacier after 2 years + transition: + - storage_class: GLACIER + days: 730 + # Never expire + expiration: {} + # Versioning isnt enabled, but these default values are still required + noncurrent_version_transition: + - storage_class: GLACIER + days: 90 + noncurrent_version_expiration: {} + ``` + +
+ + ```yaml + import: + - catalog/s3-bucket/defaults + + components: + terraform: + s3-bucket/ecs-tasks-mirror: #NOTE this is the component instance name. + metadata: + component: s3-bucket + inherits: + - s3-bucket/defaults + vars: + enabled: true + name: ecs-tasks-mirror + ``` + +2. Create an ECS Service in Terraform + +
Set up the ECS Service in Terraform using the + [`ecs-service` component](https://github.com/cloudposse/Terraform-aws-components/tree/main/modules/ecs-service). This + will create the ECS Service and upload the task definition to the S3 bucket. + +
To enable Partial Task Definitions, set the variable `s3_mirror_name` to be the component instance name of the + bucket to mirror to. For example `s3-bucket/ecs-tasks-mirror` + + ```yaml + components: + terraform: + ecs-services/defaults: + metadata: + component: ecs-service + type: abstract + vars: + enabled: true + ecs_cluster_name: "ecs/cluster" + s3_mirror_name: s3-bucket/ecs-tasks-mirror + ``` + +3. Set up an Application repository with GitHub workflows. + + An example application repository can be found [here](https://github.com/cloudposse-examples/app-on-ecs). + +
Two things need to be pulled from this repository: + + - The `task-definition.json` file under `deploy/task-definition.json` + - The GitHub Workflows. + + An important note about the GitHub Workflows, in the example repository they all live under `.github/workflows`. This + is done so development of workflows can be fast, however we recommend moving the shared workflows to a separate + repository and calling them from the application repository. The application repository should only contain the + workflows `main-branch.yaml`, `release.yaml` and `feature-branch.yml`. + +
To enable Partial Task Definitions in the workflows, the call to + [`cloudposse/github-action-run-ecspresso` (link)](https://github.com/cloudposse-examples/app-on-ecs/blob/main/.github/workflows/workflow-cd-ecspresso.yml#L133-L147) + should have the input `mirror_to_s3_bucket` set to the S3 bucket name. the variable `use_partial_taskdefinition` + should be set to `'true'` + +
+ Example GitHub Action Step + + ```yaml + - name: Deploy + uses: cloudposse/github-action-deploy-ecspresso@0.6.0 + continue-on-error: true + if: ${{ steps.db_migrate.outcome != 'failure' }} + id: deploy + with: + image: ${{ steps.image.outputs.out }} + image-tag: ${{ inputs.tag }} + region: ${{ steps.environment.outputs.region }} + operation: deploy + debug: false + cluster: ${{ steps.environment.outputs.cluster }} + application: ${{ steps.environment.outputs.name }} + taskdef-path: ${{ inputs.path }} + mirror_to_s3_bucket: ${{ steps.environment.outputs.s3-bucket }} + use_partial_taskdefinition: "true" + timeout: 10m + ``` + +
+ +
+ +## Operation + +Changes through Terraform will not immediately be reflected in the ECS Service. This is because the task template has +been updated, but whatever was in the `task-definition.json` file in the S3 bucket will be used for deployment. + +To update the ECS Service after updating the Terraform for it, you must deploy through GitHub Actions. This will then +download the new template and create a new updated `task-defintion.json` to store in s3. diff --git a/docs/layers/software-delivery/ecs-ecspresso/setup.mdx b/docs/layers/software-delivery/ecs-ecspresso/setup.mdx index 9ee445561..147c4c414 100644 --- a/docs/layers/software-delivery/ecs-ecspresso/setup.mdx +++ b/docs/layers/software-delivery/ecs-ecspresso/setup.mdx @@ -23,7 +23,8 @@ import AtmosWorkflow from '@site/src/components/AtmosWorkflow'; | 3. Validate the environment configuration | Click Ops | | 4. Create a GitHub PAT | Click Ops | | 5. Set all Example App repository secrets | Click Ops | -| 6. Deploy the example ECS services | `atmos workflow deploy/app-on-ecs -f app-on-ecs` | +| 6. Deploy the shared ECS Task Definition S3 Bucket | `atmos apply s3-bucket/ecs-tasks-mirror -s < YOUR STACK >` | +| 7. Deploy the example ECS services | `atmos workflow deploy/app-on-ecs -f app-on-ecs` | @@ -306,6 +307,12 @@ We do not recommend keeping all shared workflows in the same repository as in th + + ### Configure the S3 Mirror Bucket, if not already configured + + If you haven't already configured the S3 mirror bucket, deploy and configure the shared S3 bucket for ECS tasks definitions now. Follow the [ECS Partial Task Definitions guide](/layers/software-delivery/ecs-ecspresso/ecs-partial-task-definitions/#steps) + + ### Deploy the Example App ECS Service @@ -368,7 +375,7 @@ We do not recommend keeping all shared workflows in the same repository as in th - Apply this component with the following: + Finally, apply the `ecs-services/example-app-on-ecs` component to deploy the Example App ECS service. diff --git a/package-lock.json b/package-lock.json index 3f666001f..8d20ec124 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6428,8 +6428,8 @@ "license": "MIT" }, "node_modules/custom-loaders": { - "resolved": "plugins/custom-loaders", - "link": true + "version": "0.0.0", + "resolved": "file:plugins/custom-loaders" }, "node_modules/cytoscape": { "version": "3.30.1", @@ -18860,9 +18860,6 @@ "type": "github", "url": "https://github.com/sponsors/wooorm" } - }, - "plugins/custom-loaders": { - "version": "0.0.0" } } } diff --git a/static/assets/ecs-partial-task-definitions.png b/static/assets/ecs-partial-task-definitions.png new file mode 100644 index 000000000..cbdfeef95 Binary files /dev/null and b/static/assets/ecs-partial-task-definitions.png differ