Cloudflare Services: Cloudflare 服务一览、R2 对象存储与 Tunnel

Cloudflare 起家是 CDN 和 DNS,现在的产品线已经覆盖网络、安全、开发者平台和存储。这篇先按用途列一遍常用服务,再单独讲 R2 对象存储和 Tunnel。各服务的额度和价格会调整,以官方文档为准(本文核对于 2026-10)。 服务一览 网络与安全 服务 说明 DNS 权威 DNS,免费。域名的 NS 指到 Cloudflare 以后,其他服务才能接上 CDN / 代理 DNS 记录打开代理(橙色云朵)后,流量先经过 Cloudflare 边缘节点,静态内容在边缘缓存 SSL/TLS 边缘证书自动签发;回源可用 Origin CA 证书(只被 Cloudflare 信任,有效期最长 15 年),模式应选 Full (strict) WAF / DDoS 防护 代理开着时自动生效,免费版有基础规则 Turnstile 人机验证,替代 reCAPTCHA,免费 Registrar 域名注册,按成本价续费,不加价 开发者平台 服务 说明 Pages 静态站点和前端项目托管,连 Git 仓库自动构建,见 Hugo + Cloudflare Pages 搭建个人博客 Workers 边缘 Serverless 运行环境,见 Cloudflare Workers KV 全球分布的键值存储,读多写少,最终一致 D1 基于 SQLite 的关系型数据库 R2 对象存储,兼容 S3 API,没有出口流量费,见下文 Durable Objects 带强一致状态的单实例对象,适合协同编辑、计数、WebSocket Queues 消息队列 Workers AI 在边缘调用推理模型 KV、D1、R2、Durable Objects、Queues 都可以通过 binding 注入 Worker 使用。 ...

Created 14146-10-14 · Updated 20206-10-20 · 4 min · 690 words · -

Ansible Vault: 加密 Ansible 仓库里的密钥

解决什么问题 Ansible 仓库里迟早会出现密钥:数据库密码、API token、TLS 私钥。playbook 和变量文件要进 git,密钥如果跟着明文进去,所有能克隆仓库的人和程序就都拿到了它,而且会永远留在历史里。 Ansible Vault 是 Ansible 自带的加密功能(命令是 ansible-vault,不用另外安装)。它解决的是一件事:让密钥以密文的形式和 playbook 放在同一个仓库里,运行 playbook 时自动解密。 它和 HashiCorp Vault 没有关系,只是名字像。HashiCorp Vault(以及它的 fork OpenBao)是一个常驻的密钥服务;Ansible Vault 只是一个文件加密工具,没有服务端。 原理 加密后的文件是这样的: $ANSIBLE_VAULT;1.1;AES256 62313365396662343061393464336163383764373764613633653634306231386433626436623361 6134333665353966363534333632666535333761666131620a663537646436643839616531643561 ... 第一行是头部:格式版本 1.1,算法 AES256。用了 vault ID(见下文)时版本是 1.2,头部末尾多一个标签。 加密过程:从 vault 密码用 PBKDF2-SHA256 加随机盐派生出密钥,用 AES-256(CTR 模式)加密内容,再用 HMAC-SHA256 防篡改,最后转成十六进制文本。 整个仓库通常只用一个 vault 密码。谁有这个密码,谁就能解开所有加密文件。 两种加密粒度 加密整个文件 # Create a new encrypted file and open it in $EDITOR ansible-vault create group_vars/prod/vault.yml # Encrypt an existing plaintext file in place ansible-vault encrypt group_vars/prod/vault.yml # Edit / view without leaving a plaintext copy on disk ansible-vault edit group_vars/prod/vault.yml ansible-vault view group_vars/prod/vault.yml # Change the password ansible-vault rekey group_vars/prod/vault.yml 只加密单个变量 ansible-vault encrypt_string 's3cr3t' --name 'db_password' 输出可以直接贴进普通的变量文件,文件其他部分仍是明文: ...

Created 20206-10-20 · Updated 20206-10-20 · 2 min · 301 words · -

OpenTofu 入门:用 IaC 在 AWS 创建 VPC 和 EC2

什么是 OpenTofu OpenTofu 是 Terraform 的开源分支,用于以声明式的方式管理云基础设施(IaC,Infrastructure as Code)。 与 AWS CLI 的区别: OpenTofu AWS CLI 方式 声明式(描述终态) 命令式(执行具体操作) 状态管理 有 state 文件,追踪资源状态 无状态 典型场景 创建/销毁一整套基础设施 查询、临时操作 OpenTofu 和 AWS CLI 都直接调用 AWS API,不存在封装关系。 核心概念 Provider Provider 是 OpenTofu 操作各家云服务的插件,tofu init 时自动下载。 required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } Resource vs Data Source resource — 创建资源(EC2、VPC、安全组等) data — 查询已有信息,不创建资源 # 查询最新的 Amazon Linux 2023 AMI(不创建资源) data "aws_ami" "al2023" { most_recent = true owners = ["137112412989"] filter { name = "name" values = ["al2023-ami-2023.*-x86_64"] } } # 创建 EC2 实例(使用上面查到的 AMI ID) resource "aws_instance" "server" { ami = data.aws_ami.al2023.id instance_type = "t2.nano" } Variables 变量分两个文件: ...

