如何实现docker内部容器之间的端口访问

Docker 的普及促使众多应用迁至其上部署,得益其诸多优势。然而,相较于传统非 Docker 环境中各应用通过 127.0.0.1:端口 即可轻松互访,Docker 容器若未经端口映射,彼此间端口则无法直接相通。是否存在更优方案以应对这一挑战?

1 场景描述

场景简述:alpine-client 与 alpine-server 两容器,前者访问后者监听之端口,以此探析 Docker 内部容器间端口访问机制。

2 建立两个容器

2.1 通过 Dockerfile 构建镜像

由于这次测试功能很简单,可以通过一个 Dockerfile 来创建容器,一个镜像加载成两个容器,容器里执行的代码不同而已。

2.1.1 创建 Dockerfile 文件

此 Dockerfile 可以用做一个通用的模板,包含了基本功能框架,用户可以自行在此基础上修改。

# 以 alpine:3.10 为基础镜像
FROM alpine:3.10# 设置镜像源为清华大学镜像
RUN echo "https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.10/main" > /etc/apk/repositories \&& echo "https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.10/community" >> /etc/apk/repositories \&& apk update && apk upgrade# 安装依赖包及工具
RUN apk add --no-cache \bash \ netcat-openbsd# 设置工作目录
WORKDIR /root# 拷贝需要的文件,支持通配符
# COPY *.sh /root/# 在 Dockerfile 中添加Entrypoint test.sh,根据需要添加即可
# ENTRYPOINT ["/bin/bash", "-c", "/root/test.sh"]

简单解释一下这个 Dockerfile 模板文件:

1)引用基础镜像
这个必须有(此语句后面的语句都是可选项),且必须是第一句。我习惯引用 alpine 镜像,体积小巧、功能强大。

2)设置镜像源
先改写镜像路径文件,并运行 update、upgrade,使更改生效。关于镜像源,清华、阿里根据您的喜好选择就可以了,主要是用来加快软件安装速度。

3)安装依赖包及工具
使用 RUN 命令来执行依赖包及工具的安装,安装工作最好是在一个命令里执行完成,这样镜像就不会添加很多层,导致镜像文件变大。其中"\“是用来将分行的命令字符串串接起来,”&&"是用来按序依次安装多个命令。

4)设置工作目录
设置工作目录后,容器内部默认目录就是设置的工作目录,方便操作。

5)拷贝需要的文件
这一步可以将需要的文件从本机拷入镜像文件。

6)执行 ENTRYPOINT 入口脚本(或者使用CMD)
当容器启动时,会执行此处指定的脚本或命令。

2.1.2 编译镜像

docker build -t alpine-net:1.0.0 .

2.2 生成容器

生成 alpine-client 容器:

docker run -itd --name alpine-client alpile-net:1.0.0

