How do I mount a host directory as a volume in docker compose
Asked Answered
S

8

388

I have a development environment I'm dockerizing and I would like the ability to livereload my changes without having to rebuild docker images. I'm using docker compose because redis is one of my app's dependencies and I like being able to link a redis container

I have two containers defined in my docker-compose.yml:

node:
  build: ./node
  links:
    - redis
  ports:
    - "8080"
  env_file:
    - node-app.env

redis:
  image: redis
  ports:
    - "6379"

I've gotten to the point in my node app's dockerfile where I add a volume, but how do I mount the the host's directory in the volume so that all my live edits to the code are reflected in the container?

Here's my current Dockerfile:

# Set the base image to Ubuntu
FROM    node:boron

# File Author / Maintainer
MAINTAINER Amin Shah Gilani <[email protected]>

# Install nodemon
RUN npm install -g nodemon

# Add a /app volume
VOLUME ["/app"]

# TODO: link the current . to /app

# Define working directory
WORKDIR /app

# Run npm install
RUN npm install

# Expose port
EXPOSE  8080

# Run app using nodemon
CMD ["nodemon", "/app/app.js"]

My project looks like this:

/
- docker-compose.yml
- node-app.env
- node/
  - app.js
  - Dockerfile.js
Slaw answered 1/12, 2016 at 8:25 Comment(0)
S
410

Checkout their documentation

From the looks of it you could do the following on your docker-compose.yml

volumes:
    - ./:/app

Where ./ is the host directory, and /app is the target directory for the containers.


EDIT:
Previous documentation source now leads to version history, you'll have to select the version of compose you're using and look for the reference.

For the lazy – v3 / v2 / v1

Side note: Syntax remains the same for all versions as of this edit

Shondrashone answered 1/12, 2016 at 8:30 Comment(9)
Tried it, it didn't work: Error: Cannot find module '/data/app.js'Slaw
wait.. your VOLUME and WORKDIR points to /app/ why is your CMD pointing to /dataShondrashone
That was an error! Thank you for catching that! Fixed, and now I get Error: Cannot find module 'express' I'm gonna try a few things now.Slaw
For windows containers, you'll want a windows style path like - .:c:/app (this tripped me up)Tulley
I have lots of stuff in my current directory but the volume directory has nothing in it. volumes: - .:/stocksMicron
There's no mention of volume in docs.docker.com/compose/compose-file/#volumesDisaccredit
Does this volumes belong to services section or stand alone section?Hastate
Side note. If you need to mount 1 dir above the host dir, just use standard .. syntax: - ../:/app works on Linux containers and - ..\:\app works on Windows containers. At least it works with Docker engine 20.10.11 for me.Teacake
Follow-on to @jrbe228's comment: In the the case that your docker-compose YAML file is not in your current directory (i.e., you're using docker-compose's -f option), ./ will refer to the directory containing the YAML file.Casting
L
256

There are a few options

Short Syntax

Using the host : guest format you can do any of the following:

volumes:
  # Just specify a path and let the Engine create a volume
  - /var/lib/mysql

  # Specify an absolute path mapping
  - /opt/data:/var/lib/mysql

  # Path on the host, relative to the Compose file
  - ./cache:/tmp/cache

  # User-relative path
  - ~/configs:/etc/configs/:ro

  # Named volume
  - datavolume:/var/lib/mysql

Long Syntax

As of docker-compose v3.2 you can use long syntax which allows the configuration of additional fields that can be expressed in the short form such as mount type (volume, bind or tmpfs) and read_only.

version: "3.2"
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - type: volume
        source: mydata
        target: /data
        volume:
          nocopy: true
      - type: bind
        source: ./static
        target: /opt/app/static

networks:
  webnet:

volumes:
  mydata:

Check out https://docs.docker.com/compose/compose-file/#long-syntax-3 for more info.

Lamelli answered 25/1, 2018 at 11:54 Comment(2)
To add to your answer, there are also :cached and :delegated annotations in the short syntax. These matter if the host is Docker Desktop for Mac. They are documented in docker-docs.netlify.app/docker-for-mac/osxfs-caching but unfortunately not in the Docker Compose docs.Geosynclinal
@RominRonin the website xy2401.com looks suspicious.Gaily
A
122

If you would like to mount a particular host directory (/disk1/prometheus-data in the following example) as a volume in the volumes section of the Docker Compose YAML file, you can do it as below, e.g.:

version: '3'

services:
  prometheus:
    image: prom/prometheus
    volumes:
      - prometheus-data:/prometheus

volumes:
  prometheus-data:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /disk1/prometheus-data

By the way, in prometheus's Dockerfile, You may find the VOLUME instruction as below, which marks it as holding externally mounted volumes from native host, etc. (Note however: this instruction is not a must though to mount a volume into a container.):

