Rust-虽然9天过去了,结果是没有结果(Docker容器的端口映射问题)

news2024/12/22 20:25:14

这篇文章收录于Rust 实战专栏。这个专栏中的相关代码来自于我开发的笔记系统。它启动于是2023年的9月14日。相关技术栈目前包括:Rust,Javascript。关注我,我会通过这个项目的开发给大家带来相关实战技术的分享。


前言

上上周了吧,写了一篇Rust-后端服务调试入坑记,现在看来那个坑根本就不算什么。这次这个坑才是真正的坑。到写文章这一刻,我只是确定了复现这个问题的最简单代码(参考目录验证4:基于Debian:11镜像创建最简单Rust的http服务)。但依然没有找到解决这个问题的办法。

现在把这个问题以及我的验证过程整理出来,以便路过的朋友了解,我相信肯定有大神知道其中的缘由和解决办法。还望各位大神留言赐教。

问题描述

我用Rust语言创建了一个基于Rocket框架(0.5-rc)的Restful服务api(以下简称api),并将其部署在docker容器内调试。
在这里插入图片描述

容器相关描述:

  • 容器名称: notes-api
  • 网络模式: bridge
  • 端口映射: 8003:8000

当容器成功启动后,问题及相关情况描述:

  • 不能从宿住机访问容器中的api,错误码56,命令行: curl http://localhost:8003/api/notes
  • 能够从宿主机上ping通容器,命令行:ping 172.22.0.2
  • 登录到容器中,能够运行命令行成功访问api,命令行: sudo docker exec -it notes-api curl http://localhost:8000/api/notes
  • 如果将网络模式改为host,能够从宿主机上正常访问容器中的api,命令行: curl http://localhost:8000/api/notes

对自己的怀疑

这个问题导致了我对我的Docker使用经验和相关的记忆产生怀疑。难道Docker容器在网络模式为bridge时,不能从宿住机访问?很快,这个问题被否定了,因为我早些时候就在Nginx服务器上配置过多个api的路由,这些api都通过Docker部署在一台服务器上,通过不同的端口来访问部署在这些容器中的api。
即然是早些时候,我的下一个判断是,会不会是因为我现在这台服务器上安装的Docker版本比较新,新版本的Docker Engine是否有一些关于端口映射的设置,导致部署在Docker容器中的api不能够被正常访问呢?

验证之路

1. Python应用

说实话,我的关于用Docker容器部署Api的经验主要来至于Python。我还是第一次将Rust构建的api部署到Docker容器中。因此,我决定用Python创建一个简单的api,将其部署到Docker容器中,看是否能够从宿主机上正常访问。
docker-compose.yml

version: '3'

services:  
  web:
    build:
      context: ./
      dockerfile: Dockerfile
    container_name: python-api
    network_mode: bridge
    ports:
      - 8004:5000

Dockerfile

from python:latest

workdir /app
copy ./main.py ./requirements.txt /app/

run pip install -r requirements.txt
cmd ["python3", "main.py"]

结果:能够从宿主机上成功访问到容器内的api。

因此,是不是镜像本身的问题呢?
我对比了Python镜像和Rust镜像所使用的linux系统。Python镜像使用的是"Debian GNU/Linux 11",Rust使用的是"Debian GNU/Linux 12"。

2. 从Debian:11镜像来创建Rust的镜像

因此,我决定基于Debian:11的镜像来制作Rust的api容器的镜像。
docker-compose.yml

version: '3'
services:  
  web:
    build:
      context: ./
      dockerfile: Dockerfile
    container_name: notes-api1
    network_mode: bridge
    ports:
      - 8004:8000

Dockerfile

from debian:11
run apt update
run apt install -y curl gcc

run curl -s --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 
env PATH=/root/.cargo/bin:$PATH 
run rustup default nightly

workdir /app

copy ./Cargo.toml ./config.toml ./Cargo.lock /app/
copy ./src /app/src

cmd ["cargo", "run"]

结果:不能从宿主机访问Docker容器中的api。
会不会是Python的镜像虽然基于"Debian GNU/Linux 11",但是,在制作镜像的时候有一些设置关于端口映射的设置呢?

3. 从Debian:11镜像来创建Python的镜像

因此,为了排出关于“设置”的猜想,我决定基于Debian:11的镜像来制作Python的api容器的镜像。
如果能够正常访问,说明不存在关于“设置”的猜想。
docker-compose.yml

version: '3'

services:  
  web:
    build:
      context: ./
      dockerfile: Dockerfile
    container_name: my-python2 
    network_mode: bridge
    ports:
      - 8009:5000

Dockerfile

from debian:11
run apt update
run apt install -y curl gcc

run apt install python3 pip -y

workdir /app
copy ./main.py ./requirements.txt /app/

env PATH=/usr/local/bin:$PATH

run pip install -r requirements.txt

cmd ["python3", "main.py"]

结果:能够从宿主机上成功访问到容器内的api。
说明,Python的镜像中,关于端口映射的相关“设置”猜想不存在。

