news 2026/10/8 14:22:14

90DaysOfDevOps:Docker 网络与安全实战指南(Day 47)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
90DaysOfDevOps:Docker 网络与安全实战指南(Day 47)
  • 文档/教程

【免费下载链接】90DaysOfDevOps

This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.

项目地址:https://gitcode.com/gh_mirrors/90/90DaysOfDevOps
点击查看免费下载

导读

本指南对应 90DaysOfDevOps 学习路线中容器专题的第 47 天,主题是 Docker 网络与安全。此前几天的动手实验大多停留在"让容器跑起来"的层面,本篇文章将深入剖析容器背后的网络机制(默认 bridge 网络、端口映射与 NAT 转发),并系统讲解容器安全的最佳实践(非 root 用户、私有镜像仓库与精简镜像)。读完本文,你将掌握docker network系列命令的实际用法、桥接网络的工作原理,以及如何通过 Dockerfile 与运行参数把容器从"默认 root 权限"收敛到"最小权限",并能在 2022/Days/Containers 目录的配套示例中找到可直接复用的配置。

Docker 网络基础:docker network命令族

打开终端执行docker network,这是 Docker 中配置与管理容器网络的主命令。它暴露了一组子命令,覆盖了网络的全生命周期管理:

子命令作用
docker network create创建新的自定义网络
docker network ls/list列出宿主机上已有的全部网络
docker network inspect查看某个网络的详细配置(ID、驱动、连接的容器等)
docker network rm移除不再使用的网络

安装 Docker 之后,未做任何配置时,执行docker network ls会看到开箱即用的默认网络(对应截图 Day47_Containers2.png):

  • 每个网络都有唯一的ID与NAME;
  • 每个网络只关联一个 driver(驱动);
  • 注意:bridge网络与host网络恰好与它们各自的驱动同名,名字相同并不代表两者是同一个东西——网络是"实例",驱动是"实现",两者相关联但概念不同。

如果想深入了解某个网络,用docker network inspect bridge。返回的 JSON 中包含了名称、ID、驱动、已连接的容器以及更多配置细节(对应截图 Day47_Containers3.png)。

Docker Bridge 网络:单主机网络的实现基础

Docker Desktop 标准安装会提供一个预置网络bridge。从docker network ls的输出可以看到,名为bridge的网络由bridge驱动支撑,且作用域(Scope)为local。

这里有两个关键事实:

  1. bridge 驱动只提供单主机网络:bridge网络仅存在于当前 Docker 宿主机上,使用 bridge 驱动的所有网络都是如此——它无法跨多台主机联通;
  2. 底层实现是 Linux bridge(虚拟交换机):所有用 bridge 驱动创建的网络的底层都是 Linux 内核的 bridge 设备,可以把它理解为运行在 Linux 内核中的"虚拟交换机",负责在同一台宿主机内的容器之间转发二层数据帧。

连接容器到 bridge 网络

默认情况下,新建容器都会被挂到bridge网络,除非你在docker run时用--network显式指定其他网络。这正是默认网络如此重要的原因。

创建一个后台运行的 Ubuntu 容器:

docker run -dt ubuntu sleep infinity

sleep infinity让容器始终在后台保持运行状态,方便我们后续进入容器内做实验。执行后终端会返回一串容器 ID(对应截图 Day47_Containers4.png)。

再次执行docker network inspect bridge,就会在 "Containers" 字段里看到刚才创建的容器——因为我们没有指定网络,它被自动接入了 bridge 网络。

进入容器内部一探究竟:

docker ps # 先拿到真实的容器 ID docker exec -it <容器ID> bash

由于基础镜像非常精简,里面没有 ping 工具,需要先安装:

apt-get update && apt-get install -y iputils-ping ping -c5 www.90daysofdevops.com

这能验证容器经由 bridge + 主机网络能否访问外网(对应截图 Day47_Containers6.png)。

实验结束后清理容器:

docker stop <容器ID>

配置 NAT:通过端口映射对外提供服务

默认情况下,bridge 网络上的容器 IP 是 Docker 内部网段(例如 172.17.0.0/16),外部网络无法直接路由到容器 IP。要让外部流量到达容器内的服务,就需要端口映射,其本质是宿主机上的 NAT(网络地址转换):宿主机监听某个端口,把进入该端口的流量转发到容器内的目标端口。

