1

I have two Dockerfiles, one for a database, and one for a web server. The web server's Dockerfile has a RUN statement which requires a connection to the database container. The web server is unable to resolve the database's IP then errors out. But if I comment out the RUN line, then manually run it inside the container, it successfully resolves the database. Should the web server be able to resolve the database during its build process?

# Web server
FROM tomcat:9.0.26-jdk13-openjdk-oracle

# The database container cannot be resolved when myscript runs.  "Unable to connect to the database." is thrown.
RUN myscript

CMD catalina.sh run
# But if I comment out the RUN line then connect to web server container and run myscript, the database container is resolved
docker exec ... bash

# This works
./myscript
Hank
  • 13
  • 2
  • 1
    You should use entrypoint to achieve that instead of RUN command. Because `RUN` will be executed when you build your images and at that time, there is no database to connect to. But with `ENTRYPOINT` when ever you run your container, it will execute your entrypoints and at that time, there is a database so your entrypoint script can connect to your database container – Toan Quoc Ho Oct 11 '19 at 21:31
  • I have the database spun up separately, so the database does exist and can accept connections during the web server's build process. Or are you saying other containers will never be available for `RUN` commands? – Hank Oct 11 '19 at 21:33
  • Yes, I just mean that RUN command only run when you build your image, but when you `start` your container `RUN` won't run again to connect to your database. – Toan Quoc Ho Oct 11 '19 at 21:41
  • That's the behavior I'm looking for. The web server's build process requires certain queries to be executed against the DB container, which is why I'm trying to connect to it during the `RUN` phase. – Hank Oct 11 '19 at 21:46
  • Wow that's interest. So I think you could public your database so that your build process can connect to. For now your database is also a container so that they can't connect because there is no network interface between them. – Toan Quoc Ho Oct 11 '19 at 21:54

1 Answers1

3

I ran into the same problem on database migrations and NuGet pushes. You may want to run something similar on your db like migrations, initial/test data and so on. It could be solved in two ways:

  1. Move your DB operations to the ENTRYPOINT so that they're executed at runtime (where the DB container is up and reachable).

  2. Build your image using docker build instead of something like docker-compose up --build because docker build has a switch called --network. So you could create a network in your compose file, bring the DB up with docker-compose up -d db-container and then access them during the build with docker build --network db-container-network -t your-image .

I'd prefer #1 over #2 if possible because

  • it's simpler: the network is only present in docker-compose file, not on multiple places
  • you can specify relations usind depends_on and make sure that they're respected properly without taking manually care of it

But depending on the action you want to execute, you need to take care that it's not executed multiple times because it's running on every start and not just during build (when the cache got purged by file changes).

However, I'd consider this as best practice anyway when running such automated DB operations to expect that they may executed more than one and should create the expected result anyway (e.g. by checking if the migration version or change is present).

Lion
  • 16,606
  • 23
  • 86
  • 148