梦境亦相通:上手 Docker Network

2024-03-17 08:10
文章标签 docker network 梦境 相通

本文主要是介绍梦境亦相通:上手 Docker Network,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在实际应用中,不同的服务之间是需要通信的,例如后端 API 和数据库;幸运的是,Docker 为我们提供了网络(Network)机制,能够轻松实现容器互联。这篇文章将带你轻松上手 Docker 网络,学会使用默认网络和自定义网络,成为一名能够连接多个“梦境”的筑梦师!

在上一篇教程[1]中,我们带你了解了镜像和容器这两大关键的概念,熟悉了常用的 docker 命令,并成功地容器化了第一个应用。但是,那只是我们“筑梦之旅”的序章。接下来,我们将实现后端 API 服务器 + 数据库的容器化。

我们为你准备好了应用程序代码,请运行以下命令:

# 如果你看了上一篇教程,仓库已经克隆下来了
cd docker-dream
git fetch origin network-start
git checkout network-start# 如果你打算直接从这篇教程开始
git clone -b network-start https://github.com/tuture-dev/docker-dream.git
cd docker-dream

和之前容器化前端静态页面服务器相比,多了一个难点:服务器和数据库分别是两个独立的容器,但是服务器需要连接和访问数据库,怎么实现跨容器之间的通信?

在《盗梦空间》中,不同的梦境之间是无法连接的,然而幸运的是在 Docker 中是可以的——借助 Docker Network。

提示

在早期,Docker 容器可以通过 docker run 命令的 --link 选项来连接容器,但是 Docker 官方宣布这种方式已经过时,并有可能被移除 (参考文档[2])。而本文将讲解 Docker 官方推荐的方式连接容器:自定义网络(User-defined Networks)。

Network 类型

Network,顾名思义就是“网络”,能够让不同的容器之间相互通信。首先有必要要列举一下 Docker Network 的五种驱动模式(driver):

bridge:默认的驱动模式,即“网桥”,通常用于单机(更准确地说,是单个 Docker 守护进程)•overlay:Overlay 网络能够连接多个 Docker 守护进程,通常用于集群,后续讲 Docker Swarm 的文章会重点讲解•host:直接使用主机(也就是运行 Docker 的机器)网络,仅适用于 Docker 17.06+ 的集群服务•macvlan:Macvlan 网络通过为每个容器分配一个 MAC 地址,使其能够被显示为一台物理设备,适用于希望直连到物理网络的应用程序(例如嵌入式系统、物联网等等)•none:禁用此容器的所有网络

这篇文章将围绕默认的 Bridge 网络驱动展开。没错,就是连接不同梦境的那座“桥”。

小试牛刀

我们还是通过一些小实验来理解和感受 Bridge Network。与上一节不同的是,我们将使用 Alpine Linux[3] 镜像作为实验原材料,因为:

•非常轻量小巧(整个镜像仅 5MB 左右)•功能丰富,比“瑞士军刀” Busybox[4] 还要完善

网桥网络可分为两类:

1.默认网络(Docker 运行时自带,不推荐用于生产环境)2.自定义网络(推荐使用)

让我们分别实践一下吧。

默认网络

这个小实验的内容如下图所示:

我们会在默认的 bridge 网络上连接两个容器 alpine1 和 alpine2。运行以下命令,查看当前已有的网络:

docker network ls

应该会看到以下输出(注意你机器上的 ID 很有可能不一样):

NETWORK ID          NAME                DRIVER              SCOPE
cb33efa4d163        bridge              bridge              local
010deedec029        host                host                local
772a7a450223        none                null                local

这三个默认网络分别对应上面的 bridgehost 和 none 网络类型。接下来我们将创建两个容器,分别名为 alpine1 和 alpine2,命令如下:

docker run -dit --name alpine1 alpine
docker run -dit --name alpine2 alpine

-dit 是 -d(后台模式)、-i(交互模式)和 -t(虚拟终端)三个选项的合并。通过这个组合,我们可以让容器保持在后台运行而不会退出(没错,相当于是在“空转”)。

用 docker ps 命令确定以上两个容器均在后台运行:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
501559d2fab7        alpine              "/bin/sh"           2 seconds ago       Up 1 second                             alpine2
18bed3178732        alpine              "/bin/sh"           3 seconds ago       Up 2 seconds                            alpine1