下面启动一个官方 NGINX 容器,把宿主机的 8080 端口映射到容器内的 80 端口:

docker run --name web1 -d -p 8080:80 nginx

首次运行时 Docker 会先从镜像仓库拉取 nginx 镜像(对应截图 Day47_Containers7.png)。

执行docker ps查看容器状态与端口映射(对应截图 Day47_Containers8.png):

CONTAINER ID IMAGE COMMAND PORTS NAMES ... nginx "/docker-entrypoint.…" 0.0.0.0:8080->80/tcp web1

关键信息解读:

  • 第一行即为新启动的web1容器,它正在运行 NGINX 的入口脚本;
  • 端口映射0.0.0.0:8080->80/tcp表示:宿主机所有网卡接口(0.0.0.0)上的 8080 端口,被转发到 web1 容器内的 80 端口;
  • 正是这条映射让容器的 Web 服务对外可达——外部访问者只需访问"Docker 宿主机的 IP:8080"。

接下来拿到宿主机真实 IP。在 WSL 终端里执行:

ip addr

(对应截图 Day47_Containers9.png)记下宿主机的 IP 地址,然后在浏览器访问:

http://<宿主机IP>:8080/

例如文档实验中的http://172.25.218.154:8080/(你的 IP 可能不同)。看到 NGINX 欢迎页即说明端口映射与 NAT 转发全部生效(对应截图 Day47_Containers10.png)。

这部分实验思路源自 2017 年 DockerCon 的官方网络演练,虽然年代久远,但 bridge 网络与端口映射的核心机制至今依然适用;原文演练的后半部分涉及 Docker Swarm,不属于本课主题,故不展开。

仓库中的端口映射实践

本仓库的多个 Compose 示例都是上述端口映射机制在真实应用中的落地,可对照阅读:

  • elasticsearch-logstash-kibana/docker-compose.yml 通过ports暴露了 Elasticsearch 的9200/9300、Logstash 的5000/5044/9600与 Kibana 的5601,并在文件末尾显式声明了networks: elastic: driver: bridge——即用 bridge 驱动构建一个名为elastic的自定义网络,把三个服务隔离在同一虚拟交换机上;
  • my_wordpress/docker-compose.yaml 中ports: "8000:80"把宿主机 8000 端口映射到 WordPress 容器的 80 端口,与文中-p 8080:80的映射原理完全一致。

容器安全:从默认 root 走向最小权限

容器相比传统"整机"服务器,为工作负载提供了更安全的运行环境:它能把应用拆成更小、更松耦合的组件,彼此隔离,从而整体收窄攻击面。但这绝不意味着容器对恶意攻击者免疫——理解技术的安全缺陷并遵循最佳实践仍然必不可少。

告别 root 权限

到目前为止,我们部署的所有容器内部进程都是以root身份运行的,这意味着进程对容器以及宿主机环境拥有完整的管理权限。实验环境可以容忍这种临时行为,但生产环境绝不能如此。

两条改进路径:

路径一:在 Dockerfile 中创建非 root 用户(推荐)。仓库 2022/Days/Containers/Dockerfile 中保存着与本课完全一致的示例:

# Use the official Ubuntu 18.04 as base FROM ubuntu:18.04 # Install nginx and curl RUN apt-get update && apt-get upgrade -y #RUN apt-get install -y nginx curl #RUN rm -rf /var/lib/apt/lists/* RUN groupadd -g 1000 basicuser && useradd -r -u 1000 -g basicuser basicuser USER basicuser

