AWS Lambda: [Errno 13] Permission denied: '/tmp/ffmpeg'

0

Hi, I am trying to use moviepy in my serverless application on AWS Lambda. Since ffmpeg is used inside moviepy I am facing errors related to ffmpeg while executing the function.

  1. I have created a docker file and deployed the container image for the function. I am using M1 (arm64)- MacOS as the platform
  2. I have set the exec variable before importing moviepy, as shown below
os.environ["IMAGEIO_FFMPEG_EXE"] = "/tmp/ffmpeg"
  1. I have uploaded the ffmpeg executable to S3 and am downloading to /tmp/ffmpeg in the lambda function handler.
  2. After downloading I am changing the permissions of "/tmp/ffmpeg" to 755.
  3. Still I am getting error as shown below:
errorMessage": "[Errno 13] Permission denied: '/tmp/ffmpeg'",
  "errorType": "PermissionError",
  "stackTrace": [
    "  File \"/var/task/app.py\", line 65, in handler\n    scaledDownFilename = scaleDown(event[\"filename\"])\n",
    "  File \"/var/task/app.py\", line 40, in scaleDown\n    clip = mp.VideoFileClip(filename + \".mp4\")\n",
    "  File \"/var/task/moviepy/video/io/VideoFileClip.py\", line 88, in __init__\n    self.reader = FFMPEG_VideoReader(filename, pix_fmt=pix_fmt,\n",
    "  File \"/var/task/moviepy/video/io/ffmpeg_reader.py\", line 35, in __init__\n    infos = ffmpeg_parse_infos(filename, print_infos, check_duration,\n",
    "  File \"/var/task/moviepy/video/io/ffmpeg_reader.py\", line 257, in ffmpeg_parse_infos\n    proc = sp.Popen(cmd, **popen_params)\n",
    "  File \"/var/lang/lib/python3.8/subprocess.py\", line 858, in __init__\n    self._execute_child(args, executable, preexec_fn, close_fds,\n",
    "  File \"/var/lang/lib/python3.8/subprocess.py\", line 1704, in _execute_child\n    raise child_exception_type(errno_num, err_msg, err_filename)\n"
  ]
}

Does anyone know how to resolve this ?

asked a year ago2405 views
1 Answer
0

Hi ! Running a binary from /tmp should work in general. Probably the chmod 755 you are doing is not succeeding, so the binary is not executable when the library tries to run it.

Nevertheless, I would recommend that you install the binary directly on the container image. Amazon Linux 2, the official base of a Lambda container image, does not provide ffmpeg on its repositories, so the easiest way to get it is downloading and installing the official "Linux Static Builds" from ffmpeg website. This Dockerfile does it, using a two stage build:

FROM public.ecr.aws/lambda/python:3.9 as builder
# install helpers
RUN yum -y install tar xz

# install ffmpeg
RUN curl https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz > /tmp/ffmpeg-release.tar.xz && tar xvf /tmp/ffmpeg-release.tar.xz -C /opt && mv /opt/ffmpeg-* /opt/ffmpeg && cd /opt/ffmpeg && mv model /usr/local/share && mv ffmpeg ffprobe qt-faststart /usr/local/bin && rm /tmp/ffmpeg-release.tar.xz

FROM  public.ecr.aws/lambda/python:3.9 as app
COPY --from=builder /opt/ffmpeg /opt/ffmpeg
COPY --from=builder /usr/local/share/model /usr/local/share
COPY --from=builder /usr/local/bin/ff* /usr/local/bin
COPY --from=builder /usr/local/bin/qt-* /usr/local/bin

# install lambda function
COPY app/* ${LAMBDA_TASK_ROOT}
COPY requirements.txt .
RUN pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"

CMD [ "app.handler" ]

You mentioned that you are using an M1 Mac, so, as you probably already know, you have to build the image specifying the correct architecture:

docker build --platform linux/amd64 -t ffmpeg-lambda:latest .

The resulting image will have the binary on /usr/local/bin, which is already on the PATH environment variable.

If you want to use the AWS provided python runtime instead, you can still run the binary without any issue. Make sure you download the correct architecture depending on the function architecture and not your laptop. (I've done that error !!) If you use SAM, the following template.yaml could create the layer:

Resources:
  BinaryLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      ContentUri: binary_layer
      CompatibleRuntimes:
        - python3.9
      CompatibleArchitectures:
        - x86_64
    Metadata:
      BuildMethod: makefile

In the binary_layer subdirectory, place the ffmpeg statically linked binaries and the following Makefile:

build-BinaryLayer:
	mkdir -p "$(ARTIFACTS_DIR)/bin"
	cp ffmpeg*/ffmpeg "$(ARTIFACTS_DIR)/bin"
	chmod 755 "$(ARTIFACTS_DIR)/bin/ffmpeg"

If you merge the BinaryLayer to your function, it will provide the ffmpeg binary on /opt/bin/ffmpeg, with the correct permissions.

AWS
Alf
answered a year ago
  • Hi Alf, Thanks for your answer. Since I am using container image to load my lambda function, it will not allow me to add a layer to the function. Do you know how I could make this work using a container image ?

  • Hi Flag, It seems that ffmpeg is not included anymore on Amazon Linux 2, the official base of a lambda container image. If you are are using that, your best option then is to download the static binaries too. I'll edit my answer to add a suitable Dockerfile

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions