iptables实现docker容器动态端口映射实操

2024-04-24 14:28

本文主要是介绍iptables实现docker容器动态端口映射实操,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

之前在《Docker 动态修改容器端口映射的方法》一文中,说明了如何使用修改配置和加防火墙规则实现动态端口映射。但是没有具体分享加防火墙实现动态端口映射的实际案例。今天就分享一下实际操作案例,供大家参考。

分析

动态端口映射的用途

容器端口的动态映射,是用于实现外部访问服务器上的容器内运行的服务的。

如果容器已经运行了,不想停止Docker服务,又想增加端口映射,以便让外部可以立即访问,那就需要使用iptables来实现端口的动态映射。如果可以重启Docker服务,那么采用前面的文章里的方法即可。

实践操作的环境

宿主机局域网IP:192.168.1.15

容器的IP:172.17.0.2

容器已映射端口:443

容器内有监听0.0.0.0的端口:8086

容器内是否开启防火墙:没有开启

宿主机是否正常访问容器的端口:是

宿主机是否开启IPv4转发:是

宿主机局域网IP查看:

ip addr

找到eth0即宿主机使用的网卡这一组,可以看到。

容器IP查看:

docker exec {容器名或容器ID} ip addr

找到eth0@ifxxx这样的一组,查看对应的IP。一般是172开头的,默认一般是172.17.0.2。

容器已有的端口映射查看:

docker ps

找到容器名那一行,找到PORTS那一列,就是已经做好的端口映射。例如:0.0.0.0:443->443/tcp 。

查看容器内已监听的端口:

docker exec {容器名或容器ID} netstat -ltnp|grep 0.0.0.0|grep -v 127.0.0.1

这里过滤出来监听0.0.0.0的端口并排除监听127.0.0.1的端口。选择一个没有做端口映射的来作为测试,我们这里选择的是8086。

查看容器是否开启防火墙:

docker exec {容器名或容器ID} service iptables status | grep Active

如果不是running状态,即没有运行。

因为我移除了iptbales服务配置文件,容器内的防火墙是没有起来的。

查看宿主机是否正常telnet访问容器的8086端口:

如上图所示,看到了Escape character is '^]'即表示端口是通的,可以正常访问,如果没有出现则表示不通。

查看宿主机是否开启IPv4转发:

sysctl net.ipv4.ip_forward

如果返回的值为1即表示开启了,值为0表示未开启。

可以看到,已经开启了IPv4的转发。

实践操作目标

我们使用iptables添加规则,实现在不重启Docker服务和容器的前提下,让外部可以访问容器里的8086服务,即可以telnet宿主机192.168.1.15的8086端口。

实践步骤

1.测试宿主机IP是否可以telnet 连接192.168.1.15 的8086

可以发现:

Trying 192.168.1.15...
telnet: connect to address 192.168.1.15: Connection refused

因为本机并没有监听8086端口,所以使用本机无法telnet8086端口。那从外部执行本机的8086就更不可能成功了。此时我们就是无法从外部访问容器的8086端口的。

2.设置根据端口的转发

只要宿主机IP接收到8086的端口的请求,就转发到172.17.0.2上的8086。前面我们已经确认了172.17.0.2的8086端口是可以通信的。所以请求只要转发到172.17.0.2的8086,请求就可以进入容器。

iptables -t nat -A DOCKER -p tcp --dport {容器外部端口} -j DNAT --to-dest {容器ip}:{容器内部端口}

-t nat:用于指定在nat表添加规则。NAT表用于做IP和端口转换的。

-p tcp:用于指定转换的协议为tcp,这个根据监听的协议来填写。

-A DOCKER:在DOCKER链追加一条规则。如果要把规则写到最开始即最优先匹配,可以把A换成I。A即add,追加到末尾,I即insert,插入到开头。

--dport即容器外部的端口,也即宿主机的端口。这里我们替换为8086。

-j DNAT:就是做DNAT的转换,把目的IP和端口进行转换。

