0

(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.

  • BTW, you do not want to use any sort of application auto-updating with EB. Doing so will guarantee data corruption and instability in the application. – EEAA May 24 '17 at 13:55
  • I see what you're saying, but I don't understand why this is the case if I am able to serve the entire application from an EFS. – Rob Methven May 24 '17 at 14:02
  • I don't know all that much about EB, but I wonder if you'd be better off using EC2 and EFS directly for this scenario. – Tim May 24 '17 at 19:41
  • True, I'm sure that for a seasoned Linux admin, that would definitely be preferable. However, whilst I can get by well enough for development purposes, for production, I don't​ trust myself not to miss something glaringly obvious. It seems the main selling point of EB, and definitely the main draw for me personally, is that the environment is managed for me. – Rob Methven May 24 '17 at 20:03
  • Rob, EB doesn't get you out of the standard sysadmin tasks like patching, etc. If you want to be completely hands-off, use Heroku. – EEAA May 25 '17 at 0:49
0

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.

0

Let me followup on Craig's answer. What Craig implements is the option simply change the root directory of the application to be the mount directory itself, as mentioned in the question. However, this approach does not work. The redeploy fails, as flip.sh cannot move /var/app/current, because EFS is mounted inside of it. flip.sh is part of Beanstalk environment, provided by AWS.
/var/www/html used in Craig's mountpoint path is just symbolic link to /var/app/current.

I have successfully implemented the other option mentioned in the question, which is create a symbolic link between the application root and the mount directory.

The implementation:
For mounting EFS, I use config file .ebextensions/storage-efs-mountfilesystem.config, provided by AWS. In the .ebextensions/storage-efs-mountfilesystem.config, I set mountpoint as follows:
option_settings: aws:elasticbeanstalk:application:environment: MOUNT_DIRECTORY: '/efs' Then, in Beanstalk application package, I created a symbolic link:
ln -s /efs ./docroot In order to include the symbolic link in the Beanstalk application package, I created the ZIP archive with the following command:
zip --symlinks -r ../beanstalk_application.zip . --exclude=*.git* The excluded files are git repository related, as I use git to store the configuration and it is not desirable to include the git repository files in the package.

In Elastic Beanstalk > Configuration > Software Configuration the option Document root needs to be set to /docroot

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.