'How do I both expose the port on a container to the local host AND bind persistent data to the container?

I am using dockerode to create a new PostgreSQL docker container. I want to be able to:

  1. Expose port 5432 on the local host
  2. Have the container use a directory on the local host as the persistent data store

I've been able to get a working implementation that creates a Docker container and exposes port 5432 on the local host with the following code:

docker.createContainer({
      Image: "postgres",
      Env: [`POSTGRES_PASSWORD=postgres`],
      HostConfig: {
        PortBindings: {
          "5432/tcp": [{ HostPort: "5432" }]
        },
      },
      ExposedPorts: {
        "5432/tcp": {}
      },
      name: "container-name"
})
  • In this implementation, the data is not persistent - restarting the container will always start from a "fresh" DB
    • I need to have persistent data

From reading the Docker REST API documentation (and through reading lots of community posts), I found that I need to use the Binds parameter. I updated my code to the following:

docker.createContainer({
      Image: "postgres",
      Env: [`POSTGRES_PASSWORD=postgres`],
      HostConfig: {
        PortBindings: {
          "5432/tcp": [{ HostPort: "5432" }]
        },
        // NEW CODE
        Binds: [
          "/path/on/host/machine:/path/on/container"
        ],
      },
      ExposedPorts: {
        "5432/tcp": {}
      },
      name: "container-name"
})
  • However, after adding the Binds parameter, I am no longer able to connect to the database from the host machine

Can anyone tell me what I am doing wrong here? I can't figure out what Binds needs to be in this particular setup. Eventually, I won't need the database exposed to the local machine, but for now, I need to be able to for testing purposes. Thanks in advance!

UPDATE 1 - 6/15/2019

I retested this with a similar setup as suggested, which really wasn't all that different from what I was already doing. However, the suggestions helped me get on the right track and understand where my error was.

It seems that the problem was happening because I was trying to reuse a directory on my local host that had already been used for a different database setup. I thought this was supported; I'm guessing there is something I am missing?

In either case, I have this working now, but I don't quite get why I can't reuse the same directory on my host machine that I was using when I start the containers from the command line.

Clarification

I failed to mention that I can get this working by starting the container from the command line. The problem is when trying to use dockerode - however, I don't think this is a problem with Dockerode, but rather with some misunderstanding I have with the Docker REST API.

I can use the same directory for all databases IF I started the containers from the Command line, but not if I start the containers using the Docker REST API (dockerode in my case).

UPDATE 2 - 6/15/2019

It seems there was something wrong with the path my code was generating. After I went through this a bit, it seems I simply overlooked that error. Strangely, I didn't get any errors in the container when I checked the logs - that's why I didn't think there was anything wrong with the path.

So, for those who encounter this, it may be a simple matter of needing to fix the path you referenced on the host machine.

With that being said, I've marked the accepted solution by mchawre - his solution was correct for the original question I asked. The rest of the issues I had were due to a bug, it seems.

(I do wish the Docker logs would have said something like "no such directory" for the container when it started, though - that would have led to a much-quicker resolution)

Relevant Info I found the following info here:

Warning: the Docker specific variables will only have an effect if you start the container with a data directory that is empty; any pre-existing database will be left untouched on container startup.

  • I think this is why I hit this issue, but not 100% sure yet


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source