--to-dest:将请求的目的IP和端口修改为什么。这里换为容器的IP和容器内监听的8086。

容器外部的端口和容器内部的端口可以不一样,但是容器内部的端口必须是内部已经监听的端口,而容器外部的端口就是外部拿来通信的端口。

最终的命令如下:

iptables -t nat -A DOCKER -p tcp --dport 8086 -j DNAT --to-dest 172.17.0.2:8086

执行后查看iptables的nat表:

iptables -t nat -nL DOCKER | grep 8086

在宿主机上试一下telnet就通了。

这样就搞定了吗?你从局域网的其他机器执行telnet 192.168.1.15 8086,发现还是不通。

到此,我们已经打通了宿主机可以通过宿主机IP对端口的直接访问,但是外部的还不行。如果你只是需要宿主机可以访问,那就到此结束了。如果你需要在局域网的其他机器也能访问,那还要继续。

3.添加允许外部IP访问8086端口的规则

iptables -A DOCKER -p tcp -s {外部IP} --dport {宿主机的端口} -j ACCEPT

默认不加-t参数,默认就是filter表。-s(源IP)参数用于指定外部特定IP允许访问宿主机。如果不加-s表示外部所有IP都可以访问。--dport则表示只能访问指定的端口。-j ACCEPT表示允许。

最终的命令如下:

iptables -A DOCKER -p tcp -s 外部IP --dport 8086 -j ACCEPT

不过你会发现,此时还是无法从外部IP访问8086。此时虽然外部能请求到宿主机的8086,但是宿主机将这个请求丢了。在宿主机上请求,因为都是内部IP,不管是用宿主机的局域网IP还是172的,都是内部流量,所以会通过容器的网桥进行转发,所以宿主机上可以通过宿主机IP访问到8086。

那从外部来的流量为什么能够转发呢?

因为前面已经将所有的发往8086的流量转发到172.17.0.2上了。现在允许外部请求到宿主机上,就会触发上面的转发规则,就马上转发到172.17.0.2了。一气呵成。

需要注意的是,添加外部允许访问8086端口,必须在DOCKER链,添加INPUT链是没有用的。为什么呢?

iptables先判断nat表中的DOCKER链是否存在对应的端口的转发,如果有则使用filter表的DOCKER来过滤流量,而不再过滤INPUT链了。所以此时必须将允许外部IP访问的规则加在filter表的DOCKER才有用。

如果DOCKER链没有对应端口的转发,则转入INPUT链过滤。

至于为什么会这样,请阅读《一文讲清楚docker利用iptables实现容器网络的原理》。

这样操作之后,就为容器动态添加了端口映射了。把规则删除之后,端口映射即消失。

总结

容器的端口映射,核心就是一个端口转发。另外一个规则就是一个允许外部访问的规则。


原文地址: iptables实现docker容器动态端口映射实操-七秒鱼笔记

这篇关于iptables实现docker容器动态端口映射实操的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

vue基于ElementUI动态设置表格高度的3种方法

《vue基于ElementUI动态设置表格高度的3种方法》ElementUI+vue动态设置表格高度的几种方法,抛砖引玉,还有其它方法动态设置表格高度,大家可以开动脑筋... 方法一、css + js的形式这个方法需要在表格外层设置一个div,原理是将表格的高度设置成外层div的高度,所以外层的div需要

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

使用Python实现高效的端口扫描器

《使用Python实现高效的端口扫描器》在网络安全领域,端口扫描是一项基本而重要的技能,通过端口扫描,可以发现目标主机上开放的服务和端口,这对于安全评估、渗透测试等有着不可忽视的作用,本文将介绍如何使... 目录1. 端口扫描的基本原理2. 使用python实现端口扫描2.1 安装必要的库2.2 编写端口扫

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

SQL Server使用SELECT INTO实现表备份的代码示例

《SQLServer使用SELECTINTO实现表备份的代码示例》在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误,在SQLServer中,可以使用SELECTINT... 在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误。在 SQL Server 中,可以使用 SE

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端