I am migrating from Vercel to AWS, and I'm trying to run my app with ECS using ECR.
The problem es that the environment variables defined in the ECS are not found in runtime, and if I run a query to an AWS Service, it doesn't recognize the role neither. If I set the environment variables in the github actions workflow and include RUN printenv > .env.production
before the RUN npm run build
in my Dockerfile, it does find the environment variables, and of course I do not like the solution.
My Dockerfile is something like this:
FROM node:18-alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f package-lock.json ]; then npm ci; \
elif [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ARG NODE_ENV
ENV NODE_ENV=${NODE_ENV}
ENV NEXT_TELEMETRY_DISABLED 1
RUN printenv > .env.production
RUN npm run build
FROM base AS runner
WORKDIR /app
RUN apk add --no-cache curl
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]
This solves the environment variables problem, but I couldn't find a solution for the permissions, as of course I don't want to add the access keys in this way. The error is "Could not load credentials from any providers", so is not a problem that the policy does not have a permission, it does not inherit the role from the ECS.
After a few tries, I found out that my problem was because the nextjs output was set as standalone
as nextjs documentaciones recommends. But this is for apps that are 100% statics, in my case where I use environments that are configured in ECS or where I have api routes that need to use the assume role it was useless.
I had to remove the output from next.config.js, and add more files / folders in my Dockerfile so they are copied to the container in ECR. My Dockerfile ended up looking something like this:
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f package-lock.json ]; then npm ci; \
elif [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY package*.json ./
ARG NODE_ENV
ENV NODE_ENV=${NODE_ENV}
ENV NEXT_TELEMETRY_DISABLED 1
RUN yarn install
RUN yarn build
FROM base AS runner
WORKDIR /app
RUN apk add --no-cache curl
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
RUN mkdir .next
RUN chown nextjs:nodejs .next
#Copy all necessary files for runtime, including configurations
COPY --from=builder --chown=nextjs:nodejs /app/next.config.js ./next.config.js
COPY --from=builder --chown=nextjs:nodejs /app/utils ./utils
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["yarn", "start"]