【k8s】什么是Service

在 Kubernetes(K8s)中,Service(服务) 是一个非常核心、关键的抽象概念。它的主要作用是: ✅ 为一组 Pod 提供稳定的网络访问入口(IP + Port),实现服务发现和负载均衡。 为什么需要 Service? 在 Kubernetes 中: Pod 是临时的、动态的 —— 它们随时可能被调度、重启、扩缩容,IP 会变 如果其他应用或用户直接访问 Pod IP,一旦 Pod 重建,连接就会失败 我们需要一个稳定的访问端点(Service),无论后端 Pod 如何变化 Service 的核心功能为: 功能 说明 服务发现 通过 Service 名称(在集群内 DNS 可解析)访问后端应用 负载均衡 自动将请求分发到后端多个 Pod 实例 解耦访问与实现 用户访问 Service,无需关心后端是哪些 Pod、IP 是多少 支持多种暴露方式 可在集群内访问、节点上暴露、或对外暴露公网访问 Service 如何工作? 创建一个 Service,并指定“选择器(selector)”来匹配一组 Pod(如 app: my-app) Kubernetes 为 Service 分配一个集群内唯一的虚拟 IP(ClusterIP) kube-proxy 组件在每个节点上设置 iptables/IPVS 规则,实现流量转发和负载均衡 当请求发送到 Service 的 IP:Port,流量会被自动转发到后端健康的 Pod Service 的 4 种类型 1️⃣ ClusterIP(默认) 只在集群内部可访问 为 Service 分配一个集群内虚拟 IP 适用于微服务之间互相调用 spec: type: ClusterIP ports: - port: 80 targetPort: 8080 selector: app: my-app 2️⃣ NodePort 在每个节点上开放一个端口(默认 30000-32767) 外部用户可通过 http://<NodeIP>:<NodePort> 访问服务 适合开发、测试或没有 LoadBalancer 的环境 spec: type: NodePort ports: - port: 80 targetPort: 8080 nodePort: 30007 # 可选,不填则自动分配 selector: app: my-app 3️⃣ LoadBalancer 适用于云平台(AWS、GCP、Azure、阿里云等) 云平台会自动创建一个外部负载均衡器,并分配公网 IP 用户通过公网 IP 访问服务 最适合生产环境对外暴露服务 spec: type: LoadBalancer ports: - port: 80 targetPort: 8080 selector: app: my-app 在 Minikube 或本地环境,可以使用 minikube service <service-name> 来模拟 LoadBalancer。 ...

2025-09-07 · 2 min · 292 words · Kerolt

Windows11右键菜单关闭扩展

关闭右键扩展: reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve taskkill /f /im explorer.exe & start explorer.exe 如果想要恢复右键扩展: reg delete "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}" /f taskkill /f /im explorer.exe & start explorer.exe

2025-09-03 · 1 min · 25 words · Kerolt

【问题记录】ddns-go与IPv6网络配置

在完成 Rustdesk 自建服务器 的搭建后,我又想到:由于实验室服务器的公网 IPv6 地址 并非永久不变,直接使用 IP 进行远程连接(如 SSH 或 Rustdesk)并不现实,如何确保远程访问的稳定性和便利性呢。为了解决这一痛点,我决定利用 动态域名解析(DDNS) 技术,配合 ddns-go 和 阿里云 DNS 服务,将服务器的动态 IP 地址实时绑定到一个易于记忆的域名上。 本文将记录我在配置过程中遇到的三个主要问题及其解决方案。 问题 1:IPv6 临时地址导致域名解析不稳定 现象与原因分析 在启用 ddns-go 服务后,我发现尽管程序运行正常,但我的域名解析记录却频繁失效。经过排查,我意识到罪魁祸首是 IPv6 临时地址(Temporary Address)。这是一种为了增强用户隐私而设计的特性,系统会定期生成新的、临时的 IPv6 地址用于出站连接。当服务器的地址发生变化时,DDNS 服务来不及同步更新,就会导致域名无法解析到正确的 IP 地址。 解决方案:禁用 IPv6 临时地址 要解决这个问题,最直接的方法就是从系统层面禁用 IPv6 临时地址功能,强制使用稳定的、非临时的地址。 编辑 sysctl 配置文件: 使用 vim 或其他编辑器打开 sysctl.conf 文件,该文件用于在系统启动时配置内核参数。 sudo vim /etc/sysctl.conf 添加配置项: 在文件末尾添加以下两行,分别用于全局禁用和默认禁用所有网络接口的 IPv6 临时地址功能。 # 禁用 IPv6 临时地址 net.ipv6.conf.all.use_tempaddr = 0 net.ipv6.conf.enp4s0.use_tempaddr = 0 注意:如果只想针对特定网卡(例如 enp4s0)进行配置,可以添加 net.ipv6.conf.enp4s0.use_tempaddr = 0。你可以通过 ip a 命令查看你机器的网卡名称。 ...

