面试官:如何将多个容器暴露到一个端口上?问倒一大片。。。

2023-11-20 21:51

本文主要是介绍面试官:如何将多个容器暴露到一个端口上?问倒一大片。。。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

点击下方名片,设为星标

回复“1024”获取2TB学习资源!

大家好,我是民工哥!

富 Web 时代,应用变得越来越强大,与此同时也越来越复杂。集群部署、隔离环境、灰度发布以及动态扩容缺一不可,而容器化则成为中间的必要桥梁。

IT 软件中所说的 “Docker” ,是指容器化技术,用于支持创建和使用 Linux 容器。而 Docker 技术就是这样一种神奇的存在:懂,万物皆可容器化;不懂,则重复“搬砖”,繁忙而不自知。bfa348702beae5388770c79a1b3e7221.png我们的容器需要对外提供访问的话,就是必须使用端口暴露。

Docker 容器暴露端口的形式有四种:

-p    
#将指定的容器端口映射到宿主机所有地址的一个随机端口-p : 
#将容器端口映射到指定的主机端口-p ::
#将容器端口映射到主机指定ip的随机端口-p ::
#将容器端口映射到指定主机ip的指定端口

在日常工作环境中,我们会部署多个相同的服务来对外提供服务,这样可以有效保证集群的高可用性,从而使用户得到很好的体验。

那么,如果多个容器提供一个服务,对外只暴露一个端口,怎么做呢?

通常有以下三种主流方法。

反向代理

当请求达到后,通过反向代理比如nginx、haproxy等,负载均衡的方式将流量转发到后端不同的容器里面。对外就可以暴露一个端口了。309e4319d661fa98056ce071c715ead8.png

步骤一:创建一个网络

首先,我们需要创建一个网络,使得多个容器能够相互通信。我们可以使用Docker命令docker network create来创建网络。下面是创建一个名为my-network的网络的代码示例:

docker network create my-network

这将创建一个名为my-network的网络,供后续的容器使用。

启动多个容器

接下来,我们需要启动多个容器,并将它们连接到之前创建的网络上。同时,我们需要将容器的端口映射到宿主机的端口上,以便外部可以访问。以下是启动三个容器并进行端口映射的代码示例:

docker run -d --network my-network --name container1 -p 8080:80 image1
docker run -d --network my-network --name container2 -p 8080:80 image2
docker run -d --network my-network --name container3 -p 8080:80 image3

上述代码中,我们使用docker run命令分别启动了三个容器,并指定了容器的网络为my-network。--name参数用于指定容器的名称,-p参数用于进行端口映射,将容器的80端口映射到宿主机的8080端口上。

步骤三:配置负载均衡

最后,我们需要配置一个负载均衡容器,将外部对于宿主机的访问请求分发到多个容器上。在本示例中,我们使用了Nginx作为负载均衡容器。以下是配置负载均衡容器的代码示例:

docker run -d --network my-network -p 8080:80 --name load-balancer nginx

上述代码中,我们使用docker run命令启动了一个Nginx容器,并将容器的网络设置为my-network。-p参数用于进行端口映射,将容器的80端口映射到宿主机的8080端口上。

DNAT

熟悉k8s Nodeport 实现的话就会发现,k8s里面service iptables 实现就是基于DNAT。关于k8s Nodeport的实现参见之前k8s的文章。我们可以先通过docker 命令启动两个容器:

$ CONT_PORT=9090$ docker run -d --rm \--name http_server_foo \-e INSTANCE=foo \-e PORT=$CONT_PORT \http_server$ docker run -d --rm \--name http_server_bar \-e INSTANCE=bar \-e PORT=$CONT_PORT \http_server

获取这个两个容器的IP

$ CONT_FOO_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' http_server_foo)
$ echo $CONT_FOO_IP
172.17.0.2$ CONT_BAR_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' http_server_bar)
$ echo $CONT_BAR_IP
172.17.0.3

然后创建 DNAT 规则

$ FRONT_PORT=80# Not secure! Use global ACCEPT only for tests.
$ sudo iptables -I FORWARD 1 -j ACCEPT# DNAT 本地流量,宿主机访问
$ sudo iptables -t nat -I OUTPUT 1 -p tcp --dport $FRONT_PORT \-m statistic --mode random --probability 1.0  \-j DNAT --to-destination $CONT_FOO_IP:$CONT_PORT$ sudo iptables -t nat -I OUTPUT 1 -p tcp --dport $FRONT_PORT \-m statistic --mode random --probability 0.5  \-j DNAT --to-destination $CONT_BAR_IP:$CONT_PORT# DNAT 外部流量,其他机器访问
$ sudo iptables -t nat -I PREROUTING 1 -p tcp --dport $FRONT_PORT \-m statistic --mode random --probability 1.0  \-j DNAT --to-destination $CONT_FOO_IP:$CONT_PORT$ sudo iptables -t nat -I PREROUTING 1 -p tcp --dport $FRONT_PORT \-m statistic --mode random --probability 0.5  \-j DNAT --to-destination $CONT_BAR_IP:$CONT_PORT