Created 29296-04-29 · Updated 19196-10-19 · 7 min · 1329 words · -

Resend: 事务邮件发送服务

Resend 是什么 Resend 是一个面向开发者的邮件发送服务(ESP,Email Service Provider)。程序调一个 HTTP API,Resend 负责把邮件真正投递到收件人的邮箱。2023 年上线,主打 API 简单、文档清楚,同一团队还维护了用 React 写邮件模板的 React Email。 它主要用来发事务邮件(transactional email):注册验证、密码重置、账单通知、给管理员的告警。这类邮件是某个事件触发的、一对一的,和营销群发不是一回事(Resend 也有群发功能,叫 Broadcasts,这里不涉及)。 免费档每月 3,000 封、每天 100 封,对个人项目的通知邮件足够。具体额度以官网定价页为准。 为什么不自己发 服务器自己跑 SMTP 往外发信,基本进不了收件箱: 新 IP 没有发信信誉,Gmail、Outlook 会直接扔进垃圾箱或拒收。 云主机通常封了 25 端口出站(AWS EC2 默认就封)。 要自己处理退信、投诉、限速、重试。 ESP 的价值就在这里:它有养好信誉的发信 IP,处理退信和投诉,你只要证明「这个域名是我的,允许你代我发信」。 收信和发信是两件事 以 catglish.com 为例,两个方向用的是两套服务: 方向 服务 地址 作用 收信 Cloudflare Email Routing support@、privacy@ 别人写给这些地址的信,转发到我的 Gmail 发信 Resend no-reply@ enx-api 往外发通知邮件 Cloudflare Email Routing 只能收、不能发;Resend 只管发。两者的 DNS 记录互不冲突:收信的 MX 在根域 catglish.com 上,Resend 的记录在 send.catglish.com 子域和 resend._domainkey 上。 ...

Created 17176-10-17 · Updated 17176-10-17 · 2 min · 320 words · -

Linux Containers on macOS: Colima, Apple container, OrbStack

macOS 内核不能直接跑 Linux 容器,所有方案都是先起一个 Linux 虚拟机,再在里面跑容器运行时。区别在于虚拟机怎么起、几个容器共用一台虚拟机、对外提供什么 CLI。 分层 层级 例子 作用 容器运行时 containerd、Docker Engine 拉镜像、起容器,跑在 Linux 里 Mac 上的 Linux 环境 Colima(基于 Lima)、Apple container、OrbStack、Docker Desktop 在 macOS 上提供 Linux 虚拟机,并把 CLI 暴露给宿主 CLI nerdctl、docker、container 用户敲的命令 containerd 和 Colima 不是同一类东西:containerd 是引擎,Colima 负责给 containerd 准备一台 Linux 虚拟机。 Colima 基于 Lima,所有容器共用一台 Linux 虚拟机 运行时可选 docker 或 containerd,选 containerd 时用 nerdctl,和 Linux 服务器上的用法一致 支持 compose(nerdctl compose 或 docker compose),可选内置 k3s MIT 协议,商用免费,只有 CLI brew install colima # native arm64 VM, use Rosetta for amd64 images colima start --arch aarch64 --vm-type vz --vz-rosetta --runtime containerd colima nerdctl -- run --rm hello-world colima list colima stop 注意 --arch x86_64 会让整台虚拟机走模拟,在 Apple Silicon 上很慢。需要 amd64 镜像时,用 arm64 虚拟机加 --platform linux/amd64 构建即可。 ...

Created 15156-10-15 · Updated 15156-10-15 · 2 min · 252 words · -

Homelab CNB Frontend Build: 用 Cloud Native Buildpacks 构建前端镜像

这篇文档讲什么 Homelab 里两个前端 enx-ui(Next.js)和 rssx-ui(Vue + Vite)的镜像,现在都用 Cloud Native Buildpacks(CNB)构建,不再用 Dockerfile + Kaniko。本文按实际配置说明这套构建是怎么搭起来的:编译用哪个镜像、运行用哪个镜像、自己写的 buildpack 做了什么、Tekton 里怎么跑。 CNB 本身的概念(buildpack、builder、lifecycle、platform)见 CNB: Cloud Native Buildpacks 与 Paketo;为什么会有 CNB、它和 Dockerfile 的取舍见 Dockerfile/BuildKit vs CNB。这里只写 homelab 的落地。 为什么换掉 Kaniko Kaniko 上游(GoogleContainerTools/kaniko)2025-06 已归档,executor:v1.23.0 之后没有安全更新。 enx-ui 用 Kaniko 构建一次约 5 分 20 秒,其中解压缓存的 node_modules 层 78 秒,每次新建并挂载 Longhorn RWX 卷约 40 秒。 备选里 BuildKit 需要常驻 buildkitd,rootless 模式也要放宽 seccomp/AppArmor;CNB 的 lifecycle 以普通用户运行,不需要特权,还支持 rebase。所以选了 CNB。2026-10 rssx 也迁过来之后,集群里已经没有 Kaniko 了。 三个组件:builder、buildpack、run image CNB 构建出来的镜像,是把「构建产物」叠到「运行镜像」上。homelab 里这三样东西分别是: ...