2025-08-29 · 2 min · 239 words · Kerolt

Rustdesk自建服务器

对于现在常见的远程控制软件,例如 ToDesk、向日葵,其免费版本总有诸多限制(帧率低、分辨率低、控制时间有限制),而 RustDesk 的公共服务器现在在国内也不可用,因此我就想到了 RustDesk 的自建服务器。现在我们实验室有几台空闲的电脑,并且这些电脑都有 IPv6,这就省去了我购买云服务器的花费,可以实现零成本搭建远程服务😁 安装 RustDesk Server 我使用 https://github.com/sshpc/rustdesktool 这里的脚本来一键安装,安装完后,RustDesk Server 的默认安装目录为: /usr/local/rustdesk-sever 开放端口 我们需要放行防火墙 TCP & UDP 端口 21115-21119,其中 21115 是 hbbs 用作 NAT 类型测试 21116/UDP 是 hbbs 用作 ID 注册与心跳服务 21116/TCP 是 hbbs 用作 TCP 打洞与连接服务 21117 是 hbbr 用作中继服务 # 允许 TCP 端口 sudo ufw allow 21115:21119/tcp # 允许 UDP 端口 sudo ufw allow 21115:21119/udp sudo ufw enable 然后执行 sudo ufw status 如果有如下类似输出,表明端口已经放行并且防火墙正在运行。 状态:活动 至 动作 来自 -- -- -- 21115:21119/tcp ALLOW Anywhere 21115:21119/udp ALLOW Anywhere 21115:21119/tcp (v6) ALLOW Anywhere (v6) 21115:21119/udp (v6) ALLOW Anywhere (v6) 启动服务 在我们用脚本一键安装后,服务安装目录为: ...

2025-08-25 · 1 min · 136 words · Kerolt

C&C++类型双关转换

#include <iostream> auto ASSERT(bool flag, const char* msg) { if (!flag) { std::cerr << msg << std::endl; } } // READ: 枚举类型 <https://zh.cppreference.com/w/cpp/language/enum> // `enum` 是 C 的兼容类型,本质上其对应类型的常量。 // 在 `enum` 中定义标识符等价于定义 constexpr 常量, // 这些标识符不需要前缀,可以直接引用。 // 因此 `enum` 定义会污染命名空间。 enum ColorEnum : unsigned char { COLOR_RED = 31, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, }; // 有作用域枚举型是 C++ 引入的类型安全枚举。 // 其内部标识符需要带前缀引用,如 `Color::Red`。 // 作用域枚举型可以避免命名空间污染,并提供类型安全保证。 enum class Color : int { Red = COLOR_RED, Green, Yellow, Blue, }; ColorEnum convert_by_pun(Color c) { // READ: <https://zh.cppreference.com/w/cpp/language/union> // `union` 表示在同一内存位置存储的不同类型的值。 // 其常见用法是实现类型双关转换,即将一种类型的值转换为另一种无关类型的值。 // 但这种写法实际上仅在 C 语言良定义,在 C++ 中是未定义行为。 // 这是比较少见的 C++ 不与 C 保持兼容的特性。 // READ: 类型双关 <https://tttapa.github.io/Pages/Programming/Cpp/Practices/type-punning.html> union TypePun { ColorEnum e; Color c; }; TypePun pun; pun.c = c; return pun.e; } int main(int argc, char **argv) { ASSERT(convert_by_pun(Color::Red) == COLOR_RED, "Type punning conversion"); ASSERT(convert_by_pun(Color::Green) == COLOR_GREEN, "Type punning conversion"); ASSERT(convert_by_pun(Color::Yellow) == COLOR_YELLOW, "Type punning conversion"); ASSERT(convert_by_pun(Color::Blue) == COLOR_BLUE, "Type punning conversion"); return 0; }

2025-08-21 · 1 min · 152 words · Kerolt

Git中文件换行符都使用LF

