# Lesson 4: Persisting data 1. Change directory into `lesson04`. 1. We saw in Lesson 3 that data written to the final container layer does not persist. How do we deal with this? One option is to have the container write to an external system like a database system or cloud storage. There is, however, another method: mounting a local file system or directory. 1. Let's create a Docker container that saves the current date to a file. Here is our first attempt: # Dockerfile FROM debian:buster-slim LABEL maintainer="adamhl@stanford.edu" ADD date.sh /root/date.sh RUN chmod a+x /root/date.sh CMD /root/date.sh # date.sh #!/bin/sh echo "echoing date to /tmp/date.output" date > /tmp/date.output $ docker build . -t date $ docker run --rm --name=fuzzle date echoing date to /tmp/date.output 1. The above will create the file `/tmp/date.output` containing the date but we know that the file will not persist after the container stops running. To get around this we "mount" a local directory into the container's `/tmp` directory. By "local directory" we mean a directory on the computer where we run the our `docker` commands. We mount the colume when we run the container. $ mkdir -p /tmp/docker $ docker run --rm --name=fuzzle --volume=/tmp/docker:/tmp date echoing date to /tmp/date.output $ cat /tmp/docker/date.output 1. You can run a container and override the `CMD` command. $ docker run --rm --name=fuzzle date ls -ld /etc drwxr-xr-x 1 root root 4096 Jan 17 17:23 /etc/ (The date.sh script did NOT run) 1. This is especially useful when you want to login to the container and debug the filesystem or CMD command. 1. You can overwrite a file in the image using the same `--volume` option. For example, let's overwrite `/etc/debian_version` with a different file. $ docker run --rm --name=fuzzle date cat /etc/debian_version 10.7 $ echo "fake-version" > /tmp/deb_ver $ docker run --rm --name=fuzzle --volume=/tmp/deb_ver:/etc/debian_version date cat /etc/debian_version fake-version 1. If you mount an external directory onto a container directory **everything** in the directory in the container is **replaced** with the external directory. $ docker run --rm --name=fuzzle date ls -l /usr total 32 drwxr-xr-x 2 root root 4096 Jan 11 00:00 bin drwxr-xr-x 2 root root 4096 Nov 22 12:37 games ... more ... # Create a directory in /tmp with a single file. $ mkdir -p /tmp/usr; cp test.txt /tmp/usr # Mount /tmp/usr over /usr in the container $ docker run --rm --name=fuzzle --volume=/tmp/usr:/usr date ls -l /usr total 4 -rw-r--r-- 1 52777 root 7 Jan 17 18:04 test.txt 1. You can mount an external directory in read-only mode. This is particularly useful when injecting secrets or configuration information into a container. Look for the `ro` in the `--volume` option below. $ mkdir -p /tmp/secrets $ echo "my-password" > /tmp/secrets/password $ docker run --rm --name=fuzzle --volume=/tmp/secrets:/secrets:ro date sleep 100000 & $ docker exec -ti fuzzle /bin/sh # cat /secrets/password my-password # echo "another secret" >> /secrets/password /bin/sh: 5: cannot create /secrets/password: Read-only file system $ docker kill fuzzle 1. You can run the entire container in read-only mode. The `docker run` option `--read-only` mounts the root filesystem (i.e., everything) in read-only excepting any externally mounted volumes. This lets you lock-down the filesystem except for those parts of the filesystem you know need to be written to (e.g., `/tmp`, `/var/log`, etc.).