因此,我的视线又回到了Rust项目,我的api是基于Rocket 0.5-rc开发的,是不是因为这个框架的原因呢?

4. 基于Debian:11镜像创建最简单Rust的http服务

因此,我让AI帮我写了一个没有任何依赖的Rust的http服务,然后将这个服务部署到基于Debian:11的镜像中。
docker-compose.yml

version: '3'
services:  
  web:
    build:
      context: ./
      dockerfile: Dockerfile
    container_name: rust-simple-http
    network_mode: bridge
    ports:
      - 8012:8080

Dockerfile

from debian:11
run apt update
run apt install -y curl gcc

# 安装rust
run curl -s --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 
env PATH=/root/.cargo/bin:$PATH 

workdir /app

copy ./Cargo.toml ./entry.sh /app/
copy ./src/main.rs /app/src/main.rs

entrypoint ["./entry.sh"]

main.rs

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};

fn handle_client(mut stream: TcpStream) {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();

    let response = "HTTP/1.1 200 OK\r\n\r\nHello, World!";
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").unwrap();

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                std::thread::spawn(|| {
                    handle_client(stream);
                });
            }
            Err(e) => {
                eprintln!("Failed to establish a connection: {}", e);
            }
        }
    }
}

entry.sh

#!/bin/bash

echo "cargo build"
cargo build --release
echo "cp bin"
cp target/release/app ./
echo "run app"
./app

结果: 不能从宿主机访问Docker容器中的api。
因此,貌似和Rocket 0.5-rc这个框架没有关系。

目前的情况可以归纳为:

  1. Rust创建的api部署到容器中,容器的网络模式为bridge,不能够从宿主机通过容器的端口访问到容器中运行的api。
  2. Python创建的api部署到容器中,容器的网络模式为bridge,能够从宿主机通过容器的端口访问到容器中运行的api。

这个特殊现象是否只存在于Rust和Python之间呢?如果再找一个应用部署到网络模式为bridge的Docker容器中,能否从宿主机通过容器端口访问到容器中运行的应用呢?如果答案是“能”,那么,多少可以得出结论:

Rust创建的api部署到网络模式为bridge的Docker容器中,不能从宿主机通过容器的端口访问到容器中运行的api。

5. 基于Debian:11镜像从apt安装简单的http服务

docker-compose.yml

version: '3'
services:  
  web:
    build:
      context: ./
      dockerfile: Dockerfile
    container_name: simple-http-server
    network_mode: bridge
    ports:
      - 8013:8080

Dockerfile

from debian:11
run apt update
run apt install -y curl gcc

run apt install libhttp-server-simple-perl -y

workdir /app
copy entry.sh /app/
entrypoint ["./entry.sh"]

entry.sh

#!/bin/bash
perl -MHTTP::Server::Simple -e 'my $server = HTTP::Server::Simple->new(); $server->run()'

结果:能够从宿主机上成功访问到容器内的api。

结论

看来目前只能得出这样的结论了:
Rust创建的api部署到网络模式为bridge的Docker容器中,不能从宿主机通过容器的端口访问到容器中运行的api。

问题整理好了,先放在这里。

后面的工作如何开展

暂时将容器的网络模式设置为host进行调试。如果后面配置的服务很多,估计需要做一个cli来管理各个服务端口的配置(这可是我的强项,哈哈)。

如有问题,欢迎大家留言交流。关注我,后面会在Rust 实战专栏中给大家带来更多关于Rust开发实战的分享。

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

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

相关文章

非母语玩家如何撰写英文研究性论文:2 Methodology

参考书——《Science Research Writing for non-native Speakers of English》 文章目录 1 Structure 结构2 语法和写作技巧2.1 Passives and Tense Pairs: 被动语态以及时态对2.2 a与the的使用方法2.3 Adverbs and adverb location: 副词及其位置 3 Build a Model——构建Meth…

【每日一题】每棵子树内缺失的最小基因值

文章目录 Tag题目来源题目解读解题思路方法一:DFS 写在最后 Tag 【dfs】【树】【2023-10-31】 题目来源 2003. 每棵子树内缺失的最小基因值 题目解读 找出每棵子树内缺失的最小基因值。 解题思路 方法一:DFS 找到基因值为 1 的节点,从该…

大中小企业对CRM系统的需求

在以前,CRM客户管理系统是大型企业的专属。如今,不论何种规模的企业都能够使用CRM系统。市面上的CRM有着丰富的功能类型,管理者可以从企业自身规模出发,选择适合的CRM系统。下面说说,大中小企业对CRM系统的需求。 一句…

Linux各个发行版之间的关系

Linux各个发行版之间的关系 可以查看链接:Linux Timeline 链接中可以下载PNG或者SVG图片

Redis Cluster (Redis 集群),使用Redis自带的集群功能搭建无主模式集群