Dockerfile

...
VOLUME ["/prometheus"]
...

Refs:

Aerostatics answered 2/5, 2019 at 12:11 Comment(9)
This worked. Thanks. Where is the documentation for the local driver type?Trabue
@Trabue The documentation is the first Refs link (docs.docker.com/compose/compose-file/#driver) It reads: Specify which volume driver should be used for this volume. Defaults to whatever driver the Docker Engine has been configured to use, which in most cases is localAerostatics
@mmell, you can find more details from this question: #42195834Aerostatics
How did you know the settings in driver_opts: o: bind type: none?Trabue
@Trabue Basically, those options are driver-dependent, and the built-in local driver on Linux accepts options similar to the linux mount command: man7.org/linux/man-pages/man8/mount.8.html. You can find more discussion at github.com/moby/moby/issues/19990#issuecomment-248955005, and #35841741Aerostatics
@JackNavaRow, check this out: #41212586Aerostatics
@Aerostatics it works in window, i added a litle configuration , I hope that you accept it, thanks bro!White
This answer should be the accepted one for a separate question about how to mount a host directory across multiple containers; twas hard to find this!Zacynthus
@Zacynthus I entirely agree -- this saved my bacon. I tried to do a bit more of a formal writeup here: aaronpung.wordpress.com/2022/06/07/…Disjunct
S
19

It was two things:

I added the volume in docker-compose.yml:

node:
  volumes:
    - ./node:/app

I moved the npm install && nodemon app.js pieces into a CMD because RUN adds things to the Union File System, and my volume isn't part of UFS.

# Set the base image to Ubuntu
FROM    node:boron

# File Author / Maintainer
MAINTAINER Amin Shah Gilani <[email protected]>

# Install nodemon
RUN npm install -g nodemon

# Add a /app volume
VOLUME ["/app"]

# Define working directory
WORKDIR /app

# Expose port
EXPOSE  8080

# Run npm install
CMD npm install && nodemon app.js
Slaw answered 1/12, 2016 at 9:5 Comment(0)
S
15

we have to create your own docker volume mapped with the host directory before we mention in the docker-compose.yml as external

1.Create volume named share

docker volume create --driver local \
--opt type=none \
--opt device=/home/mukundhan/share \
--opt o=bind share

2.Use it in your docker-compose

version: "3"

volumes:
  share:
    external: true

services:
  workstation:
    container_name: "workstation"
    image: "ubuntu"
    stdin_open: true
    tty: true
    volumes:
      - share:/share:consistent
      - ./source:/source:consistent
    working_dir: /source
    ipc: host
    privileged: true
    shm_size: '2gb'
  db:
    container_name: "db"
    image: "ubuntu"
    stdin_open: true
    tty: true
    volumes:
      - share:/share:consistent
    working_dir: /source
    ipc: host

This way we can share the same directory with many services running in different containers

Shipload answered 12/3, 2020 at 18:56 Comment(2)
why do I need to have ipc: host ?Elgin
that is only needed when we need to bind the network into host itself.Shipload
C
11

In docker-compose.yml you can use this format:

volumes:
    - host directory:container directory

according to their documentation

Cowled answered 16/12, 2020 at 21:7 Comment(1)
Does this volume belongs to services section or stand alone section?Hastate
I
3

Here is my working example for Node.js application and MongoDB database :

docker-compose.yml

version: '3'
services: 
    my-app:
        container_name: my-app-container
        restart: always
        build: .
        volumes:
            - './storage:/usr/src/app/storage'
        ports: 
            - "3000:3000"
        links:
            - my-app-db
    
    my-app-db:
        container_name: my-app-db-container
        image: mongo
        restart: always
        volumes:
            - './data:/data/db'          
        ports:
            - "27017:27017"

Dockerfile

FROM node:16.13.2
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY . /usr/src/app/
EXPOSE 3000
CMD [ "npm", "start"]
Intendance answered 16/1, 2022 at 16:42 Comment(0)
B
3

Sharing redis golang docker-compose.yaml. Using bind-mount I've achieved it.

version: '3.0'
services:
  redisdb:
    image: redis:6.0
    restart: always
    ports:
      - "6379:6379"
    container_name: redisdb-container
    command: ["redis-server", "--bind", "redisdb", "--port", "6379"]

  urlshortnerservice:
    depends_on:
      - redisdb
    ports:
      - "7777:7777"
    restart: always
    container_name: url-shortner-container
    image: url-shortner-service
    volumes:
      - ../pkg/repository/filestorage:/pkg/repository/filestorage #host directory:container directory
Bayonne answered 13/11, 2022 at 11:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.