How to Update the Prisma in a Production Docker Instance?
I Have a Node. Js Application That I Run on Ec2, and I Have That Application Running on Production. After a While, I Update the Database(Schema) by Creating...
I have a node.js application that I run on EC2, and I have that application running on production. After a while, I update the database(schema) by creating another table, how can I also run the migration on the docker container after I update the latest docker image and create a new container from that image without deleting the data but just applying the migration?
That is the dockerfile:
# Use an official Node.js runtime as the base image
FROM node:16.15.1-alpine as builder
# Set the working directory in the container
WORKDIR /app
# Copy the package.json and package-lock.json files to the container
COPY package*.json ./
# Install project dependencies
RUN npm install
# Copy the rest of the application code to the container
COPY . .
# Generate the Prisma client
RUN npx prisma generate
# Expose the port on which your Node.js application will listen
EXPOSE 4500
# Set the command to run your Node.js application
CMD ["npm", "start"]
1 Answer
Your Dockerfile currently generates the Prisma client, but it does not run the Prisma migrations, which are necessary to update the database schema.
Running such a step at build time seems not a good practice at it would look like:
docker build --build-arg DATABASE_URL=postgresql://user:password@localhost:5432/mydb \
-t my-app .
With your Dockerfile including ARG DATABASE_URL. And... that means your credentials are embedded in the Docker image layer, visible through any docker inspect.
Another approach would be to make the migration at runtime, when starting the container.
Assuming:
- you have a backup in place, and that
- your database is already accessible and that
- the required environment variables for Prisma to connect to your database are provided at build time.
Then you can use a Docker entrypoint script entrypoint.sh that runs when your Docker container is started. That script can first run the migrations, then start your application.
I am using migrate status, but be aware this command is not supported on MongoDB. Use db push instead.
#!/bin/sh
MIGRATION_STATUS=$(npx prisma migrate status)
if echo "$MIGRATION_STATUS" | grep -q "Database schema is up to date"; then
echo "No migrations needed."
else
echo "Running migrations..."
npx prisma migrate deploy
fi
npm start
Then in your Dockerfile:
# Use an official Node.js runtime as the base image
FROM node:16.15.1-alpine as builder
# Set the working directory in the container
WORKDIR /app
# Copy the package.json and package-lock.json files to the container
COPY package*.json ./
# Install project dependencies
RUN npm install
# Copy the rest of the application code to the container
COPY . .
# Generate the Prisma client
RUN npx prisma generate
# Copy the entrypoint script into the container
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Expose the port on which your Node.js application will listen
EXPOSE 4500
# Set the entrypoint script as the command to run
ENTRYPOINT ["/entrypoint.sh"]
You are passing the DATABASE_URL when running the container, and the migration step is run at that time, just before your application starts:
docker run -e DATABASE_URL=postgresql://user:password@localhost:5432/mydb -d my-app
And on the next schema update, you do not have to build a new image.
But the
npxmaybe will not be recognized as a command
That is a valid point. If the Node.js environment is not properly set up or if the PATH environment variable is not correctly configured, npx may not be recognized as a command inside your container.
In your Dockerfile, you are using node:16.15.1-alpine as your base image, which already includes Node.js and npm.
By default, Node.js and npm binaries should be added to your PATH in the node:16.15.1-alpine Docker image.
If you encounter the "npx: command not found" error, try checking the PATH environment variable inside your container. You could do this by adding the following command to your Dockerfile:
RUN echo $PATH
That will print out the PATH variable during the Docker build process, allowing you to verify that the Node.js binary directory is included.