Possible to set AWS Elastic Beanstalk document root to EFS

amazon-efsamazon-web-serviceselastic-beanstalkjoomla

(Original asked on SuperUser, but now "on hold" – view)

I'd really like to be able to use Elastic Beanstalk to host a Joomla application. However, there are a couple of issues:

  1. Users will need to be able to upload content to the Joomla site
  2. Joomla is self updating, and I expect I will need to install more
    extensions once the initial deployment has taken place.

I know that, with a lot of hacks/tweaks, I could configure a local Joomla environment, then use that for site administration and push changes to the EB app using Git.

However, I'm leaning toward the idea of performing a single deployment to Elastic Beanstalk, and configuring the environment to serve the content from an Elastic File System. This could then be shared to any of the instances within the autoscaling group created by Elastic Beanstalk.

I know that creating and mounting an EFS to the instances within the EB can be achieved with the configuration files found here, however, although the EFS is indeed mounted, the application still appears to be served from the local drive.

Furthermore, there are official AWS instructions for deploying a WordPress site using EFS here. Upon inspection of the config files in the .ebextensions folder, I can see that the config file that mounts the EFS creates a symbolic link between the mount directory and the wp-content/uploads. This may work for a WordPress installation, but what I would like to do with Joomla is to serve the entire application from an EFS.

It seems to be that I either need a way to create a symbolic link between the application root and the mount directory, or simply to change the root directory of the application to be the mount directory itself. The problem is that I can't quite work out how to do either of these things.

Any help would be much appreciated.

Best Answer

I have gotten so far with doing this myself. I'm stuck on a couple of issues. But here is what I have:

I created a file called 01-mount-efs.config in my .ebextensions folder in the root of my app with the following content:

##########################################################
Enter your EFS File System ID into EFS_VOLUME_ID and your mount point in EFS_MOUNT_DIR
##########################################################

option_settings:
  - option_name: EFS_VOLUME_ID
    value: fs-xxxxxxxx
  - option_name: EFS_MOUNT_DIR
    value: /var/www/html/efs
##########################################################
#### Do not touch below
##########################################################
  - option_name: EFS_REGION
    value: '`{"Ref": "AWS::Region"}`'

packages:
  yum:
    nfs-utils: []
    jq: []

commands:
  01_mount:
    command: "/tmp/mount-efs.sh"

files:
  "/tmp/mount-efs.sh":
      mode: "000755"
      content : |
        #!/bin/bash

        EFS_REGION=$(/opt/elasticbeanstalk/bin/get-config environment | jq -r '.EFS_REGION')
        EFS_MOUNT_DIR=$(/opt/elasticbeanstalk/bin/get-config environment | jq -r '.EFS_MOUNT_DIR')
        EFS_VOLUME_ID=$(/opt/elasticbeanstalk/bin/get-config environment | jq -r '.EFS_VOLUME_ID')

        echo "Mounting EFS filesystem ${EFS_DNS_NAME} to directory ${EFS_MOUNT_DIR} ..."

        echo "Region is ${EFS_REGION}"

        echo 'Stopping NFS ID Mapper...'
        service rpcidmapd status &> /dev/null
        if [ $? -ne 0 ] ; then
            echo 'rpc.idmapd is already stopped!'
        else
            service rpcidmapd stop
            if [ $? -ne 0 ] ; then
                echo 'ERROR: Failed to stop NFS ID Mapper!'
                exit 1
            fi
        fi

        echo 'Checking if EFS mount directory exists...'
        if [ ! -d ${EFS_MOUNT_DIR} ]; then
            echo "Creating directory ${EFS_MOUNT_DIR} ..."
            mkdir -p ${EFS_MOUNT_DIR}
            if [ $? -ne 0 ]; then
                echo 'ERROR: Directory creation failed!'
                exit 1
            fi
            chmod 777 ${EFS_MOUNT_DIR}
            if [ $? -ne 0 ]; then
                echo 'ERROR: Permission update failed!'
                exit 1
            fi
        else
            echo "Directory ${EFS_MOUNT_DIR} already exists!"
        fi

        mountpoint -q ${EFS_MOUNT_DIR}
        if [ $? -ne 0 ]; then
            AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)
            echo "mount -t nfs4 -o nfsvers=4.1 ${AZ}.${EFS_VOLUME_ID}.efs.${EFS_REGION}.amazonaws.com:/ ${EFS_MOUNT_DIR}"
            mount -t nfs4 -o nfsvers=4.1 ${AZ}.${EFS_VOLUME_ID}.efs.${EFS_REGION}.amazonaws.com:/ ${EFS_MOUNT_DIR}
            if [ $? -ne 0 ] ; then
                echo 'ERROR: Mount command failed!'
                exit 1
            fi
        else
            echo "Directory ${EFS_MOUNT_DIR} is already a valid mountpoint!"
        fi

        echo 'EFS mount complete.'

This mounts your EFS volume to a directory called 'efs' inside the root of your app. Then in Elastic Beanstalk > Configuration > Software Configuration you need to set your Document root to '/efs'

Also in Elastic Beanstalk > Configuration > Instance you need to add 'default' to the 'EC2 security groups' make sure you leave the one that is already there just append ',default' to the end.

For me this works the first time or when I select to 'Rebuild Environment' however deploying an update I get an error when the instance tries to build and run:

mv /var/app/current /var/app/current.old

It says: Directory not empty

I think it is an issue with the mount not letting it delete /var/app/current.old

If you get past this let me know, for now I need to rebuild every time I want to deploy update.