# AWS CLI Cheat Sheet — Compute: EC2, ECS & EKS

> **Tool:** AWS CLI v2
> **Category:** Cloud CLIs
> **Verified against:** aws-cli/2.33.6, flags verified via `aws <cmd> help`, 2026-08-21
> **Official docs:** https://docs.aws.amazon.com/cli/

EC2 instance lifecycle, ECS cluster/service/task management, and EKS cluster access — the compute commands you reach for while operating or debugging running infrastructure.

## Listing and inspecting EC2 instances

```bash
aws ec2 describe-instances
aws ec2 describe-instances --instance-ids i-0123456789abcdef0
aws ec2 describe-instances --filters "Name=instance-state-name,Values=running"
aws ec2 describe-instances --query 'Reservations[].Instances[].[InstanceId,State.Name,PublicIpAddress]' --output table
```

`describe-instances` returns nested `Reservations[].Instances[]` — a single call can group multiple instances under one reservation, so most useful queries need to drill through both levels.

## Launching, starting, and stopping instances

```bash
aws ec2 run-instances \
  --image-id ami-0123456789abcdef0 \
  --instance-type t3.micro \
  --key-name my-key \
  --security-group-ids sg-0123456789abcdef0 \
  --subnet-id subnet-0123456789abcdef0 \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=my-instance}]'

aws ec2 start-instances --instance-ids i-0123456789abcdef0
aws ec2 stop-instances --instance-ids i-0123456789abcdef0
aws ec2 terminate-instances --instance-ids i-0123456789abcdef0
```

`stop-instances` preserves the instance (EBS-backed data survives, you keep paying for storage); `terminate-instances` deletes it permanently along with any EBS volumes set to delete-on-termination. Don't confuse the two in a script.

## Security groups

```bash
aws ec2 describe-security-groups --group-ids sg-0123456789abcdef0
aws ec2 describe-security-groups --filters "Name=vpc-id,Values=vpc-0123456789abcdef0"
```

## Building and managing AMIs

```bash
aws ec2 create-image --instance-id i-0123456789abcdef0 --name "my-app-2026-08-21" --no-reboot
aws ec2 describe-images --owners self --filters "Name=name,Values=my-app-*"
aws ec2 copy-image --source-image-id ami-0123456789abcdef0 --source-region us-east-1 --name "my-app-dr-copy"
aws ec2 deregister-image --image-id ami-0123456789abcdef0
```

`--no-reboot` skips the default reboot-before-snapshot step for a cleaner filesystem-consistent image — faster and non-disruptive, but only safe if the instance's disk state is already consistent (e.g. nothing mid-write). `deregister-image` removes the AMI but leaves its backing EBS snapshot behind by default; pass `--delete-associated-snapshots` to remove both together.

## Spot instances

```bash
aws ec2 describe-spot-price-history --instance-types t3.micro --product-descriptions "Linux/UNIX" --start-time 2026-08-20T00:00:00Z
aws ec2 request-spot-instances --instance-count 1 --type "persistent" --launch-specification file://spot-spec.json
aws ec2 describe-spot-instance-requests --filters "Name=state,Values=active"
aws ec2 cancel-spot-instance-requests --spot-instance-request-ids sir-0123456789abcdef0
```

`--type "persistent"` re-requests a new spot instance automatically after an interruption reclaims the previous one; `"one-time"` (the default) does not. Cancelling a spot request does *not* terminate an already-running instance from it — terminate that separately with `terminate-instances`.

## Launch templates

```bash
aws ec2 create-launch-template --launch-template-name my-template --launch-template-data '{"ImageId":"ami-0123456789abcdef0","InstanceType":"t3.micro","KeyName":"my-key"}'
aws ec2 describe-launch-templates --launch-template-names my-template
aws ec2 run-instances --launch-template LaunchTemplateName=my-template,Version='$Latest' --min-count 1 --max-count 1
```

A launch template can hold multiple versions (each `create-launch-template` call after the first adds one — use `create-launch-template-version` to add without re-specifying every field). `Version='$Latest'` and `Version='$Default'` are both valid magic values in `run-instances`, distinct from a specific version number — `$Default` only moves when you explicitly call `modify-launch-template --default-version`.

## ECS clusters, services, and tasks

```bash
aws ecs list-clusters
aws ecs describe-clusters --clusters my-cluster
aws ecs list-services --cluster my-cluster
aws ecs update-service --cluster my-cluster --service my-service --desired-count 3
aws ecs update-service --cluster my-cluster --service my-service --force-new-deployment
```

`--force-new-deployment` (no argument, a flag) is the standard way to roll a service onto new task instances without changing the task definition — useful for picking up a new container image tagged `:latest` without bumping a revision.

## ECS task inspection and one-off runs

```bash
aws ecs list-tasks --cluster my-cluster --service-name my-service
aws ecs describe-tasks --cluster my-cluster --tasks <task-arn>
aws ecs run-task --cluster my-cluster --task-definition my-task:5 --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-0123456789abcdef0],securityGroups=[sg-0123456789abcdef0],assignPublicIp=ENABLED}"
```

## Registering an ECS task definition

```bash
aws ecs register-task-definition \
  --family my-task \
  --container-definitions '[{"name":"app","image":"myrepo/app:latest","memory":512,"cpu":256}]' \
  --requires-compatibilities FARGATE \
  --network-mode awsvpc \
  --cpu "256" --memory "512"
```

## EKS cluster access and node groups

```bash
aws eks list-clusters
aws eks describe-cluster --name my-cluster
aws eks update-kubeconfig --name my-cluster --alias my-cluster    # writes/merges kubeconfig context for kubectl
aws eks list-nodegroups --cluster-name my-cluster
aws eks create-nodegroup \
  --cluster-name my-cluster --nodegroup-name workers \
  --node-role arn:aws:iam::111122223333:role/EksNodeRole \
  --subnets subnet-0123456789abcdef0 \
  --scaling-config minSize=1,maxSize=5,desiredSize=2
```

`eks update-kubeconfig` is the bridge between the AWS CLI and `kubectl` — it doesn't create anything in the cluster, it just writes an entry into your local kubeconfig so `kubectl` can authenticate against that cluster using your AWS credentials.
