首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Docker入门——网络相关

Docker入门——网络相关

原创
作者头像
cocoon_yh
发布于 2019-09-09 13:04:40
发布于 2019-09-09 13:04:40
1.4K0
举报

背景

某次在试图从容器内访问到本地的数据库时,发现在本机上并没有 docker0 这个网桥。学习了一波 Docker 网络相关的知识后作出了以下总结。

相信下面这张图大家没少看过,Docker 相较于 VM 更加轻量,不需要虚拟出自己的操作系统层,具有更多的优点。

docker.png
docker.png

上图来源于网络,后文中也将对来源于网络的图做出说明

然而笔者想当然的就以为 Docker 在所有系统下都是这种架构。查阅相关资料后发现,Dockerlinux 环境下确实是这样运行的,但是在 WindowsmacOS 系统下,Docker 会先启一个 VM ,然后在该 VM 上运行 Docker 环境。新版的 Docker for Mac 已经不再使用 VirtualBox 提供虚拟机环境,而是使用更轻量的 HyperKit ,设计上更为巧妙,本文就不展开讲这个点了。下图是 Docker for Mac 的架构图。

-1.png
-1.png

因此 docker0 网桥是在虚拟机内,而不是在宿主机内。可想而知,运行在虚拟机中与运行在本机上肯定是有区别的,因此 Docker for Mac 实际上自带了 k8s 环境,并且通过端口转发到宿主机,以屏蔽用户对 VM 的感知。然而要实现容器到宿主机的通信,还需要进行另一番调研。

下面先介绍一下 Docker 支持的几种网络模式。

Docker 支持的网络模式

Network

Description

none

no networking in the container

bridge

Connect the container to the bridge via veth interfaces

host

Use the host's network stack inside the container

Container:<name\id>

Use the network stack of another container, specified via its name or id

Network

Connects the container to a user created network(using docker network create command)

NETWORK: NONE

这种网络模式下无法联网,仅有一个 loopback 回环网络,没有其他网卡。这种类型的网络无法联网,但可以通过 link 容器来实现容器间通信,这种网络模式可以很好的保证容器的安全性。同时,这种网络模式下用户自己自行创建网络,可以实现更为灵活复杂的网络。

0.png
0.png

NETWORK: BRIDGE

这是容器默认的网络模式。桥接模式会为 Docker Container 创建独立的网络堆栈,保证容器内的进程组使用独立的网络环境,从而实现容器间、容器与宿主机之间的网络栈隔离。同时,桥接模式可以通过宿主机上的 docker0 网桥来实现宿主机与容器之间的网络通信。

桥接模式会在主机上创建两个虚拟网络接口设备,一个附加在宿主机上的 docker0 网桥内,并命名为 veth0 ,另一个附加在 Docker Container 所属的 namespace 的下,并命名为 eth0

1.png
1.png

通过 veth pair 技术,其特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方,这就实现了从容器到宿主机的网络连通性。然而上面也提到了 Docker 需要运行在 linux 环境下,所以我们无法在主机上看到 docker0 网桥,这个网桥位于虚拟机中。

NETWORK: HOST

这种网络模式下容器将跟主机共享网络堆栈,因此容器可以直接使用宿主机的 eh0 实现与外界的通信,并且主机所有的接口都可以被容器访问及使用。

host.png
host.png

在这种模式下,容器将获取更高的网络性能,因为它使用主机的网络栈,不需要通过 Docker 守护进程进行一层虚拟化。但是,这种模式也会导致容器网络环境隔离性弱化,即容器不再拥有隔离的、独立的网络栈。容器会与宿主机竞争网络栈的使用,同时容器也不再拥有所有的端口资源,因为部分端口已经被宿主机本身的服务占用,还有部分端口用于桥接模式容器的端口映射。

NETWORK: CONTAINER

这种网络模式下,容器将和另一个容器共享网络堆栈,因此,同样需要注意端口冲突等问题。该模式下,两个容器与其他容器以及宿主机之间存在网络隔离。

container.png
container.png

USER-DEFINED NETWORK

开发者可以使用 Docker 网络驱动程序或者外部的网络驱动程序来创建网络,也可以把多个容器连接到同一个网络下。在这里不展开介绍。

解决方法

方案一(仅在 macOS/Windows 下可用)

Docker 本身针对这种场景已经提出了一些解决方案。从版本 18.03 开始,Docker for Mac 提供一个特殊的 DNS name 以便用户从容器内访问到本机, 这个 DNS name 被解析至主机在 docker 内使用的内部 IP 。同时其他版本的 Docker Desktop for Mac 也有对应的 host ,如下所示:

  • Docker for Mac v 18.03 and above
  • host.docker.internal
  • Docker for Mac v 17.12 to v 18.02
  • docker.for.mac.host.internal
  • Docker for Mac v 17.06 to v 17.11
  • docker.for.mac.localhost
  • Docker for Mac 17.05 and below
  • Docker 不提供,需要自己进行配置,具体配置方法可以参考 Janne Annala 的回答
代码语言:txt
AI代码解释
复制
https://stackoverflow.com/questions/24319662/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach
1的副本.png
1的副本.png