有时候我们会在多个平台上编辑文件、代码,此时我们希望所有文件,包括你在 Windows 上编辑的文件(Windows 采用的是 CRLF),都使用 LF 换行符,那么可以修改 .gitattributes 文件来强制执行这个规则: # 强制所有文件使用 LF 换行符 * text eol=lf # 避免对二进制文件进行换行符转换 *.png binary *.jpg binary *.pdf binary 在保存提交 .gitattributes 后,可能因为之前在 Windows 上编辑的文件可能已经变成了 CRLF 换行符,这时需要需要将它们转换回 LF(这里可以使用 VSCode)。 接着可以执行以下命令,让 Git 重新处理工作目录中的文件并按照新的规则来转换: git rm --cached -r . git reset --hard * text eol=lf:这条规则告诉 Git,将仓库中的所有文件都视为文本文件,并且强制它们使用 LF 作为行结束符。当你从仓库检出文件时,Git 会将其转换为 CRLF(在 Windows 上),但当你提交时,它会确保所有文件都以 LF 格式存储在仓库中。 git rm --cached -r . 和 git reset --hard:这些命令会强制 Git 重新将你的工作目录与仓库同步,并在此过程中应用 .gitattributes 文件中设置的换行符规则,从而确保所有文件都符合 LF 规范。

2025-08-21 · 1 min · 71 words · Kerolt

关于内存对齐、位域的思考

什么是内存对齐?为什么需要它? 内存对齐(Memory Alignment)是计算机系统中数据在内存中存储的一种规则:​​数据在内存中的起始地址必须是其自身大小的整数倍​​。例如,一个 4 字节的整型变量(int),其起始地址必须是 4 的倍数(如地址 0x0000、0x0004、0x0008 等)。 而需要内存对齐主要基于以下三个原因: ​​硬件访问效率​​: CPU 通过内存总线从内存读取数据时,通常以固定大小的“块”为单位(例如 4 字节或 8 字节)。如果数据对齐,CPU 一次读取操作即可获取完整数据。 ​​非对齐示例​​:假设一个 int 变量(4 字节)存储在地址 0x0001(非 4 的倍数),CPU 需要分两次读取:先读取 0x0000-0x0003(包含前 3 字节),再读取 0x0004-0x0007(包含最后 1 字节),最后拼接数据。这会显著降低性能。 ​​硬件兼容性​​: 部分架构(如 ARM、MIPS)的 CPU 无法直接访问非对齐内存。尝试访问时会导致硬件异常(如“总线错误”)。对齐保证了代码的跨平台兼容性。 ​​缓存效率优化​​: 现代 CPU 使用缓存行(Cache Line,通常 64 字节)预加载数据。对齐的数据更可能完整地位于单个缓存行中。若数据跨缓存行存储,会引发两次缓存访问,降低效率。 alignas 和 alignof c++11 以后引入两个关键字 alignas 与 alignof。 alignas 用于显式设置变量、类成员或类型的内存对齐要求;而 alignof 用于获取类型或变量的内存对齐要求。例如: struct Test1 {}; struct alignas(4) Test2 {}; static_assert(sizeof(Test1) == 1); static_assert(sizeof(Test2) == 4); static_assert(alignof(Test1) == 1); static_assert(alignof(Test2) == 4); alignas 支持三种语法形式: alignas(expression):expression 必须是计算结果为零的整数常量表达式,或者是对齐或扩展对齐的有效值(2 的倍数)。 alignas(type-id):等效于 alignas(alignof(type-id)) alignas(pack...):等效于应用于同一声明的多个 alignas 说明符,参数包的每个成员对应一个说明符,可以是类型参数包或常量参数包 Note 注意:若指定的对齐值小于编译器默认对齐要求,部分编译器可能忽略该设置。 ...

2025-07-22 · 2 min · 373 words · Kerolt

eBPF Map中的数据成员类型的宏定义

__uint, __type, __array, __ulong 这些宏主要用于 eBPF Map 的定义 中,帮助 LLVM 编译器和 BPF CO-RE (Compile Once – Run Everywhere) 理解和提取 eBPF Map 的元数据信息。它们通常与 BPF_MAP_DEF 或 struct 配合使用,在 eBPF 程序中用于告诉内核如何创建 BPF map。 常用的几个宏 1. __uint(name, val) #define __uint(name, val) int (*name)[val] 用途:定义一个名为 name 的字段,其值是一个大小为 val 的整数数组指针。 __uint(max_entries, 1024); 等价于: int (*max_entries)[1024]; 作用: 用于在 eBPF Map 的定义中指定 max_entries 这一属性(即 map 的最大容量)。这种“类型欺骗”的方式让 clang 编译器能保留这些信息在 ELF 文件的 BTF(BPF Type Format)部分里,从而被 bpftool、libbpf 提取并传给内核。 2. __type(name, val) #define __type(name, val) typeof(val) *name 用途:定义一个名为 name 的字段,其类型是 val 的指针。 ...