通过以下命令查看默认的 bridge 网络的详情:

docker network inspect bridge

应该会输出 JSON 格式的网络详细数据:

[{"Name": "bridge","Id": "cb33efa4d163adaa61d6b80c9425979650d27a0974e6d6b5cd89fd743d64a44c","Created": "2020-01-08T07:29:11.102566065Z","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.17.0.0/16","Gateway": "172.17.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {"18bed3178732b5c7a37d7ad820c111fac72a6b0f47844401d60a18690bd37ee5": {"Name": "alpine1","EndpointID": "9c7d8ee9cbd017c6bbdfc023397b23a4ce112e4957a0cfa445fd7f19105cc5a6","MacAddress": "02:42:ac:11:00:02","IPv4Address": "172.17.0.2/16","IPv6Address": ""},"501559d2fab736812c0cf181ed6a0b2ee43ce8116df9efbb747c8443bc665b03": {"Name": "alpine2","EndpointID": "da192d61e4b2df039023446830bf477cc5a9a026d32938cb4a350a82fea5b163","MacAddress": "02:42:ac:11:00:03","IPv4Address": "172.17.0.3/16","IPv6Address": ""}},"Options": {"com.docker.network.bridge.default_bridge": "true","com.docker.network.bridge.enable_icc": "true","com.docker.network.bridge.enable_ip_masquerade": "true","com.docker.network.bridge.host_binding_ipv4": "0.0.0.0","com.docker.network.bridge.name": "docker0","com.docker.network.driver.mtu": "1500"},"Labels": {}}
]

我们重点要关注的是两个字段:

IPAM:IP 地址管理信息(IP Address Management),可以看到网关地址为 172.17.0.1(由于篇幅有限,想要了解网关的同学可自行查阅计算机网络以及 TCP/IP 协议方面的资料)•Containers:包括此网络上连接的所有容器,可以看到我们刚刚创建的 alpine1 和 alpine2,它们的 IP 地址分别为 172.17.0.2 和 172.17.0.3(后面的 /16 是子网掩码,暂时不用考虑)

提示

如果你熟悉 Go 模板语法,可以通过 -fformat)参数过滤掉不需要的信息。例如我们只想查看 bridge 的网关地址:

$ docker network inspect --format '{{json .IPAM.Config }}' bridge
[{"Subnet":"172.17.0.0/16","Gateway":"172.17.0.1"}]

让我们进入 alpine1 容器中:

docker attach alpine1

注意

attach 命令只能进入设置了交互式运行的容器(也就是在启动时加了 -i 参数)。

如果你看到前面的命令提示符变成 / #,说明我们已经身处容器之中了。我们通过 ping 命令测试一下网络连接情况,首先 ping 一波图雀社区的主站 tuture.co(-c 参数代表发送数据包的数量,这里我们设为 5):

/ # ping -c 5 tuture.co
PING tuture.co (150.109.19.98): 56 data bytes
64 bytes from 150.109.19.98: seq=2 ttl=37 time=65.294 ms
64 bytes from 150.109.19.98: seq=3 ttl=37 time=65.425 ms
64 bytes from 150.109.19.98: seq=4 ttl=37 time=65.332 ms--- tuture.co ping statistics ---
5 packets transmitted, 3 packets received, 40% packet loss
round-trip min/avg/max = 65.294/65.350/65.425 ms

OK,虽然丢了几个包,但是可以连上(取决于你的网络环境,全丢包也是正常的)。由此可见,容器内可以访问主机所连接的全部网络(包括 localhost)。

接下来测试能否连接到 alpine2,在刚才 docker network inspect 命令的输出中找到 alpine2 的 IP 为 172.17.0.3,尝试能否 ping 通:

/ # ping -c 5 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.147 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.103 ms
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.102 ms
64 bytes from 172.17.0.3: seq=3 ttl=64 time=0.125 ms
64 bytes from 172.17.0.3: seq=4 ttl=64 time=0.125 ms--- 172.17.0.3 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.102/0.120/0.147 ms

完美!我们能够从 alpine1 中访问 alpine2 容器。作为练习,你可以自己尝试一下能否从 alpine2 容器中 ping 通 alpine1 哦。