Created 13136-10-13 · Updated 13136-10-13 · 5 min · 1027 words · -

Homelab Secrets Management: Bitwarden、rbw 与 OpenBao

我在整理 homelab 的配置仓库时发现,有不少密钥以明文形式进了 git:数据库密码、云服务的 API token、K8s Secret 的 manifest。还有一些放在 ~/.zshrc.local 里,作为环境变量。这篇文章记录我比较几种方案之后选定的思路,以及其中涉及的概念。 最后选的组合是:Bitwarden + rbw 管人在场的场景,OpenBao 管集群里的自动化,没有用 SOPS。 先分清「存放」和「使用」 讨论密钥放在哪里时,容易把两件事混在一起: 存放(数据源,长期) 使用(临时) git 里的密文 / Bitwarden / OpenBao → 环境变量、内存、临时文件 使用的那一刻必然是明文,任何方案都绕不开,程序总得拿到真实值。能做的是让它短暂、范围小:只在一个子进程里,不长期落盘。 真正可以选择的是存放在哪里,而且不一定要是 git。 对照这个划分,原来的两个问题分别是: 做法 问题 明文进 git(即使是私有仓库) 协作者授权、第三方 App 授权、CI 克隆、哪天转 public,都会把全部历史一起交出去 放在 ~/.zshrc.local 磁盘上是明文;shell 启动的所有子进程一直都能读到,包括各种 CLI、npm postinstall 脚本、AI agent 分类原则:谁在用,有没有人在场 场景 存在哪里 怎么取 是否需要人在场 本地开发和运维(tofu、Ansible、脚本) Bitwarden rbw get,只注入单条命令 需要 集群自举密钥(集群启动时就必须存在的少数几个) Bitwarden 重建集群时,由人执行脚本创建 需要,只在重建时 集群里应用运行时用的密钥 OpenBao 程序用自己的身份去取;数据库用动态凭据 不需要 核心思路:人在场就从 Bitwarden 取;没有人在场,就交给一个在线服务(OpenBao),程序用自己的身份去取。 ...

Created 12126-10-12 · Updated 12126-10-12 · 3 min · 638 words · -

SOPS: Secrets OPerationS 简介

SOPS 是什么 SOPS(Secrets OPerationS)是一个命令行工具,用 Go 写的。它最初由 Mozilla 开发,2023 年迁到 getsops/sops,现在是 CNCF 项目。 它只做一件事:加密和解密结构化文件,支持 YAML、JSON、ENV(dotenv)、INI 和二进制文件。典型用法是把密钥加密后提交到 git,这样 git 里只有密文。 它不是常驻服务,也不负责存储。密文就是普通文件,解密由你在需要的时候显式调用。 原理 信封加密 每个文件随机生成一把 data key,用 AES256-GCM 加密文件里的值。 再用一把或多把 master key 加密这把 data key,结果写进文件末尾的 sops: 元数据段。 master key 可以是 age、PGP、AWS/GCP/Azure 的 KMS、HashiCorp Vault(或 OpenBao)的 Transit 等。同一个文件可以同时加密给多把 master key,任意一把都能解开。 只加密值,不加密键 stringData: POSTGRES_PASSWORD: ENC[AES256_GCM,data:3mZ0...,iv:...,tag:...,type:str] sops: age: - recipient: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p enc: | -----BEGIN AGE ENCRYPTED FILE----- ... mac: ENC[AES256_GCM,data:...,type:str] git diff 能看出改的是哪个字段,review 时不用解密也能看懂结构。 非敏感字段(比如 K8s 的 metadata)可以保持明文。 文件带 MAC,密文被篡改时解密会报错。 age age 是一个小巧的文件加密工具,可以看作 PGP 的现代替代品,SOPS 官方也建议优先用它。 ...

Created 12126-10-12 · Updated 12126-10-12 · 2 min · 270 words · -

CNB: Cloud Native Buildpacks 与 Paketo