生成 alpine-server 容器:`

docker run -itd -p 8888:8888 --name alpine-server alpile-net:1.0.0

alpine-server 容器加了一个端口映射,将 alpine-server 里监听的 8888 端口映射到该容器的宿主机的 8888 端口。

3 获取 IP 地址

3.1 获取 alpine-client 相关 IP 地址

3.1.1 获得 alpine-client 容器本身的 IP 地址

在 alpine-client 终端输入:

ifconfig

运行后返回结果如下:

eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0UP BROADCAST RUNNING MULTICAST  MTU:65535  Metric:1RX packets:197 errors:0 dropped:0 overruns:0 frame:0TX packets:89 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0 RX bytes:22832 (22.2 KiB)  TX bytes:5821 (5.6 KiB)lo        Link encap:Local Loopback  inet addr:127.0.0.1  Mask:255.0.0.0UP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:7 errors:0 dropped:0 overruns:0 frame:0TX packets:7 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:524 (524.0 B)  TX bytes:524 (524.0 B)

得到两个 IP ,127.0.0.1 和 172.17.0.2

3.1.2 获取 alpine-client 容器网关 IP 地址

在 alpine-client 终端输入:

route -n

运行后返回结果如下:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

得到网关 IP 地址:172.17.0.1。

3.1.3 获取 alpine-server 容器网关 IP 地址

同上操作,过程略。
可以得到 alpine-server 相关地址:
alpine-server 本机地址:127.0.0.1 和 和 172.17.0.3
alpine-server 网关地址:172.17.0.1

4 测试访问

在 alpine-server 的终端里输入网络端口监听命令:

nc -lk 8888 # 监听 8888 端口

监听 8888 端口,测试让 alpine-client 连接。以下如果没有特殊说明,默认命令行运行窗口为 alpine-client 的终端窗口

4.1 通过容器名称访问

nc alpine-server 8888

返回:

nc: getaddrinfo: Name does not resolve

提示:目标容器名 alpine-server 找不到,所以连接失败!

4.2 通过容器 IP 访问

nc 127.17.0.3 8888

连接失败!说明容器端口并没有对“隔壁”容器开放。

4.3 通过网关 IP 访问

nc 127.17.0.1 8888

连接失败!说明容器端口映射,并不是映射到网关上。

4.4 通过 docker 宿主机名访问

docker 提供了一个宿主机名:host.docker.internal,所有容器都可以访问到这个主机名。测试:

nc host.docker.internal 8888

连接成功!且在 alpine-client 输入的信息可以成功发送到 alpine-server,且实现的是双向通讯。可以通过 host.docker.internal 这个主机名可以访问到容器映射出来的端口,但无法访问到容器内部的端口。

4.5 通过 docker-compose 创建容器的方案

此部分在我的博文《docker安装、调试qsign签名服务器》里已经应用过,此处就不再赘述。这种方式的 docker-compose.yml 文件已经定义好了容器之间的关系,将各个容器纳入一个统一的网卡里,灵活性稍差一点,推荐用在成熟、稳定的项目里。

此文描述的方式是采用“分离式”,各个容器是独立的,容器之间的联系通过映射端口的方式,通过 host.docker.internal 进行连接,便于动态灵活调整连接关系,以及系统的扩展等。

5 总结

在未实施容器分组编排的场景中,本文深入探究并揭示了一种利用 host.docker.internal 实现容器间直接互访的有效途径。相较于传统的基于 IP 地址的访问方式,选用 host.docker.internal 作为连接标识具有显著优势:
1)稳定性增强:
在容器内部的配置文件中,可以将 host.docker.internal 作为固定的目标地址进行硬编码(即“写死”)。此举消除了因依赖动态分配或可能变动的 IP 地址而导致的配置脆弱性。当容器重启、迁移或者网络环境发生调整时,IP 地址可能会发生变化,而使用 host.docker.internal 则能确保连接指向始终有效,无需随 IP 变动而频繁更新配置。
2)简化管理:
采用 host.docker.internal 作为连接字符串,简化了容器间交互的管理复杂度。运维人员无需跟踪每个容器的具体 IP 地址,也不必在 IP 变化时手动调整关联容器的配置文件。这种抽象化的寻址方式使得容器间的依赖关系更为清晰,易于理解和维护。
3)兼容性与可移植性提升:
host.docker.internal 是 Docker 系统内建的特殊域名,旨在提供一种标准、跨平台的方式来访问宿主机提供的服务。这意味着无论宿主机的实际IP如何变化,或者在不同的部署环境中(如开发、测试、生产),只要支持 Docker,该域名即可确保容器间的互访顺利进行。这种设计增强了容器应用在不同环境中的兼容性和可移植性。

综上所述,在无编排工具介入的情况下,利用 host.docker.internal 进行容器间的互访是一种既稳健又便捷的选择。它不仅避免了因 IP 变动引发的连接失败问题,还简化了管理流程,提升了应用在不同 Docker 环境下的适应性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/801217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单易懂的Metabase入门指南

简单易懂的Metabase入门指南 数据分析在现代企业决策过程中扮演着至关重要的角色。但是,数据分析和可视化工具往往过于复杂,特别是对于非技术人员而言。Metabase是一个开源的数据分析和BI(商业智能)工具,它以易用性为…

代码审计中应注意的命令执行函数以及命令

目录 1.远程代码执行函数 1.1.php 1.1.1.call_user_func() 和 call_user_func_array() 1.1.2.create_function() 1.1.3.assert() 1.1.4.preg_replace() 1.1.5.array_map(), array_walk(), array_filter() 1.1.6.register_shutdown_function() 和 register_tick_functio…

数据结构__顺序表

概念及结构 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改 需要用到数组:数组的绝对优势:下标的随机访问(因为物理空间连续) a[i]等…

NatCross实现NASCAB云可云内网穿透指南

一、简介 1、NAS_CAB介绍 跨平台NAS软件,远程管理照片,影音和文件,无需专用设备,个人版永久免费。官网地址:https://www.nascab.cn/。 2、NatCross介绍 NatCross是内网穿透工具,也是免费的端口映射和DDNS动态域名解析软件。软件从2021年上线以来&…

10.枚举

1.背景及定义 枚举是在JDK1.5以后引入的。 主要用途是: 将一组常量组织起来, 在这之前表示一组常量通常使用定义常量的方式: public static final int RED 1; public static final int GREEN 2; public static final int BLACK 3; 但是…

2005-2023年各省国内生产总值指数分季度数据

2005-2023年各省国内生产总值指数分季度数据 1、时间:2005-2023年 2、来源:国家统计局、各省统计局 3、指标:地区生产总值指数(上年同期100)_累计值(%) 4、范围:31省 5、时间跨度:季度 6、缺失情况:无…

Redis 主从复制、哨兵模式、Cluster集群

目录 一、Redis 主从复制 1、主从复制介绍 2、主从复制的作用 3、主从复制流程: 4、搭建redis主从复制 4.1所有服务器搭建redis数据库 4.2修改Redis配置文件(Master节点操作) ​4.3修改Redis配置文件(slave节点操作&#x…

【C++】详解 Unique 函数 (小白一看就懂!!!)

目录 一、前言 二、去重函数 Unique() ✨头文件 ✨用法与作用 ✨注意点 三、常考面试题 四、共勉 一、前言 经常刷算法题的朋友,肯定会经常看到题目中提到 去重 这样的字眼,或者需要我们通过 去重 来解题,由于之前对 去重 了解的不太清楚…

LinkedHashMap 集合源码分析

LinkedHashMap 集合源码分析 文章目录 LinkedHashMap 集合源码分析一、字段分析二、内部类分析三、构造方法分析四、内部方法分析五、总结 LinkedHashMap 是 HashMap 的子类,在 HashMap 的基础上维护了双向链表,保证了有序性。默认是不排序的&#xff0c…

JavaScript模块化开发的前世今生

一个兜兜转转,从“北深”回到三线城市的小码农,热爱生活,热爱技术,在这里和大家分享一个技术人员的点点滴滴。欢迎大家关注我的微信公众号:果冻想 前言 现代化的编程语言,基本都支持模块化的开发&#xff…

Transformer算法详解

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍦 参考文章:TensorFlow入门实战|第3周:天气识别🍖 原作者:K同学啊|接辅导、项目定制 一、文本输入人类理解 词向量(E…

ICLR24_OUT-OF-DISTRIBUTION DETECTION WITH NEGATIVE PROMPTS

摘要 分布外检测(OOD Detection)的研究对于开放世界(open-world)学习非常重要。受大模型(CLIP)启发,部分工作匹配图像特征和提示来实现文本-图像特征之间的相似性。 现有工作难以处理具有与已…

Java常用API_System——常用方法及代码演示

1.System.exit(int status) 方法的形参int status为状态码,如果是0,说明虚拟机正常停止,如果非0,说明虚拟机非正常停止。需要将程序结束时可以调用这个方法 代码演示: public class Test {public static void main(S…

UVA156 反片语 解题报告

UVA156 反片语 解题报告 题目链接 https://vjudge.net/problem/UVA-156 题目大意 输入一些单词,找出所有满足如下条件的单词:该单词不能通过字母重排,得到输入文本中的另外一个单词。在判断是否满足条件时,字母不分大小写&…

浏览器禁用cookie后session还能用吗?

1.背景 最近有朋友问我其面试时遇到的一个不常见的问题:浏览器禁用cookie后session还能用吗?,怎么解答。 2.cookie与session联系入手 2.1 理论基础 一般默认情况下,在会话中,服务器存储 session 的 sessionid &…

第四百四十七回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 使用方法 3. 内容总结 我们在上一章回中介绍了"如何在页面上显示蒙板层"相关的内容,本章回中将介绍overlay_tooltip这个三方包.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

AGI(通用人工智能Artificial General Intelligence)知识点

通用人工智能AGI知识点 AGI1. prompt提示工程是什么?2. 怎么构建prompt?3. Function Calling是什么?4. RAG是什么?构建 RAG 模型的步骤:RAG 的优势和应用场景: 5. 离线和在线的RAG怎么构建?5. 构…

【SCI绘图】【热力图系列2 R】多特征相关性分析热力图指定聚类 R

SCI,CCF,EI及核心期刊绘图宝典,爆款持续更新,助力科研! 本期分享: 【SCI绘图】【热力图系列2 R】多特征相关性分析热力图指定聚类 R 1.环境准备 library(gplots) library(RColorBrewer)2.数据读取 ###…

VUE实现增删改查功能

Vue 中实现增删改查功能 增删改查(CRUD)是 Web 应用程序中的基本操作,它可以让我们在数据库中创建、读取、更新和删除数据。在 Vue.js 中实现 CRUD 功能相对简单。 创建 创建新记录时,我们将使用 v-model 双向绑定数据并向服务…

python小项目——时钟模拟

钟表是一种计时的装置,也是计量和指示时间的精密仪器。钟表的样式千变万化,但是用来显示时间的表盘相差无几,大多数钟表表盘的样式由刻度(共60个,围成圆形)、指针(时针、分针和秒针)…