如上图所示,可以通过 host.docker.internal 直接访问到宿主机内的服务

方案二(仅在 Linux 下可用)

使用桥接模式。

可以看到宿主机下已经有了 docker0 网桥,且地址为 172.17.0.1

2.png
2.png

进入容器并查看容器内的网络接口信息和路由表可以发现 eth0 和宿主机中 docker0 的网段相同,且已经将 docker0 的接口地址设置为了默认网关,即匹配到的请求将通过 172.17.0.1 转发到目标地址。

3.png
3.png

那么通过该地址即可实现从容器到宿主机的访问。

4.png
4.png

方案三(仅在 Linux 下可用)

使用 host 模式启动服务就可以直接访问本机上的服务。利弊如上所述,若在生产环境使用该模式还需要自己再多做相关调研。

5.png
5.png

延展阅读

读到这的读者可能就会想,那容器内部需要访问外界,或者外界需要访问服务内部该咋办?好像刚刚提到的知识点不足以支撑这一流程呀?docker0 网段和宿主机的网段不同,外界无法得知容器 IP 更无法直接访问到容器内部。

6.png
6.png

这里就要引入另一个概念 NAT(Network Address Translation) ,是一种用于重写源IP地址或目的IP地址的技术。

外界访问容器内部

前提条件:容器运行时通过 -P 或 -p 指令主动暴露端口并将端口映射至主机上

to_docker.png
to_docker.png
  1. 外界直接请求 host_ip:port_0
  2. 通过 DNAT 将请求的目的地址修改为 container_ip:port_1
  3. 宿主机将请求转发给 veth pair
  4. veth pair 将请求通过 veth 转发至容器内部的 eth0
  5. 回包时也通过 docker0 转发至宿主机的 eth0 发送回包

通过检测数据包可以看到请求的目的 IP 被修改为了对应的容器 IP ,以完成外界对容器内部的访问

7.png
7.png
8.png
8.png

容器内部访问外界

from_docker.png
from_docker.png
  1. 容器内发出请求,此时会随机选取一个未被占用的端口 port0 作为源端口
  2. 请求通过 eth0 转发至 docker0 网桥处的 veth
  3. docker0 网球将请求转发至宿主机的 eth0
  4. 宿主机处理请求时通过 SNAT 将请求源地址修改为 host_ip:port_1 并转发出去
  5. 外界回包时发送至宿主机的 eth0
  6. 按照 iptables 规则,宿主机将请求转发至容器内部

查看 iptables 规则可知,从 172.17.0.0 网段出去访问外网的请求都会交由 MASQUERADE 处理。而 MASQUERADE 的处理就是将请求的源 ip 替换成宿主机的 ip 并发出去,也就是做了一次 NAT 处理。