是什么 Cloud Native Buildpacks(常缩写 CNB)是一套把应用源码或编译产物自动打成 OCI 容器镜像的规范与工具生态,站点在 buildpacks.io。思路类似早年 Heroku、Cloud Foundry 上的 buildpack:平台检测你推上来的是什么(Java jar、Node 项目等),自动选运行时、装依赖、写好启动命令,不必为每种语言手写 Dockerfile。 Paketo(paketo.io)是 CNB 生态里常用的开源实现,提供现成的 builder 镜像和一系列 language buildpack(Java、Node.js、Go、Python 等)。它与 Spring 无隶属关系,但 Spring Boot 的 bootBuildImage / spring-boot:build-image 默认使用 Paketo 的 builder。 CNB ← 规范 + 生态(buildpack / builder / lifecycle) │ ├── Paketo ← 开源实现(Spring Boot 默认路径) ├── Heroku buildpacks └── Google Cloud buildpacks … 调用方: pack CLI、Spring Boot 插件、Tekton、CI … → 拉 builder → 跑 buildpack → 出 OCI 镜像 Spring Boot 侧如何把 fat jar、分层 JAR、jlink 与 Buildpack 串起来,见 Spring Boot Container Packaging。 ...

Created 21216-06-21 · Updated 12126-10-12 · 3 min · 589 words · -

Dockerfile/BuildKit vs CNB: 为什么会有 Cloud Native Buildpacks

问题从哪来 构建容器镜像,最常见的做法是写一个 Dockerfile(或 Containerfile),交给 BuildKit、Buildah、Kaniko 之类的构建器执行。Cloud Native Buildpacks(CNB)则不需要 Dockerfile:把源码或 jar 交给 builder,自动产出 OCI 镜像。 既然 Dockerfile 已经能构建任意镜像,为什么还会出现 CNB?它解决的是 Dockerfile 解决不了的问题,还是别的问题?本文把这几个问题放在一起整理。CNB 的概念与 Paketo 用法见 CNB: Cloud Native Buildpacks 与 Paketo,Dockerfile 写法见 Containerfile。 先说结论:CNB 主要解决的不是「单个镜像能不能构建出来」,而是「几百上千个应用的镜像由谁来写、怎么统一、基础镜像出漏洞后怎么批量修」。这是组织规模上的问题,不是 Dockerfile 语法能力上的问题。 BuildKit 是什么 BuildKit 是 Moby 项目下的构建引擎,Docker Engine 23.0 起在 Linux 上成为 docker build 的默认后端,docker buildx 也基于它。 一个常被忽略的点:BuildKit 本身并不依赖 Dockerfile。它的结构分两层: 前端(frontend):把某种构建描述翻译成 LLB(Low-Level Build definition,一种描述构建步骤的有向无环图)。Dockerfile 只是其中一个前端,Dockerfile 首行的 # syntax=docker/dockerfile:1 指定的就是前端镜像。 求解器(solver):执行 LLB,负责并行、缓存、导出镜像。 flowchart LR DF[Dockerfile] OTHER[其他前端Dagger / Railpack 等] FE[Frontend] LLB[LLB DAG] SOLVER[BuildKit Solver并行 + 缓存] OUT[OCI 镜像 / 本地文件] DF --> FE OTHER --> LLB FE --> LLB --> SOLVER --> OUT 所以更准确的说法是:「Dockerfile 是一种构建描述语言,BuildKit 是执行引擎」。Dagger 的引擎、Railway 的 Railpack 等工具都直接生成 LLB,不写 Dockerfile 也能用 BuildKit。 ...

Created 12126-10-12 · Updated 12126-10-12 · 6 min · 1133 words · -

zookeeper

zookeeper [16/11/21 03:20:30:030 CST] main-SendThread(192.168.50.100:2181) WARN zookeeper.ClientCnxn: Session 0x0 for server 192.168.50.100/<unresolved>:2181, unexpected error, closing socket connection and attempting reconnect 检查zookeeper包版本和连接的服务端版本,有可能是版本不一致 https://blog.csdn.net/richie696/article/details/112910751 向 zookeeper 发送 stat 命令 查询 zookeeper版本 echo stat | socat - TCP:192.168.50.100:2181 server # docker docker run \ --name zookeeper \ -p 2181:2181 \ -v /etc/localtime:/etc/localtime:ro \ -v zookeeper-conf:/conf \ -v zookeeper-data:/data \ -v zookeeper-datalog:/datalog \ -d \ zookeeper # podman podman run \ --name zookeeper \ -p 2181:2181 \ -v /etc/localtime:/etc/localtime:ro \ -e ZOO_4LW_COMMANDS_WHITELIST=* \ -d \ zookeeper # conf, data volume podman run \ --name zookeeper \ -p 2181:2181 \ -v /etc/localtime:/etc/localtime:ro \ -v zookeeper-conf:/conf \ -v zookeeper-data:/data \ -v zookeeper-datalog:/datalog \ -e ZOO_4LW_COMMANDS_WHITELIST=* \ -d \ zookeeper:3.7.0 # client docker run -it --rm zookeeper zkCli.sh -server 127.0.0.1 #zkCli.sh #连接zookeeper bin/zkCli.sh -server localhost:2181 #创建节点 create /k0 v0 # 删除一个节点 delete /k0 install download zookeeper cp zoo_sample.cfg zoo.cfg ...

Created 14146-01-14 · Updated 9096-10-09 · 3 min · 443 words · -

Containerfile

