
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"]
31 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 npx
maybe 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.
ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJobm9uaW2Cc4WOoaawZaSkera8w5qrnmWknbJuvNGiqqaZXZ67bq2MqamonKWYwaq7zWabqJubmr9utc2sq5qmk5o%3D