作者: admin

  • Nginx Puls e仪表盘

    轻量级 Nginx 访问日志分析与可视化面板,提供实时统计、PV 过滤、IP 归属地与客户端解析。

    源码仓库:https://github.com/likaia/nginxpulse

    文档站点(推荐)

    在线文档站点:https://nginx-pulse-docs.kaisir.cn/

    ⚠️注意:此文档只讲解了如何使用这个项目,详细文档与示例配置请移步在线文档站点

    demo-img-1.png
    demo-img-2.png

    目录

    项目开发技术栈

    重要提示(版本 > 1.5.3):已完全弃用 SQLite;单体部署必须自备 PostgreSQL 并配置 DB_DSN(或 database.dsn)。

    • 后端Go 1.24.x · Gin · Logrus
    • 数据PostgreSQL (pgx)
    • IP 归属地ip2region(本地库) + ip-api.com(远程批量)
    • 前端Vue 3 · Vite · TypeScript · PrimeVue · ECharts/Chart.js · Scss
    • 容器Docker / Docker Compose · Nginx(前端静态部署)

    IP 归属地查询策略

    1. 快速过滤:空值/本地/回环地址返回“本地”,内网地址返回“内网/本地网络”。
    2. 解析解耦:日志解析阶段仅入库并标记“待解析”,IP 归属地由后台任务异步补齐并回填。
    3. 缓存优先:持久化缓存 + 内存缓存命中直接返回(默认上限 1,000,000 条)。
    4. 本地优先(IPv4/IPv6):优先查 ip2region,本地结果可用时直接使用。
    5. 远程补齐:本地返回“未知”或解析失败时,调用远端 API(默认 ip-api.com/batch,可配置)批量查询(超时 1.2s,单批最多 100 个)。
    6. 远程失败:返回“未知”。

    归属地解析未完成时,页面会显示“待解析”,地域统计可能不完整。

    本地数据库 ip2region_v4.xdb 与 ip2region_v6.xdb 内嵌在二进制中,首次启动会自动解压到 ./var/nginxpulse_data/,并尝试加载向量索引提升查询性能。

    本项目会访问外网 IP 归属地 API(默认 ip-api.com),部署环境需放行该域名的出站访问。同时也支持自己搭建IP归属地查询服务,详见下文。

    如何使用项目

    1) Docker

    单镜像(前端 Nginx + 后端服务):

    镜像内置 PostgreSQL,启动时会自动初始化数据库(未自备数据库时)。必须挂载数据目录/app/var/nginxpulse_data 与 /app/var/pgdata。未挂载时容器会直接退出并报错。 如果你准备在初始化向导里配置外部数据库,可先不挂载 pgdata,容器能正常启动;配置完成后重启容器即可生效。

    一键启动(极简配置,首次启动进入初始化向导):

    docker run -d --name nginxpulse \
      -p 8088:8088 \
      -v ./docker_local/logs:/share/logs:ro \
      -v ./docker_local/nginxpulse_data:/app/var/nginxpulse_data \
      -v ./docker_local/pgdata:/app/var/pgdata \
      -v ./docker_local/configs:/app/configs \
      -v /etc/localtime:/etc/localtime:ro \
      magiccoders/nginxpulse:latest

    注意:docker_local请替换为你宿主机存在的目录,确保文件权限设置正确,能被容器正常访问,否则会出现无日志的情况。

    如果更偏好配置文件方式,可将 configs/nginxpulse_config.json 挂载到容器内的 /app/configs/nginxpulse_config.json。 若未提供配置文件/环境变量,首次启动会进入“初始化配置向导”。保存后会写入 configs/nginxpulse_config.json,需重启容器生效(建议挂载 /app/configs 以持久化)。

    2) Docker Compose

    使用远程镜像(Docker Hub):

    services:
      nginxpulse:
        image: magiccoders/nginxpulse:latest
        container_name: local_nginxpulse
        ports:
          - "8088:8088"
          - "8089:8089"
        volumes:
          - ./docker_local/logs:/share/logs
          - ./docker_local/nginxpulse_data:/app/var/nginxpulse_data
          - ./docker_local/pgdata:/app/var/pgdata
          - ./docker_local/configs:/app/configs
          - /etc/localtime:/etc/localtime
        stop_grace_period: 90s
        restart: unless-stopped
    docker compose up -d

    建议保留 stop_grace_period(如 90s),让内置 PostgreSQL 在 docker compose stop 时有足够时间完成一致性关闭,避免下次启动进入恢复重试。

    时区设置(重要)

    本项目使用系统时区进行日志时间解析与统计,请确保运行环境时区正确。

    Docker / Docker Compose

    • 推荐挂载宿主机时区:-v /etc/localtime:/etc/localtime:ro(Linux)
    • 若宿主机提供 /etc/timezone,可额外挂载:-v /etc/timezone:/etc/timezone:ro
    • 若你只想指定时区,可设置 TZ=Asia/Shanghai,但需保证容器内有时区数据(例如安装 tzdata 或挂载 /usr/share/zoneinfo

    单体部署(单进程)

    • 默认使用当前系统时区
    • 可通过环境变量临时指定:TZ=Asia/Shanghai ./nginxpulse

    移动端访问(/m)

    • 入口地址:http://<host>:8088/m
    • 移动端仅提供 概览 / 日报 / 实时 / 日志 四个页面
    • 首次初始化必须在电脑端完成,移动端会提示在电脑打开

    3) 手动构建(前端、后端)

    前端构建:

    cd webapp
    pnpm install
    pnpm run build

    移动端构建(/m):

    cd webapp_mobile
    pnpm install
    pnpm run build

    后端构建:

    go mod download
    go build -o bin/nginxpulse ./cmd/nginxpulse/main.go

    本地开发(前后端一起跑):

    ./scripts/dev_local.sh

    前端开发服务默认端口 8088,并会将 /api 代理到 http://127.0.0.1:8089。 本地开发前请准备好日志文件,放在 var/log/ 下(或确保 configs/nginxpulse_config.json 的 logPath 指向对应文件)。

    4) 单体部署(单进程)

    重要提示(版本 > 1.5.3):已彻底弃用 SQLite。单体部署必须自备 PostgreSQL 并配置 DB_DSN(或在 configs/nginxpulse_config.json 填好 database.dsn)。
    从仓库的releases下载对应平台的二进制文件,执行即可。

    执行后会生成单体可执行文件(已内置前端静态资源),启动后即可同时提供前后端服务:

    • 前端:http://localhost:8088
    • 后端:http://localhost:8088/api/...

    单体部署的配置方式

    单体运行时读取配置有两种方式(任选其一):

    方式 A:配置文件(默认)

    1. 在运行目录创建 configs/
    2. 放入 configs/nginxpulse_config.json
    3. 启动:./nginxpulse

    方式 B:环境变量注入(无需文件)

    CONFIG_JSON="$(cat /path/to/nginxpulse_config.json)" ./nginxpulse

    注意事项:

    • 配置文件路径为相对路径 ./configs/nginxpulse_config.json,请确保运行时工作目录正确。
    • 如果使用 systemd,请设置 WorkingDirectory,或改用 CONFIG_JSON 注入。
    • 数据目录 ./var/nginxpulse_data 也是相对路径;找不到目录时请先确认当前进程的工作目录。

    5) Makefile 构建

    此项目也支持了通过Makefile来构建相关资源,命令如下:

    make frontend   # 构建前端(含移动端)webapp/dist + webapp_mobile/dist
    make frontend-mobile # 仅构建移动端 webapp_mobile/dist
    make backend    # 构建后端 bin/nginxpulse(不内嵌前端)
    make single     # 构建单体包(内嵌前端 + 复制配置与gzip示例)
    make dev        # 启动本地开发(前端8088,后端8089)
    make clean      # 清理构建产物

    指定版本号示例:

    VERSION=v0.4.8 make single
    VERSION=v0.4.8 make backend

    说明:

    • make single 默认构建 linux/amd64 与 linux/arm64,产物在 bin/linux_amd64/ 与 bin/linux_arm64/
    • 单平台构建时,产物在 bin/nginxpulse,配置在 bin/configs/nginxpulse_config.json(端口默认 :8088),gzip 示例在 bin/var/log/gz-log-read-test/

    Docker 部署权限说明

    镜像默认以非 root 用户(nginxpulse)运行。容器里能否读取日志、写入数据,取决于宿主机目录的权限。你在容器里用 cat 看到日志,通常是因为 docker exec 默认是 root,不代表应用用户有权限。

    推荐做法:让容器内用户的 UID/GID 与宿主机日志/数据目录的属主一致

    步骤 1:查看宿主机目录的 UID/GID

    ls -n /path/to/logs /path/to/nginxpulse_data /path/to/pgdata
    # 或
    stat -c '%u %g %n' /path/to/logs /path/to/nginxpulse_data /path/to/pgdata

    步骤 2:启动容器时传入 PUID/PGID(与上面一致)

    docker run ... \
      -e PUID=1000 \
      -e PGID=1000 \
      -v /path/to/logs:/var/log/nginx:ro \
      -v /path/to/nginxpulse_data:/app/var/nginxpulse_data:rw \
      -v /path/to/pgdata:/app/var/pgdata:rw \
      ...

    步骤 3:确保目录对该 UID/GID 可读/可写

    chown -R 1000:1000 /path/to/nginxpulse_data /path/to/pgdata
    chmod -R u+rx /path/to/logs

    如果你使用外部数据库(设置 DB_DSN),可以不挂载 pgdata。外置 PG 推荐使用 16 版本。 若你通过初始化向导配置外部数据库,同样可以不挂载 pgdata,保存后重启容器生效。

    SELinux 说明(RHEL/CentOS/Fedora 等):

    • 这些系统默认启用 SELinux,Docker 挂载目录可能因安全上下文导致“看得见但不可访问”。
    • 解决办法是在 volume 后加 :z 或 :Z 重新打标签:
      • :Z 让该目录仅供当前容器使用(更严格)。
      • :z 让该目录可被多个容器共享使用。
    docker run ... \
      -v /path/to/logs:/var/log/nginx:ro,Z \
      -v /path/to/nginxpulse_data:/app/var/nginxpulse_data:rw,Z \
      -v /path/to/pgdata:/app/var/pgdata:rw,Z \
      ...

    不推荐做法:直接 chmod -R 777。这虽然省事,但权限过宽不安全,仅建议临时排查时使用。

    常见问题

    1. 日志明细无内容
      通常是容器内无权限访问宿主机日志文件。请先阅读《Docker 部署权限说明》并按步骤处理权限。
    2. 日志存在,但 PV/UV 无法统计
      默认规则会排除内网 IP。若你希望统计内网流量,请将 PV_EXCLUDE_IPS 设为空数组并重启:
    PV_EXCLUDE_IPS='[]'

    重启后在“日志明细”页面点击“重新解析”按钮。

    1. 日志时间不正确
      通常是运行环境时区未同步导致。请确认 Docker/系统时区正确,并按“时区设置(重要)”章节调整后重新解析日志。
    2. 无法启动 报错 tmp 目录无权限写入问题(旧版本可能出现),如果容器启动后出现如下所示的报错,请确认 nginxpulse_data 可写(具体权限问题请阅读《Docker 部署权限说明》),或设置 TMPDIR 到可写目录。
    nginxpulse: initializing postgres data dir at /app/var/pgdata
    /app/entrypoint.sh: line 91: can't create /tmp/tmp.KOdAPn: Permission denied

    解决办法(任选其一):

    -e TMPDIR=/app/var/nginxpulse_data/tmp
    1. 解析入库的数据会一直保留吗
      不会。入库后的访问数据会按 system.logRetentionDays 定时清理(默认 30 天)。
      例如你一次解析了几个月数据,后续仍会逐步清理掉保留天数之外的数据。
      注意:该参数不影响原始 Nginx 日志文件,也不等于系统运行日志(var/nginxpulse_data/nginxpulse.log)的轮转策略。

    目录结构与主要文件

    .
    ├── cmd/
    │   └── nginxpulse/
    │       └── main.go                 # 程序入口
    ├── internal/                       # 核心逻辑(解析、统计、存储、API)
    │   ├── app/
    │   │   └── app.go                  # 初始化、依赖装配、任务调度
    │   ├── analytics/                  # 统计口径与聚合
    │   ├── enrich/
    │   │   ├── ip_geo.go               # IP 归属地(远程+本地)与缓存
    │   │   └── pv_filter.go            # PV 过滤规则
    │   ├── ingest/
    │   │   └── log_parser.go           # 日志扫描、解析与入库
    │   ├── server/
    │   │   └── http.go                 # HTTP 服务与中间件
    │   ├── store/
    │   │   └── repository.go           # PostgreSQL 结构与写入
    │   ├── version/
    │   │   └── info.go                 # 版本信息注入
    │   ├── webui/
    │   │   └── dist/                   # 单体嵌入的前端静态资源
    │   └── web/
    │       └── handler.go              # API 路由
    ├── webapp/
    │   └── src/
    │       └── main.ts                 # 前端入口
    ├── webapp_mobile/                  # 移动端前端(/m)
    │   └── src/
    │       └── main.ts                 # 移动端入口
    ├── configs/
    │   ├── nginxpulse_config.json      # 核心配置入口
    │   ├── nginxpulse_config.dev.json  # 本地开发配置
    │   └── nginx_frontend.conf         # 内置 Nginx 配置
    ├── docs/
    │   └── versioning.md               # 版本管理与发布说明
    ├── scripts/
    │   ├── build_single.sh             # 单体构建脚本
    │   ├── dev_local.sh                # 本地一键启动
    │   └── publish_docker.sh           # 推送 Docker 镜像
    ├── var/                            # 数据目录(运行时生成/挂载)
    │   └── log/
    │       └── gz-log-read-test/       # gzip 参考日志
    ├── Dockerfile
    └── docker-compose.yml
    

    如需更详细的统计口径或 API 扩展,建议从 internal/analytics/ 与 internal/web/handler.go 开始。

  • Kubernetes 到底是什么?

    每个月,Netflix在190+个国家播放数十亿小时的视频。Spotify 运行着数千个微服务,为 6 亿+ 百万用户提供支持。谷歌每天处理超过85亿次搜索。这些系统怎么可能不因自身重量而崩溃?

    答案不是更多服务器。它不是一个神奇的数据库,也不是一种更快的编程语言。这是一种编排系统;一个唯一任务是管理跨成千上万台机器运行的其他软件的软件。

    最受欢迎的是叫 Kubernetes,最初是谷歌内部的一个项目 Borg。


    从 Borg 到 Kubernetes

    2003年,谷歌遇到了一个问题。他们在一系列商品服务器上运行搜索、广告、Gmail,最终还有YouTube。在他们的规模下,手动部署和管理是不可能的。于是他们开发了Borg,一个内部集群管理系统,帮助他们协调一切。

    博格本就不该公开。它在谷歌内部默默运行了十多年,后来他们透露每周发布的集装箱数量高达20亿个。1

    2013年,Docker 使容器对所有人开放。突然间,将应用打包到独立、便携的设备中,不再只是谷歌的专利。但 Docker 只解决了“我如何打包这个应用”的问题,而不是“如何在 500 台机器上运行 10,000 个实例”的问题。

    谷歌看到了这个差距。2014年,他们宣布了Kubernetes(希腊语意为“舵手”或“飞行员”)2,一个基于运行Borg经验教训构建的开源容器编排系统。他们于2015年将其捐赠给新成立的云原生计算基金会,使其实现了云供应商中立。

    几年内,Kubernetes 成为事实上的标准。AWS、Azure和Google Cloud都提供托管Kubernetes服务。生态系统爆发式发展:Helm用于包管理,Prometheus用于监控,Istio用于服务网格。

    展示 Borg 到 Kubernetes 演变的时间线

    谷歌为运行自身基础设施而构建的系统现在对所有人开放。


    为什么选择配器?

    在 Kubernetes 之前,大规模部署软件大致如下:

    1. SSH连接到服务器1
    2. 拉取最新的代码
    3. 安装依赖
    4. 开始申请
    5. 服务器2到N重复此过程
    6. 希望凌晨3点没崩溃

    这是基础设施管理的关键。你一步步告诉每台机器该做什么。它不具备扩展性,容易出错,当东西坏了,你才是被呼叫的人。https://blog-animations.vercel.app/kubernetes/images/declarative-vs-imperative声明式与命令式的比较

    Kubernetes颠覆了这一模式。你没有指定如何部署,而是指定你想要的最终状态:3

    YAML音乐

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-app
    spec:
      replicas: 3

    就这样。“我要3份我的应用在运行。”Kubernetes会帮你解决剩下的;使用哪些机器,如何分配负载,甚至当机器崩溃时该怎么办。

    这就是声明式基础设施。你宣告你想要的状态,系统会不断努力让现实与你的宣言相匹配。https://blog-animations.vercel.app/kubernetes/control-loopKubernetes 控制循环——观察期望状态和实际状态如何对账

    魔法发生在所谓的控制循环中。控制器会持续监控集群的实际状态,将其与你期望的状态(你的YAML)进行比较,并采取措施修复任何潜在的漂移。如果服务器故障并带走了你的两个Pod,控制器会发现并在健康机器上启动替换。没人需要被呼叫。


    构建模块

    让我们先从基础开始。

    集装箱

    在Kubernetes之前,有Docker。Docker 容器是一种轻量级、自包含的软件单元,包含运行所需的一切:代码、运行时、库和依赖。

    可以把它想象成一个字面意义上的集装箱。在标准化集装箱出现之前,装载货物非常混乱;不同尺寸、不同的操作需求、不同的设备。标准化集装箱改变了全球贸易,因为任何船只、火车或卡车都可以处理任何集装箱。

    软件容器也是同样的。但有一个重要的区别:图像是包(蓝图),容器是该图像的运行实例。你只需用应用及其所有依赖构建一个镜像,推送到注册表,然后从该镜像在任何地方运行容器;你的笔记本电脑、测试服务器、生产环境,任何云端都可以。

    # Build a Docker image (the blueprint)
    docker build -t my-app:v1 .
    
    # Run a container from that image
    docker run -p 8080:8080 my-app:v1
    
    # Push the image to a registry
    docker push myregistry/my-app:v1

    舱体

    体是Kubernetes中最小的可部署单位。它是包裹一个或多个共享存储和网络资源的容器的包裹器。4https://blog-animations.vercel.app/kubernetes/images/pod-anatomy舱体解剖图

    大多数舱内只有一个容器。但有时候你需要侧车容器;一个日志代理、一个代理、一个数据同步器。同一Pod中的容器可以在上相互访问并共享挂载的卷(文件系统)。localhost

    把舱体想象成公寓。容器是室友,他们共用厨房和客厅,但各自有自己的卧室。

    YAML音乐

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      containers:
      - name: app
        image: nginx:1.14.2
        ports:
        - containerPort: 80
      # Second container
      - name: sidecar
        image: fluent/fluent-bit

    节点

    节点是一种运行 pod 的机器(物理或虚拟)。每个节点都有一个代理与控制平面通信,确保容器按预期运行。kubelet

    工作节点负责实际工作;运行你的应用容器,而控制平面节点运行 Kubernetes 本身。

    星团

    集群是一组节点(包括工作面和控制面)协同工作的节点。至少,你有:

    • 控制平面:大脑。存储状态,做排班决策,管理控制器。
    • 工节点:肌肉。实际上它能运行你的工作负载。

    https://blog-animations.vercel.app/kubernetes/images/cluster-architecture集群架构图

    当你运行 kubectl 命令时,你是在与控制平面的 API 服务器通信,服务器随后与工作节点协调以实现任务。

    服务(稳定网络)

    舱体是短暂的,或短暂的。他们来来去去。每次创建时都会获得新的IP地址。那么系统的其他部分是如何可靠地与它们通信的呢?

    服务提供稳定的网络端点。5服务位于一组Pod前方,提供一个统一的IP地址和DNS名称。所有流量都会在所有健康舱之间自动负载均衡。

    YAML音乐

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
    spec:
      selector:
        app: my-app
      ports:
      - port: 80
        targetPort: 8080
      # Common Internal-only Service
      type: ClusterIP

    现在,其他服务不再追踪单个Pod的IP,而是直接调用。my-service:80

    部署

    部署实际上是帮你管理舱体。你声明要多少副本(相同的运行舱),运行哪个镜像,剩下的由部署控制器处理。

    部署还会处理滚动更新。当你推送新版本时,Kubernetes会逐步用新Pod替换旧Pod,确保零停机。如果新版本坏了,你只需一个命令就能回滚。https://blog-animations.vercel.app/kubernetes/yaml将鼠标悬停在YAML上,可以看到每个字段生成的内容


    动手体验:你的第一个集群

    我们真的来运行 Kubernetes。Minikube 会在你的本地机器上创建一个单节点集群。

    # Install minikube (macOS)
    # Installation guide: https://minikube.sigs.k8s.io/docs/start/
    brew install minikube
    
    # Start a cluster
    minikube start
    
    # Verify it's running
    kubectl get nodes

    你应该会看到这样的输出:

    文本

    NAME       STATUS   ROLES           AGE   VERSION
    minikube   Ready    control-plane   30s   v1.34.0

    现在让我们部署一些东西:

    # Create a deployment
    kubectl create deployment hello --image=nginx
    
    # Check the pod
    kubectl get pods

    文本

    NAME                     READY   STATUS    RESTARTS   AGE
    hello-5d7b9d8c7f-x2k4j   1/1     Running   0          10s

    放大它:

    # Scale to 3 replicas
    kubectl scale deployment hello --replicas=3
    
    # Watch pods come up
    kubectl get pods -w

    文本

    NAME                     READY   STATUS    RESTARTS   AGE
    hello-5d7b9d8c7f-x2k4j   1/1     Running   0          30s
    hello-5d7b9d8c7f-m8n2p   1/1     Running   0          5s
    hello-5d7b9d8c7f-q9r3s   1/1     Running   0          5s

    将其作为服务曝光:

    # Create a LoadBalancer service
    kubectl expose deployment hello --type=LoadBalancer --port=80
    
    # Get the URL (minikube specific)
    minikube service hello --url

    你现在拥有了一个负载均衡、可扩展的 Kubernetes 网络服务器。在你的笔记本电脑上。

    完成后如何清理:

    # Delete the service and deployment
    kubectl delete service hello
    kubectl delete deployment hello
    
    # Stop the minikube cluster (frees up memory)
    minikube stop
    
    # Or delete the cluster entirely
    minikube delete

    https://blog-animations.vercel.app/kubernetes/cluster互动集群——尝试部署、扩展和杀死小队


    深度潜入

    扩展基础设施才是Kubernetes真正闪耀的地方。有三个维度:

    1. 水平舱自动标配(HPA)

    负载增加时,更多舱体。这是最常见的方法。

    YAML音乐

    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: nginx-hpa
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: nginx-deployment
      minReplicas: 2
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 50

    翻译:

    “保持2到10个舱体。如果平均CPU超过50%,就加装Pods。如果掉到下面,就移除舱体。”

    https://blog-animations.vercel.app/kubernetes/images/hpa-scalingHPA缩放可视化

    HPA控制器默认每15秒检查一次指标。它比较保守,不会立刻缩小以防止暴打。

    2. 垂直舱自动缩放(VPA)

    用更大的舱体而不是更多的舱体。VPA会调整现有Pod的CPU和内存请求/限制。

    这适用于:

    • 无法并行化的单线程应用程序
    • 舱启动成本较高的工作负载
    • 数据库与有状态应用

    YAML音乐

    apiVersion: autoscaling.k8s.io/v1
    kind: VerticalPodAutoscaler
    metadata:
      name: my-vpa
    spec:
      targetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: my-deployment
      updatePolicy:
        updateMode: Auto

    3. 集群自动缩放

    当无法调度舱时,节点会更多。集群自动扩展器会监控卡在状态中的Pod(通常是因为现有节点CPU或内存不足),并自动从你的云服务商配置新节点。Pending

    当负载降低且节点利用不足时,它通过排空和移除节点来缩减规模。它不会移除具有以下条件的节点:

    • 非复制的舱体(如DaemonSets))
    • 带有任何本地存储的Pod
    • 带PodDisruption的Pod防止被淘汰的预算

    以下是配置方式(AWS EKS 示例):

    YAML音乐

    apiVersion: autoscaling.k8s.io/v1
    kind: ClusterAutoscaler
    metadata:
      name: cluster-autoscaler
    spec:
      scaleDown:
        enabled: true
        delayAfterAdd: 10m
        unneededTime: 10m
      resourceLimits:
        minNodes: 2
        maxNodes: 10
        cores:
          min: 4
          max: 100
        memory:
          min: 8
          max: 256

    内容如下:

    “保持2到10个节点之间。缩放后,等待10分钟再考虑缩减。移除那些已经10+分钟未充分利用的节点。”

    实际操作中的情况:

    1. HPA可以从3→10个部署舱扩展到你
    2. 有些小组无法安排时间(资源不足)→Pending
    3. 集群自动缩放器看到后,会新增两个节点
    4. 待处理的 Pod 会被调度到新的节点
    5. 后来流量下降,HPA会缩减舱群规模
    6. 在利用率不足10分钟后,集群自动调整器会移除多余的节点

    这就是扩展故事的全部:

    • HPA:节点内的扩展舱体
    • VPA:按字面尺寸缩放舱体尺寸
    • 集群自动缩放器:调整节点本身
    https://blog-animations.vercel.app/kubernetes/autoscaler模拟交通激增,观看自动扩展的实际应用

    控制平面:引擎盖之下

    是时候看看到底是什么在运行 Kubernetes。https://blog-animations.vercel.app/kubernetes/images/control-plane控制平面组件图

    API服务器

    前门。每一个命令、每一个控制器操作、每一个节点的心跳都经过API服务器。它是唯一直接与 etcd 通信的组件。kubectl

    它暴露了REST API,并处理认证、授权和准入控制。

    etcd

    真相的源头。6etcd 是一个分布式键值存储器,存储所有集群状态:哪些 pod 存在,哪些节点健康,哪些秘密存储,哪些配置地图定义。

    Kubernetes 里的所有东西都存储在 etcd 里。没有备份就丢失etcd,也失去集群状态。

    调度器

    当你创建一个 pod 时,调度器会决定哪个节点运行它。它考虑了:

    • 资源需求(CPU,内存)
    • 节点亲和力/反亲和规则
    • 污染与耐受
    • 当前节点利用情况

    调度器实际上不会启动舱体。它只是通过写入 etcd 来分配节点。该节点上的 kubelet 会接收并完成实际工作。

    财务主管

    这里是控制环路所在的地方。每个控制器监控特定资源类型,并努力将实际状态与期望状态进行协调:

    • 部署控制器:确保存在正确数量的复制集
    • ReplicaSet 控制器:确保存在正确数量的 Pod
    • 节点控制器:监控节点健康状况,驱逐故障节点的舱体
    • 服务控制器:为负载均衡器服务创建云负载均衡器

    库贝莱特

    代理人7在每个工作节点上。它:

    • 从API服务器接收Pod规格
    • 与容器运行时(containerd、CRI-O)配合启动容器
    • 向控制平面报告节点和舱体状态
    • 运行活性和准备探测器

    到底谁会用 Kubernetes?

    这听起来很多,甚至可能对很多事情有点过头了。Kubernetes 不仅仅是解决谷歌规模的问题,更有助于看到谁在大规模运行它。

    • Spotify:4000+微服务,从他们内部的Helios系统迁移过来。它们在区域内运行多个集群,拥有数千个节点。
    • Pinterest:它们集群中共有250,000+个Pods。他们建立了自己的Kubernetes平台团队和工具。
    • Airbnb:从单一的Rails应用转向基于Kubernetes的微服务。他们在所有环境中统一使用 Kubernetes。

    为什么公司选择Kubernetes?

    诉求始于供应商中立性。你可以在任何云端(AWS、GCP、Azure,或你自己的数据中心)上运行完全相同的工作负载。从一个云端开始,如果价格变动或需求变化,可以转到另一个云端。无需重写应用代码,也无需厂商锁定。

    然后是生态系统Helm Charts 用于包管理,Prometheus 用于指标,Istio 用于服务网格,ArgoCD 用于 GitOps 部署。围绕Kubernetes的工具无与伦比,因为大家都基于它进行了标准化。需要解决问题吗?可能已经有一个维护良好的开源工具了。

    但真正的作战胜利是自我修复。舱体坠毁了?Kubernetes 会自动重启它。节点死亡?Pod 会在几秒钟内重新调度到健康节点。部署发生内存泄漏?设定资源限制后,敌人会被击杀并重启,才能击败邻居。这时工程师凌晨3点不会被呼叫。

    最后,一切都是声明性。你的整个运行环境(部署、服务、秘密、配置)都存在于版本控制的YAML中。想看看网站宕机后发生了什么变化吗?想要回滚吗?撤销提交。它是基础设施即代码,但涵盖整个栈,而不仅仅是虚拟机。git diff


    更大的视角

    Kubernetes 不仅仅是一个部署工具。这是我们对基础设施思考方式的范式转变。

    同样的模式支撑着谷歌搜索,运行着Netflix4亿+百万小时的月流媒体播放,以及Spotify的4000个微服务;也对任何学习写YAML并以声明式思维方式进行的人开放。

    从谷歌的博格管理数十亿个容器,到你在笔记本电脑上运行,抽象层面是一样的。基础设施的复杂性隐藏在一个干净的API背后。kubectl

    我们从手动SSH服务器到用代码声明基础设施。这不仅仅是自动化;这是我们对软件运行思维方式的根本转变。

    学习曲线确实存在。YAML内容繁琐。人脉关系会让你至少怀疑一次自己的职业选择。但一旦你真正明白了,你就能使用全球最大公司使用的相同基础设施模式。


    → 凯尔


    注释

    1. 1.格论文于2015年在EuroSys发表。它说谷歌每周推出超过20亿个集装箱。
    2. 2.“Kubernetes”常缩写为“K8s”(发音为“kay-ates”)。这是一种数字词,8代表’K’和’s’之间的八个字母。类似的模式:i18n(国际化)、a11y(无障碍)。
    3. 3.声明式与命令式:在命令式编程中,你要一步步指定如何实现结果。在声明式编程中,你指定想要的结果,让系统自己决定如何实现。SQL 是声明式的(“给我所有年龄> 21 岁的用户”),而对数组进行 for-loop 过滤是必不可少的。
    4. 4.Pod 内部结构:Pod 通过 Linux 内核特性实现:命名空间(用于网络隔离、PID、挂载点)和 cgroups(用于资源限制)。同一Pod中的容器共享网络命名空间(它们可以在localhost上相互访问),并且可以共享卷。
    5. 5.服务类型:Kubernetes 提供多种服务类型:ClusterIP(默认)将服务暴露在仅能在集群内部访问的内部 IP。NodePort 在每个节点的静态端口(30000-32767)上暴露 IP。LoadBalancer 提供外部负载均衡器(云服务提供商专用)。ExternalName 映射到 DNS 名称。服务使用标签选择器来确定哪些Pod接收到流量。
    6. 6.etcd:一种分布式键值存储,使用Raft共识算法在多个节点间保持一致性。它存储所有集群状态:Pod 规格、秘密、配置文件地图、服务账户。名称来源于 Unix 的“/etc”目录(用于配置)+ “d”(分布式)。
    7. 7.资源限制与OOMKilled:没有资源限制,单个Pod可以消耗节点上的所有CPU/内存,导致其他Pod陷入饥饿。Kubernetes 使用请求(保证最低请求)和限制(硬上限)。如果容器超过其内存限制,内核的 OOM(内存外)杀手会终止该容器;你会看到“OOMKilled”显示在舱内状态。CPU的限制机制不同:容器被限速,而不是被杀死。
  • 世界,您好!

    欢迎使用 WordPress。这是您的第一篇文章。编辑或删除它,然后开始写作吧!