Containerfile, Dockerfile buildkit 默认会查找当前目录的 Containerfile 或者 Dockerfile FROM golang:1.22.0 AS build ENV GO111MODULE on ARG APP_NAME=rssx-api WORKDIR /workdir COPY . . RUN CGO_ENABLED=0 GOOS=linux GOPROXY=https://goproxy.io go build -a -o ${APP_NAME} main.go FROM alpine:3.19.1 AS prod ARG APP_NAME=rssx-api COPY --from=build /workdir/${APP_NAME} /data/${APP_NAME} COPY config.toml config.toml COPY config.toml /data/config.toml ENV APPLICATION_NAME ${APP_NAME} CMD "/usr/local/bin/${APPLICATION_NAME}" FROM golang:1.12.4 AS build ENV GO111MODULE on WORKDIR /go/src/xxx.com/xxx ADD . . ADD cmd cmd ADD internal internal ADD pkg pkg RUN CGO_ENABLED=0 GOOS=linux go build -a cmd/xxx.go FROM alpine AS prod COPY --from=build /go/src/xxx.com/xxx/xxx . # dev ADD configs/xxx.json . CMD ["./xxx"] buildah -f Dockerfile-0 --build-arg foo="bar" 环境变量 设置环境变量 USERNAME 默认值为 admin,后面可以通过docker run -e USERNAME=“XXXXXX"修改,这个环境变量在容器里也可以$USERNAME获取 ...

Created 22226-12-22 · Updated 9096-10-09 · 3 min · 608 words · -

jenkins api token

jenkins api token Jenkins REST API提供了API token,使得可以在程序中使用API token进行认证 (而不是使用你真实的密码) 。 API token可以在用户个人设置界面查看 到用户→用户id→设置页面,在API Token区域点击Show API token按钮,便可查看API token,同时还可以更改API token 相应的URL是http://<JENKINS_URL>/user/<userid>/configure 取编译结果 BUILD_STATUS=$(curl -k -user user0:jenkins_token_0 -silent ${BUILD_URL}api/json | jq -r ‘.result’) https://cloud.tencent.com/developer/article/1415887 https://stackoverflow.com/questions/22264431/getting-a-jobs-build-status-as-post-build-variable 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;categories 改为 Cloud 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 22226-03-22 · Updated 9096-10-09 · 1 min · 50 words · -

Docker Network 网络

docker 网络 安装 Docker 时,它会自动创建 3 个网络。可以使用 docker network ls 命令列出这些网络。 $ docker network ls NETWORK ID NAME DRIVER 7fca4eb8c647 bridge bridge 9f904ee27bf5 none null cf03ee007fb4 host host 运行一个容器时,可以使用 the -net 标志指定您希望在哪个网络上运行该容器。 bridge 网络表示所有 Docker 安装中都存在的 docker0 网络。除非使用 docker run --net=<NETWORK> 选项另行指定,否则 Docker 守护进程默认情况下会将容器连接到此网络。在主机上使用 ifconfig命令,可以看到此网桥是主机的网络堆栈的一部分。 none 网络在一个特定于容器的网络堆栈上添加了一个容器。该容器缺少网络接口。 host 网络在主机网络堆栈上添加一个容器。您可以发现,容器中的网络配置与主机相同。 用户定义的网络 您可以创建自己的用户定义网络来更好地隔离容器。Docker 提供了一些默认网络驱动程序来创建这些网络。您可以创建一个新 bridge 网络或覆盖一个网络。也可以创建一个网络插件或远程网络并写入您自己的规范中。 您可以创建多个网络。可以将容器添加到多个网络。容器仅能在网络内通信,不能跨网络进行通信。一个连接到两个网络的容器可与每个网络中的成员容器进行通信。当一个容器连接到多个网络时,外部连接通过第一个 (按词典顺序) 非内部网络提供。 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 docker-network.md;title 改为「Docker Network 网络」;url 改为 docker-network;旧 url 加入 aliases 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 19196-04-19 · Updated 9096-10-09 · 1 min · 82 words · -

k8s command

