My objective is to build a Docker image that includes MySQL prefilled with the tables and data produced by an Alembic migration. Unfortunately, Alembic can't produce the necessary data without an active MySQL instance, nor can it independently create a SQL dump to be loaded by MySQL on first run.
I've attempted to use multi-stage builds to use both the mysql
and python
containers for this, but the MySQL daemon is brought down again as soon as the Python stage begins.
# start MySQL daemon
FROM mysql:5.6
RUN docker-entrypoint.sh
# install and run Alembic
FROM python:2.7-alpine
# [install Alembic]
COPY ./alembic-migrations /alembic-migrations
# [run migrations]
I'm not hung up on this particular solution, but it seemed like the simplest option. Is there a way to do what I'm attempting? Should I resign myself to installing Python and Alembic in the MySQL container?
It'll probably make some Docker evangelist's eyes bleed, but this is how I was able to accomplish the behaviour I was looking for. It was actually simpler and runs faster than I'd expected.
FROM python:2.7-alpine as python
FROM mysql:5.6
# set up a functional chroot of the Python image at /python
COPY --from=python / /python
RUN set -ex; \
cp /etc/resolv.conf /python/etc/resolv.conf; \
mknod -m 0644 /python/dev/random c 1 8; \
mknod -m 0644 /python/dev/urandom c 1 9;
# install software depedencies in chroot jail
RUN set -ex; \
chroot /python apk --no-cache --virtual add [some dependencies]
# install Python libraries
COPY ./requirements.txt /python/tmp/requirements.txt
RUN chroot /python pip install -r /tmp/requirements.txt;
# apply Alembic migrations and remove the Python chroot jail
COPY ./usr/local/bin/build.sh /usr/local/bin/
COPY ./alembic /python/alembic
RUN build.sh && rm -rf /python;
ENTRYPOINT ["docker-entrypoint.sh", "--datadir=/var/lib/mysql-persist"]
EXPOSE 3306
CMD ["mysqld"]
The build.sh
script simply forks the docker-entrypoint.sh
script from the MySQL container, then invokes the Alembic-specific code within the Python chroot.
#!/bin/sh
docker-entrypoint.sh --datadir=/var/lib/mysql-persist 2>/dev/null &
chroot /python build.sh
Note that I'm setting a custom data directory (/var/lib/mysql-persist
) because the upstream mysql container defines VOLUME /var/lib/mysql
, which I can't override.
The result is a built image that contains MySQL, complete with database, but does not contain any traces of the Python container or Alembic scripts. It can now be distributed via a registry and fetched by docker-compose
, avoiding the need for all users to execute the Alembic migrations independently.