When running a Docker container on ECS Fargate, persistent storage is often a necessity. I initially attempted to solve this by manually creating the required directory on EFS using a Lambda-backed custom resource. While this worked, it introduced unnecessary complexity. Through experimentation, I discovered a more elegant solution—using EFS access points. In this post, I'll walk through my journey, the challenges I faced, and how I ultimately simplified the setup with fewer resources and less maintenance.
Setting up EFS
When you start a container on ECS Fargate, you must define a TaskDefinition. This definition is used to start the container. Within this definition, you can define Volumes. These volumes can then be mounted in the container by specifying a mount point per container.
So far, so good! But I quickly ran into an issue. The task could not be started because the path on EFS did not yet exist. I tried to mount /my-task/data on /data in the container. However, the /my-task/data path does not exist on the EFS drive. The easy solution would be to hook it up to an EC2 instance and create the folder from there. You might think that the problem is solved, but this is not the solution to the underlying problem. As you could have read in my previous blog, I like to be able to spin up multiple versions of a stack. With this manual step in between, you can’t do that.
How about a custom resource?
We know we need to create a folder on the EFS drive. A Lambda function could do this, so I started implementing a custom resource. The idea is very simple: create a Lambda function that mounts the root of the EFS, and then the Lambda code would simply make the folder on EFS. We mark this custom resource as a dependency on the ECS Fargate service to ensure that the folder exists before we start the container and we are done.
I fully implemented this flow, and it worked perfectly. When you deploy your stack, the custom resource does its thing, and the container can be launched successfully.
Is there a better way?
When implementing the custom resource, I needed to create an access point. A Lambda function can only mount an EFS drive through an access point. This access point allows you to define a path on EFS and the user and group ID used to access this path. If you supply /my-lambda/ as the path, the function can only see the content of the my-lambda folder. This is great for protecting other paths from being accessed. From the lambda functions perspective, you don’t see the my-lambda folder you only see the content.
Why is this so important, you might ask? Well, this path is created on the EFS drive for you. I looked at the ECS documentation, and you can also use an access point for container volumes. Using the access point to define the /my-task/data, I set the uid and gid to the same ID the user executed in the container. We could run the container without the need for a custom resource, so I deleted the function from my template.
Conclusion
Experimentation often leads to better solutions. My initial approach—using a Lambda function to create the necessary EFS directory—worked but added unnecessary complexity. By leveraging EFS access points, I achieved the same result with a cleaner, more maintainable setup. This experience reinforced an important lesson: the simplest solution is often the best. When working with cloud infrastructure, it's always worth exploring built-in features before resorting to custom implementations.
Photo by Nataliya Vaitkevich
Author Of article : Joris Conijn Read full article