App-FargateStack
view release on metacpan or search on metacpan
share/README.md view on Meta::CPAN
build a web application you can start with this minimal configuration:
---
app:
name: my-web-app
domain: my-web-app.example.com
tasks:
apache:
type: https
image: my-web-app:latest
This will create an externally facing web application for you with
these resources:
- A certificate for your domain
- A Fargate cluster
- IAM roles and policies
- A listener and listener rules
- A CloudWatch log group
- Security groups
- A target group
- A task definition
- An ALB if one is not detected
Once again, launching a Fargate service requires a
lot of fiddling with AWS resources! Getting all of the plumbing
installed and working requires a lot of what and how knowledge.
## Adding or Changing Resources
Adding or updating resources for an existing application should also
be easy. Updating the infrastructure should just be a matter of
updating the configuration and re-running the framework's script. When
you update the configuration the `App::FargateStack` will detect the
changes and update the necessary resources.
Currently the framework supports adding a single SQS queue, a single
S3 bucket, volumes using EFS mount points, environment variables and
secrets from AWS Secrets Manager.
my-worker:
image: my-worker:latest
command: /usr/local/bin/my-worker.pl
type: task
schedule: cron(00 15 * * * *)
bucket:
name: my-worker-bucket
queue:
name: my-worker-queue
environment:
ENVIRONMENT=prod
secrets:
db_password:DB_PASSWORD
efs:
id: fs-abcde12355
path: /
mount_point: /mnt/my-worker
Adding new resources would normally require you to update your
policies to allow your worker to access these resource. However, the
framework automatically detects that the policy needs to be updated
when new resources are added (even secrets) and takes care of that for
you.
See `app-Fargate help configuration` for more information about
resources and options.
## Configuration as State
The framework attempts to be as transparent as possible regarding what
it is doing, how long it takes, what the result was and most
importantly _what defaults were used during resource
provisioning_. Every time the framework is run, the configuration file
is updated based on any new resources provisioned or configured. For
example, if you did not specify subnets, they are inferred by
inspecting your VPC and automatically added to the configuration file.
This gives you a single view into your Fargate application
[Back to Table of Contents](#table-of-contents)
# CLI OPTION DEFAULTS
When enabled, `App::FargateStack` automatically remembers the most recently
used values for several CLI options between runs. This feature helps streamline
repetitive workflows by eliminating the need to re-specify common arguments
such as the AWS profile, region, or config file.
The following options are tracked and persisted:
- `--profile`
- `--region`
- `--config`
- `--route53-profile`
- `--max-events`
These values are stored in `.fargatestack/defaults.json` within your current
project directory. If you omit any of these options on subsequent runs, the
most recently used value will be reused.
Typically, you would create a dedicated project directory for your
stack and place your configuration file there. Once you invoke a
command that includes any of the tracked CLI options, the
`.fargatestack/defaults.json` file will be created
automatically. Future commands run from that directory can then omit
those options. A typical workflow to create a new stack with a
scheduled job might look like this:
mkdir my-project
cd my-project
app-FargateStack create-stack foo task:my-cron image:my-project 'schedule:cron(0 10 * * * *)'
app-FargateStack plan
app-FargateStack apply
That's it...you just created a scheduled job that will run at 10 AM every day!
## Disabling and Resetting
Use the `--no-history` option to temporarily disable this feature for a single
run. This allows you to override stored values without modifying or deleting
them.
To clear all saved defaults entirely, use the `reset-history` command. This
removes all of the tracked values from the `.fargatestack/defaults.json` file,
but preserves the file itself.
## Notes
Only explicitly provided CLI options are tracked. Values derived from
environment variables or configuration files are not saved.
This feature is enabled by default.
[Back to Table of Contents](#table-of-contents)
share/README.md view on Meta::CPAN
# CLOUDWATCH LOG GROUPS
A CloudWatch log group is automatically provisioned for each
application stack. By default, the log group name is
/ecs/<application-name>, and log streams are created per task.
For example, given the following configuration:
app:
name: my-stack
...
tasks:
apache:
type: https
The framework will:
- ...create a log group named /ecs/my-stack
- ...configure the apache task to write log streams with a prefix
like my-stack/apache/\*
By default, the log group is set to retain logs for 14 days if
`retention_days` is not specified. You can override this by
specifying a custom retention period using the `retention_days` key
in the task's log\_group section:
log_group:
retention_days: 30
## Log Group Notes
- The log group is reused if it already exists.
- Only numeric values accepted by CloudWatch are valid for
retention\_days (e.g., 1, 3, 5, 7, 14, 30, 60, 90, etc.).
- You can customize the log group name by setting the name in
the `log_group:` section (not recommended).
log_group:
retention_days: 14
name: /ecs/my-stack
- You can change the retention period by updating the
configuration file and re-running `apply`.
- To retain logs indefinitely, remove the `retention_days`
entry in your configuration file.
[Back to Table of Contents](#table-of-contents)
# IAM PERMISSIONS
This framework uses a single IAM role for all tasks defined within an
application stack. The assumption is that services within the stack
share a trust boundary and operate on shared infrastructure. This
simplifies IAM management while maintaining strict isolation between
stacks.
IAM roles and policies are automatically created based on your
configuration. Only the minimum required permissions are granted.
For example, if your configuration defines an S3 bucket, the ECS task
role will be permitted to access only that specific bucket - not all
buckets in your account. The policy is updated when new resources are
added to the configuration file.
The task execution role name and role policy name are found under the
`role:` key in the configuration. The task role is found under the
`task_role:` key. Role names and role policy names are automatically
fabricated for you from the name you specified under the `app:` key.
## Task Execution Role vs. Task Role
It's important to understand that App::FargateStack provisions two
distinct IAM roles for your service. The Task Role, which is detailed
above, grants your application the specific permissions it needs to
interact with other AWS services like S3 or SQS. In addition, the
framework also creates a Task Execution Role. This second role is used
by the Amazon ECS container agent itself and grants it permission to
perform essential actions, such as pulling container images from ECR
and sending logs to CloudWatch. You typically won't need to modify the
Task Execution Role, as the framework manages its permissions
automatically.
[Back to Table of Contents](#table-of-contents)
# SECURITY GROUPS
A security group is automatically provisioned for your Fargate
cluster. If you define a task of type `http` or `https`, the
security group attached to your Application Load Balancer (ALB) is
automatically authorized for ingress to your Fargate task. This is a
rule allowing ALB-to-Fargate traffic.
[Back to Table of Contents](#table-of-contents)
# FILESYSTEM SUPPORT
EFS volumes are defined per task and mounted according to the task
definition. This design provides fine-grained control over EFS usage,
rather than treating it as a global, stack-level resource.
Each task that requires EFS support must include both a volume and
mountPoint configuration. The ECS task role is automatically updated
to allow EFS access based on your specification.
To specify EFS support in a task:
efs:
id: fs-1234567b
mount_point: /mnt/my-stack
path: /
readonly:
Acceptable values for `readonly` are "true" and "false".
## Field Descriptions
- id:
The ID of an existing EFS filesystem. The framework does not provision
the EFS, but will validate its existence in the current AWS account
and region.
- mount\_point:
The container path to which the EFS volume will be mounted.
- path:
The path on the EFS filesystem to map to your container's mount point.
- readonly:
Optional. Set to `true` to mount the EFS as read-only. Defaults to
`false`.
## Additional Notes
- The ECS role's policy for your task is automatically modified
to allow read/write EFS access. Set `readonly:` in your task's
`efs:` section to "true" if only want read support.
- Your EFS security group must allow access from private subnets
where the Fargate tasks are placed.
- No changes are made to the EFS security group; the framework
assumes access is already configured
- Only one EFS volume is currently supported per task configuration.
- EFS volumes are task-scoped and reused only where explicitly configured.
- The framework does not automatically provision an EFS
filesystem for you. The framework does however validate that the
filesystem exists in the current account and region.
[Back to Table of Contents](#table-of-contents)
# CONFIGURATION
The `App::FargateStack` framework defines your application stack
using a YAML configuration file. This file describes your
application's services, their resource needs, and how they should be
deployed. Then configuration is updated whenever your run `plan` or
`apply`.
## GETTING STARTED
The fastest way to get up and running with `App::FargateStack` is to
use the `create-stack` command to generate a configuration file,
inspect the deployment plan, and then apply it.
### Step 1: Create a Configuration Stub
First, generate a minimal YAML configuration file. The `create-stack`
command provides a shorthand syntax to do this. You only need to
provide an overall application name, a service type, a service name,
and the container image to use.
This command will create a file named `my-stack.yml` in your current
directory. Make sure you have your AWS profile configured in your
environment or pass it using the `--profile` option.
app-FargateStack create-stack my-stack daemon:my-stack-daemon image:my-stack-daemon:latest
This will produce a configuration stub that looks like this:
app:
name: my-stack
tasks:
my-stack-daemon:
image: my-stack-daemon:latest
type: daemon
This file contains the three key pieces of information you provided:
the application name, the task name, and the image to use.
### Step 2: Plan the Deployment (Dry Run)
Next, run the `plan` command. This is a crucial step that acts as a
dry run. The framework will:
- Read your minimal configuration file.
- Intelligently discover resources in your AWS account (like your VPC and subnets).
- Determine what new resources need to be created (like IAM roles, a security group, an ECS cluster and a CloudWatch log group).
- Report a full plan of action without making any actual changes.
- Update your configuration file with the discovered values and
sensible defaults.
app-FargateStack plan
After this command completes, your `my-stack.yml` file will be fully
populated with all the information needed to provision your stack.
### Step 3: Apply the Plan
Once you have reviewed the plan and are satisfied with the proposed
changes, run the `apply` command. This will execute the plan and
create all the necessary AWS resources.
app-FargateStack apply
### Step 4: Deploy and Start the Service
share/README.md view on Meta::CPAN
The configuration must specify at least two subnets in different AZs.
If subnets are not specified, the framework attempts to discover them,
but still requires at least two usable subnets (either both private or
both public). If fewer than two are available, it errors with guidance.
Notes on internet access and ALBs:
- Internet-facing ALB
An internet-facing ALB must be created in public subnets. Tasks may (and
usually should) remain in private subnets behind it.
- Egress from private subnets
For image pulls and outbound calls, use either a NAT Gateway in each AZ
or VPC endpoints for ECR (api and dkr) and S3.
- Egress from public subnets
If tasks are placed in public subnets without endpoints or NAT, they
require `assignPublicIp=ENABLED` to reach ECR/S3.
## REQUIRED SECTIONS
At minimum, your configuration must include the following:
app:
name: my-stack
tasks:
my-task:
image: my-image
type: daemon | task | http | https
For task types `http` or `https`, you must also specify a domain name:
domain: example.com
## FULL SCHEMA OVERVIEW
The framework will expand and update your configuration file with default values as needed.
Here is the full schema outline. All keys are optional unless otherwise noted:
---
account:
alb:
arn:
name:
port:
type:
app:
name: # required
version:
certificate_arn:
cluster:
arn:
name:
default_log_group:
domain: # required for http/https tasks
id:
last_updated:
region:
role:
arn:
name:
policy_name:
route53:
profile:
zone_id:
security_groups:
alb:
group_id:
group_name:
fargate:
group_id:
group_name:
subnets:
private:
public:
tasks:
my-task:
arn:
cpu:
family:
image: # required
log_group:
arn:
name:
retention_days:
memory:
name:
size:
target_group_arn:
target_group_name:
task_definition_arn:
type: # required (daemon, task, http, https)
vpc_id:
[Back to Table of Contents](#table-of-contents)
# TASK SIZE
To simplify task configuration, the framework supports a shorthand key called
`size` that maps to common CPU and memory combinations supported by Fargate.
If specified, the `size` parameter should be one of the following profile names:
tiny => 256 CPU, 512 MB memory
small => 512 CPU, 1 GB memory
medium => 1024 CPU, 2 GB memory
large => 2048 CPU, 4 GB memory
xlarge => 4096 CPU, 8 GB memory
2xlarge => 8192 CPU, 16 GB memory
When a `size` is provided, the framework will automatically populate the
corresponding `cpu` and `memory` values in the task definition. If you
manually specify `cpu` or `memory` alongside `size`, those manual values
will take precedence and override the defaults from the profile.
**Important:** If you change the `size` after an initial deployment, you should
remove any manually defined `cpu` and `memory` keys in your configuration.
share/README.md view on Meta::CPAN
If the task type is "https" and no ACM certificate currently exists
for your domain, the framework will automatically provision one. The
certificate will be created in the same region as the ALB and issued
via AWS Certificate Manager. If the certificate is validated via DNS
and subsequently attached to the listener on port 443.
## Port and Listener Rules
For external-facing apps, a separate listener on port 80 is
created. It forwards traffic to port 443 using a default redirect rule
(301). If you do not want a redirect rule, set the `redirect_80:` in
the `alb:` section to "false".
If you want your internal application to listen on a port other than
80, set the `port:` key in the `alb:` section to a new port
value.
## Example Minimal Configuration
app:
name: http-test
domain: http-test.example.com
task:
apache:
type: http
image: http-test:latest
Based on this minimal configuration `app-FargateStack` will enrich
the configuration with appropriate defaults and proceed to provision
your HTTP service.
To do that, the framework attempts to discover the resources required
for your service. If your environment is not compatible with creating
the service, the framework will report the missing resources and
abort the process.
Given this minimal configuration for an internal ("http") or
external ("https") HTTP service, discovery entails:
- ...determining your VPC's ID
- ...identifying the private subnet IDs
- ...determining if there is and existing load balancer with the
correct scheme
- ...finding your load balancer's security group (if an ALB exists)
- ...looking for a listener rule on port 80 (and 443 if type is
"https"), including a default forwarding redirect rule
- ...validating that you have a private or public hosted zone
in Route 53 that supports your domain
- ...setting other defaults for additional resources to be built (log
groups, cluster, target group, etc)
- ...determining if an ACM certificate exists for your domain
(if type is "https")
_Note: Discovery of these resources is only done when they are
missing from your configuration. If you have multiple VPCs for example
you can should explicitly set `vpc_id:` in the configuration to
identify the target VPC. Likewise you can explicitly set other
resource configurations (subnets, ALBs, Route 53, etc)._
Resources are provisioned and your configuration file is updated
incrementally as `app-FargateStack` compares your environment to the
environment required for your stack. When either plan or
apply complete your configuration is updated giving you complete
insight into what resources were found and what resources will be
provisioned. See [CONFIGURATION](https://metacpan.org/pod/CONFIGURATION) for complete details on resource
configurations.>
Your environment will be validated against the criteria described
below.
- You have at least 2 private subnets available for deployment
Technically you can launch a task with only 1 subnet but for services
behind an ALB Fargate requires 2 subnets.
_When you create a service with a load balancer, you must specify
two or more subnets in different Availability Zones. - AWS Docs_
- You have a hosted zone for your domain of the appropriate type
(private for type "http", public for type "https")
As discovery progresses, existing and required resources are logged
and your configuration file is updated. If you are **NOT** running in
dryrun mode, resources will be created immediately as they are
discovered to be missing from your environment.
## Application Load Balancer
When you provision an HTTP service, whether or not it is secure, the
service will placed behind an application load balancer. Your Fargate
service is created in private subnets, so your VPC must contain at
least two private subnets. Your load balancer can either be
_internally_ or _externally facing_.
By default, the framework looks for and will reuse a load balancer
with the correct scheme (internal or internet-facing), in a subnet
aligned with your task type. The ALB will be placed in public subnets
if it is internet-facing. You can override that behavior by either
explicitly setting the ALB arn in the `alb:` section of the
configuration or pass `--create-alb` when you run our plan and apply.
If no ALB is found or you passed the `--create-alb` option, a new ALB
is provisioned. When creating a new ALB, `app-FargateStack` will also
create the necessary listeners and listener rules for the ports you
have configured.
### Why Does the Framework Force the Use of a Load Balancer?
While it is possible to avoid the use or the creation of a load balancer
for your service, the framework forces you to use one for at least two
reasons. Firstly, the IP address of your service may not be stable and
is not friendly for development or production purposes. The framework
is, after all trying its best to promote best practices while
preventing you from having to know how all the sausage is made.
Secondly, it is almost guaranteed that you will eventually want
a domain name for your production service - whether it is an
internally facing microservice or an externally facing web
application.
Creating an alias in Route 53 for your domain pointing to the ALB
ensures you don't need to update application configurations with the
service's dynamic IP address. Additionally, using a load balancer
allows you to create custom routing rules to your service. If you want
to run multiple tasks for your service to support handling more
traffice a load balancer is required.
With those things in mind the framework automatically uses an ALB for
HTTP services and creates an alias record (A) for your domain for both
internal and external facing services.
## AWS WAF Support
For external-facing HTTPS services, `App::FargateStack` can automate
the creation and association of an AWS Web Application Firewall (WAF)
to provide an essential layer of security. This protects your
application from common web exploits and bots that could affect
availability or compromise security.
The framework follows a "Hybrid Management Model" for WAF, designed to
provide a secure, sensible baseline out-of-the-box while giving you
full control over fine-grained rule customization.
share/README.md view on Meta::CPAN
alb:
# ... existing alb configuration ...
waf:
enabled: true
### Configuring Managed Rules
To simplify configuration, `App::FargateStack` uses a keyword-based
system for enabling AWS Managed Rule Groups. You can specify a list of
keywords under the `managed_rules` key in your `waf` configuration.
If the `managed_rules` key is omitted, the framework will apply the
`default` bundle, which provides a strong and cost-effective security
baseline.
waf:
enabled: true
managed_rules: [linux-app, admin, -php]
The framework supports both individual rule sets and pre-configured
"bundles" for common application types. It also supports a subtractive
syntax (prefixing a keyword with a `-`) to remove rule sets from a
bundle.
#### Rule Set Keywords
- **base**: A strong baseline including `AWSManagedRulesCommonRuleSet`, `AWSManagedRulesAmazonIpReputationList`, and `AWSManagedRulesKnownBadInputsRuleSet`.
- **admin**: Protects exposed administrative pages (`AWSManagedRulesAdminProtectionRuleSet`).
- **sql**: Protects against SQL injection attacks (`AWSManagedRulesSQLiRuleSet`).
- **linux**: Includes rules for Linux and Unix-like environments.
- **php**: Includes rules for applications running on PHP.
- **wordpress**: Includes rules specific to WordPress sites.
- **windows**: Includes rules for Windows Server environments.
- **anonymous**: **Use with caution.** Blocks traffic from anonymous sources like VPNs and proxies, which may block legitimate users.
- **ddos**: Mitigates application-layer (Layer 7) DDoS attacks like HTTP floods.
- **premium**: **Warning: Extra Cost.** Enables advanced, paid protections for bot control and account takeover prevention.
#### Rule Bundles
- **default**: Includes `base` and `sql`. This is the recommended starting point for most applications.
- **linux-app**: Includes `default` and `linux`.
- **wordpress-app**: Includes `default`, `linux`, and `wordpress`.
- **windows-app**: Includes `default` and `windows`.
- **all**: Includes all standard, non-premium rule sets. **Warning:** This will likely exceed the default WCU quota and may incur additional costs.
### The Bootstrap Process (First Run)
On the first `apply` run with WAF enabled, the framework will perform
a one-time bootstrap:
1. It generates a default `web-acl.json` file in your project
directory. This file contains the complete definition of your Web ACL,
including the rules generated from your `managed_rules` keywords.
2. It calls `aws wafv2 create-web-acl` to create a new Web ACL.
3. It calls `aws wafv2 associate-web-acl` to link the new Web ACL to
your Application Load Balancer.
4. It updates your configuration file with the state of the new
WAF resources, including its Name, ID, ARN, LockToken, and a checksum
of the `web-acl.json` file.
5. The `waf` block in your `fargate-stack.yml` is updated to reflect
the bootstrapped state. If the `managed_rules` key was not present,
it will be added with the default value of `[default]`.
### Ongoing Management (Subsequent Runs)
After the initial creation, you take full control of the rules. To
add, remove, or modify rules, you simply edit the `web-acl.json` file
directly.
On subsequent runs of `apply`, `App::FargateStack` will:
- Calculate a checksum of your `web-acl.json` file.
- If the checksum has changed, it will safely update the remote Web ACL
with your new rule set.
- If the checksum has not changed, it will skip the update to avoid
unnecessary API calls.
This model gives you the best of both worlds: the "minimal
configuration, maximum results" of a secure default, and the full
"transparent box" control to customize your security posture as your
application's needs evolve.
### Conflict and Drift Management
The framework includes robust safety checks to prevent accidental data
loss. If it detects that the Web ACL has been modified in the AWS
Console _and_ you have also modified your local `web-acl.json` file,
it will detect the state conflict, refuse to make any changes, and
provide a clear error message with instructions on how to resolve it.
### Estimated Cost
The default WAF configuration is designed to provide a strong security
baseline while remaining cost-effective. When you enable WAF without
specifying any `managed_rules`, the framework applies the `default`
bundle, which includes the `base` and `sql` rule sets.
The approximate monthly cost for this default configuration is
**~$9.00 per month**, plus per-request charges.
The cost is broken down as follows:
- **$5.00 / month** for the Web ACL itself.
- **$4.00 / month** for the four AWS Managed Rule Groups included
in the `default` bundle (3 in 'base', 1 in 'sql').
- **$0.60 / per 1 million requests** processed by the Web ACL.
**Warning:** Enabling the `premium` rule set will incur significant
additional monthly and per-request fees for services like Bot Control
and Account Takeover Prevention. Always review the [AWS WAF
pricing](https://aws.amazon.com/waf/pricing/) page before enabling
premium features.
## Roadmap for HTTP Services
- path based routing on ALB listeners
[Back to Table of Contents](#table-of-contents)
# AUTOSCALING
share/README.md view on Meta::CPAN
- **EFS Mount Failures**: The task cannot mount an EFS volume, often due
to a misconfigured security group or incorrectly specified path.
These errors are opaque because they happen deep inside the
AWS-managed environment. The high-level ECS API only reports a generic
failure, and since it's not an API call error, it won't appear in
CloudTrail.
### The Solution: Finding the `stoppedReason`
To solve this, `App-FargateStack` provides an optional argument to
the `list-tasks` command. By default, this command only shows
`RUNNING` tasks. However, if you add the `stopped` argument, it will
show recently stopped tasks and, most importantly, the reason they
stopped.
**The Command:**
app-FargateStack list-tasks stopped
This will display a table of stopped tasks, including a `Stopped
Reason` column. This column often contains the detailed, multi-line
error message from the underlying AWS service that caused the failure,
giving you the exact information you need to debug the problem.
For example, if an EFS mount failed, the `stoppedReason` might
contain:
ResourceInitializationError: failed to invoke EFS utils
commands... mount.nfs4: mounting failed, reason given by server: No
such file or directory
This tells you immediately that the problem is with the EFS path, not
a generic "task failed" message.
## Why is my task or service still using an old image?
This is one of the most common points of confusion when working with
ECS and Fargate.
You may have just built and pushed a new image to ECR using the same
tag (e.g. `latest`), but when you launch a task or deploy a service,
ECS appears to continue using the old image. Here's why.
### One-off tasks: `run-task` uses a fixed image digest
When you run a task using:
app-FargateStack run-task my-task
ECS uses the exact task definition revision as registered. If the
image was specified using a tag like `:latest`, ECS resolves that tag
once -- at the time the task starts -- and stores the resolved digest
(e.g. `sha256:...`).
This means:
- Tasks launched this way will continue to run the old image, even if
the `latest` tag in ECR now points to a newer image.
- The only way to run a task with the new image is to register a new
task definition that references the updated image. You can force a new
task definition by registering the definition.
app-FargateStack register my-task
### Services: `create-service` and `update-service` use frozen images too
When you create or update a service, ECS also resolves any image tags
to their current digest and stores that in the registered task
definition.
This means that ECS services are also tied to the image that existed
at the time of task definition registration.
If you push a new image to ECR using the same tag (e.g. `:latest`),
the service will not automatically use it. ECS does not re-resolve
the tag unless you explicitly tell it to.
### `--force-new-deployment` re-pulls image tags (if not pinned by digest)
If your task definition references the image by tag
(e.g. `http-service:latest`), and not by digest, then running:
app-FargateStack redeploy my-service
will cause ECS to:
- Stop the currently running tasks
- Start new tasks using the same task definition revision
- Re-resolve and pull the image tag from ECR
This allows your service to pick up a newly pushed image without
registering a new task definition, as long as the task definition used
a tag (not a digest).
### Confirm what your task definition is using
To see whether your task definition uses a tag or a digest, run:
aws ecs describe-task-definition --task-definition my-task:42
Look at the `image` field under `containerDefinitions`. It will either be:
image: http-service:latest # tag -- will be re-resolved by --force-new-deployment
image: http-service@sha256:... # digest -- frozen, cannot be re-resolved
### Best practices
- Avoid using `:latest` in production. Use immutable tags
(e.g. `:v1.2.3`) or digests.
- If you want to deploy a new image, the safest and most deterministic approach is to:
- Build and push the image using a new tag or digest
- Register a new task definition revision referencing that tag or digest
- Update your service to use the new task definition
- Use `--force-new-deployment` only if your task definition uses a tag
and you want to re-resolve it without changing the task definition
itself.
[Back to Table of Contents](#table-of-contents)
( run in 0.717 second using v1.01-cache-2.11-cpan-e1769b4cff6 )