Reputation: 129
My goal is to build a docker image with certbot installed and use that as the container image for my AWS Lambda function. I am able to build the image successfully with docker and get it running locally with
docker build -t image-name:tag . && docker tag image-name:tag username/image-name:tag && docker push username/image-name:tag
and then to run image locally
docker run -p 9000:8080 image-name:tag
and to test the endpoint
curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
Then after the successful test I run the push commands shown on the AWS ECR repository page to get my docker image moved to ECR, and copy the ECR image URI to use as my Lambda container image URI and deploy the function.
Nothing seems to work live on AWS. I get an error from the Lambda Test console. I know that the /tmp dir is the only writable one on AWS Lambda and I am trying to use that dir for the certbot installation in my Dockerfile but it doesn't seem to be working correctly.
ERROR Error: Error: Command failed: /tmp/opt/certbot/certbot-auto --no-bootstrap --no-self-upgrade --help
/bin/sh: /tmp/opt/certbot/certbot-auto: No such file or directory
at ChildProcess.exithandler (node:child_process:402:12)
at ChildProcess.emit (node:events:513:28)
at maybeClose (node:internal/child_process:1100:16)
at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5) {
code: 127,
killed: false,
signal: null,
cmd: '/tmp/opt/certbot/certbot-auto --no-bootstrap --no-self-upgrade --help',
stdout: '',
stderr: '/bin/sh: /tmp/opt/certbot/certbot-auto: No such file or directory\n'
}
here is my Dockerfile
FROM public.ecr.aws/lambda/nodejs:16
ARG FUNCTION_DIR=${LAMBDA_TASK_ROOT}
ARG LAMBDA_TEMP_DIR=/tmp
# Install Certbot
ENV CERTBOT_DIR=""${LAMBDA_TEMP_DIR}"/opt/certbot"
ARG CERTBOT_VERSION=0.31.0
RUN mkdir -p ${CERTBOT_DIR}
RUN yum update -y && \
yum install -y git && \
git --version && \
git clone https://github.com/certbot/certbot $CERTBOT_DIR && \
if [ "${CERTBOT_VERSION}" != "latest" ]; then \
cd $CERTBOT_DIR && git checkout tags/v${CERTBOT_VERSION} ; \
fi && \
$CERTBOT_DIR/certbot-auto --no-bootstrap --no-self-upgrade --help && \
yum remove -y git && \
yum clean all && \
rm -rf /var/cache/yum/*
COPY app.js package*.json ./
RUN npm install
CMD [ "app.handler" ]
here is my app.js file with handler function
const util = require('util');
const exec = util.promisify(require('child_process').exec);
exports.handler = async (event, context) => {
try {
const tmpDirectory = '/tmp';
const { stdout: lsCommand } = await exec(`ls -lah ${tmpDirectory}`);
const lsCommandMessage = "ls command results: " + lsCommand;
const { stdout: certbotCommand } = await exec(`${tmpDirectory}/opt/certbot/certbot-auto --no-bootstrap --no-self-upgrade --help`);
const certbotCommandMessage = "certbot command results: " + certbotCommand;
const resObj = {
message: "Hello world from Docker!",
lsCommandMessage: lsCommandMessage,
certbotCommandMessage: certbotCommandMessage
};
const response = {
statusCode: 200,
body: resObj,
};
return response;
} catch (error) {
console.error('Error:', error);
}
};
Now if i were to change my app.js file with the certbot command commented out and rebuild image and repush to ecr etc everything works and I dont get error in Lambda test
const util = require('util');
const exec = util.promisify(require('child_process').exec);
exports.handler = async (event, context) => {
try {
const tmpDirectory = '/tmp';
const { stdout: lsCommand } = await exec(`ls -lah ${tmpDirectory}`);
const lsCommandMessage = "ls command results: " + lsCommand;
// const { stdout: certbotCommand } = await exec(`${tmpDirectory}/opt/certbot/certbot-auto --no-bootstrap --no-self-upgrade --help`);
// const certbotCommandMessage = "certbot command results: " + certbotCommand;
const resObj = {
message: "Hello world from Docker!",
lsCommandMessage: lsCommandMessage,
// certbotCommandMessage: certbotCommandMessage
};
const response = {
statusCode: 200,
body: resObj,
};
return response;
} catch (error) {
console.error('Error:', error);
}
};
Again again both versions of my app.js seem to work when tested on local endpoint. Version that executes certbotCommand in app.js does not work when deployed live to AWS Lambda with container image selected from private ECR repository.
Trying to figure out what is going on here or where I am messing this up. Any help would be great! Thanks in advance.
Upvotes: 1
Views: 756
Reputation: 16302
/tmp
is the location of ephemeral storage on Lambda, which means it masks anything in the container's /tmp
.
Don't use /tmp
for persistent stuff in any environment - it's purely for ephemeral stuff. Looking at your Dockerfile, there's no reason not to put your stuff somewhere else, like just /opt/certbot
for example.
Upvotes: 1