文章目录 一、概述二、模拟配置说明三、脚本方式创建 Redis Cluster3.1 配置创建脚本3.2 启动集群实例3.3 创建集群3.4 测试集群3.5 停止集群实例3.6 删除(清空)集群 四、手动创建集群 Redis Cluster4.1 启动集群实例4.2 手动创建集群4.4 测试集群 五、集…

Studio One6最新版本保姆级下载安装教程

根据使用者情况表明Vocoder一个与众不同的创意游乐场,它能够将两个输入信号组合在一起,创建由一系列带通滤波器处理的最新声音,将您的声音或任何音频源转换为独特的合成器或效果器,声码器将激发您玩转音频的无限创意。值得肯定的是…

【Python 常用脚本及命令系列 9 -- 图片文字识别 EasyOCR使用】

文章目录 1.1 EasyOCR 介绍1.1.1 EasyOCR 安装1.1.2 EasyOCR 使用方法1.1.2.1 EasyOCR 支持的语言种类1.1.2.2 EasyOCR 支持的图像格式 EasyOCR 提高图片文字识别正确率1.3 问题总结 1.1 EasyOCR 介绍 Python中有一个不错的OCR库-EasyOCR,在GitHub已有9700 star。它…

对话式AI驱动的计算机辅助设计【CAD】

大型语言模型 (LLM) 为 CAD 软件公司提供了通过对话式 AI 增强设计工作流程的新机会。 工程师无需浏览复杂的菜单,而是可以用简单的语言描述需求并接收由集成数据支持的智能响应。 例如,工程师可以通过询问“2 盎司以下的铝支架”来查询零件数据库。 LL…

荣获IoT最具潜力企业奖,美格智能引领AIoT应用变革

10月30日,2023第十届IoT大会在深圳盛大开幕。大会同期举办第八届IoT创新奖评选,美格智能顺利通过层层遴选,获颁“IoT最具潜力企业奖”。这一荣誉不仅是对公司目前研发水平、产品服务、业务发展及综合实力的高度认可,更是对创新能力…

基于SSM的高校疫情防控出入信息管理系统设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

2023年上海市初中生“爱我中华”主题征文的详细框架(续)

“中文自修杯”2023年上海市初中生“爱我中华”主题征文活动自由报名最后提交时间为今天(10月31日),请记得及时提交文稿。 前一篇文章,六分成长介绍了大家在提交征文时候的三个困惑以及解决方法。这篇文章继续为大家列出后面三个主…

springboot+vue基于Hadoop短视频流量数据分析与可视化系统的设计与实现【内含源码+文档+部署教程】

博主介绍:✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久,选择我们就是选择放心、选择安心毕业✌ 🍅由于篇幅限制,想要获取完整文章或者源码,或者代做&am…

学习视频剪辑:如何从指定时段快速抽出视频图片!高效技巧分享

随着数字媒体的普及,越来越多的人开始接触视频剪辑。在视频剪辑过程中,有时候我们需要从指定时段快速抽出视频图片。这不仅可以帮助我们提高剪辑效率,还可以让我们的视频更加丰富多彩。本文将分享一些高效技巧,帮助你轻松实现从指…

关键点检测、姿态识别、目标检测、车牌识别等项目部署代码+数据集汇总

一、AI健身计数 1、图片视频检测 (cpu运行): 注:左上角为fps,左下角为次数统计。 1.哑铃弯举:12,14,16 详细环境安装教程:pyqt5AI健身CPU实时检测mediapipe 可视化界面…

react-组件生命周期

一、生命周期阶段 官方文档:https://zh-hans.legacy.reactjs.org/docs/react-component.html React组件生命周期可分为三个阶段:挂载、更新、卸载 挂载:当组件实例被创建并插入 DOM 中时。其生命周期调用顺序如下: constructor()s…

【Java每日一题】——第四十四题:综合案例:编程模拟智能手机和普通手机功能。(2023.10.31)

🎃个人专栏: 🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客 🐳Java基础:Java基础_IT闫的博客-CSDN博客 🐋c语言:c语言_IT闫的博客-CSDN博客 🐟MySQL&#xff1a…

广西建筑模板厂家:行业先锋,品质之选

在建筑行业繁荣发展的今天,广西建筑模板厂家作为产业链中的关键环节,扮演着举足轻重的角色。这些厂家以卓越的创新力、精湛的技术和优质的客户服务,为建筑行业提供了无数可靠的解决方案。 一、创新引领进步广西建筑模板厂家始终坚持创新是推动…

如何使用内网穿透远程访问Linux SVN服务?

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…

基于javaweb的吃了吗管理系统

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…

Oracle查询表结构、索引和备注

1, ORACLE 查询表结构 SELECT table_name, column_name, data_type,DATA_LENGTH,COLUMN_ID,user_tab_comments,user_col_comments FROM USER_TAB_COLUMNS WHERE table_name upper(T_Acc_Settle_Account);SELECT * FROM user_tab_columns WHERE table_nameT_Acc_Settle_Accoun…