注意

如果你不想让 alpine1 停下来,记得通过 Ctrl + P + Ctrl + Q(按住 Ctrl,然后依次按 P 和 Q 键)“脱离”(detach,也就是刚才 attach 命令的反义词)容器,而不是按 Ctrl + D 哦。

自定义网络

如果你跟着上面一路试下来,会发现默认的 bridge 网络存在一个很大的问题:只能通过 IP 地址相互访问。这毫无疑问是非常麻烦的,当容器数量很多的时候难以管理,而且每次的 IP 都可能发生变化。

而自定义网络则很好地解决了这一问题。在同一个自定义网络中,每个容器能够通过彼此的名称相互通信,因为 Docker 为我们搞定了 DNS 解析工作,这种机制被称为服务发现(Service Discovery)。具体而言,我们将创建一个自定义网络 my-net,并创建 alpine3 和 alpine4 两个容器,连上 my-net,如下图所示。

让我们开始动手吧。首先创建自定义网络 my-net

docker network create my-net
# 由于默认网络驱动为 bridge,因此相当于以下命令
# docker network create --driver bridge my-net

查看当前所有的网络:

docker network ls

可以看到刚刚创建的 my-net

NETWORK ID          NAME                DRIVER              SCOPE
cb33efa4d163        bridge              bridge              local
010deedec029        host                host                local
feb13b480be6        my-net              bridge              local
772a7a450223        none                null                local

创建两个新的容器 alpine3 和 alpine4

docker run -dit --name alpine3 --network my-net alpine
docker run -dit --name alpine4 --network my-net alpine

可以看到,我们通过 --network 参数指定容器想要连接的网络(也就是刚才创建的 my-net)。

提示

如果在一开始创建并运行容器时忘记指定网络,那么下次再想指定网络时,可以通过 docker network connect 命令再次连上(第一个参数是网络名称 my-net,第二个是需要连接的容器 alpine3):

docker network connect my-net alpine3

进入到 alpine3 中,测试能否 ping 通 alpine4

$ docker attach alpine3
/ # ping -c 5 alpine4
PING alpine4 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.247 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.176 ms
64 bytes from 172.19.0.3: seq=2 ttl=64 time=0.180 ms
64 bytes from 172.19.0.3: seq=3 ttl=64 time=0.176 ms
64 bytes from 172.19.0.3: seq=4 ttl=64 time=0.161 ms--- alpine4 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.161/0.188/0.247 ms

可以看到 alpine4 被自动解析成了 172.19.0.3。我们可以通过 docker network inspect 来验证一下:

$ docker network inspect --format '{{range .Containers}}{{.Name}}: {{.IPv4Address}} {{end}}' my-net
alpine4: 172.19.0.3/16 alpine3: 172.19.0.2/16

可以看到 alpine4 的 IP 的确为 172.19.0.3,解析是正确的!

一些收尾工作

实验做完了,让我们把之前所有的容器全部销毁:

docker rm -f alpine1 alpine2 alpine3 alpine4

把创建的 my-net 也删除:

docker network rm my-net

动手实践

容器化服务器

我们首先对后端服务器也进行容器化。创建 server/Dockerfile,代码如下:

FROM node:10# 指定工作目录为 /usr/src/app,接下来的命令全部在这个目录下操作
WORKDIR /usr/src/app# 将 package.json 拷贝到工作目录
COPY package.json .# 安装 npm 依赖
RUN npm config set registry https://registry.npm.taobao.org && npm install# 拷贝源代码
COPY . .# 设置环境变量(服务器的主机 IP 和端口)
ENV MONGO_URI=mongodb://dream-db:27017/todos
ENV HOST=0.0.0.0
ENV PORT=4000# 开放 4000 端口
EXPOSE 4000# 设置镜像运行命令
CMD [ "node", "index.js" ]

可以看到这个 Dockerfile 比上一篇教程[5]中的要复杂不少。每一行的含义已经注释在代码中了,我们来看一看多了哪些新东西:

RUN 指令用于在容器中运行任何命令,这里我们通过 npm install 安装所有项目依赖(当然之前配置了一下 npm 镜像,可以安装得快一点)•ENV 指令用于向容器中注入环境变量,这里我们设置了 数据库的连接字符串 MONGO_URI注意这里给数据库取名为 dream-db,后面就会创建这个容器),还配置了服务器的 HOST 和 PORTEXPOSE 指令用于开放端口 4000。之前在用 Nginx 容器化前端项目时没有指定,是因为 Nginx 基础镜像已经开放了 8080 端口,无需我们设置;而这里用的 Node 基础镜像则没有开放,需要我们自己去配置•CMD 指令用于指定此容器的启动命令(也就是 docker ps 查看时的 COMMAND 一列),对于服务器来说当然就是保持运行状态。在后面“回忆与升华”部分会详细展开。

注意

初次尝试容器的朋友很容易犯的一个错误就是忘记将服务器的 host 从 localhost127.0.0.1)改成 0.0.0.0,导致服务器无法在容器之外被访问到(我自己学习的时候也浪费了很多时间)。

与之前前端容器化类似,创建 server/.dockerignore 文件,忽略服务器日志 access.log 和 node_modules,代码如下:

node_modules
access.log

在项目根目录下运行以下命令,构建服务器镜像,指定名称为 dream-server

docker build -t dream-server server

连接服务器与数据库

根据之前的知识,我们为现在的“梦想清单”应用创建一个自定义网络 dream-net

docker network create dream-net

我们使用官方的 mongo 镜像创建并运行 MongoDB 容器,命令如下:

docker run --name dream-db --network dream-net -d mongo

我们指定容器名称为 dream-db(还记得这个名字吗),所连接的网络为 dream-net,并且在后台模式下运行(-d)。

提示

你也许会问,为什么这里开启容器的时候没有指定端口映射呢?因为在同一自定义网络中的所有容器会互相暴露所有端口,不同的应用之间可以更轻松地相互通信;同时,除非通过 -p--publish)手动开放端口,网络之外无法访问网络中容器的其他端口,实现了良好的隔离性。网络之内的互操作性网络内外的隔离性也是 Docker Network 的一大优势所在。

危险!

这里我们在开启 MongoDB 数据库容器时没有设置任何鉴权措施(例如设置用户名和密码),所有连接数据库的请求都可以任意修改数据,在生产环境是极其危险的。后续文章中我们会讲解如何在容器中管理机密信息(例如密码)。

然后运行服务器容器:

docker run -p 4000:4000 --name dream-api --network dream-net -d dream-server

查看服务器容器的日志输出,确定 MongoDB 连接成功:

$ docker logs dream-api                                                       
Server is running on http://0.0.0.0:4000
Mongoose connected.

接着你可以通过 Postman 或者 curl 来测试一波服务器 API (localhost:4000 ),这里为了节约篇幅就省略了。当然你也可以直接跳过,因为马上我们就可以通过前端来操作数据了!

容器化前端页面

正如上一篇文章[6]所实现的那样,在项目根目录下,通过以下命令进行容器化:

docker build -t dream-client client

然后运行容器:

docker run -p 8080:80 --name client -d dream-client

可以通过 docker ps 命令检验三个容器是否全部正确开启:

最后,访问 localhost:8080

可以看到,我们在最后刷新了几次页面,数据记录也都还在,说明我们带有数据库的全栈应用跑起来了!让我们通过交互式执行的方式进入到数据库容器 dream-db 中,通过 Mongo Shell 简单地查询一波刚才的数据:

$ docker exec -it dream-db mongo
MongoDB shell version v3.4.10
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
Welcome to the MongoDB shell.
For interactive help, type "help".
> use todos
switched to db todos
> db.getCollection('todos').find()
{ "_id" : ObjectId("5e171fda820251a751aae6f5"), "completed" : true, "text" : "了解 Docker Network", "timestamp" : ISODate("2020-01-09T12:43:06.865Z"), "__v" : 0 }
{ "_id" : ObjectId("5e171fe08202517c11aae6f6"), "completed" : true, "text" : "搭建默认网络", "timestamp" : ISODate("2020-01-09T12:43:12.205Z"), "__v" : 0 }
{ "_id" : ObjectId("5e171fe3820251d1a4aae6f7"), "completed" : false, "text" : "搭建自定义网络", "timestamp" : ISODate("2020-01-09T12:43:15.962Z"), "__v" : 0 }