通过上面模仿k8s Nodeport的实现,就是可以轻松实现一个端口对应多个容器了。

多服务监听

这个方法稍微hack 一点,其实 socket 在listen 的时候,支持 SO_REUSEPORT ,它的效果是运行多个程序监听同一个端口。

func main() {lc := net.ListenConfig{Control: func(network, address string, conn syscall.RawConn) error {var operr errorif err := conn.Control(func(fd uintptr) {operr = syscall.SetsockoptInt(int(fd),unix.SOL_SOCKET,unix.SO_REUSEPORT,1,)}); err != nil {return err}return operr},}ln, err := lc.Listen(context.Background(),"tcp",os.Getenv("HOST")+":"+os.Getenv("PORT"),)if err != nil {panic(err)}http.HandleFunc("/", func(w http.ResponseWriter, _req *http.Request) {w.Write([]byte(fmt.Sprintf("Hello from %s\n", os.Getenv("INSTANCE"))))})if err := http.Serve(ln, nil); err != nil {panic(err)}
}

这个我们就启动多个容器,共享 network namespace,同时监听这个端口了。

参考链接:https://www.toutiao.com/article/7055968933

785944583/ https://blog.51cto.com/u_16213361/7531581

读者专属技术群

构建高质量的技术交流社群,欢迎从事后端开发、运维技术进群(备注岗位,已在技术交流群的请勿重复添加)。主要以技术交流、内推、行业探讨为主,请文明发言。广告人士勿入,切勿轻信私聊,防止被骗。

扫码加我好友,拉你进群

cfa4bf0c052f69ed9e72ada640a4d8cf.jpeg

推荐阅读 点击标题可跳转

啪啪打脸!k8s 为啥又把 swap 拿回来了

彻底凉凉!停止支持!

知名车企被爆大规模裁员!比例 10%-20%

Windows 全新虚拟机发布!

待遇最好的 10 家央国企名单!

专为 90 后定制的 Shell,到底有啥不一样!

961e9bb60777f47a779f44c728ee6a6c.png

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下在看,加个星标,这样每次新文章推送才会第一时间出现在你的订阅列表里。点在看支持我们吧!

这篇关于面试官:如何将多个容器暴露到一个端口上?问倒一大片。。。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存

Python函数返回多个值的多种方法小结

《Python函数返回多个值的多种方法小结》在Python中,函数通常用于封装一段代码,使其可以重复调用,有时,我们希望一个函数能够返回多个值,Python提供了几种不同的方法来实现这一点,需要的朋友... 目录一、使用元组(Tuple):二、使用列表(list)三、使用字典(Dictionary)四、 使

SpringIOC容器Bean初始化和销毁回调方式

《SpringIOC容器Bean初始化和销毁回调方式》:本文主要介绍SpringIOC容器Bean初始化和销毁回调方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录前言1.@Bean指定初始化和销毁方法2.实现接口3.使用jsR250总结前言Spring Bea

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Java中Switch Case多个条件处理方法举例

《Java中SwitchCase多个条件处理方法举例》Java中switch语句用于根据变量值执行不同代码块,适用于多个条件的处理,:本文主要介绍Java中SwitchCase多个条件处理的相... 目录前言基本语法处理多个条件示例1:合并相同代码的多个case示例2:通过字符串合并多个case进阶用法使用

CentOS7更改默认SSH端口与配置指南

《CentOS7更改默认SSH端口与配置指南》SSH是Linux服务器远程管理的核心工具,其默认监听端口为22,由于端口22众所周知,这也使得服务器容易受到自动化扫描和暴力破解攻击,本文将系统性地介绍... 目录引言为什么要更改 SSH 默认端口?步骤详解:如何更改 Centos 7 的 SSH 默认端口1

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

如何使用Nginx配置将80端口重定向到443端口

《如何使用Nginx配置将80端口重定向到443端口》这篇文章主要为大家详细介绍了如何将Nginx配置为将HTTP(80端口)请求重定向到HTTPS(443端口),文中的示例代码讲解详细,有需要的小伙... 目录1. 创建或编辑Nginx配置文件2. 配置HTTP重定向到HTTPS3. 配置HTTPS服务器

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元