EC2 is the foundation many other services run on, and knowing its knobs explains most AWS compute pricing and behaviour.
An EC2 instance is a virtual machine launched from an AMI (Amazon Machine Image: a root volume snapshot plus launch settings) into a subnet of a VPC, in one Availability Zone.
Instance types read like m7g.large: family m (general purpose; c compute, r memory, t burstable, g/p GPU), generation 7, attribute g (AWS Graviton ARM; i Intel, a AMD), size large. Graviton types usually give the best price-performance if your software runs on ARM64. t types run on CPU credits and suit spiky, mostly idle workloads.
Launch settings you will always touch:
- Security groups (the firewall) and the subnet (which decides public or private).
- An instance profile (IAM role) so code gets credentials without keys.
- User data: a script that runs as root on first boot, typically to install and start your app.
- IMDSv2 required (
HttpTokens=required) to protect the metadata service.
Connect with SSM Session Manager (needs the SSM agent, preinstalled on Amazon Linux, and the AmazonSSMManagedInstanceCore policy) instead of SSH: no open port 22, no key pairs, and sessions are logged.
Lifecycle: stop keeps the EBS root volume (you stop paying for compute, not storage); terminate deletes the instance and, by default, its root volume. Data on instance store disks is lost on stop. Public IPv4 addresses are billed hourly, so avoid them where you can. Treat instances as replaceable: bake or script everything rather than hand-configuring servers.
Example
# Latest Amazon Linux 2023 AMI for ARM, from a public SSM parameter
AMI=$(aws ssm get-parameter \
--name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64 \
--query Parameter.Value --output text)
ID=$(aws ec2 run-instances --image-id "$AMI" --instance-type t4g.small \
--subnet-id subnet-0a1b2c3d --security-group-ids sg-0a1b2c3d \
--iam-instance-profile Name=ssm-core \
--metadata-options HttpTokens=required \
--user-data file://init.sh \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-1}]' \
--query 'Instances[0].InstanceId' --output text)
aws ec2 wait instance-running --instance-ids "$ID"
aws ssm start-session --target "$ID" # shell, no SSH port needed
aws ec2 stop-instances --instance-ids "$ID" # keeps EBS data
aws ec2 terminate-instances --instance-ids "$ID" # gone for goodRemember
- Instance = AMI + type + subnet + security groups + IAM role + user data
- Read type names: family, generation, processor attribute, size
- Use Session Manager instead of SSH keys and open ports
- Stop keeps EBS volumes; terminate and instance store lose data
Watch out for
- Storing important data on instance store volumes or hand-configuring a pet server you can't rebuild.