完美!然后按 Ctrl + D 就可以退出来了。

回忆与升华

理解命令:梦境的主旋律

每个容器自从被创建之时,就注定要运行一道命令(Command),就好像在筑梦时要安排一个主旋律、一个基调那样。之前在运行 docker ps 的时候,你应该也注意到了 COMMAND 一栏,正是每个容器所运行的命令。那么我们怎么指定容器的命令呢?又能不能运行新的命令呢?

首先,我们主要通过两种方式指定容器的命令:

通过 Dockerfile 提供默认命令

在构建镜像时,我们可以在 Dockerfile 的最后通过 CMD 指令指定命令,例如在构建后端服务器时的 [ "node", "server.js" ] 命令。在指定命令时,我们有三种写法:

CMD ["executable","param1","param2"](exec 格式,推荐)•CMD ["param1","param2"](需要结合 Entrypoint 使用)•CMD command param1 param2(shell 格式)

其中 executable 代表可执行文件的路径,例如 node/bin/shparam1param2 代表参数。我们在后续讨论 Dockerfile 的高阶使用时会讨论 Entrypoint 的使用,这篇文章不会涉及

注意

在使用第一种 exec 格式时,必须使用双引号,因为整个命令将以 JSON 格式被解析。

提示

如果要执行变量替换等 Shell 操作,例如 echo $HOME,直接写成 ["echo", "$HOME"] 是无效的,需要改写成 ["sh", "-c", "echo $HOME"]

创建或运行容器时指定命令

在创建或运行容器时,通过添加命令参数可以覆盖构建镜像时指定的命令,例如:

docker run nginx echo hello

通过指定 echo hello 命令参数,就会让这个容器输出一个 hello 然后退出,而不会运行默认的 nginx -g 'daemon off;'

当然,正如第一篇文章[7]所实践的,我们还可以指定命令为 bash(或 shmongonode 等其他交互式程序),然后结合 -it 选项,就可以进入容器中交互式运行了。

通过 exec 运行新的命令

通过 docker exec,我们可以让已经运行中的容器执行新的命令。例如,对于我们之前的 dream-db 容器,我们通过 mongodump 命令来创建数据库备份:

docker exec dream-db mongodump

然后可以进一步通过 docker exec -it 来进入 dream-db 中进行交互式运行,检查刚才导出的 dump 目录:

$ docker exec -it dream-db bash
root@c51d9355d8da:/# ls dump/
admin  todos

同样地,按 Ctrl + D 退出就可以了。

提示

你也许会好奇,为什么在 docker run 交互式执行的时候按 Ctrl + D 就容器就直接停止了,而在 docker exec 的情况下退出却不会导致容器停止呢?因为 docker exec -it 相当于在现有的容器上运行了一个新的终端进程,而不会影响之前的主命令进程。只要主进程不结束,容器就不会停止。

小诀窍:如何轻松记住几十个 Docker 命令?

在刚才的实战中,我们也接触了很多新的 Docker 命令,怎么记住那么多命令呢?其实 docker 大部分命令都符合以下格式:

docker <对象类型> <操作名称> [其他选项和参数]

对象类型:到目前,我们接触的 Docker 对象类型包括容器 container镜像 image 和网络 network操作名称:操作可以分为两大类:1)适用于所有对象的操作,例如 lsrminspect 和 prune 等等;2)对象专属操作,例如容器专有的 run 操作,镜像专有的 build 操作,以及网络专有的 connect 操作等等•其他选项和参数:可通过 help 命令或 --help 查阅每个命令具体的选项和参数

由于部分命令很常用,Docker 还提供了方便的简写命令,例如显示当前所有容器 docker container ls,可以简写成 docker ps

我们首先复习一下容器(Container)对象上的命令吧(红色代表适用于所有对象的操作,蓝色代表此对象的专有操作):

再复习一下镜像(Image)对象上的命令:

最后复习一下网络(Network)对象上的命令:

至此,这篇教程也结束了。但是我们的筑梦之旅才刚刚开始——还有很多问题没有解决:1)现在前端应用还无法在除了本地以外的环境使用(因为访问的后端 API 是硬编码的 localhost);2)还没有真正部署到远程机器;3)MongoDB 还处于“裸奔”的状态(没设置密码)。不要方,我们在接下里的教程中就会去解决哦。

