Reputation: 422
I am learning docker these days, and starts with building mysql image by myself.
Dockerfile:
FROM centos
MAINTAINER Michael
ENV REFRESHED_AT 2016-07-29
RUN yum install -y mysql mariadb-server
VOLUME /var/lib/mysql
ENTRYPOINT ["/usr/libexec/mysqld", "--user=root"]
EXPOSE 3306
docker run command
docker run -d --name mysql -v /root/docker/mysql/data:/var/lib/mysql -p 3306:3306 michael/mysql
This gave an error because I have to exec mysql_install_db
first to init DB. But I could not add RUN mysql_install_db
in the Dockerfile since I want to use Volume
as external data store.
So how should I do this ?
I know there's an official image named mysql
. I just want to do this as practice.
UPDATE:
Thanks to @Pieter . I finally did this by using his solution which is provide another entrypoint.sh
combines init & start scripts then make it as ENTRYPOINT in Dockerfile :
FROM centos
MAINTAINER Michael
ENV REFRESHED_AT 2016-07-29
RUN yum install -y mysql mariadb-server
VOLUME /var/lib/mysql
COPY entrypoint.sh /usr/local/bin/
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3306
entrypoint.sh
#!/bin/bash
if [ ! -d "/var/lib/mysql/mysql" ]; then #check whether the DB is initialized.
echo 'Initializing database'
mysql_install_db
echo 'Database initialized'
fi
/usr/libexec/mysqld --user=root
docker run
docker run -d --name mysql -v /root/docker/mysql/data:/var/lib/mysql -p 3306:3306 michael/mysql
And this gives a generic solution for such scenario.
Upvotes: 7
Views: 16391
Reputation: 8693
There's also another nice way to do it which I found from this blog post so full credit goes to it.
But I got an error while running ENTRYPOINT
command:
Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "entrypoint.sh": executable file not found in $PATH: unknown
I tried implementing it because I needed a way to initialize my *.sqlite
database for the first time. And then the rest of the times I needed a way to restore backups using litestream. I tried using entrypoint.sh
but it gave weird errors.
So I just copied that code-block in my run.sh
at the start.
#!/bin/bash
set -e
# Set the directory of the database in a variable
DB_PATH=/data/users.prod.sqlite
# Copied from https://pranavmalvawala.com/run-script-only-on-first-start-up
CONTAINER_FIRST_STARTUP="CONTAINER_FIRST_STARTUP"
if [ ! -e /data/$CONTAINER_FIRST_STARTUP ]; then
# Place your script that you only want to run on first startup.
echo 'Initialize database first time only'
touch /data/$CONTAINER_FIRST_STARTUP
# Only install dependencies for drizzle migration. Those are not bundled via `next build` as its optimized to only install dependencies that are used in next.js app
echo "Installing production dependencies"
cd scripts
pnpm config set store-dir ~/.pnpm-store
pnpm fetch
pnpm install --prod --prefer-offline
cd ..
echo "Creating '/data/users.prod.sqlite' using bind volume mount"
pnpm db:migrate:prod & PID=$!
# Wait for migration to finish
wait $PID
fi
# Restore the database if it does not already exist.
if [ -f $DB_PATH ]; then
echo "Database already exists, skipping restore"
else
echo "No database found, restoring from replica if exists"
# Restore backup from litestream if backup exists
litestream restore -if-replica-exists $DB_PATH
fi
echo "Starting production server..."
# Run litestream with your app as the subprocess.
exec litestream replicate -exec "node server.js"
The first code-block in the if
statement above is all you need to run any script just once.
The final project is at https://github.com/deadcoder0904/easypanel-nextjs-sqlite/
Upvotes: 0
Reputation: 2783
I'm no expert but for all I know there is no way to run some script before ENTRYPOINT as ENTRYPOINT is literally the first thing your container runs.
What you can do is add a custom script to your docker container that contains both the mysql_install_db and mysqld instructions and use that as the entrypoint.
So your dockerfile might look like this.
FROM centos
MAINTAINER Michael
ENV REFRESHED_AT 2016-07-29
RUN yum install -y mysql mariadb-server
VOLUME /var/lib/mysql
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
EXPOSE 3306
entrypoint.sh would simply look like this.
/usr/libexec/mysql_install_db --user=root
/usr/libexec/mysqld --user=root
Note that the same technique is also used in the official mariadb docker image. See https://github.com/docker-library/mariadb/tree/d969a465ee48fe10f4b532276f7337ddaaf3fc36/10.1
Note that the official image combines ENTRYPOINT with CMD. As you're learning docker you might want to take a look at https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/ for more information on how ENTRYPOINT and CMD can be used together.
UPDATE Assuming that mysql_install_db simply creates some files under /var/lib/mysql you should be able to run mysql_install_db as part of your docker build. (This doesn't mean that you should though -> see official mariadb image).
The docker run command initializes a newly created volume with any data that exists at the specified location within the base image. See https://docs.docker.com/engine/reference/builder/#/volume
Upvotes: 6