k8s command commands kubekey https://github.com/kubesphere/kubekey Rancher https://rancher.com/ archlinux install k8s ubuntu install k8s commands # 查看某一个 pod 配置 kubectl get pod <pod-name> -n <namespace> -o yaml # 找到 Pod 所属的 Controller(通常是 Deployment) kubectl get pod <pod-name> -o jsonpath="{.metadata.ownerReferences[0].name}" # 查看 Deployment 的 YAML 启动命令 kubectl get deployment bgp-opt-backend -o yaml # exec api kubectl exec -it "$(kubectl get pods | grep -Eo '^[^ ]+' |grep api)" -- bash # pod kubectl get pod -A -o wide # 查看 pod, 比如能看到镜像版本 kubectl describe pods pod0 # configmap kubectl apply -f redis-config.yaml kubectl get configmap kubectl get configmap -n namespace0 kubectl edit configmap configmap0 kubectl delete configmap configmap0 # 显示集群信息 kubectl cluster-info kubectl cluster-info dump # 查询所有节点标签信息 kubectl get node -o wide --show-labels # kube-system namespace 的 pod kubectl get pods -n kube-system kubectl label node 192.168.0.212 gpu=true kubectl get node -L gpu kubectl get node -L kubernetes.io/arch # delete lable kubectl label node minikube disktype- kubectl describe node node0 节点关机操作 # 1. 标记节点为不可调度(防止新 Pod 调度到该节点) kubectl cordon <node-name> # 2. 驱逐节点上的 Pod(优雅地将 Pod 迁移到其他节点) kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data # 3. 验证节点上是否还有 Pod 运行 kubectl get pods --all-namespaces -o wide | grep <node-name> # 4. 关机 sudo poweroff # 5. 节点重新上线后,恢复调度(取消不可调度状态) kubectl uncordon <node-name> # 查看 pod 状态 kubectl get pods --all-namespaces # kubectl exec # 注意:旧语法 `kubectl exec -it pod0 bash` 已废弃,必须用 -- 分隔命令 # "--" 用于将要传递给命令的参数与 kubectl 的参数分开,避免歧义 kubectl exec -it pod0 -- sh kubectl exec -it pod0 -n namespace0 -- sh kubectl exec --stdin --tty shell-demo -- /bin/bash # 精简镜像(alpine/distroless)通常没有 bash,用 sh 代替 # 不进入容器,直接执行单条命令并返回输出(不加 -it) kubectl exec pod0 -n namespace0 -- curl http://ip.3322.net kubectl exec pod0 -n namespace0 -- env # logs kubectl logs pod0 kubectl logs -f kube-flannel-ds-kp9mt kubectl logs -f --since 5m istiod-9cbc77d98-kk98q -n istio-system kubectl logs --namespace <NAMESPACE> <NAME> # scale, 扩缩容 kubectl scale --replicas=0 deployment/deployment0 # 滚动重启 deployment(推荐,不中断服务) # 触发 deployment 的滚动更新,逐步替换旧 Pod 为新 Pod,整个过程不会中断服务 # 等同于手动更新了一个无实际变化的字段(如 annotation),让 k8s 认为配置发生变化从而触发重启 # 适用场景:刷新 ConfigMap/Secret 挂载、解决 Pod 僵尸状态、强制拉取新镜像等 kubectl rollout restart deployment <deployment-name> -n <namespace> # 查看滚动更新状态 kubectl rollout status deployment <deployment-name> -n <namespace> # 回滚到上一个版本 kubectl rollout undo deployment <deployment-name> -n <namespace> # 查看发布历史(每次 apply/set image/rollout restart 都会产生一个新 revision) kubectl rollout history deployment <deployment-name> -n <namespace> # 示例输出: # REVISION CHANGE-CAUSE # 1 <none> # 2 kubectl set image deployment/nginx nginx=nginx:1.19 # 3 kubectl rollout restart deployment/nginx # 查看某个具体 revision 的详细信息 kubectl rollout history deployment <deployment-name> -n <namespace> --revision=2 # 回滚到指定 revision kubectl rollout undo deployment <deployment-name> -n <namespace> --to-revision=2 # 删除 pod kubectl delete pod pod0 ## 强制删除 kubectl delete pod pod0 --force --grace-period=0 kubectl delete pod pod0 -n namespace0 --force --grace-period=0 kubectl get pods calico-node-tcwtg -n kube-system -o yaml | grep image:| cut -c 4-|sort|uniq kubectl get nodes kubectl -o wide get pod kubectl describe svc svc0 kubectl describe pods -n namespace0 pod0 # ENDPOINTS kubectl get ep -n namespace0 kubectl set image deployment/kong kong=kong1.0 -n namespace0 # cp, source file: /tmp/foo, dest file: /tmp/bar kubectl cp namespace0/pod0:/tmp/foo /tmp/bar kubectl get pv,pvc kubectl get pod -A -o wide kubectl get pods --all-namespaces kubectl get svc ## 卸载服务, delete service and deployment kubectl delete -f deployment.yaml kubectl get configmap # 查看 k8s 版本 kubectl version --output=yaml systemctl status kubelet # 重置 kubeadm reset # 检查k8s dns svc 启动是否正常 kubectl get svc -n kube-system # 节点的状态 kubectl get nodes -o wide kubectl get pod # 所有 Pod 信息 kubectl get pods --all-namespaces -o wide kubectl get pods -A kubectl get pods -n kube-system -o wide # 重启 pod kubectl replace --force -f kube-flannel.yml kubectl delete node k8s-test-2.novalocal crictl ps kubeadm token list kubectl get svc nginx-app kubectl describe svc nginx-app # check status kubectl get pods --all-namespaces kubectl get pods --all-namespaces -o wide kubectl describe pod -n <NAMESPACE> <NAME> kubectl cluster-info kubectl get nodes kubectl get po -n default kubectl delete deployment deployment0 kubectl delete svc svc0 kubectl create namespace influxdb kubectl explain pod # 强制替换pod ,相当于重启 kubectl replace --force -f kube-flannel.yml kubectl rollout rollout 是 Kubernetes 的滚动发布机制,不是简单的重启。它按策略逐步替换 Pod,新 Pod 健康检查通过后旧 Pod 才下线,全程不中断服务。 ...

