Docker on macOS: Getting Started

In this Docker tutorial, you’ll learn Docker vocabulary and the commands for creating, inspecting and removing containers, networks and data volumes. You’ll learn how to run Docker containers in the background or foreground, and switch between the two; how to publish ports; how to connect a database app and a web app running in separate containers; and how to share directories between containers and your Mac and among containers. By Audrey Tam.

4.6 (23) · 3 Reviews

Download materials
Save for later
Share
You are currently viewing page 5 of 6 of this article. Click here to view the first page.

Choosing Between Volume & Bind Mount

You’ve now seen two different ways to mount host directories in a container: couchdbVolume is a volume, while the EmojiJournalServer directory is a bind mount. The main differences between a volume and a bind mount are where it lives on the host file system, and whether you can access it directly through the host file system.

You bind-mount a specific path on your local system — like the EmojiJournalServer folder — to a specific path in the container — /root/project. You can interact directly with the local directory and changes will appear in the container. Likewise, changes made by the container appear in Finder.

You create a volume by specifying a name, like couchdbVolume, in either a docker run or a docker volume create command. The volume lives in Docker’s storage directory, in the Docker engine on your local system. You cannot interact directly with the contents of this directory. You can mount it into containers, and you can inspect its metadata or remove it. Docker manages reading and writing files in the volume.

Another big difference is what happens when you expose an existing container directory.

If you bind-mount a local directory to an existing container directory, what’s in the local directory obscures the container directory’s contents — this is what happens if you bind-mount your local couchdb-config directory to the CouchDB container’s local.d directory. You effectively overwrite the container directory. Don’t worry, the original directory is still in the read-only image!

If you expose a container directory as a volume, its contents are copied into the volume on the host. This is what happened when you created couchdbVolume with the CouchDB container’s /opt/couchdb/data directory as its target.

--mount or --volume?

There are also two different options you can use to mount volumes or bind-mount local directories. They do the same thing — they just use different syntax.

The --mount option is newer than --volume. It uses comma-separated key=value pairs, and the order of the keys doesn’t matter. This option doesn’t have a shorthand version.

The --volume flag, shorthand -v, has three colon-separated fields: the order matters, but you have to remember, or look up, the meaning of each field.

Docker documentation recommends using the --mount option instead of the -v option: it’s more verbose, but that makes it easier to understand and remember.

The following two commands are equivalent — they bind-mount the current local directory to a new /home directory in the container:

docker run --mount type=bind,source=/`pwd`,target=/home ibmcom/kitura-ubuntu
docker run -v $PWD:/home ibmcom/kitura-ubuntu

The following two commands are equivalent — they create a volume in Docker’s storage directory:

docker run --mount source=KituraVolume,target=/Kitura-Starter ibmcom/kitura-ubuntu
Note: type=volume is the default.
docker run -v KituraVolume:/Kitura-Starter ibmcom/kitura-ubuntu
Note: The first field of the -v option is a name, not a path, so Docker creates a volume, not a bind mount.

Both commands copy /Kitura-Starter‘s contents into a volume named KituraVolume. The Kitura container then mounts and uses KituraVolume. You can mount KituraVolume in other containers, to give them access to its contents.

You can specify read-only access:

docker run --mount source=KituraVolume,target=/Kitura-Starter,readonly --name kitura ibmcom/kitura-ubuntu
docker run -v KituraVolume:/Kitura-Starter:ro --name kitura ibmcom/kitura-ubuntu

Here’s yet another difference between the behavior of --mount and --volume, from Docker’s documentation:

  • If you use -v or --volume to bind-mount a file or directory that does not yet exist on the Docker host, -v creates the endpoint for you. It is always created as a directory.
  • If you use --mount to bind-mount a file or directory that does not yet exist on the Docker host, Docker does not automatically create it for you, but generates an error.

Note that if you use -v to bind-mount a directory that doesn’t exist on the host, to a directory that exists in the container, it will be created as an empty directory on the host, so its emptiness will obscure the original contents in the container. For example, if you try to copy the Kitura-Starter directory from the container to your local file system with -v $PWD/kitura-dir:Kitura-Starter, all you’ll get are empty directories in both your file system and the container.

Copying Files Between Host & Container

If you just want to save a file or directory from a running Docker container to your local system, you can just copy it:

docker cp kitura:/Kitura-Starter . 

You can also copy a file or directory from your local system to a container:

docker cp kilroy.txt kitura:/var/tmp 

Summary of Docker Commands

You’ve seen a lot of Docker commands in this tutorial! Below is a list of them. Terms in square brackets, like [image], are placeholders for specific names or IDs.

The docker run command:

docker run [options] [image] [command for -it options]

The docker run options you’ve used in this tutorial:

- --detach / -d
- --env / -e [ENV_VAR=value] 
- --interactive --tty / -it ... [command]
- --name [name]
- --network [network]
- --mount source=[volume],target=[container-dir]
- --publish / -p [host port]:[container port]
- --volume / -v [host-dir]:[container-dir]

The other Docker commands you’ve used in this tutorial (plus one or two related commands you haven’t seen):

- docker pull [image]
- docker images or docker image ls
- docker ps -a or docker container ls -a
- docker ps -a -q -f [filter condition]
- docker exec -it [container] bash
- docker stop [container]
- docker start [container]
- docker rm $(docker ps -a -q -f status=exited)
- docker rm $(docker stop $(docker ps -q))
- docker rm [container IDs or names] 
- docker rmi [image] or docker image rm [image]
- docker container inspect [container]
- docker network create [network-name]
- docker network inspect [network-name]
- docker network ls
- docker network prune
- docker volume create [volume-name]
- docker volume inspect [volume-name]
- docker volume ls
- docker volume prune
- docker cp [container:container-path] [host-path]
- docker cp [host-path] [container:container-path] 

Some useful ways to detach containers running in the foreground:

  • Control-P-Q detaches without stopping the container
  • If the container is in the foreground because you ran docker run -it ... bash, exit at the bash shell prompt stops the container.
  • If the container is in the foreground because you ran docker exec -it ... bash, exit at the bash shell prompt exits the bash shell but doesn’t stop the container.

Contributors

Over 300 content creators. Join our team.