参考来源:
(应用的容器化实践)docker官方入门指南 https://docs.docker.com/get-started/
本指南包含有关如何开始使用 Docker 的分步说明。本指南介绍如何:
将映像作为容器生成并运行。
使用 Docker Hub 共享映像。
使用带有数据库的多个容器部署 Docker 应用程序。
使用 Docker Compose 运行应用程序。
step6 使用绑定挂载
目录 table of contents
·快速卷类型比较 comparisons
·试用绑定挂载
·开发容器
·在开发容器中运行应用
·使用开发容器开发应用
在第 5 部分中,您使用卷装载将数据保存在数据库中。当您需要持久性位置来存储应用程序数据时,卷装载是一个不错的选择。
绑定挂载是另一种类型的挂载,它允许您将主机文件系统中的目录共享到容器中。在处理应用程序时,可以使用绑定挂载将源代码挂载到容器中。一旦你保存文件,容器就会立即看到你对代码所做的更改。这意味着您可以在容器中运行进程来监视文件系统更改并响应它们。
在本章中,您将了解如何使用绑定挂载和名为 nodemon 的工具来监视文件更改,然后自动重新启动应用程序。在大多数其他语言和框架中都有等效的工具。
快速卷类型比较
以下是使用以下 --mount 方法的命名卷和绑定挂载的示例:
命名卷
命名卷: type=volume,src=my-volume,target=/usr/local/data
绑定安装: type=bind,src=/path/to/data,target=/usr/local/data
下表概述了卷装载和绑定装载之间的主要区别。
试用绑定挂载
在了解如何使用绑定挂载开发应用程序之前,您可以运行一个快速实验(最小功能单元-红细胞),以实际了解绑定挂载的工作原理。
- 验证您的 getting-started-app 目录是否位于 Docker Desktop 的文件共享设置中定义的目录中。此设置定义了可以与容器共享文件系统的哪些部分。有关访问该设置的详细信息,请参阅适用于 Mac、Windows 或 Linux 的主题。
- 打开终端并将目录更改为该 getting-started-app 目录
- 运行以下命令,在具有绑定挂载的 ubuntu 容器中启动 bash 。
docker run -it --mount type=bind,src="$(pwd)",target=/src ubuntu bash
- 运行命令后,Docker 会在容器文件系统的根目录中启动交互 bash 式会话
root@ac1237fad8db:/# pwd
/
root@ac1237fad8db:/# ls
bin dev home media opt root sbin srv tmp var
boot etc lib mnt proc run src sys usr
- 将目录更改为 src 目录。
这是您在启动容器时挂载的目录。列出此目录的内容将显示与主机上目录 getting-started-app 中的文件相同的文件。
root@ac1237fad8db:/# cd src
root@ac1237fad8db:/src# ls
Dockerfile node_modules package.json spec src yarn.lock
- 创建一个名为 myfile.txt 的新文件
root@ac1237fad8db:/src# touch myfile.txt
root@ac1237fad8db:/src# ls
Dockerfile myfile.txt node_modules package.json spec src yarn.lock
- 打开主机上的 getting-started-app 目录,并观察 myfile.txt 文件是否在目录中。
├── getting-started-app/
│ ├── Dockerfile
│ ├── myfile.txt
│ ├── node_modules/
│ ├── package.json
│ ├── spec/
│ ├── src/
│ └── yarn.lock
root@ub1804:/home/xiaoyue/workdir/dockerdir/getting-started-app# ls
Dockerfile node_modules README.md src yarn.lock
myfile.txt package.json spec yarn-error.log
- 从主机中删除文件 myfile.txt 。
- 在容器中,再次列出 app 目录的内容。观察文件现在不见了。
root@ac1237fad8db:/src# ls
Dockerfile node_modules package.json spec src yarn.lock
以上就是绑定挂载的简要介绍。此过程演示了如何在主机和容器之间共享文件,以及如何立即在两端反映更改。现在,您可以使用绑定挂载来开发软件。
开发容器
使用绑定挂载在本地开发设置中很常见。优点是开发计算机不需要安装所有生成工具和环境。使用单个 docker run 命令,Docker 会拉取依赖项和工具。
在开发容器中运行应用
以下步骤介绍如何使用执行以下操作的绑定装载运行开发容器:
将源代码装载到容器中
安装所有依赖项
开始 nodemon 监视文件系统更改
可以使用 CLI 或 Docker Desktop 运行具有绑定挂载的容器
1.确保当前没有任何 getting-started 正在运行的容器。
2.从 getting-started-app 目录中运行以下命令。
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 以启动开发服务器。如果查看 package.json ,您将看到 dev 脚本开始 nodemon 。
3.您可以使用 docker logs .当你看到这个时,你就会知道你已经准备好了:
docker logs -f <container-id>
nodemon -L src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000
看完日志后,按 Ctrl + C 退出。
------>个人实践故障处理
root@ub1804:/home/xiaoyue/workdir/dockerdir/getting-started-app# docker logs -f 3864
yarn install v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
error An unexpected error occurred: "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz: connect ECONNREFUSED 104.16.1.35:443".
info If you think this is a bug, please open a bug report with the information provided in "/app/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
遇到一个和一开始安装时一样的问题,连接是遇到一个错误,决定在构建是将基础镜像从 node:18-alpine 换成vigneshasdf/node-18.15.0-alpine
docker run -dp 127.0.0.1:3000:3000 -w /app --mount type=bind,src="$(pwd)",target=/app vigneshasdf/node-18.15.0-alpine sh -c "yarn install && yarn run dev"
Unable to find image 'vigneshasdf/node-18.15.0-alpine:latest' locally
latest: Pulling from vigneshasdf/node-18.15.0-alpine
f56be85fc22e: Pull complete
51fa4270e0cc: Pull complete
a89e758f145e: Pull complete
d3f921cbf16e: Pull complete
58d4e4b64043: Pull complete
Digest: sha256:b4b390bc51c4a7324667b5cf607ee6c28bc1fb508474ab76b0c39269e4ff42c0
Status: Downloaded newer image for vigneshasdf/node-18.15.0-alpine:latest
620f2952aed8c0a9b1b18021db2ac47e965dd2ac5ab0acc44009b9695dcd7ce5
查看日志
root@ub1804:/home/xiaoyue/workdir/dockerdir/getting-started-app# docker logs -f 620f
yarn install v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 29.18s.
yarn run v1.22.19
$ nodemon -L src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000
使用开发容器开发应用
在主机上更新应用,并查看容器中反映的更改。
1.在 src/static/js/app.js 文件的第 109 行,将“添加项目”按钮更改为简单地说“添加”:
- {submitting ? 'Adding...' : 'Add Item'}
+ {submitting ? 'Adding...' : 'Add'}
Save the file. 保存文件。
2. 在 Web 浏览器中刷新页面,由于绑定挂载,您应该几乎立即看到更改。Nodemon 检测到更改并重新启动服务器。节点服务器可能需要几秒钟才能重新启动。如果出现错误,请尝试在几秒钟后刷新。
[右边绿色的添加按钮名称,只有Add了]
3. 请随意进行您想要进行的任何其他更改。每次进行更改并保存文件时,由于绑定装载,更改都会反映在容器中。当 Nodemon 检测到更改时,它会自动重新启动容器内的应用程序。完成后,停止容器并使用以下命令生成新映像:
docker build -t getting-started .
实践记录
root@ub1804:/home/xiaoyue/workdir/dockerdir/getting-started-app# docker build -t getting-started .
Sending build context to Docker daemon 65.2MB
Step 1/6 : FROM vigneshasdf/node-18.15.0-alpine
---> daf65da30dd3
Step 2/6 : WORKDIR /app
---> Using cache
---> dd0ea449b57a
Step 3/6 : COPY . .
---> Using cache
---> 46ad008eed25
Step 4/6 : RUN yarn install --production
---> Running in 79d88111be9d
yarn install v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 23.30s.
Removing intermediate container 79d88111be9d
---> 211e5183719a
Step 5/6 : CMD ["node", "src/index.js"]
---> Running in 9e7488c31184
Removing intermediate container 9e7488c31184
---> 1a06057f0835
Step 6/6 : EXPOSE 3000
---> Running in 49267d8db39b
Removing intermediate container 49267d8db39b
---> 5503a7f2147d
Successfully built 5503a7f2147d
Successfully tagged getting-started:latest
root@ub1804:/home/xiaoyue/workdir/dockerdir/getting-started-app# docker images | grep "started"
getting-started latest 5503a7f2147d About a minute ago 318MB
总结
此时,您可以保留数据库并在开发时查看应用中的更改,而无需重新生成映像。
除了卷挂载和绑定挂载之外,Docker 还支持其他挂载类型和存储驱动程序,以处理更复杂和专业的用例。
后续步骤
为了准备应用以供生产使用,您需要将数据库从在 SQLite 中工作迁移到可以更好地扩展的数据库。为简单起见,您将继续使用关系数据库,并将应用程序切换为使用 MySQL。但是,你应该如何运行MySQL?如何让容器相互通信?您将在下一节中了解这一点。
step 7 多容器应用
目录
容器网络
启动MySQL
连接到MySQL
使用MySQL运行应用
容器网络
请记住,默认情况下,容器是独立运行的,并且对同一台计算机上的其他进程或容器一无所知。那么,如何允许一个容器与另一个容器通信呢?答案是网络。如果将两个容器放在同一个网络上,它们可以相互通信。
启动MySQL
有两种方法可以将容器放在网络上:
在启动容器时分配网络。
将已在运行的容器连接到网络。
在以下步骤中,你将首先创建网络,然后在启动时附加 MySQL 容器。
1.创建网络。
docker network create todo-app
- 启动 MySQL 容器并将其附加到网络。您还将定义一些环境变量,数据库将使用这些变量来初始化数据库。要了解有关 MySQL 环境变量的更多信息,请参阅 MySQL Docker Hub 列表中的“环境变量”部分。
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 标志。在后面的部分中,你将了解有关此标志的详细信息。
Tip
您会注意到上述命令中命名 todo-mysql-data 的卷,该卷挂载在 /var/lib/mysql ,这是 MySQL 存储其数据的位置。但是,您从未运行过命令 docker volume create 。Docker 识别您要使用命名卷,并自动为您创建一个.
实践记录
root@ub1804:/home/xiaoyue/workdir/dockerdir# 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
Unable to find image 'mysql:8.0' locally
8.0: Pulling from library/mysql
07bc88e18c4a: Pull complete
2546f0005eef: Pull complete
1021dda8eecf: Pull complete
1bb57662dd7f: Pull complete
7fb14d8034cd: Pull complete
73124c42ecbe: Pull complete
74830c23cea0: Pull complete
0139fa284505: Pull complete
5165942f42d6: Pull complete
2915d634a344: Pull complete
9a1f1e1ee309: Pull complete
Digest: sha256:7cf8a10b3c17273a47c5cd876cdb790c551012b40b36909b8ca0d9ab5721ed2c
Status: Downloaded newer image for mysql:8.0
531704bc2aca4781e83b9acb2ec2b3ff8a520a3706b4df35bdba4b29ac3402f5
root@ub1804:/home/xiaoyue/workdir/dockerdir# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
531704bc2aca mysql:8.0 "docker-entrypoint.s…" About a minute ago Up 54 seconds 3306/tcp, 33060/tcp romantic_williams
3.若要确认数据库已启动并正在运行,请连接到数据库并验证它是否已连接。
docker exec -it <mysql-container-id> mysql -u root -p
当密码提示出现时,键入 secret 。在 MySQL shell 中,列出数据库并验证是否看到该 todos 数据库
mysql> SHOW DATABASES;
您应该会看到如下所示的输出:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| todos |
+--------------------+
5 rows in set (0.00 sec)
- 退出 MySQL shell 以返回到计算机上的 shell。
现在,您已经拥有了一个 todos 数据库,可供您使用。
连接到MySQL
现在您知道MySQL已启动并运行,您可以使用它。但是,你如何使用它?如果在同一网络上运行另一个容器,如何找到该容器?请记住,每个容器都有自己的 IP 地址。
为了回答上述问题并更好地了解容器网络,您将使用 nicolaka/netshoot 容器,它附带了许多可用于故障排除或调试网络问题的工具。
- 使用 nicolaka/netshoot 映像启动一个新容器。确保将其连接到同一网络。
docker run -it --network todo-app nicolaka/netshoot
实践记录:
在构建中遇到其中一层下载出现很长时间都没有进度,然后中断程序后重新运行下载镜像,操作了2次后下载成功
- 在容器中,您将使用该 dig 命令,这是一个有用的 DNS 工具。您将查找主机名 mysql 的 IP 地址。
dig mysql
实践记录:
0d53ba91dcde ~ dig mysql
; <<>> DiG 9.18.25 <<>> mysql
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48270
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;mysql. IN A
;; ANSWER SECTION:
mysql. 600 IN A 172.18.0.2
;; Query time: 27 msec
;; SERVER: 127.0.0.11#53(127.0.0.11) (UDP)
;; WHEN: Sun Jun 02 06:57:59 UTC 2024
;; MSG SIZE rcvd: 44
在“ANSWER SECTION”中,您将看到 A mysql 解析为 172.18.0.2 (您的 IP 地址很可能具有不同的值)的记录。虽然 mysql 通常不是有效的主机名,但 Docker 能够将其解析为具有该网络别名的容器的 IP 地址。请记住,您使用了较早的 --network-alias 。
这意味着你的应用只需要连接到名为 mysql 的主机,它就会与数据库通信。
使用MySQL运行应用
todo应用程序支持设置一些环境变量来指定MySQL连接设置。他们是:
MYSQL_HOST - 正在运行的MySQL服务器的主机名
MYSQL_USER - 用于连接的用户名
MYSQL_PASSWORD - 用于连接的密码
MYSQL_DB - 连接后要使用的数据库
Note注意
虽然通常接受使用 env vars 来设置连接设置,但在生产环境中运行应用程序时,强烈建议不要这样做。Docker 的前安全主管 Diogo Monica 写了一篇精彩的博客文章来解释原因。
更安全的机制是使用容器业务流程框架提供的机密支持。在大多数情况下,这些机密将作为文件装载到正在运行的容器中。你会看到许多应用(包括 MySQL 镜像和 todo 应用)也支持带有 _FILE 后缀的 env var,以指向包含变量的文件。
例如,设置 MYSQL_PASSWORD_FILE var 将导致应用使用引用文件的内容作为连接密码。Docker 不做任何事情来支持这些环境变量。你的应用需要知道查找变量并获取文件内容。
现在可以启动开发就绪容器。
- 指定前面的每个环境变量,并将容器连接到应用网络。请确保在运行此命令时位于目录中 getting-started-app 。
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 ) 的日志,您应该会看到类似于以下内容的消息,这表明它正在使用 mysql 数据库。
实践记录:
root@ub1804:/home/xiaoyue/workdir/dockerdir/getting-started-app# docker logs -f 63ba
yarn install v1.22.19
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.32s.
yarn run v1.22.19
$ nodemon -L src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Waiting for mysql:3306.
Connected!
Connected to mysql db at host mysql
Listening on port 3000
- 在浏览器中打开应用程序,然后将一些项目添加到您的待办事项列表中。
4.连接到 mysql 数据库并证明项目正在写入数据库。请记住,密码是 secret
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 |
+--------------------------------------+--------------------+-----------+
实践记录
root@ub1804:/home/xiaoyue/workdir/dockerdir/getting-started-app# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
63ba3386b23e node:18-alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 127.0.0.1:3000->3000/tcp sharp_cohen
0d53ba91dcde nicolaka/netshoot "zsh" 9 minutes ago Up 9 minutes sweet_lalande
531704bc2aca mysql:8.0 "docker-entrypoint.s…" 33 minutes ago Up 32 minutes 3306/tcp, 33060/tcp romantic_williams
root@ub1804:/home/xiaoyue/workdir/dockerdir/getting-started-app# docker exec -it 5317 mysql -p todos
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.37 MySQL Community Server - GPL
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> select * from todo_items;
+--------------------------------------+--------+-----------+
| id | name | completed |
+--------------------------------------+--------+-----------+
| ad2c682d-79b4-49c4-ac31-1328ba848ea7 | create | 0 |
| d8af6b0e-93f9-4dc0-8344-6391a72d84a8 | str | 1 |
+--------------------------------------+--------+-----------+
2 rows in set (0.00 sec)
mysql>
总结
此时,您有一个应用程序,该应用程序现在将其数据存储在单独容器中运行的外部数据库中。你了解了一些关于使用 DNS 的容器网络和服务发现的知识
后续步骤
您很有可能开始对启动此应用程序所需的一切感到有点不知所措。您必须创建网络、启动容器、指定所有环境变量、公开端口等。要记住的事情很多,这肯定会让事情更难传递给其他人。
在下一节中,你将了解 Docker Compose。使用 Docker Compose,您可以更轻松地共享应用程序堆栈,并让其他人使用单个简单的命令来启动它们