9.png
9.png
通过检测数据包可知,请求的源 ip 确实被从 docker0 网段的容器 ip:172.17.0.2 修改为 eth1:10.12.91.17
10.png
10.png
11.png
11.png

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
HTML5 表单验证 API
HTML5 表单验证在现代浏览器中得到了广泛支持。但在使用新特性时,仍需考虑兼容性问题。可以使用特性检测来提供优雅的降级处理:
空白诗
2024/12/13
5110
HTML5表单及其验证
将原本type为text的input控件声明为以上特殊类型,是为了给用户呈现不同的输入界面(移动平台上支持这些不同的输入界面,这里就不细说),而且表单提交时会对其值做进一步的验证。下面展示这些新表单元素,请用支持这些表单元素的浏览器查看,IE对其支持最差。
HUC思梦
2020/09/03
2.1K0
HTML 表单和约束验证的完整指南
在本文中,我们将研究 HTML 表单字段和 HTML5 提供的验证选项。我们还将研究如何通过使用 CSS 和 JavaScript 来增强这些功能。
玖柒的小窝
2021/09/13
10.1K0
HTML 表单和约束验证的完整指南
HTML基础-表单元素与属性:深入浅出指南
在网页设计中,表单(Form)是收集用户输入信息的重要组成部分,它允许用户与网站进行交互,如注册新账户、填写调查问卷或提交反馈等。本文将深入浅出地介绍HTML中表单元素与属性的基础知识,探讨一些常见问题、易错点,并提供避免错误的方法及代码示例。
Jimaks
2024/06/05
3170
HTML基础-表单元素与属性:深入浅出指南
HTML 交互式表单验证
在 HTML 中创建表单总是有点复杂。你首先得将 HTML 标记编写正确,然后需要确保每一个表单项在提交之前都有一个可用的值,最后还需要在有问题时用提醒来告知用户。   还好 HTML5 引入了一些新
用户1667431
2018/04/18
2.4K0
HTML 交互式表单验证
纯CSS实现表单验证
在我们的日常业务中,表单验证是个很常见设计需求,像一些登录注册框,问卷调查也都需要用到表单验证。
陈大鱼头
2020/04/16
1.7K0
纯CSS实现表单验证
HTML5新增的表单验证功能
一、HTML5表单的特点: HTML5 表单增加了许多内置的控件和控件属性 XHTML 中需要放在 form 之中的诸如 input/button/select/textarea 等标签元素,在 HTML 5 中完全可以放在页面任何位置,并通过新增的 form 属性指向元素所属表单的 ID 值,即可关联起来。 二、HTML5新增的控件类型: email输入类型:<input type="email" name="email" /> 要求输入格式正确的 email 地址,否则浏览器不允许提交,同时会提示错
Leophen
2019/08/23
2.8K0
angularjs 表单验证
一、常用的表单验证指令  1. 必填项验证 某个表单输入是否已填写,只要在输入字段元素上添加HTML5标记required即可: <input type="text" required />   2. 最小长度 验证表单输入的文本长度是否大于某个最小值,在输入字段上使用指令ng-minleng= "{number}": <input type="text" ng-minlength="5" /> 3. 最大长度 验证表单输入的文本长度是否小于或等于某个最大值,在输入字段上使用指令ng-maxlength=
柴小智
2018/04/10
7.3K0
angularjs 表单验证
html5 表单元素示例
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>html5中的表单</title> <script type="text/javascript"> var flag = true; function checkMail(){ var url = document.getElementById("url"); if (url.value==""){ //表单提交时 自定义验证信息
用户7718188
2021/11/02
1.8K0
用神奇的 form 验证 API 来优化你的表单验证
鱼头曾在 『极限版』不掺水,用纯 CSS 来实现超飒的表单验证功能 一文中分享过一个花里胡哨的 纯 CSS 的表单验证功能 。虽然仅仅依赖 CSS 是无法满足我们的日常开发需求的,但是配合着各种原生的 form 验证 API ,情况又不一样了。
陈大鱼头
2021/01/05
1.2K0
【Web前端】如何构建简单HTML表单?
HTML 表单是 Web 开发中非常重要的组成部分。它们是与用户交互的主要方式,能够收集用户输入的数据。表单的灵活性使它们成为 HTML 中最复杂的结构之一,但若使用正确的结构和元素,可以确保其可用性和无障碍性。
一条晒干的咸鱼
2024/11/26
4080
【Web前端】如何构建简单HTML表单?
6.HTML输入表单标签元素介绍
描述: 表单是一个包含表单元素的区域,表单元素是允许用户在表单中输入内容,其包含 文本框、文本域(textarea)、按钮、下拉列表、单选框(radio-buttons)、复选框(checkboxes)等元素都要放在form标签里面或者进行form的id值的调用,否则提交的数据到不了后端。
全栈工程师修炼指南
2023/03/21
5.6K0
HTML5-输入验证
HTML5引入了对输入验证的支持。设计者可告知浏览器自己需要什么类型的数据,然后浏览器在提交表单之前会使用这些信息检查用户输入的数据是否有效。其好处是:用户可以立刻得到问题反馈。
奋飛
2019/08/15
2.4K0
Angularjs的表单验证
在AngularJS中,有许多用于验证的指令。我们将先学习几个最流行的内置指令,然后再创建一个自定义验证规则的指令。
星回
2018/08/02
2.6K0
angularjs输入验证[通俗易懂]
原文 http://www.cnblogs.com/woshinidezhu/p/Form-validation-with-AngularJS.html
全栈程序员站长
2022/09/15
1.8K0
简单总结Layui中的表单验证
简单来说,实现Layui框架中的表单验证很简单,只需要给表单元素添加上”lay-verify“属性
知识分子没文化
2023/07/01
4.1K0
【Java 进阶篇】创建 HTML 注册页面
在这篇博客中,我们将介绍如何创建一个简单的 HTML 注册页面。HTML(Hypertext Markup Language)是一种标记语言,用于构建网页的结构和内容。创建一个注册页面是网页开发的常见任务之一,它允许用户提供个人信息并注册成为网站的会员。我们将从头开始创建一个包含基本表单元素的注册页面,并介绍如何处理用户提交的数据。
繁依Fanyi
2023/10/12
1.2K0
【Java 进阶篇】创建 HTML 注册页面
[HTML5] 一文读懂H5新特性的应用
<header> 标签用于定义文档或文档某部分的头部内容,通常包含导航链接、网站标识、标题、搜索框等。
DevKevin
2024/08/17
1K0
PHP 表单处理与验证
表单是 Web 应用程序中最基本的组成部分之一,它允许用户与应用程序进行交互。无论是用户注册、登录、填写调查问卷还是提交评论,表单都是数据传输的桥梁。在 PHP 中,表单处理与验证是每个 Web 开发者都必须掌握的重要技能。
繁依Fanyi
2025/01/18
7570
HTML的笔记及展示(2)(表单元素、input元素、label、button以及HTML5新增的一些元素)
1.<form…/>元素 用于生成输入表单,该元素不会生成可视化部分。如单行文本框、多行文本框、单选按钮、复选框等都需要放在<form…/>元素内
鲲志说
2025/04/07
6440
HTML的笔记及展示(2)(表单元素、input元素、label、button以及HTML5新增的一些元素)
相关推荐
HTML5 表单验证 API
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档