本文是根据官网Get Started做的笔记,如有不对之处,请大家指正。
Part 1: 概述
此文包含有关如何开始使用 Docker 的步骤说明。将介绍如何:
- 把镜像作为容器构建并运行。
- 使用Docker Hub共享镜像。
- 使用带有数据库的多个容器部署Docker应用程序。
- 使用Docker Compose运行镜像。
什么是容器?
容器是运行在主机上的沙盒进程,与该主机上运行的所有其他进程隔离。这种隔离利用了kernel namespaces and cgroups,这些功能已经在 Linux 中存在了很长时间。Docker使这些功能变得易于使用。总之,容器:
- 是镜像的可运行实例。可以使用 Docker API 或 CLI 创建、启动、停止、移动或删除容器
- 可以运行在本地计算机、虚拟机上,也可以部署到云中。
- 是可移植的(并且可以在任何操作系统上运行)。
- 与其他容器隔离,并运行自己的软件、二进制文件、配置等。
什么是镜像?
正在运行的容器使用隔离的文件系统。这个隔离的文件系统由镜像提供,镜像必须包含运行应用程序所需的所有依赖项、配置、脚本、二进制文件等。该镜像还包含容器的其他配置,例如环境变量、要运行的默认命令和其他元数据。
Part 2: 容器化应用程序
接下来,将使用在 Node.js上运行的简单待办事项列表管理器。如果不熟悉 Node.js,请不要担心。这里不需要任何 JavaScript 经验。
准备事项
- 需要安装Docker
- 需要安装Git客户端
获取应用
- 克隆应用程序使用以下命令
git clone https://github.com/docker/getting-started-app.git
- 查看克隆库的内容,如以下文件和子目录。
getting-started-app/
package.json
README.md
spec/
src/
yarn.lock
构建应用镜像
构建镜像需要使用Dockerfile,Dockerfile 只是一个没有文件扩展名包含指令的基于文本的文件。Docker使用此脚本来构建镜像。
- 进入到
getting-started-app目录里,并创建Dockerfile文件
# 需要替换为自己的路径
cd /path/to/getting-started-app
# Linux下创建一个空文件命名为Dockerfile
touch Dockerfile
- 使用文本编辑器,在Dockerfile里添加以下内容:
# syntax=docker/dockerfile:1
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
- 定位到getting-started-app目录下,构建镜像使用以下命令
docker build -t getting-started .
运行应用容器
- 使用
docker run命令运行窗口,如下:
docker run -dp 127.0.0.1:3000:3000 getting-started
-d是--detach的简写,表示后台运行容器。-p是--publish的简写,创建一个主机和容器之间的端口映射。- 格式
HOST:CONTAINER; - 没有端口映射,就不能在主机上访问应用;
- 格式
- 过一会儿,在浏览器上访问http://localhost:3000 ,就能看到应用页面。
- 查看容器列表
docker ps
Part 3: 更新应用
在这一部分,将会更新应用和镜像,也会学习到怎样停止或删除容器。
更新源代码
- 在
src/static/js/app.js文件里, 更新56行
- <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>
- 构建镜像的更新版本,使用
docker build命令
docker build -t getting-started .
- 启动更新代码后的容器
docker run -dp 127.0.0.1:3000:3000 getting-started
可能会遇到这样的错误
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.
发生这个错误的原因是,旧容器存在并在运行时无法启动新容器。原因是旧容器已在使用主机的端口3000,并且计算机上只有一个进程(包括容器)可以侦听特定端口。要解决此问题,需要删除旧容器。
删除旧容器
- 获取容器ID,使用
docker ps命令:
docker ps
- 停止容器,使用
docker stop命令:
docker stop <the-container-id>
- 删除容器,使用
docker rm命令:
docker rm <the-container-id>
也可使用如下命令强制删除正在运行的容器
docker rm -f <the-container-id>
再次创建并运行应用容器
docker run -dp 127.0.0.1:3000:3000 getting-started
Part 4: 分享应用
构建镜像后,也可以上传到Docker Hub分享这个镜像。
创建仓库
推送镜像,首先得在Docker Hub上创建仓库。
- 注册或登录Docker Hub
- 选择Create Repository按钮
- 存储库名称命名为
getting-started,确保可见性是公开的。
推送镜像
- 登录Docker Hub使用命令。
docker login -u YOUR-USER-NAME
- 使用
docker tag命令给getting-started指定新名称。
docker tag getting-started YOUR-USER-NAME/getting-started
- 推送到Docker Hub使用命令
docker push YOUR-USER-NAME/getting-started
Part 5: 持久化到数据库
我们发现同一个镜像创建的不同容器启动后,有些数据不能被共享,接下来我们说明为什么会这样。
容器的文件系统
当容器运行时,它会将镜像中的各种层用于其文件系统。每个容器都有自己的“暂存空间”来创建/更新/删除文件。任何更改都不会显示在另一个容器中,即使它们使用相同的镜像也是如此。
小试一下
将会启动两个容器并在每个容器中创建一个文件。我们会看到在一个容器中创建的文件在另一个容器中不可用。
- 启动一个
ubuntu容器,该容器将创建一个名为/data.txt的文件,该文件的随机数在1到10000之间
docker run -d ubuntu bash -c "shuf -i 1-10000 -n 1 -o /data.txt && tail -f /dev/null"
- 验证是否可以通过访问容器中的终端来查看输出。
docker exec <container-id> cat /data.txt
- 现在,启动另一个
ubuntu容器(相同的镜像像),您将看到没有相同的文件。
docker run -it ubuntu ls /
- 删除第一个容器,使用
docker rm -f <container-id>。
容器卷
在前面的试验中,可以看到每个容器每次启动时都从镜像定义开始。容器可以创建、更新和删除文件。当删除容器并且 Docker 隔离对该容器的所有更改时,这些更改会丢失。使用卷,使这些更改不会丢失。
卷提供了将容器的特定文件系统路径连接回主机的功能。如果在容器中装载目录,则还会在主机上看到该目录中的更改。如果在容器重启后挂载相同的目录,则会看到相同的文件。
卷有两种主要类型。您最终将同时使用两者,但您将从卷装载开始。
保留 todo data
todo 应用程序默认将其数据存储在容器文件系统中的 /etc/todos/todo.db SQLite 数据库中。SqLite只是一个关系数据库,将所有数据存储在单个文件中。它适用于小型应用演示。稍后将了解如何将其切换到其他数据库引擎。
由于数据库是单个文件,如果可以将该文件保留在主机上并使其可用于下一个容器,则它应该能够从最后一个容器停止的地方继续。通过创建卷并将其附加到(通常称为“挂载”)到存储数据的目录,可以保留数据。当容器写入 todo.db 文件时,它会将数据保存到卷中的主机。
如前所述,您将使用卷装载。将卷装载视为不透明的数据桶。Docker 完全管理卷,包括磁盘上的存储位置。您只需要记住卷的名称。
创建卷并启动容器
- 使用 docker 卷创建命令创建卷。
docker volume create todo-db
- 使用
docker rm -f <id>把之前仍在运行todo应用的容器删除掉 - 启动todo应用程序容器,但需要添加
--mount选项以指定卷装载。给容器卷命名,并将其挂载到容器中的/etc/todos,这将捕获在该路径上创建的所有文件。在 Mac 或 Linux 终端中,或者在 Windows 命令提示符或 PowerShell 中,运行以下命令:
docker run -dp 127.0.0.1:3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
验证数据持久性
- 容器启动后,打开应用并将一些项目添加到待办事项列表中。
- 停止并删除待办事项应用的容器。 使用
docker ps获取ID,然后使用docker rm -f <id>将其删除。 - 使用前面的步骤启动新容器。
- 打开应用。您应该会看到您的项目仍在列表中。
- 删除容器。 现在,你已了解如何保留数据。
深入了解卷
很多人经常问当我使用卷时,Docker 将我的数据存储在哪里?如果你想知道,你可以使用docker volume inspect命令
docker volume inspect todo-db
[
{
"CreatedAt": "2019-09-26T02:18:36Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
"Name": "todo-db",
"Options": {},
"Scope": "local"
}
]
Part 6: 使用 bind mounts
绑定挂载是另一种类型的挂载,允许将主机文件系统中的目录共享到容器中。处理应用程序时,可以使用绑定挂载将源代码装载到容器中。保存文件后,容器会立即看到您对代码所做的更改。这意味着您可以在容器中运行进程来监视文件系统更改并响应它们。
简单比较
下表概述了卷装载和绑定装载之间的主要区别。
| Named volumes | Bind mounts | |
|---|---|---|
| Host location | Docker chooses | You decide |
Mount example (using --mount) | type=volume,src=my-volume,target=/usr/local/data | type=bind,src=/path/to/data,target=/usr/local/data |
| Populates new volume with container contents | Yes | No |
| Supports Volume Drivers | Yes | No |
尝试绑定装载
在了解如何使用绑定装载开发应用程序之前,可以运行一个快速实验,以实际了解绑定装载的工作原理。
- 打开终端并将目录更改为入门应用目录
- 运行以下命令以
bash运行并绑定挂载的ubuntu的容器。 Mac/Linux
docker run -it --mount type=bind,src="$(pwd)",target=/src ubuntu bash
Windows,在PowerShell中运行此命令
docker run -it --mount "type=bind,src=$pwd,target=/src" ubuntu bash
--mount 选项告诉 Docker 创建一个绑定挂载,src 是宿主机上(getting-started-app)的当前工作目录, target 指定的目录应该出现在窗口内的位置(/src)。
3. 运行命令后,docker 在容器文件系统的根目录中启动交互式 bash 会话。
root@cf90e1c75cc7:/# pwd
/
root@cf90e1c75cc7:/# ls
bin dev home lib32 libx32 mnt proc run src sys usr
boot etc lib lib64 media opt root sbin srv tmp var
root@cf90e1c75cc7:/#
- 进入到
src目录。
root@5b840153cf1b:/# cd src
root@5b840153cf1b:/src# ls
Dockerfile README.md package.json spec src yarn.lock
这是启动容器时装载的目录。列出此目录的内容将显示与主机上的getting-started-app目录中相同的文件。
5. 创建一个新的文件名为 myfile.txt.
root@5b840153cf1b:/src# touch myfile.txt
root@5b840153cf1b:/src# ls
Dockerfile README.md myfile.txt package.json spec src yarn.lock
- 在主机上打开
getting-started-app目录,并观察文件myfile.txt.
Name
----
spec
src
Dockerfile
myfile.txt
package.json
README.md
yarn.lock
- 在主机上删除
myfile.txt文件. - 在容器上,再一次观察
myfile.txt文件,发现已经没有了。 - 使用
Ctrl + D停止交互式容器会话。
开发容器
在本地开发设置中,使用绑定装载很常见。优点是开发计算机不需要安装所有生成工具和环境。通过单个 docker 运行命令,Docker 可以提取依赖项和工具。
在开发容器中运行应用
以下步骤介绍如何使用执行以下操作的绑定装载运行开发容器:
- 将源代码挂载到容器中
- 安装所有依赖项
- 启动
nodemon以监视文件系统更改
CLI
- 确保当前没有任何
getting-started容器正在运行。 - 从
getting-started-app目录运行以下命令。
# CLI (Mac / Linux)
docker run -dp 127.0.0.1:3000:3000 \
-w /app --mount type=bind,src="$(pwd)",target=/app \
node:18-alpine \
sh -c "yarn install && yarn run dev"
# CLI (Windows)
docker run -dp 127.0.0.1:3000:3000 `
-w /app --mount "type=bind,src=$pwd,target=/app" `
node:18-alpine `
sh -c "yarn install && yarn run dev"
以下是该命令的解释:
-dp 127.0.0.1:3000:3000以后台模式运行并创建一个端口映射-w /app设置“工作目录”--mount type=bind,src="$(pwd)",target=/app绑定当前目录从主机到容器中的/app目录node:18-alpine使用的镜像。请注意这是Dockerfile中应用的基本镜像sh -c "yarn install && yarn run dev"你正在使用sh(alpine没有bash)启动一个shell,并运行yarn install来安装软件包,然后运行yarn run dev来启动开发服务器。你查看pakcage.json,你会看到dev脚本启动了nodemon。
- 你可以使用登命令
docker logs <container-id>查看日志。当看到以下显示这些,容器已启动好了。
docker logs -f <container-id>
nodemon src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000
查看完日志后,按 Ctrl+C 退出。
使用开发容器开发应用
更新主机上的应用,并查看容器中反映的更改。
- 在
src/static/js/app.js文件,在行109,更改"Add Item"按钮为"Add"
- {submitting ? 'Adding...' : 'Add Item'}
+ {submitting ? 'Adding...' : 'Add'}
保存文件
3. 随意进行您想要进行的任何其他更改。每次进行更改并保存文件时,nodemon 进程都会自动重新启动容器中的应用程序。完成后,停止容器并使用以下命令生成新镜像:
docker build -t getting-started .
总结
此时,可以保留数据库,并在开发过程中查看应用中的更改,而无需重新生成镜像。
除了卷挂载和绑定挂载之外,Docker 还支持其他挂载类型和存储驱动程序,以处理更复杂和更专业的用例。
Part 7: 多容器应用
到目前为止,一直在使用单个容器应用。现在会添加MySQL到应用程序栈中。经常会出现后面这些问题-“MySQL会在哪里运行?将其安装在同一个容器中还是单独运行?” 一般来说,每个容器应该做好一件事。以下是单独运行容器的几个原因:
- 很有可能会以不同的数据库方式扩展API和前端
- 使用单独的容器可以独立的版本管理更新
- 运行多个进程将需要进程管理器(容器仅启动一个进程),这增加了容器启动/关闭的复杂性。
容器网络
默认情况下,容器是孤立运行的,对同一台机器上的其他进程或容器是不能通信的。那么,一个容器与另一个容器通信就需要网络了。将两个容器放在同一个网络,它们就可以相互通信了。
启动MySQL
有两种方法可以将容器放在网络上:
- 启动容器时分配网络。
- 将已在运行的容器连接到网络。
以下步骤中,会先创建网络,在启动容器时附加上网络。
- 创建网络
docker network create todo-app
- 启动MySQL容器并附加上网络。还可以定义一些初始化数据库的变量。要了解有关 MySQL 环境变量的更多信息,请参阅 MySQL Docker Hub 列表中的“环境变量”部分
Mac/Linux
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:8.0
Windows
在PowerShell中运行
docker run -d `
--network todo-app --network-alias mysql `
-v todo-mysql-data:/var/lib/mysql `
-e MYSQL_ROOT_PASSWORD=secret `
-e MYSQL_DATABASE=todos `
mysql:8.0
上面的命令中看到了 --network-alias标识。后面的部分中,会有介绍。被命名为 todo-mysql-data 的卷绑定 /var/lib/mysql 这是存储MySQL数据的地方。这个卷并未使用 docker volume create 命令创建,Docker会识别出并自动创建卷。
- 若要确认数据库已启动并正在运行,请连接到数据库并验证它是否已连接。
docker exec -it <mysql-container-id> mysql -u root -p
当密码提示出现时,键入密码。在 MySQL shell 中,列出数据库并验证您看到的是 todos 数据库。
mysql> SHOW DATABASES;
您应该看到如下所示的输出:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| todos |
+--------------------+
5 rows in set (0.00 sec)
- 退出MySQL
mysql> exit
现在todo数据库已准备好
连接到MySQL
每个容器都有自己的 IP 地址。可以根据IP进行连接通信。
nicolaka/netshoot 容器,该容器附带了许多可用于故障排除或调试网络问题的工具。
- 使用 nicolaka/netshoot 镜像启动一个新容器。确保将其连接到同一网络。
docker run -it --network todo-app nicolaka/netshoot
- 在容器内部,使用
dig命令,这是一个有用的DNS工具。
dig mysql
应该获得如下所示的输出。
; <<>> DiG 9.18.8 <<>> mysql
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32162
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;mysql. IN A
;; ANSWER SECTION:
mysql. 600 IN A 172.23.0.2
;; Query time: 0 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Tue Oct 01 23:47:24 UTC 2019
;; MSG SIZE rcvd: 44
在 "ANSWER SECTION"部分中, 看到mysql解析为172.23.0.2的A记录(您的 IP 地址很可能具有不同的值)。虽然mysql通常不是有效的主机名,但 Docker 能够将其解析为具有该网络别名的容器的 IP 地址。这是因为之前使用发--network-alias的原因。
这意味着应用程序只需要连接到名为mysql的主机,它将与数据库通信。
运行应用使用mysql作为数据库
todo应用支持设置一些环境变量来指定MySQL连接设置。它们是:
MYSQL_HOST- the hostname for the running MySQL serverMYSQL_USER- the username to use for the connectionMYSQL_PASSWORD- the password to use for the connectionMYSQL_DB- the database to use once connected
- 指定前面的每个环境变量,并将容器连接到应用网络。运行此命令确保当前在
getting-started-app目录。
CLI
## Mac 或 Linux
docker run -dp 127.0.0.1:3000:3000 \
-w /app -v "$(pwd):/app" \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:18-alpine \
sh -c "yarn install && yarn run dev"
## Windows在PowerShell中运行
docker run -dp 127.0.0.1:3000:3000 `
-w /app -v "$(pwd):/app" `
--network todo-app `
-e MYSQL_HOST=mysql `
-e MYSQL_USER=root `
-e MYSQL_PASSWORD=secret `
-e MYSQL_DB=todos `
node:18-alpine `
sh -c "yarn install && yarn run dev"
- 查看容器的日志(docker logs -f <container-id>),应该会看到类似于以下内容的消息,指示它正在使用 MySQL 数据库。
nodemon src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] starting `node src/index.js`
Connected to mysql db at host mysql
Listening on port 3000
- 在浏览器上打开 todo 应用程序添加待办到待办列表
- 连接到 mysql 数据库并验证项目写入数据库
docker exec -it <mysql-container-id> mysql -p todos
在 mysql shell 中,运行以下命令:
mysql> select * from todo_items;
+--------------------------------------+--------------------+-----------+
| id | name | completed |
+--------------------------------------+--------------------+-----------+
| c906ff08-60e6-44e6-8f49-ed56a0853e85 | Do amazing things! | 0 |
| 2912a79e-8486-4bc3-a4c5-460793a575ab | Be awesome! | 0 |
+--------------------------------------+--------------------+-----------+
Part 8 : 使用 Docker Compose
Docker Compose是一个帮助您定义和共享多容器应用程序的工具。使用Compose,您可以创建一个YAML文件来定义服务,只需一个命令,就可以调整所有内容或将其全部删除。
使用Compose的最大优点是可以在文件中定义应用程序堆栈。
创建Compose文件
在 getting-started-app 目录,创建一个名为 compose.yaml 的文件
touch compose.yaml
定义应用程序服务
在 Part 7,使用了命令来启动应用程序服务。接下来将在 compose.yaml 文件中定义此服务。
- 在文本或代码编辑器中打开
compose.yaml,首先定义应用程序中的第一个服务(或容器)的名称和镜像,该名称将自动成为网络别名,这在定义MySQL服务时非常有用。
services:
app:
image: node:18-alpine
- 通常
command命令经常出现在image下面
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
- 配置端口号
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 127.0.0.1:3000:3000
- 接下来,定义工作目录(
-w /app)和卷映射(-v "$(pwd):/app"),在yaml中分别使用working_dir和volumes定义。
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 127.0.0.1:3000:3000
working_dir: /app
# Docker Compose定义卷的一个优点是可以使用相对路径,如当前目录
volumes:
- ./:/app
- 使用
environment定义环境变量
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 127.0.0.1:3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
定义MySQL服务
现在,是时候定义MySQL服务了。之前用于该容器的命令如下:
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:8.0
- 首先定义新服务并将其命名为
mysql,会自动获得网络别名,并指定要使用的镜像。
services:
app:
# The app service definition
mysql:
image: mysql:8.0
- 接下来定义卷映射,当运行容器命令
docker run,Docker自动创建了命名卷。但是,使用Compose运行时不会发生这种情况。需要在顶级定义volumes:然后在服务中配置卷。
services:
app:
# The app service definition
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
volumes:
todo-mysql-data:
- 最终需要指定环境变量
services:
app:
# The app service definition
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
此时,完整的compose.yaml是这样的。
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 127.0.0.1:3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
运行应用程序栈
- 确保没有容器的其他副本先运行。使用
docker ps查看容器列表并使用docker rm -f <ids>删除它们。 - 使用
docker compose up命令启动应用程序堆栈。添加-d表示在后台运行。
docker compose up -d
运行完命令时,应看到如下所示的输出:
Creating network "app_default" with the default driver
Creating volume "app_todo-mysql-data" with default driver
Creating app_app_1 ... done
Creating app_mysql_1 ... done
注意:Docker Compose创建了卷和网络。默认情况下,Docker Compose会自动为应用程序栈创建一个网络。
- 使用
docker compose-logs -f命令查看日志。
mysql_1 | 2019-10-03T03:07:16.083639Z 0 [Note] mysqld: ready for connections.
mysql_1 | Version: '8.0.31' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
app_1 | Connected to mysql db at host mysql
app_1 | Listening on port 3000
如果想查看特定服务的日志,可以将服务名称添加到日志命令的末尾,如docker compose logs -f app
- 此时,可以打开应用了,在浏览器上访问http://localhost:3000。
查看Docker Dashboard中的应用程序栈
在Docker Dashboard中,会看到有一个名为getting-started-app的组。这是Docker Compose中的项目名称,默认情况下,项目名称是compose.yaml所在目录的名称。
全部移除
只需运行 docker compose down。
当运行docker compose down 时,在默认情况下,命名的卷是不会被移除的。如果需要移除,那么需要添加上--volumes。
Part 9 Image-building best practices
我理解的不太透,先贴出官方文档:Image-building best practices