update part 5 (#17054)

This commit is contained in:
Craig Osterhout 2023-04-12 14:38:08 -07:00 committed by GitHub
parent 3f6e5455d8
commit 5cc58035b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 55 additions and 40 deletions

View File

@ -1,21 +1,21 @@
---
title: "Persist the DB"
keywords: get started, setup, orientation, quickstart, intro, concepts, containers, docker desktop
description: Making our DB persistent in our application
description: Making your DB persistent in your application
---
In case you didn't notice, our todo list is being wiped clean every single time
we launch the container. Why is this? Let's dive into how the container is working.
In case you didn't notice, your todo list is empty every single time
you launch the container. Why is this? In this part, you'll dive into how the container is working.
## The container's filesystem
When a container runs, it uses the various layers from an image for its filesystem.
Each container also gets its own "scratch space" to create/update/remove files. Any
changes won't be seen in another container, _even if_ they are using the same image.
changes won't be seen in another container, even if they're using the same image.
### See this in practice
To see this in action, we're going to start two containers and create a file in each.
To see this in action, you're going to start two containers and create a file in each.
What you'll see is that the files created in one container aren't available in another.
1. Start an `ubuntu` container that will create a file named `/data.txt` with a random number
@ -25,11 +25,31 @@ What you'll see is that the files created in one container aren't available in a
$ docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
```
In case you're curious about the command, we're starting a bash shell and invoking two
commands (why we have the `&&`). The first portion picks a single random number and writes
In case you're curious about the command, you're starting a bash shell and invoking two
commands (why you have the `&&`). The first portion picks a single random number and writes
it to `/data.txt`. The second command is simply watching a file to keep the container running.
2. Validate that you can see the output by accessing the terminal in the container. To do so, go to **Containers** in Docker Desktop, hover over the container running the **ubuntu** image, and select the **Show container actions** menu. From the dropdown menu, select **Open in terminal**.
2. Validate that you can see the output by accessing the terminal in the container. To do so, you can use the CLI or Docker Desktop's graphical interface.
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" data-target="#cli">CLI</a></li>
<li><a data-toggle="tab" data-target="#gui">Docker Desktop</a></li>
</ul>
<div class="tab-content">
<div id="cli" class="tab-pane fade in active" markdown="1">
On the command line, use the `docker exec` command to access the container. You need to get the
container's ID (use `docker ps` to get it). In your Mac or Linux terminal, or in Windows Command Prompt or PowerShell, get the content with the following command.
```console
$ docker exec <container-id> cat /data.txt
```
<hr>
</div>
<div id="gui" class="tab-pane fade" markdown="1">
In Docker Desktop, go to **Containers**, hover over the container running the **ubuntu** image, and select the **Show container actions** menu. From the dropdown menu, select **Open in terminal**.
You will see a terminal that is running a shell in the Ubuntu container. Run the following command to see the content of the `/data.txt` file. Close this terminal afterwards again.
@ -37,17 +57,13 @@ What you'll see is that the files created in one container aren't available in a
$ cat /data.txt
```
If you prefer the command line you can use the `docker exec` command to do the same. You need to get the
container's ID (use `docker ps` to get it) and get the content with the following command.
<hr>
</div>
</div>
```console
$ docker exec <container-id> cat /data.txt
```
You should see a random number.
You should see a random number!
3. Now, let's start another `ubuntu` container (the same image) and we'll see we don't have the same
file.
3. Now, start another `ubuntu` container (the same image) and you'll see you don't have the same file. In your Mac or Linux terminal, or in Windows Command Prompt or PowerShell, get the content with the following command.
```console
$ docker run -it ubuntu ls /
@ -61,31 +77,30 @@ What you'll see is that the files created in one container aren't available in a
## Container volumes
With the previous experiment, we saw that each container starts from the image definition each time it starts.
While containers can create, update, and delete files, those changes are lost when the container is removed
and all changes are isolated to that container. With volumes, we can change all of this.
With the previous experiment, you saw that each container starts from the image definition each time it starts.
While containers can create, update, and delete files, those changes are lost when you remove the container
and Docker isolates all changes to that container. With volumes, you can change all of this.
[Volumes](../storage/volumes.md) provide the ability to connect specific filesystem paths of
the container back to the host machine. If a directory in the container is mounted, changes in that
directory are also seen on the host machine. If we mount that same directory across container restarts, we'd see
the container back to the host machine. If you mount a directory in the container, changes in that
directory are also seen on the host machine. If you mount that same directory across container restarts, you'd see
the same files.
There are two main types of volumes. We will eventually use both, but we will start with volume mounts.
There are two main types of volumes. You'll eventually use both, but you'll start with volume mounts.
## Persist the todo data
By default, the todo app stores its data in a SQLite database at
`/etc/todos/todo.db` in the container's filesystem. If you're not familiar with SQLite, no worries! It's simply a relational database in
which all of the data is stored in a single file. While this isn't the best for large-scale applications,
it works for small demos. We'll talk about switching this to a different database engine later.
`/etc/todos/todo.db` in the container's filesystem. If you're not familiar with SQLite, no worries! It's simply a relational database that stores all the data in a single file. While this isn't the best for large-scale applications,
it works for small demos. You'll learn how to switch this to a different database engine later.
With the database being a single file, if we can persist that file on the host and make it available to the
With the database being a single file, if you can persist that file on the host and make it available to the
next container, it should be able to pick up where the last one left off. By creating a volume and attaching
(often called "mounting") it to the directory the data is stored in, we can persist the data. As our container
writes to the `todo.db` file, it will be persisted to the host in the volume.
(often called "mounting") it to the directory where you stored the data, you can persist the data. As your container
writes to the `todo.db` file, it will persist the data to the host in the volume.
As mentioned, we are going to use a volume mount. Think of a volume mount as an opaque bucket of data.
Docker fully manages the volume, including where it is stored on disk. You only need to remember the
As mentioned, you're going to use a volume mount. Think of a volume mount as an opaque bucket of data.
Docker fully manages the volume, including the storage location on disk. You only need to remember the
name of the volume.
1. Create a volume by using the `docker volume create` command.
@ -96,8 +111,8 @@ name of the volume.
2. Stop and remove the todo app container once again in the Dashboard (or with `docker rm -f <id>`), as it is still running without using the persistent volume.
3. Start the todo app container, but add the `--mount` option to specify a volume mount. We will give the volume a name, and mount
it to `/etc/todos` in the container, which will capture all files created at the path.
3. Start the todo app container, but add the `--mount` option to specify a volume mount. Give the volume a name, and mount
it to `/etc/todos` in the container, which captures all files created at the path.
```console
$ docker run -dp 3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
@ -112,11 +127,11 @@ name of the volume.
6. Start a new container using the same command from above.
7. Open the app. You should see your items still in your list!
7. Open the app. You should see your items still in your list.
8. Go ahead and remove the container when you're done checking out your list.
Hooray! You've now learned how to persist data!
You've now learned how to persist data.
## Dive into the volume
@ -138,20 +153,20 @@ $ docker volume inspect todo-db
]
```
The `Mountpoint` is the actual location on the disk where the data is stored. Note that on most machines, you will
need to have root access to access this directory from the host. But, that's where it is!
The `Mountpoint` is the actual location of the data on the disk. Note that on most machines, you will
need to have root access to access this directory from the host. But, that's where it is.
> **Accessing volume data directly on Docker Desktop**
>
> While running in Docker Desktop, the Docker commands are actually running inside a small VM on your machine.
> If you wanted to look at the actual contents of the Mount point directory, you would need to look inside of
> If you wanted to look at the actual contents of the mount point directory, you would need to look inside of
> that VM.
## Next steps
At this point, you have a functioning application that can survive restarts! You can show it off to your investors and hope they can catch your vision!
At this point, you have a functioning application that can survive restarts.
However, you saw earlier that rebuilding images for every change takes quite a bit of time. There's got to be a better
way to make changes, right? With bind mounts (which was hinted at earlier), there is a better way!
way to make changes, right? With bind mounts, there is a better way.
[Use bind mounts](06_bind_mounts.md){: .button .primary-btn}