Created 10106-03-10 · Updated 9096-10-09 · 17 min · 3454 words · -

Homelab topology:硬件、PVE 宿主机与 K8s 集群

背景 homelab 里硬件、PVE 宿主机、K8s 节点、网络分散记录在多篇文章里:Hardware 记了全部硬件清单,PVE、Proxmox VE 存储、pve + openwrt 记了 PVE 与软路由操作,k8s 记了 K8s 概念。但没有一篇把"哪台物理机 → 哪个 PVE 宿主机 → 跑了哪些 K8s 节点 → 怎么连网"串起来。 本文只画这条链路。集群里部署了哪些服务(RSSX、Diun、Grafana 等)见 Homelab Services。PVE 宿主机上除 K8s 节点外的其它虚拟机(win11-ltsc、VPN 客户端、netbird-router 等)不展开。数据来源于 w10n-config 仓库的 infra/homelab/opentofu/pve/main.tf(OpenTofu,宿主机与 VM 的权威定义)和 infra/homelab/inventory/homelab-vms.ini(IP 与节点角色)。 一张图:物理机 → PVE → K8s 节点 → 网络 flowchart TB onu["光猫 ONU"] -->|PPPoE WAN| openwrt subgraph n100_host["物理机 n100 · 192.168.50.6"] openwrt["VM openwrt-24-10软路由 · LAN 192.168.50.1"] k8s67["VM k8s-67control-plane"] k8s71["VM k8s-71worker"] end openwrt -->|vmbr0 LAN 口| lan["交换机 / LAN 192.168.50.0/24"] lan --- j4125_host lan --- pve03_host lan --- r86s_host lan --- n100_host lan --- vip["kube-vip VIP192.168.50.100"] lan --- ap["无线 APRuckus R310"] ap -.->|Wi-Fi 2.4G / 5G| wifi_clients["无线终端手机 / 笔记本 / Switch"] subgraph j4125_host["物理机 j4125 · 192.168.50.2"] k8s21["VM k8s-21worker"] end subgraph pve03_host["物理机 pve03 · 192.168.50.3"] k8s38["VM k8s-38control-plane"] k8s39["VM k8s-39worker"] end subgraph r86s_host["物理机 r86s · 192.168.50.5"] k8s50["VM k8s-50worker"] k8s51["VM k8s-51control-plane"] end 要点: ...

Created 23236-07-23 · Updated 9096-10-09 · 2 min · 380 words · -

Cloudflare Workers: 边缘 Serverless 运行环境

Cloudflare Workers 是什么 Cloudflare Workers 是 Cloudflare 提供的 Serverless 运行环境:把一段 JavaScript / TypeScript(也支持 Python 和编译成 WebAssembly 的 Rust、Go 等)部署到 Cloudflare 全球的边缘节点上,请求打到离用户最近的节点时直接在那里执行代码并返回响应,不需要自己管服务器。 和 AWS Lambda 这类传统 FaaS 相比,主要区别在运行时: 对比项 Cloudflare Workers 传统 FaaS(如 Lambda) 隔离方式 V8 Isolate,多个 Worker 共享一个进程 容器 / microVM 冷启动 毫秒级,基本可忽略 百毫秒到秒级 部署位置 全球所有边缘节点 选定的一个或几个 region 运行时 类浏览器的 Web 标准 API(fetch、Request、Response 等),部分兼容 Node.js API 完整的 Node.js / Python 等运行时 限制 CPU 时间、内存(128 MB)、包体积有限制 限制相对宽松 V8 Isolate 是 Chrome 的 JS 引擎里用来隔离不同页面的机制,开销比容器小很多,所以冷启动快、单机能跑大量 Worker;代价是不能运行任意二进制,也不能使用依赖原生模块的 npm 包。 ...

Created 4046-10-04 · Updated 4046-10-04 · 3 min · 500 words · -

Helm Chart: Kubernetes 包管理

Helm 是什么 Helm 是 Kubernetes 的包管理器,地位类似 Linux 上的 pacman / apt。apt 安装的单位是 deb 包,Helm 安装的单位是 chart。 # archlinux pacman -S helm # macOS brew install helm # curl curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Chart 解决什么问题 在 K8s 里部署一个应用,需要的远不止一个镜像。以 Kong(API 网关 + Ingress Controller)为例,一次部署要创建这些资源: Deployment:跑 Kong 网关和 Ingress Controller 两个容器 Service:proxy、admin、webhook 等多个 ServiceAccount、ClusterRole、ClusterRoleBinding:Controller 要读集群里的 Ingress ValidatingWebhookConfiguration:校验用户提交的 Kong 资源 Secret:webhook 用的 TLS 证书 CRD:KongPlugin、KongConsumer 等自定义资源 手写这些 YAML 有几个问题: ...