想要学习更多精彩的实战技术教程?来图雀社区[8]逛逛吧。

References

[1] 上一篇教程: https://zhuanlan.zhihu.com/p/100995490
[2] 参考文档: https://docs.docker.com/network/links/
[3] Alpine Linux: https://www.alpinelinux.org/
[4] Busybox: https://www.busybox.net/
[5] 上一篇教程: https://juejin.im/post/5e0f43bd5188253aa83e29d2
[6] 上一篇文章: https://zhuanlan.zhihu.com/p/100995490
[7] 第一篇文章: https://juejin.im/post/5e0f43bd5188253aa83e29d2
[8] 图雀社区: https://tuture.co?utm_source=juejin_zhuanlan

喜欢本文,点个“在看”告诉我

这篇关于梦境亦相通:上手 Docker Network的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/818350

相关文章

Docker镜像修改hosts及dockerfile修改hosts文件的实现方式

《Docker镜像修改hosts及dockerfile修改hosts文件的实现方式》:本文主要介绍Docker镜像修改hosts及dockerfile修改hosts文件的实现方式,具有很好的参考价... 目录docker镜像修改hosts及dockerfile修改hosts文件准备 dockerfile 文

Docker镜像pull失败两种解决办法小结

《Docker镜像pull失败两种解决办法小结》有时候我们在拉取Docker镜像的过程中会遇到一些问题,:本文主要介绍Docker镜像pull失败两种解决办法的相关资料,文中通过代码介绍的非常详细... 目录docker 镜像 pull 失败解决办法1DrQwWCocker 镜像 pull 失败解决方法2总

通过Docker Compose部署MySQL的详细教程

《通过DockerCompose部署MySQL的详细教程》DockerCompose作为Docker官方的容器编排工具,为MySQL数据库部署带来了显著优势,下面小编就来为大家详细介绍一... 目录一、docker Compose 部署 mysql 的优势二、环境准备与基础配置2.1 项目目录结构2.2 基

关于Docker Desktop的WSL报错问题解决办法

《关于DockerDesktop的WSL报错问题解决办法》:本文主要介绍关于DockerDesktop的WSL报错问题解决办法的相关资料,排查发现是因清理%temp%文件夹误删关键WSL文件,... 目录发现问题排查过程:解决方法其实很简单:重装之后再看就能够查到了:最后分享几个排查这类问题的小www.cp

如何使用Docker部署FTP和Nginx并通过HTTP访问FTP里的文件

《如何使用Docker部署FTP和Nginx并通过HTTP访问FTP里的文件》本文介绍了如何使用Docker部署FTP服务器和Nginx,并通过HTTP访问FTP中的文件,通过将FTP数据目录挂载到N... 目录docker部署FTP和Nginx并通过HTTP访问FTP里的文件1. 部署 FTP 服务器 (

解读docker运行时-itd参数是什么意思

《解读docker运行时-itd参数是什么意思》在Docker中,-itd参数组合用于在后台运行一个交互式容器,同时保持标准输入和分配伪终端,这种方式适合需要在后台运行容器并保持交互能力的场景... 目录docker运行时-itd参数是什么意思1. -i(或 --interactive)2. -t(或 --

Docker部署Jenkins持续集成(CI)工具的实现

《Docker部署Jenkins持续集成(CI)工具的实现》Jenkins是一个流行的开源自动化工具,广泛应用于持续集成(CI)和持续交付(CD)的环境中,本文介绍了使用Docker部署Jenkins... 目录前言一、准备工作二、设置变量和目录结构三、配置 docker 权限和网络四、启动 Jenkins

ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法

《ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法》本文介绍了Elasticsearch的基本概念,包括文档和字段、索引和映射,还详细描述了如何通过Docker... 目录1、ElasticSearch概念2、ElasticSearch、Kibana和IK分词器部署

docker如何删除悬空镜像

《docker如何删除悬空镜像》文章介绍了如何使用Docker命令删除悬空镜像,以提高服务器空间利用率,通过使用dockerimage命令结合filter和awk工具,可以过滤出没有Tag的镜像,并将... 目录docChina编程ker删除悬空镜像前言悬空镜像docker官方提供的方式自定义方式总结docker

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