2025-07-07 · 2 min · 300 words · Kerolt

Curl使用

curl 是一个强大的命令行工具,用于传输数据,支持多种协议(HTTP、HTTPS、FTP 等)。以下是 curl 的基本使用方法和常见示例。 基本语法 curl [options] [URL...] 常用选项 选项 描述 -X 指定 HTTP 请求方法 (GET, POST, PUT, DELETE 等) -H 添加请求头 -d 发送 POST 请求数据 -F 发送表单数据 (multipart/form-data) -G 将 -d 数据作为 GET 请求的查询参数 -o 将输出保存到文件 -O 将输出保存到文件,使用远程文件名 -L 跟随重定向 -v 显示详细输出 (verbose) -u 指定用户名和密码 -A 设置 User-Agent -k 允许不安全的 SSL 连接 -I 只获取响应头 -s 静默模式 (不显示进度或错误信息) --data-urlencode URL 编码 POST 数据 常见用法示例 1. 发送 GET 请求 curl https://example.com 2. 发送 POST 请求 curl -X POST https://example.com/api -d 'name=value' 3. 发送 JSON 数据 curl -X POST https://example.com/api \ -H "Content-Type: application/json" \ -d '{"key1":"value1", "key2":"value2"}' 4. 发送表单数据 curl -X POST https://example.com/form \ -d 'username=admin' \ -d 'password=123456' 5. 上传文件 curl -X POST https://example.com/upload \ -F "file=@/path/to/file.txt" 6. 设置请求头 curl -H "Authorization: Bearer token" \ -H "Content-Type: application/json" \ https://example.com/api 7. 下载文件 curl -O https://example.com/file.zip 8. 跟随重定向 curl -L https://example.com/redirect 9. 使用基本认证 curl -u username:password https://example.com 10. 保存 cookie 并发送 # 保存 cookie curl -c cookies.txt https://example.com/login -d "user=name&pass=123" # 使用 cookie curl -b cookies.txt https://example.com/dashboard 11. 测试 API 响应时间 curl -o /dev/null -s -w 'Total: %{time_total}s\n' https://example.com 12. 限制下载速度 curl --limit-rate 100K -O https://example.com/largefile.zip 高级用法 发送多部分请求 curl -X POST https://example.com/upload \ -F "file=@image.jpg" \ -F "description=My image" 使用代理 curl -x http://proxy.example.com:8080 https://example.com 调试请求 curl -v https://example.com 只获取响应头 curl -I https://example.com 使用自定义 User-Agent curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" https://example.com 注意事项 在脚本中使用 curl 时,考虑添加 -s 或 -sS 选项(-S 显示错误) 处理 JSON 数据时,可以使用 jq 工具进行格式化 对于复杂的 API 调用,考虑将请求保存为文件并使用 -K 选项 在 Windows 上,使用双引号 " 而不是单引号 '

2025-07-01 · 2 min · 248 words · Kerolt

【eBPF学习】使用fentry跟踪tcp连接

本文是对 cilium/ebpf examples: fentry 的一个学习记录 在这里,我们将会利用 ebpf 监控并记录系统上所有新发起的 IPv4 TCP 连接,其工作流程如下: 挂载点:程序使用 fentry 机制把自己附加到内核函数 tcp_connect 的入口。每当系统中有任何一个进程尝试发起一个 TCP 连接时,这个内核函数就会被调用,从而触发我们的 eBPF 程序。 过滤:程序首先检查连接的地址族是否为 AF_INET,即 IPv4。如果不是(例如是 IPv6),程序会直接退出,不做任何处理。 数据提取:对于 IPv4 连接,程序会从传递给 tcp_connect 函数的 struct sock 参数中提取以下关键信息: 源 IP 地址 (saddr) 目标 IP 地址 (daddr) 目标端口 (dport) 源端口 (sport) 获取进程信息:使用 bpf_get_current_comm() 辅助函数获取当前发起连接的进程名(例如 curl, ssh 等)。 数据发送:程序将收集到的所有信息(IP 地址、端口、进程名)打包成一个 struct event 结构体,并通过一个高效的 ringbuf 映射发送到用户空间。 什么是 fentry fentry 是 eBPF 中的一种程序附加类型,全称为 “function entry”(函数入口)。它是现代 Linux 内核中用于跟踪和性能分析的高效机制。 fentry 允许将 eBPF 程序附加到内核函数的入口点,当该函数被调用时,eBPF 程序会在函数的主体执行前运行。这种机制让我们可以: ...

2025-06-22 · 3 min · 538 words · Kerolt