# Introduction and more

# Introduction

> Get started with Docker. You'll learn about Docker Desktop, developing with Docker, as well as how to build and push your first image.

# Introduction

Embark on a comprehensive learning path to understand Docker and
containerization, beginning with foundational concepts and installation
procedures. Progress through hands-on exercises that cover essential Docker
commands, image creation, and container orchestration.**Skill level** Beginner**Time to complete** 15 minutes**Prerequisites** None

## About this series

In this guide series, you will gain hands-on experience with Docker, starting
with installing and setting up Docker Desktop on your local machine. You will
learn how to run your first container, understanding the basics of
containerization and its benefits. This series guides you through building your
first Docker image, providing insights into creating efficient and reusable
images. Finally, you will explore how to publish your image on Docker Hub,
enabling you to share your work with the broader community and leverage
Docker's powerful ecosystem for collaborative development and deployment.

## What you'll learn

- Set up Docker Desktop
- Run your first container
- Build your first image
- Publish your image on Docker Hub

## Modules

Getting Docker Desktop up and running is the first crucial step for
developers diving into containerization, offering a seamless and
user-friendly interface for managing Docker containers. Docker Desktop
simplifies the process of building, sharing, and running applications in
containers, ensuring consistency across different environments.

[Start](https://docs.docker.com/get-started/introduction/get-docker-desktop/)

Learn how to run your first container, gaining hands-on experience with
Docker's powerful features. We'll cover making real-time changes to both
backend and frontend code within the containerized environment, ensuring
seamless integration and testing.

[Start](https://docs.docker.com/get-started/introduction/develop-with-containers/)

Learn how to build your first Docker image, a key step in containerizing your
application. We'll guide you through the process of creating an image
repository and building and pushing your image to Docker Hub. This enables
you to share your image easily within your team.

[Start](https://docs.docker.com/get-started/introduction/build-and-push-first-image/)

Now that you have set up Docker Desktop, developed with containers, and built
and pushed your first image, you are ready to take the next step and dive
deep into what a container is and how it works.

[Start](https://docs.docker.com/get-started/introduction/whats-next/)

---

# Educational resources

> Get started resources learning docker

# Educational resources

   Table of contents

---

Docker and the broader community of Docker experts have put together many different ways to get further training and hands-on experience with Docker. Expand your understanding of Docker and Kubernetes with these additional free and paid resources.

## Docker Training

Expand your knowledge on all things Docker with [basic to advanced trainings from Docker experts](https://www.docker.com/trainings/).

You can find recorded content at your own convenience, or register for a live session to participate in Q&A.

## Hosted labs

These self-paced and hands-on workshops use a free, hosted environment ([Play with Kubernetes](https://labs.play-with-k8s.com/)) that doesn't require any installation. Follow along and learn more about Kubernetes.

- [Kubernetes Workshop](https://training.play-with-kubernetes.com/kubernetes-workshop/)

* Labs are free but require registration with a Docker ID.

## Self-guided tutorials

Created by experts in the Docker community, these free tutorials provide guided step-by-step workflows for working with the Docker platform.

- **Integrating Docker with Your IDE**
  - [Java Development: Eclipse](https://training.play-with-docker.com/java-debugging-eclipse/)
  - [Java Development: IntelliJ](https://training.play-with-docker.com/java-debugging-intellij/)
  - [Java Development: Netbeans](https://training.play-with-docker.com/java-debugging-netbeans/)
  - [Live Debugging Node.js with Docker and Visual Studio Code](https://training.play-with-docker.com/nodejs-live-debugging/)
- **Windows Containers**
  - [Windows Container Setup](https://training.play-with-docker.com/windows-containers-setup/)
  - [Windows Container Basics](https://training.play-with-docker.com/windows-containers-basics/)
  - [Windows Containers Multi-Container Applications](https://training.play-with-docker.com/windows-containers-multicontainer/)

## Books

If books are your preferred learning style, check out these written by the [Docker Captains](https://www.docker.com/community/captains). Docker Captain is a distinction that Docker awards to select members of the community that are both experts in their field and are committed to sharing their Docker knowledge with others.

- [Learn Docker in a Month of Lunches](https://www.manning.com/books/learn-docker-in-a-month-of-lunches), Elton Stoneman. Use the code `stonemanpc` for a 40% discount.
- [Docker on Windows: From 101 to Production with Docker on Windows](https://www.amazon.com/Docker-Windows-Elton-Stoneman-ebook/dp/B0711Y4J9K/), Elton Stoneman
- [Learn Kubernetes in a Month of Lunches](https://www.manning.com/books/learn-kubernetes-in-a-month-of-lunches), Elton Stoneman. Use the code `stonemanpc` for a 40% discount.
- [Docker in Action 2nd Edition](https://www.manning.com/books/docker-in-action-second-edition) Jeff Nickoloff, Oct 2019
- [The Kubernetes Book](https://www.amazon.com/Kubernetes-Book-Nigel-Poulton/dp/1521823634/ref=sr_1_3?ie=UTF8&qid=1509660871&sr=8-3&keywords=nigel+poulton), Nigel Poulton, Nov 2018
- [Docker Deep Dive](https://www.amazon.com/Docker-Deep-Dive-Nigel-Poulton-ebook/dp/B01LXWQUFF), Nigel Poulton, 2024 Edition
- [Portuguese] [Docker para desenvolvedores](https://leanpub.com/dockerparadesenvolvedores) (2017) by Rafael Gomes
- [Spanish] [Érase una vez Docker](https://leanpub.com/erase-una-vez-docker), Manuel Morejón, March 2023
- [Spanish] [Érase una vez Kubernetes](https://leanpub.com/erase-una-vez-kubernetes), Manuel Morejón, Jan 2022

## CLI cheat sheet

The
[Docker CLI cheat sheet](https://docs.docker.com/get-started/docker_cheatsheet.pdf) features the common Docker CLI commands for easy reference. It covers working with Images, Containers, Docker Hub, and other general purpose commands.

## Self-Paced online learning

A number of Docker Captains have also created video courses on Docker and Kubernetes.

- [Bret Fisher](https://www.bretfisher.com/courses/): Docker Mastery, Docker Swarm Mastery, Docker Mastery for Node.js Projects
- [Elton Stoneman](https://docker4.net/udemy): Docker for .NET Apps - on Linux and Windows. Includes the discount code `644ABCBC33F474541885`.
- [Nick Janetakis](https://nickjanetakis.com/courses/) Dive into Docker, Docker for DevOps
- [Nigel Poulton](https://nigelpoulton.com/video-courses): Kubernetes 101, Getting Started with Kubernetes, Docker and Kubernetes: The Big Picture, Kubernetes Deep Dive, Docker Deep Dive
- [Arun Gupta](https://www.lynda.com/Docker-tutorials/Docker-Java-developers/576584-2.html): Docker for Java Developers
- [Ajeet Singh Raina](https://collabnix.com/): Docker and Kubernetes Labs
- [French] [Luc Juggery](https://www.udemy.com/user/lucjuggery/): Introduction to Kubernetes, The Docker Platform

* Many of the courses are fee-based

## Community-translated docs

> Note
>
> The following section contains a subset of Docker docs that are translated by community
> members. This is not an officially translated version of Docker docs and it may not be up to date.
> You must use the community-translated docs at your own discretion.

- [Subset of Docker docs in Japanese](https://docs.docker.jp/index.html) translated by Docker Captain [Masahito Zembutsu](https://github.com/zembutsu).

---

# Containerize an application

> Follow this step-by-step guide to learn how to create and run a containerized application using Docker

# Containerize an application

   Table of contents

---

For the rest of this guide, you'll be working with a simple todo
list manager that runs on Node.js. If you're not familiar with Node.js,
don't worry. This guide doesn't require any prior experience with JavaScript.

## Prerequisites

- You have installed the latest version of
  [Docker Desktop](https://docs.docker.com/get-started/get-docker/).
- You have installed a [Git client](https://git-scm.com/downloads).
- You have an IDE or a text editor to edit files. Docker recommends using [Visual Studio Code](https://code.visualstudio.com/).

## Get the app

Before you can run the application, you need to get the application source code onto your machine.

1. Clone the [getting-started-app repository](https://github.com/docker/getting-started-app/tree/main) using the following command:
  ```console
  $ git clone https://github.com/docker/getting-started-app.git
  ```
2. View the contents of the cloned repository. You should see the following files and sub-directories.
  ```text
  ├── getting-started-app/
  │ ├── .dockerignore
  │ ├── package.json
  │ ├── package-lock.json
  │ ├── README.md
  │ ├── spec/
  │ ├── src/
  ```

## Build the app's image

To build the image, you'll need to use a Dockerfile. A Dockerfile is simply a text-based file with no file extension that contains a script of instructions. Docker uses this script to build a container image.

1. In the `getting-started-app` directory, the same location as the
  `package.json` file, create a file named `Dockerfile` with the following contents:
  ```dockerfile
  # syntax=docker/dockerfile:1
  FROM node:24-alpine
  WORKDIR /app
  COPY . .
  RUN npm install --omit=dev
  CMD ["node", "src/index.js"]
  EXPOSE 3000
  ```
  This Dockerfile does the following:
  - Uses `node:24-alpine` as the base image, a lightweight Linux image with Node.js pre-installed
  - Sets `/app` as the working directory
  - Copies source code into the image
  - Installs the necessary dependencies
  - Specifies the command to start the application
  - Documents that the app listens on port 3000
2. Build the image using the following commands:
  In the terminal, make sure you're in the `getting-started-app` directory. Replace `/path/to/getting-started-app` with the path to your `getting-started-app` directory.
  ```console
  $ cd /path/to/getting-started-app
  ```
  Build the image.
  ```console
  $ docker build -t getting-started .
  ```
  The `docker build` command uses the Dockerfile to build a new image. You might have noticed that Docker downloaded a lot of "layers". This is because you instructed the builder that you wanted to start from the `node:24-alpine` image. But, since you didn't have that on your machine, Docker needed to download the image.
  After Docker downloaded the image, the instructions from the Dockerfile copied in your application and used `npm` to install your application's dependencies.
  Finally, the `-t` flag tags your image. Think of this as a human-readable name for the final image. Since you named the image `getting-started`, you can refer to that image when you run a container.
  The `.` at the end of the `docker build` command tells Docker that it should look for the `Dockerfile` in the current directory.

## Start an app container

Now that you have an image, you can run the application in a container using the `docker run` command.

1. Run your container using the `docker run` command and specify the name of the image you just created:
  ```console
  $ docker run -d -p 127.0.0.1:3000:3000 getting-started
  ```
  The `-d` flag (short for `--detach`) runs the container in the background.
  This means that Docker starts your container and returns you to the terminal
  prompt. Also, it does not display logs in the terminal.
  The `-p` flag (short for `--publish`) creates a port mapping between the
  host and the container. The `-p` flag takes a string value in the format of
  `HOST:CONTAINER`, where `HOST` is the address on the host, and `CONTAINER`
  is the port on the container. The command publishes the container's port
  3000 to `127.0.0.1:3000` (`localhost:3000`) on the host. Without the port
  mapping, you wouldn't be able to access the application from the host.
2. After a few seconds, open your web browser to [http://localhost:3000](http://localhost:3000).
  You should see your app.
  ![Empty todo list](https://docs.docker.com/get-started/workshop/images/todo-list-empty.webp)  ![Empty todo list](https://docs.docker.com/get-started/workshop/images/todo-list-empty.webp)
3. Add an item or two and see that it works as you expect. You can mark items as complete and remove them. Your frontend is successfully storing items in the backend.

At this point, you have a running todo list manager with a few items.

If you take a quick look at your containers, you should see at least one container running that's using the `getting-started` image and on port `3000`. To see your containers, you can use the CLI or Docker Desktop's graphical interface.

Run the `docker ps` command in a terminal to list your containers.

```console
$ docker ps
```

Output similar to the following should appear.

```console
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
df784548666d        getting-started     "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        127.0.0.1:3000->3000/tcp   priceless_mcclintock
```

In Docker Desktop, select the **Containers** tab to see a list of your containers.

![Docker Desktop with get-started container running](https://docs.docker.com/get-started/workshop/images/dashboard-two-containers.webp)  ![Docker Desktop with get-started container running](https://docs.docker.com/get-started/workshop/images/dashboard-two-containers.webp)

## Summary

In this section, you learned the basics about creating a Dockerfile to build an image. Once you built an image, you started a container and saw the running app.

Related information:

- [Dockerfile reference](https://docs.docker.com/reference/dockerfile/)
- [docker CLI reference](https://docs.docker.com/reference/cli/docker/)

## Next steps

Next, you're going to make a modification to your app and learn how to update your running application with a new image. Along the way, you'll learn a few other useful commands.

[Update the application](https://docs.docker.com/get-started/workshop/03_updating_app/)

---

# Update the application

> Making changes to your application

# Update the application

   Table of contents

---

In [part 1](https://docs.docker.com/get-started/workshop/02_our_app/), you containerized a todo application. In this part, you'll update the application and image. You'll also learn how to stop and remove a container.

## Update the source code

In the following steps, you'll change the "empty text" when you don't have any todo list items to "You have no todo items yet! Add one above!"

1. In the `src/static/js/app.js` file, update line 56 to use the new empty text.
  ```diff
  - <p className="text-center">No items yet! Add one above!</p>
  + <p className="text-center">You have no todo items yet! Add one above!</p>
  ```
2. Build your updated version of the image, using the `docker build` command.
  ```console
  $ docker build -t getting-started .
  ```
3. Start a new container using the updated code.
  ```console
  $ docker run -dp 127.0.0.1:3000:3000 getting-started
  ```

You probably saw an error like this:

```console
docker: Error response from daemon: driver failed programming external connectivity on endpoint laughing_burnell
(bb242b2ca4d67eba76e79474fb36bb5125708ebdabd7f45c8eaf16caaabde9dd): Bind for 127.0.0.1:3000 failed: port is already allocated.
```

The error occurred because you aren't able to start the new container while your old container is still running. The reason is that the old container is already using the host's port 3000 and only one process on the machine (containers included) can listen to a specific port. To fix this, you need to remove the old container.

## Remove the old container

To remove a container, you first need to stop it. Once it has stopped, you can remove it. You can remove the old container using the CLI or Docker Desktop's graphical interface. Choose the option that you're most comfortable with.

### Remove a container using the CLI

1. Get the ID of the container by using the `docker ps` command.
  ```console
  $ docker ps
  ```
2. Use the `docker stop` command to stop the container. Replace `<the-container-id>` with the ID from `docker ps`.
  ```console
  $ docker stop <the-container-id>
  ```
3. Once the container has stopped, you can remove it by using the `docker rm` command.
  ```console
  $ docker rm <the-container-id>
  ```

> Note
>
> You can stop and remove a container in a single command by adding the `force` flag to the `docker rm` command. For example: `docker rm -f <the-container-id>`

### Remove a container using Docker Desktop

1. Open Docker Desktop to the **Containers** view.
2. Select the trash can icon under the **Actions** column for the container that you want to delete.
3. In the confirmation dialog, select **Delete forever**.

### Start the updated app container

1. Now, start your updated app using the `docker run` command.
  ```console
  $ docker run -dp 127.0.0.1:3000:3000 getting-started
  ```
2. Refresh your browser on [http://localhost:3000](http://localhost:3000) and you should see your updated help text.

## Summary

In this section, you learned how to update and rebuild an image, as well as how to stop and remove a container.

Related information:

- [docker CLI reference](https://docs.docker.com/reference/cli/docker/)

## Next steps

Next, you'll learn how to share images with others.

[Share the application](https://docs.docker.com/get-started/workshop/04_sharing_app/)

---

# Share the application

> Sharing your image you built for your example application so you can run it else where and other developers can use it

# Share the application

   Table of contents

---

Now that you've built an image, you can share it. To share Docker images, you have to use a Docker
registry. The default registry is Docker Hub and is where all of the images you've used have come from.

> **Docker ID**
>
>
>
> A Docker ID lets you access Docker Hub, which is the world's largest library and community for container images. Create a [Docker ID](https://hub.docker.com/signup) for free if you don't have one.

## Create a repository

To push an image, you first need to create a repository on Docker Hub.

1. [Sign up](https://www.docker.com/pricing?utm_source=docker&utm_medium=webreferral&utm_campaign=docs_driven_upgrade) or Sign in to [Docker Hub](https://hub.docker.com).
2. Select the **Create Repository** button.
3. For the repository name, use `getting-started`. Make sure the **Visibility** is **Public**.
4. Select **Create**.

In the following image, you can see an example Docker command from Docker Hub. This command will push to this repository.

![Docker command with push example](https://docs.docker.com/get-started/workshop/images/push-command.webp)  ![Docker command with push example](https://docs.docker.com/get-started/workshop/images/push-command.webp)

## Push the image

Let's try to push the image to Docker Hub.

1. In the command line, run the following command:
  ```console
  docker push docker/getting-started
  ```
  You'll see an error like this:
  ```console
  $ docker push docker/getting-started
  The push refers to repository [docker.io/docker/getting-started]
  An image does not exist locally with the tag: docker/getting-started
  ```
  This failure is expected because the image isn't tagged correctly yet.
  Docker is looking for an image name `docker/getting started`, but your
  local image is still named `getting-started`.
  You can confirm this by running:
  ```console
  docker image ls
  ```
2. To fix this, first sign in to Docker Hub using your Docker ID: `docker login YOUR-USER-NAME`.
3. Use the `docker tag` command to give the `getting-started` image a new name. Replace `YOUR-USER-NAME` with your Docker ID.
  ```console
  $ docker tag getting-started YOUR-USER-NAME/getting-started
  ```
4. Now run the `docker push` command again. If you're copying the value from
  Docker Hub, you can drop the `tagname` part, as you didn't add a tag to the
  image name. If you don't specify a tag, Docker uses a tag called `latest`.
  ```console
  $ docker push YOUR-USER-NAME/getting-started
  ```

## Run the image on a new instance

Now that your image has been built and pushed into a registry, you can run your app on any machine that has Docker installed. Try pulling and running your image on another computer or a cloud instance.

## Summary

In this section, you learned how to share your images by pushing them to a
registry. You then went to a brand new instance and were able to run the freshly
pushed image. This is quite common in CI pipelines, where the pipeline will
create the image and push it to a registry and then the production environment
can use the latest version of the image.

Related information:

- [docker CLI reference](https://docs.docker.com/reference/cli/docker/)
- [Multi-platform images](https://docs.docker.com/build/building/multi-platform/)
- [Docker Hub overview](https://docs.docker.com/docker-hub/)

## Next steps

In the next section, you'll learn how to persist data in your containerized application.

[Persist the DB](https://docs.docker.com/get-started/workshop/05_persisting_data/)

---

# Persist the DB

> Making your DB persistent in your application

# Persist the DB

   Table of contents

---

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're using the same image.

### See this in practice

To see this in action, you're going to start two containers. In one container,
you'll create a file. In the other container, you'll check whether that same
file exists.

1. Start an Alpine container and create a new file in it.
  ```console
  $ docker run --rm alpine touch greeting.txt
  ```
  > Tip
  >
  > Any commands you specify after the image name (in this case, `alpine`)
  > are executed inside the container. In this case, the command `touch greeting.txt` puts a file named `greeting.txt` on the container's filesystem.
2. Run a new Alpine container and use the `stat` command to check whether the file exists.
  ```console
  $ docker run --rm alpine stat greeting.txt
  ```
  You should see output similar to the following that indicates the file does not exist in the new container.
  ```console
  stat: can't stat 'greeting.txt': No such file or directory
  ```

The `greeting.txt` file created by the first container did not exist in the
second container. That is because the writeable "top layer" of each container
is isolated. Even though both containers shared the same underlying layers that
make up the base image, the writable layer is unique to each container.

## Container volumes

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](https://docs.docker.com/engine/storage/volumes/) provide the ability to connect specific filesystem paths of
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. 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 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 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 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, 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.

### Create a volume and start the container

You can create the volume and start the container using the CLI or Docker Desktop's graphical interface.

1. Create a volume by using the `docker volume create` command.
  ```console
  $ docker volume create todo-db
  ```
2. Stop and remove the todo app container once again 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. 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 127.0.0.1:3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
  ```
  > Note
  >
  > If you're using Git Bash, you must use different syntax for this command.
  >
  >
  >
  > ```console
  > $ docker run -dp 127.0.0.1:3000:3000 --mount type=volume,src=todo-db,target=//etc/todos getting-started
  > ```
  >
  >
  >
  > For more details about Git Bash's syntax differences, see
  > [Working with Git Bash](https://docs.docker.com/desktop/troubleshoot-and-support/troubleshoot/topics/#docker-commands-failing-in-git-bash).

To create a volume:

1. Select **Volumes** in Docker Desktop.
2. In **Volumes**, select **Create**.
3. Specify `todo-db` as the volume name, and then select **Create**.

To stop and remove the app container:

1. Select **Containers** in Docker Desktop.
2. Select **Delete** in the **Actions** column for the container.

To start the todo app container with the volume mounted:

1. Select the search box at the top of Docker Desktop.
2. In the search window, select the **Images** tab.
3. In the search box, specify the image name, `getting-started`.
  > Tip
  >
  > Use the search filter to filter images and only show **Local images**.
4. Select your image and then select **Run**.
5. Select **Optional settings**.
6. In **Host port**, specify the port, for example, `3000`.
7. In **Host path**, specify the name of the volume, `todo-db`.
8. In **Container path**, specify `/etc/todos`.
9. Select **Run**.

### Verify that the data persists

1. Once the container starts up, open the app and add a few items to your todo list.
  ![Items added to todo list](https://docs.docker.com/get-started/workshop/images/items-added.webp)  ![Items added to todo list](https://docs.docker.com/get-started/workshop/images/items-added.webp)
2. Stop and remove the container for the todo app. Use Docker Desktop or `docker ps` to get the ID and then `docker rm -f <id>` to remove it.
3. Start a new container using the previous steps.
4. Open the app. You should see your items still in your list.
5. Go ahead and remove the container when you're done checking out your list.

You've now learned how to persist data.

## Dive into the volume

A lot of people frequently ask "Where is Docker storing my data when I use a volume?" If you want to know,
you can use the `docker volume inspect` command.

```console
$ docker volume inspect todo-db
```

You should see output like the following:

```console
[
    {
        "CreatedAt": "2019-09-26T02:18:36Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
        "Name": "todo-db",
        "Options": {},
        "Scope": "local"
    }
]
```

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.

## Summary

In this section, you learned how to persist container data.

Related information:

- [docker CLI reference](https://docs.docker.com/reference/cli/docker/)
- [Volumes](https://docs.docker.com/engine/storage/volumes/)

## Next steps

Next, you'll learn how you can develop your app more efficiently using bind mounts.

[Use bind mounts](https://docs.docker.com/get-started/workshop/06_bind_mounts/)