逐行解读:

  • FROM ubuntu:18.04:以官方 Ubuntu 18.04 为基础镜像;
  • RUN apt-get update && apt-get upgrade -y:刷新软件源并升级基础软件包(原文档中 Dockerfile 里被注释掉的nginx curl安装行与rm -rf /var/lib/apt/lists/*清理行,正是"精简镜像"思路的体现,详见后文);
  • RUN groupadd -g 1000 basicuser && useradd -r -u 1000 -g basicuser basicuser:创建 GID/UID 均为 1000 的系统用户basicuser及其同名用户组。指定固定 UID/GID 可以保证镜像内用户身份与宿主机命名空间可预期,便于卷权限管理;
  • USER basicuser:此后的所有指令(以及容器运行时主进程)都以basicuser身份执行,不再使用 root。

路径二:用docker run --user运行时覆盖(仅作补充)。

docker run --user 1009 ubuntu

--user会覆盖 Dockerfile 里指定的用户,容器将以 UID 1009 运行——只要该 UID 权限最低,就近似实现了最小权限原则。但文档明确指出:这种方式并未解决镜像本身底层的安全缺陷(镜像内若有以 root 身份执行的入口脚本,仍可能被利用)。因此更稳妥的做法是在 Dockerfile 中直接指定非 root 用户,让容器无论何时被启动都处于安全状态。

私有镜像仓库:把镜像供给收进自己手里

前几天的练习大量使用了 DockerHub 这样的公共镜像仓库。而由组织自建的私有镜像仓库(可在任意位置自托管,也可选用托管服务)能让团队完全掌控可用的镜像集合:

  • 可控性:只有经过审核、签名的镜像才能进入私有仓库,避免从公共源拉取到来源不明的镜像;
  • 信任模型:DockerHub 适合提供"基线"镜像,但它本质上是基础服务,你需要把大量信任押在镜像发布者身上;私有仓库则把信任边界收回到组织内部。

精简镜像:更小的镜像 = 更小的攻击面

镜像体积虽然与安全性不是直接强相关,却深刻影响攻击面:应用用不到的资源,就不应该出现在容器里。多余的库、工具和依赖越多,可被利用的潜在入口就越多。

文档特别提醒:盲目拉取latest标签容易带来大量"臃肿"内容(例如镜像里残留的 apt 缓存),这正是上节 Dockerfile 中注释掉rm -rf /var/lib/apt/lists/*清理行的原因所在。DockerHub 仓库页面会显示每个镜像的压缩后大小,本地则用docker images快速核对各镜像的体积(对应截图 Day47_Containers11.png)。建议生产镜像遵循"分层构建 + 清理中间产物 + 固定版本标签"的组合策略。

小结

Day 47 的核心收获可以归纳为三句话:

  1. 网络:bridge是 Docker 默认的单主机网络,底层为 Linux bridge(虚拟交换机),所有未指定网络的容器默认接入其中;
  2. 对外联通:bridge 网络内部 IP 不可被外部直接路由,必须借助-p <主机端口>:<容器端口>的端口映射(NAT)把服务暴露出去;
  3. 安全:坚持"最小权限"(Dockerfile 中USER非 root 用户 +docker run --user兜底)、"镜像可控"(私有仓库)与"镜像精简"(按需裁剪、避免latest臃肿)三原则。

下一篇(Day 48)将继续推进 90DaysOfDevOps 容器专题的学习;文中涉及的 Dockerfile 与 Compose 网络配置均可直接在 2022/Days/Containers 目录中查看与复用。

  • 文档/教程

【免费下载链接】90DaysOfDevOps

This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.

项目地址:https://gitcode.com/gh_mirrors/90/90DaysOfDevOps
点击查看免费下载
上一篇:Browser Use Action Controller 与 Action Registry 深度解析:LLM 计划如何变成真实的浏览器操作
下一篇:PowerSploit Recon 模块 Get-DomainDNSZone:PowerView 枚举 Active Directory DNS 分区实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 14:20:45

【消息队列】如何选型?

初步介绍了Kafka、RabbitMQ、RocketMQ和ActiveMQ4种消息队列的优缺点&#xff0c;并进行了简单的对比。这个系列计划会更新5-6篇文章&#xff0c;前面介绍常用消息队列的初步原理&#xff0c;后面会选一种消息队列&#xff0c;重点介绍环境搭建和实战部分&#xff0c;文章内容大…

作者头像 李华
网站建设 2026/10/8 14:20:08

OpenMontage:用AI智能体驱动视频剪辑的开源实践

1. 当剪辑台变成对话窗口&#xff1a;OpenMontage 到底在解决什么问题第一次看到 OpenMontage 这个名字&#xff0c;我脑子里蹦出来的不是某个具体功能&#xff0c;而是一个很朴素的疑问&#xff1a;视频剪辑这件事&#xff0c;能不能像跟人说话一样完成&#xff1f;不是那种&q…

作者头像 李华
网站建设 2026/10/8 14:12:54

微信聊天记录导出与永久备份:WeChatMsg(留痕)免费一键教程

微信聊天记录导出与永久备份&#xff1a;WeChatMsg&#xff08;留痕&#xff09;免费一键教程 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.co…

作者头像 李华