How to use Amazon EFS with EC2 containers

Dave Clark
LoyaltyLion Engineering
3 min readMay 2, 2017

--

Using EFS (Elastic File Storage) is a natural fit for ECS (EC2 Container Service) if you have any data you want to persist across containers lifetimes. Some use cases for that might be:

  • WordPress and friends with media uploads. Instead of sending them off to S3 you can just keep things simple and write them to file
  • A shared/persistent database store
  • Our particular use case: setting up Locomotive CMS, which has assets living in its file system

In principle this is an easy thing to do, but there’s a fair few steps. The basic idea: you mount an EFS volume on your ECS instance host, and then provide that as a volume for your containers.

Prepare security groups

To make life easier, we’ll set up our security groups first. Head to your VPC and create a new security group for your upcoming EFS volume. I named mine efs-docker. As for the rules, you'll want:

  • A single inbound rule for NFS (2049) . You should restrict the source as necessary; if this volume is only going to be used by containers, you should restrict it to your ECS instance security group. Otherwise you could stick in a CIDR if you'll want to access it from other instances too.
  • For outbound, delete the “ALL to ALL” rule and replace it with the same as above.

While you’re here, make sure that the security group you’re using for your ECS container instances allows outbound traffic on NFS (2049) to the above group.

Create an EFS volume

Next, head to the AWS Console and create a new EFS file system.

The first step is to create some mount targets in your VPC and subnets of choice. You’ll want to have a mount point available in all the AZs that your ECS instance hosts can live in. If you’re keeping things simple, you probably just have one subnet-per-AZ for your cluster, so just make sure that subnet gets a mount target too.

If you’ve forgotten, you can see what you picked through the AWS CLI tool, or the “Cluster resources” button in the dropdown when you’re in the cluster.

For each mount target, you can leave the IP address as “Automatic” and select the security group you made earlier.

You’ll want to give it a name and any other tags, e.g.

  • environment: production
  • name: efs-docker

Submit the form and then a short while later you should be looking a shiny new EFS store. Note that it might take a few minutes for the mount points to become available (“life cycle state”). Moving on!

Add the volume to the container instance

Alas, not as simple as attaching an EBS volume: it needs to have nfs installed and the mount point added. You could SSH in to your existing instance and do it by hand - this would be OK if you're not planning on autoscaling the host. Additionally, you could script it for any new container instances.

The simplest way to do this is add the necessary bootstrap to your EC2 container instance Launch Configuration. If you’re using the Amazon Linux AMI (optimised for ECS) you’ll only need to add a few lines to the user data:

yum install -y nfs-utils
mkdir /efs
mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 fs-xxxxxxx.efs.eu-west-1.amazonaws.com:/ /efs
service docker restart
start ecs

The fs-xxxxxx should be the DNS name shown on the EFS volume's page in the console. This address automatically resolves to the volume's mount target in the connecting instance's AZ, so it ought to be very robust.

The docker service needs to be restarted after adding the EFS volume, or it won’t be able to see it.

Use the EFS volume for container mounts

Last step! Create a new task definition within your cluster and, at the bottom, hit “Add volume”. In the pop up, give it a name like efs and in the source path, use your mount path, e.g. /efs

Next, create or edit a container definition. Under the “Storage and Logging” section you’ll be able to select “efs” from the “Source volume” dropdown. You can now add in any container paths to be persisted on your EFS volume, e.g. /srv/www/uploads or /app/public/media

And that should be about it!

--

--