Created 24246-11-24 · Updated 3036-10-03 · 3 min · 521 words · -

Prometheus client_golang vs OpenTelemetry: Go 服务指标埋点

给 Go 服务加指标(比如「查一次词花了多少毫秒」),代码里要选一个埋点库。常见的两个选择是 Prometheus 官方的 client_golang 和 OpenTelemetry 的 Go SDK。两者都能产出同样的 Prometheus 指标,差别在覆盖范围、配置量和对后端的绑定程度。 采集、存储、展示这一层(Alloy、Prometheus、Loki、Grafana)的对比见 可观测性工具对比。本文只讲应用代码里的埋点这一层。 埋点库在哪一层 graph LR A["应用代码埋点库:client_golang 或 OTel SDK"] --> B["采集Prometheus 抓取 / Alloy / OTel Collector"] B --> C["存储Prometheus / Mimir / Grafana Cloud"] C --> D["展示Grafana"] 埋点库决定两件事:代码里怎么记录一个数字,以及这个数字以什么格式交出去(Prometheus 的 /metrics 文本格式,或者 OTLP 协议)。它不决定数据最后存在哪。 Prometheus client_golang github.com/prometheus/client_golang 是 Prometheus 项目的官方 Go 客户端,只做指标。 工作方式是拉(pull):应用在内存里维护计数器和直方图,通过 HTTP 暴露一个 /metrics 端点,Prometheus(或 Alloy)定期来抓。应用不知道谁来读,也不主动往外发。 四种指标类型: 类型 用途 例子 Counter 只增不减的计数 请求总数、错误总数 Gauge 可增可减的当前值 正在处理的请求数、队列长度 Histogram 按桶统计分布,服务端可算分位数 请求耗时,用来算 p95/p99 Summary 客户端直接算分位数 很少用;分位数无法跨实例聚合,一般用 Histogram 最小示例: ...

Created 29296-09-29 · Updated 29296-09-29 · 3 min · 443 words · -

Homelab Services: 部署了哪些服务

这篇写什么 本文只回答「集群里现在跑了哪些服务」。对外 HTTPS 走 Kong Ingress,持续部署走 Argo CD。物理机、PVE 宿主机、K8s 节点和网段见 Homelab 拓扑。两篇分工: 问题 看哪篇 哪台物理机 → 哪个 PVE → 哪些 K8s 节点 Homelab 拓扑 集群里部署了哪些服务、怎么访问 本文 清单以 w10n-config 的 infra/homelab/k8s/ 为准。域名由 OpenWrt 解析到 Kong Ingress VIP 192.168.50.101。 平台层 集群自己用的组件,一般不直接当「业务应用」打开。 服务 Namespace 访问 说明 kube-vip kube-system API 192.168.50.100;Ingress 192.168.50.101 control-plane 与 Kong LoadBalancer 各一个 VIP Kong kong (所有 *.wiloon.com / *.wiloon.lab HTTPS) Ingress Controller,TLS 在这一层终止 Longhorn longhorn-system https://longhorn.wiloon.com 集群存储 cert-manager cert-manager (无独立 UI) 通配符证书;Ingress 用已签发的 Secret,不用 cert-manager 注解 Reflector kube-system (无独立 UI) 跨 namespace 同步 TLS / Telegram 等 Secret,见 Reflector Argo CD argocd https://argocd.wiloon.com GitOps,manifest 在 git 里改完即 sync Descheduler kube-system (无独立 UI) Pod 重平衡,见 Descheduler Metrics Server kube-system kubectl top 给 HPA 和排障用 应用 服务 Namespace 访问 说明 RSSX rssx https://rssx-lab.wiloon.com RSS 阅读器 RSSHub rsshub https://rsshub.wiloon.lab 把没有原生 RSS 的站点转成 feed,给 RSSX 订阅 ENX enx UI https://enx.wiloon.lab ;API https://enx-api.wiloon.lab 英语学习扩展的后端和 UI;CI/CD 见 enx-api Homelab CI/CD Calibre default https://calibre.wiloon.com 电子书 QuantDinger quantdinger https://quantdinger.wiloon.com 量化相关 backend + frontend PM Toolkit pm-toolkit https://pm-toolkit.wiloon.lab FastAPI + Next.js 内网工具 Pomodoro default https://pomodoro-lab.wiloon.com 番茄钟 Nexus nexus UI https://nexus.wiloon.com ;Docker Hub 代理 https://docker-registry.wiloon.com 镜像缓存;另有 GHCR / GCR / hosted 等子域 ddns-go ddns-go https://ddns-go.wiloon.com 家用出口 IP 变了之后更新 Cloudflare DNS nettest default NodePort 192.168.50.100:30880 whoami,用来测连通性 Pathfinder 已从集群下线,不在上表。 ...

Created 20206-02-20 · Updated 14146-09-14 · 2 min · 303 words · -