AWS for DevOps — EFS (Elastic File System)
5.5 — EFS (Elastic File System)
EFS is a shared, scalable NFS file system that multiple EC2 instances (and ECS containers) can mount simultaneously. Unlike EBS, which is attached to one instance at a time, EFS can be accessed from many instances across multiple AZs.
EBS vs EFS
| Feature | EBS | EFS |
|---|---|---|
| Type | Block storage | File storage (NFS) |
| Attach to | One instance (one AZ) | Many instances (multi-AZ) |
| Resize | Manual | Automatic (grows/shrinks) |
| Performance | Consistent IOPS | Scales with size |
| Protocol | Block device | NFSv4.1 |
| Cost | ~$0.08/GB/month (gp3) | ~$0.30/GB/month (Standard) |
| Use case | Databases, boot volumes | Shared config, web content, container storage |
When to Use EFS
- Auto Scaling Group — all instances need the same configuration files
- ECS / Fargate — persistent storage for containers
- Shared content — multiple web servers serving the same files
- Home directories — shared developer environments
Creating an EFS File System
# Create the file system
$ aws efs create-file-system \
--performance-mode generalPurpose \
--throughput-mode bursting \
--encrypted \
--tags Key=Name,Value=shared-config
{
"FileSystemId": "fs-abc123",
"LifeCycleState": "creating",
"Encrypted": true
}
# Create mount targets in each AZ (one per subnet)
$ aws efs create-mount-target \
--file-system-id fs-abc123 \
--subnet-id subnet-prv1a \
--security-groups sg-efs123
$ aws efs create-mount-target \
--file-system-id fs-abc123 \
--subnet-id subnet-prv1b \
--security-groups sg-efs123
Security Group for EFS
Allow NFS (port 2049) from your application security group:
$ aws ec2 authorize-security-group-ingress \
--group-id sg-efs123 \
--ip-permissions \
'IpProtocol=tcp,FromPort=2049,ToPort=2049,UserIdGroupPairs=[{GroupId=sg-app123}]'
Mounting EFS on EC2
# Install the EFS mount helper
$ sudo yum install -y amazon-efs-utils
# Mount using the helper (recommended — handles TLS encryption)
$ sudo mkdir /shared
$ sudo mount -t efs -o tls fs-abc123:/ /shared
# Make it persistent
$ echo 'fs-abc123:/ /shared efs _netdev,tls 0 0' | sudo tee -a /etc/fstab
EFS with ECS / Fargate
In an ECS task definition, you can mount an EFS volume:
{
"family": "web-app",
"containerDefinitions": [
{
"name": "app",
"image": "123456789012.dkr.ecr.ap-south-1.amazonaws.com/my-app:latest",
"mountPoints": [
{
"sourceVolume": "shared-data",
"containerPath": "/app/shared"
}
]
}
],
"volumes": [
{
"name": "shared-data",
"efsVolumeConfiguration": {
"fileSystemId": "fs-abc123",
"transitEncryption": "ENABLED"
}
}
]
}
EFS Storage Classes
| Class | Availability | Cost | Access |
|---|---|---|---|
| Standard | Multi-AZ | $0.30/GB | Frequent |
| Standard-IA | Multi-AZ | $0.025/GB + retrieval | Infrequent |
| One Zone | Single AZ | $0.16/GB | Frequent |
| One Zone-IA | Single AZ | $0.0133/GB + retrieval | Infrequent |
Enable lifecycle management to move files automatically:
$ aws efs put-lifecycle-configuration \
--file-system-id fs-abc123 \
--lifecycle-policies \
'TransitionToIA=AFTER_30_DAYS' \
'TransitionToPrimaryStorageClass=AFTER_1_ACCESS'
Common Mistakes
| Mistake | Why It Hurts | Fix |
|---|---|---|
| No mount target in the instance’s AZ | Mount fails | Create mount targets in all AZs |
| Security group missing port 2049 | Mount times out | Allow NFS from app SG |
| Using EFS for high-IOPS database | EFS latency is higher than EBS | Use EBS io2 for databases |
| Not enabling encryption | Data at rest is unencrypted | Always set --encrypted |
Quick Reference
| Task | Command |
|---|---|
| Create EFS | aws efs create-file-system --encrypted --tags Key=Name,Value=NAME |
| Create mount target | aws efs create-mount-target --file-system-id FS --subnet-id SUBNET --security-groups SG |
| Mount on EC2 | sudo mount -t efs -o tls FS_ID:/ /mount/point |
| Set lifecycle | aws efs put-lifecycle-configuration --file-system-id FS --lifecycle-policies ... |
| Describe EFS | aws efs describe-file-systems --file-system-id FS |
| Delete EFS | aws efs delete-file-system --file-system-id FS |
Next → Storage Exercises