一、Docker容器命令
1.1 docker常用命令
# 创建并使一个容器在后台运行(最常用)
docker run -itd --name mynginx nginx
# 查看容器日志(主进程输出信息)
docker logs mynginx
# 实时查看容器日志
docker logs -f mynginx
# 获取容器详细信息(JSON 格式)
docker inspect mynginx
# 获取容器资源使用情况(CPU、内存等)
docker stats mynginx
小知识:可通过修改
vim .bashrc
-- 给较长的命令取别名
alias 别名='命令'
1.2 Docker 容器本质
Docker 容器本质上是一个隔离的进程环境,其生命周期依赖于它的主进程(PID 1)。
为什么有些容器按
Ctrl+D
会退出,而有些不会?这取决于容器的主进程是否结束。
如果主进程是交互式 shell(如 bash),按
Ctrl+D
会导致容器退出;如果主进程是
tail -f /dev/null
或其他永不结束的命令,则容器不会退出。
覆盖默认命令
每个 Docker 镜像都有其预设的入口点(ENTRYPOINT)和默认命令(CMD)。
当使用 docker run
启动容器时,可以通过指定新的命令来覆盖这些默认值。
示例
正常方式运行 Nginx
docker run -it --name web nginx
docker run -itd --name web nginx
覆盖默认命令为 tail -f /dev/null
docker run -d --name web nginx tail -f /dev/null
如何判断容器内是否运行了 Nginx?
使用以下命令检查容器中是否有 Nginx 进程:
docker exec -it web ps aux
二、 Docker 端口映射
端口映射是 Docker 容器网络配置中的一个核心概念,它允许将宿主机的端口与容器内部的服务端口进行关联。
通过这种方式,外部网络可以通过访问宿主机的某个端口来间接访问运行在容器内的服务。
2.1 基本概念
-
端口映射:指的是将宿主机上的一个或多个端口转发到容器内的指定端口。
-
这种机制使得外部网络可以访问容器内部的服务,即使这些服务只监听了容器内部的特定端口。
使用场景
-
当需要让容器内的服务对外提供服务时,比如运行一个 Web 应用。
-
需要对不同的服务分配不同的宿主机端口以避免冲突。
2.2 命令语法
在使用 docker run
启动容器时,可以通过 -p
或 --publish
参数来进行端口映射。
docker run -d -p <宿主机端口>:<容器端口> [OPTIONS] IMAGE [COMMAND] [ARG...]
<宿主机端口>
:宿主机上开放的端口。
<容器端口>
:容器内服务监听的端口。
2.3 示例
基本端口映射
有一个 Nginx 容器,默认情况下 Nginx 监听的是 80 端口。可以这样启动容器并将其映射到宿主机的 8081 端口:
docker run -d --name mynginx -p 8081:80 nginx
现在,可以通过访问宿主机的 IP 地址和 8081 端口来访问 Nginx 服务:
http://<宿主机IP>:8080/
随机分配宿主机端口
如果不关心宿主机的具体端口号,可以让 Docker 自动为选择一个未被占用的端口:
docker run -d --name mynginx -p 80 nginx
在这种情况下,Docker 会随机分配一个宿主机端口,并将其映射到容器的 80 端口。可以通过以下命令查看具体的映射关系:
docker port mynginx
映射 UDP 端口
默认情况下,-p
参数映射的是 TCP 端口。如果想映射 UDP 端口,可以在端口号后面加上 /udp
:
docker run -d --name myapp -p 53:53/udp myimage
多个端口映射
如果需要映射多个端口,可以多次使用 -p
参数:
docker run -d --name myapp -p 80:80 -p 443:443 -p 8080:8080 myimage
查看端口映射情况
使用 docker ps
docker ps
注意事项
-
端口冲突:确保宿主机上没有其他服务正在使用要映射的端口。
-
安全性:暴露宿主机端口可能会带来安全风险,特别是当将敏感服务(如数据库)端口映射出来时,建议仅限于受信任的网络环境中使用。
-
防火墙设置:如果宿主机有防火墙,确保已开放相应的端口。
高级端口映射
指定绑定地址
如果想限制哪个网络接口可以访问该端口,可以指定绑定地址:
docker run -d --name mynginx -p 127.0.0.1:8080:80 nginx
映射到特定的 IP 地址
如果想将端口映射到宿主机的特定 IP 地址而不是所有接口,可以这样做:
docker run -d --name mynginx -p 192.168.1.100:8080:80 nginx
三、Docker 网络模式
查看当前 Docker 网络类型
我们可以先看看目前有哪些可用的网络:
docker network ls
3.1 Bridge 网络
Docker的bridge网络模式是Docker的默认网络模式。
当Docker进程启动时,它会在主机上创建一个名为docker0的虚拟网桥。
此主机上启动的Docker容器会连接到这个虚拟网桥上。
这个虚拟网桥的工作方式类似于物理交换机,使得主机上的所有容器都通过交换机连接在一个二层网络中。
在这种模式下,Docker会为每个新创建的容器分配独立的Network Namespace和IP段等,同时文件系统、进程等也是隔离的。
容器内部会有一个虚拟网卡,名为eth0,容器之间可以通过这个虚拟网卡和内部的IP地址进行通信。
另外,从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。
然而,处于桥接模式的容器和宿主机网络不在同一个网段,容器一般使用172.16.0.xx/24这种网段。
因此,容器不能直接和宿主机以外的网络进行通信,而必须要经过NAT转换。
同时,容器需要在宿主机上竞争端口,完成端口映射的配置后,从外部到容器内的网络访问tcp流量将会通过DNAT从宿主机端口转发到容器内对应的端口上。
此外,容器对于宿主机以外是不可见的,从容器发出的网络请求会通过SNAT从已对接的虚拟网桥(如宿主机的docker0)上统一发出。
3.2 Host 网络
Docker的host网络模式是另一种网络模式,与bridge模式不同,它将容器直接融入到主机的网络栈中,使得容器直接使用主机的网络接口和IP地址。
在这种模式下,容器不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。
因此,容器内部的服务可以使用宿主机的网络地址和端口,无需进行NAT转换,网络性能较好。
使用host网络模式的一个典型场景是需要容器与宿主机共享网络资源或者容器需要快速访问宿主机网络服务的场景。
例如,如果需要在容器内部运行一些网络相关的应用,如网络监控、日志收集等,这些应用需要直接访问宿主机的网络接口和IP地址,此时就可以使用host网络模式。
需要注意的是,由于容器与宿主机共用一个网络栈,因此容器的网络隔离性较差,可能存在安全隐患。如果需要在不同主机上运行容器并实现跨主机通信,则不能使用host网络模式。
总的来说,Docker的host网络模式提供了一种将容器与宿主机网络栈直接融合的方式,使得容器可以直接使用宿主机的网络接口和IP地址,适用于一些需要快速访问宿主机网络服务的场景。
但是需要注意的是,该模式下容器的网络隔离性较差,需要谨慎使用。
3.3 None 网络
Docker的none网络模式是Docker提供的一种特殊网络模式,它将容器与宿主机隔离开来,不提供任何网络能力。
在这种模式下,容器内部没有网卡、IP地址、路由等信息,只有一个回环网络(loopback)接口。
这意味着容器不能访问外部网络,也不能被外部网络访问。
none网络模式通常用于一些特殊场景,比如需要在容器内部运行一些独立的、与网络无关的应用程序,或者需要进行一些网络调试。
由于容器与外部网络完全隔离,这种模式可以增加容器的安全性。
网络模式 | 是否有独立 IP | 能否与其他容器通信 | 备注 |
---|---|---|---|
默认 bridge | 是 | 同网络可通信 | 默认网络,适合一般应用 |
host | 否 | 可以访问宿主机所有服务 | 无隔离,性能最好 |
none | 否 | 不能 | 完全隔离网络 |
自定义 bridge | 是 | 同网络可通信 | 推荐用于多容器间通信 |
不同网络之间 | 是 | 不能 | 需要配置网络互通 |
3.4 bridge 实验
创建两个基于 centos 的容器,加入默认 bridge 网络(默认)
docker run -d --name centos1 centos:7 tail -f /dev/null
docker run -d --name centos2 centos:7 tail -f /dev/null
我们用
tail -f /dev/null
让容器一直运行,便于测试。
查看容器 IP 地址
docker inspect centos1
docker inspect centos2
假设输出为:
172.17.0.2
172.17.0.3
进入 centos1 容器,尝试 ping centos2 的 IP
docker exec -it centos1 bash
ping 172.17.0.3
3.5 host 实验
启动一个使用 host 网络模式的容器
docker run -d --name h1 --network host centos:7 tail -f /dev/null
查看这个容器的 IP 地址
你会发现它没有独立的 IP,因为它共享宿主机的网络栈。
在宿主机上直接访问它的服务(如果启动了 web 服务等)即可。
在 host 模式下运行第一个 Nginx 容器
docker run -d --name n1 --network host nginx
尝试运行第二个 Nginx 容器
现在我们尝试运行第二个 Nginx 容器:
docker run -d --name n2 --network host nginx
但你会发现这个命令可能失败,提示如下错误:
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
这是因为第一个容器已经在 host
模式下占用了宿主机的 80 端口,第二个容器无法再绑定同一个端口。
内容 | 说明 |
---|---|
使用场景 | host 模式适合对性能要求高、不需要隔离网络的应用 |
容器数量限制 | 同一宿主机端口只能被一个容器绑定 |
多服务部署 | 可以通过修改服务监听端口实现多个容器共存 |
网络访问 | 所有容器直接暴露在宿主机网络中,可直接通过宿主机 IP/端口访问 |
缺点 | 容易造成端口冲突,缺乏网络隔离 |
3.6 container 网络
Docker的container网络模式是指新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。
这意味着新创建的容器不会创建自己的网卡、配置自己的IP地址,而是和一个已存在的容器共享IP地址、端口范围等网络资源。
同时,这两个容器的进程可以通过lo网卡设备通信。然而,这两个容器在其他方面,如文件系统、进程列表等,仍然是隔离的。
使用container网络模式的一个典型场景是,当需要多个容器之间共享网络配置时,可以使用该模式。
例如,可以使用该模式创建一个nginx容器,并指定其网络模型为container模式,和另一个已经存在的容器共享网络命名空间。
这样,nginx容器就可以直接使用另一个容器的IP地址和端口,无需进行额外的网络配置。
Docker 的 container
网络模式是一种比较特殊的网络配置方式,它允许你将新容器加入到另一个已经存在的容器的网络命名空间中。这种方式使得两个容器可以共享同一个网络栈,这意味着它们共享 IP 地址和端口空间,并且可以直接通过 localhost 访问彼此的服务,而无需进行额外的网络配置。
container
网络模式的作用
-
资源共享:当你希望多个容器紧密协作,并且需要直接访问对方的服务时,使用
container
模式可以简化这种交互。例如,一个应用容器和它的调试工具容器可以共享网络,从而允许调试工具直接连接到应用容器的服务。 -
减少端口冲突:由于共享相同的网络命名空间,因此不需要担心不同容器之间因为监听相同端口而导致的冲突问题。所有服务都可以绑定到 localhost 上的相同端口。
-
简化网络配置:对于某些场景,特别是当容器间需要频繁通信并且要求低延迟时,
container
模式提供了一种简便的方法来实现这一点,而无需设置复杂的网络策略或依赖 Docker 的其他网络功能(如自定义桥接网络)。
使用 container
网络模式
下面我们将创建两个容器,其中一个运行 Nginx 作为 Web 服务器,另一个则使用 container
模式与第一个容器共享网络命名空间。
并尝试从第二个容器内部访问第一个容器的服务。
步骤 1:启动第一个容器(Nginx)
首先,我们启动一个 Nginx 容器:
docker run -d --name web_container nginx
这会启动一个名为 web_container
的 Nginx 容器,默认情况下它会在 80 端口上监听 HTTP 请求。
步骤 2:启动第二个容器并使用 container
模式
接下来,我们启动一个新的容器,并让它与 web_container
共享网络:
docker run -it --rm --network container:web_container centos:7 bash
这里我们使用了 centos:7
镜像来启动一个临时容器,并通过 --network container:web_container
参数指定了该容器应与 web_container
共享网络。
步骤 3:测试连通性
现在,在这个新的 CentOS 容器内,你可以尝试通过 localhost
来访问 web_container
提供的服务:
curl http://localhost
你应该能看到 Nginx 默认欢迎页面的内容,表明两个容器确实共享了同一个网络命名空间。
-
局限性:虽然
container
模式简化了一些特定情况下的网络配置,但它也限制了灵活性。例如,无法为每个容器单独指定端口映射。 -
适用场景:主要用于那些需要高度集成的应用程序组件之间,或者当你想要构建类似“sidecar”模式的架构时特别有用。
四、Docker 自定义网络(重要)
docker network create 命令用于在 Docker 中创建一个新的网络。
这个命令允许指定网络的名称、驱动程序以及其他选项,以满足不同的网络需求。
为什么要使用自定义网络?
1.实现不同项目之间的网络隔离
2.ip是根据启动顺序来的(自定义网络,ip可以固定)
3.自定义可以实现DNS解析(根据容器名来转化成ip)
docker network create [OPTIONS] NETWORK
OPTIONS:这是可选参数,可以用来指定网络的属性,如网络驱动程序、子网、网关等。
NETWORK:这是要创建的网络的名称,可以根据实际需求进行命名。
创建一个默认的 bridge 网络
docker network create my-network
docker network create --driver overlay my-overlay-network
docker network create \
--driver bridge \
--subnet=172.25.0.0/16 \
--gateway=172.25.0.1 \
--ip-range=172.25.50.0/24 \
--aux-address="my-router=172.25.50.10" \
my-custom-network
这将创建一个名为 my-custom-network 的自定义 bridge 网络,具有指定的子网、网关、IP 地址范围和辅助地址。
--driver 或 -d:指定网络驱动程序,如 bridge 或 overlay。
--subnet:指定网络的子网地址。
--gateway:指定网络的网关地址。
--ip-range:指定网络的 IP 地址范围。
--aux-address:指定网络的辅助地址。
连接容器到网络
为了实现两个不同 Docker 自定义网络中的容器相互通信,我们需要使用一些额外的配置。默认情况下,Docker 容器只能与位于同一自定义网络中的其他容器直接通信。
但是,通过创建自定义桥接网络,并利用 Docker 的 docker network connect
命令,我们可以将一个容器连接到多个网络中,从而实现跨网络通信。
这个选项允许指定容器应该使用的网络,并且可以与docker run命令一起使用来创建并启动容器。
docker run --network <网络名称> <其他选项> <镜像名称>
<网络名称>是想要容器连接的网络的名称
<其他选项>是创建和启动容器时可能需要的其他参数(如容器名称、端口映射等)
<镜像名称>是要运行的Docker镜像的名称。
例如,要将名为running-container的容器连接到my-network网络,可以运行
docker network connect my-network running-container
操作目标
-
创建两个自定义 Docker 网络。
-
在每个网络中启动一个容器。
-
使用
docker network connect
将其中一个容器连接到另一个网络。 -
验证容器之间的连通性。
操作步骤
创建两个自定义网络
首先,我们创建两个自定义的 Docker 网络:
docker network create net1
docker network create net2
启动容器并加入各自网络
接下来,在每个网络中启动一个 CentOS 容器。我们将分别为这些容器命名以便于识别:
# 启动第一个容器并加入 net1 网络
docker run -d --name container1 --network net1 centos:7 tail -f /dev/null
# 启动第二个容器并加入 net2 网络
docker run -d --name container2 --network net2 centos:7 tail -f /dev/null
这里我们使用了 tail -f /dev/null
来保持容器运行。
查看容器的 IP 地址
获取每个容器在各自网络中的 IP 地址:
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container1
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container2
假设输出如下:
172.18.0.2
172.19.0.2
尝试从一个容器 ping 另一个容器
尝试从 container1
ping container2
的 IP 地址:
docker exec -it container1 bash
ping 172.19.0.2
你会发现无法 ping 通,因为它们位于不同的网络中。
使用 docker network connect
连接容器到另一个网络
为了让 container1
能够访问 container2
,我们需要将其连接到 net2
网络:
docker network connect net2 container1
现在,container1
已经同时属于 net1
和 net2
网络。
再次查看 container1
的 IP 地址
重新检查 container1
的 IP 地址,注意它现在应该有两个 IP 地址,分别对应 net1
和 net2
:
docker inspect container1
如下的输出,表明 container1
拥有 net1
和 net2
的 IP 地址:
{
"net1": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"container1",
"172.18.0.2"
],
"NetworkID": "some-network-id",
"EndpointID": "some-endpoint-id",
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2",
...
},
"net2": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"container1",
"172.19.0.3"
],
"NetworkID": "another-network-id",
"EndpointID": "another-endpoint-id",
"Gateway": "172.19.0.1",
"IPAddress": "172.19.0.3",
...
}
}
测试连通性
再次进入 container1
并尝试 ping container2
的 IP 地址:
docker exec -it container1 bash
ping 172.19.0.2
这次你应该能看到成功的 ping 回应,说明两个容器已经可以互相通信了。