使用 Netmaker 快速组建 WireGuard mesh 网络

前段时间在逛 LET 看到有人发帖询问在 VPS 上安装了什么,论坛中的 @Galeej 提到,自己将所有的 VPS 通过 Tailscale 私有网络连接,对其他 VPS 的操作都通过一台新加坡的 relay 服务器转发(并且设置其他 VPS 的网络连接只允许特定的 IP),而所有需要暴露到公开互联网上的端口都隐藏在 Cloudflare 之后,我看到这样的配置之后发现这样的 VPS 配置非常的安全,公开互联网上没有暴露任何可以攻击的端口,所有的服务都在 WireGuard 内网中。

然后在之后的讨论中 @Ouji 又提出,他将用 Netmaker 来替换 Tailscale,然后我就调研了一下 Netmaker 发现这是 Tailscale 的开源版本,不仅提供了非常友好的配置管理界面,还能够提供自定的网络段(我使用 Tailscale 不舒服的一点就是分配的内网 IP 都是随机的)。所以下面就简单的介绍一下 Netmaker 的使用,并简单的演示一下创建一个点对点 mesh 网络。

什么是 Netmaker

Netmaker 是一个开源的、基于 [[WireGuard]] 的网络(overlay network) 控制工具,可以非常快速的用来组建 WireGuard 网络。

如果你有两台连接互联网的设备,那么 Netmaker 可以组建一个安全的网络,并打通一个安全的隧道提供给两台机器通信。而如果你有数千台机器分布在不同的地区,不同的数据中心,不同的网络中,那么 Netmaker 也可以组建一个网络来提供给这些不同的节点通信。

如果熟悉 AWS,那么 Netmaker 就像 VPC 一样,不过 Netmaker 可以应用在任意的机器中。从 Netmaker 网络中的机器来看,同一个网络中的机器尽管在世界各地,但其相互通信就像是在同一个局域网中一样。

Netmaker 和其他一些产品非常相似,比如 [[Tailscale]], [[ZeroTier]],[[Nebula]] 但不同于这些产品的是,Netmaker 连接更快,更加灵活。Netmaker 使用 [[WireGuard]] 所以更快,Netmaker 中的节点不管是服务端还是Agent都完全可配置,所以提供了更大的灵活性。

Netmaker 优于 [[Tailscale]] 的地方还在于 ,Netmaker 不需要 Google, Microsoft 或者 GitHub 账号。Netmaker 可以认为是一个可以自行托管的 Tailscale。

Netmaker 工作原理

Netmaker 依赖于 WireGuard 来在机器间创建隧道(tunnel), Netmaker 通过管理不同机器的 WireGuard 来创建网络。简单来说,Netmaker 实现 Client/Server 架构:

  • the admin server 管理端,称为 Netmaker,管理网络的界面
  • the agent,客户端,称为 Netclient,客户端通过 gRPC 与服务端通信

作为 Network 管理端,你可以通过管理端来创建网络,管理连接的设备。服务端会保存所有网络和设备的配置信息,这些信息会被 netclient (agent) 来获取使用。

客户端(netclient) 是一个二进制文件,netclient 会在节点被添加到网络中的时候安装到不同的机器中,netclient 可以在大多数系统中运行,不管是虚拟机,物理机,或者 IoT 设备都可以运行 netclient。netclient 会连接服务端,通过服务端的配置来自动管理 WireGuard,动态更新 Peers。通过不断向网络中添加节点的方式,可以创建一个动态的,完全可以配置的虚拟网络。

Netmaker server 不会路由网络流量,否则这个网络就变成了一个中心辐射模型(hub-and-spoke model),这会使得中心服务器变成瓶颈,并且拖慢网络。相反,Network 会告诉网络中的节点他们之间可以相互直接通信,这被称为 full mesh network(网状网络),这会让节点和节点的连接更快。即使管理端宕机,只要现存的节点没有变化,那么这个网络依然可以正常工作。

应用场景 Use Cases

Netmaker 有非常多的应用场景,事实上,现在可能就已经在使用了。

用例:

  • 自动创建 WireGuard mesh network
  • 在云环境和数据中心之间创建 flat, secure 网络
  • 给 IoT 设备提供更安全的网络访问
  • 增强家庭,或办公网络的安全性
  • 在现存网络上增加一层加密
  • 安全的 site-to-site 连接
  • 管理 cryptocurrency proof-of-stake 机器
  • 创建动态的安全的 Kubernetes underlay network

更多的用例也可以参考官网

架构

Netmaker 的架构图:

概念

熟悉一下 Netmaker 中常常被提到的概念,有助于理解。

WireGuard

[[WireGuard]] 相对比较新,但非常强大,WireGuard 被加入到了 Linux kernel。WireGuard 可以非常简单快速地在设备之间创建加密通道。从 WireGuard 官网的介绍中可以看到,“WireGuard 可以被认为是工业界最安全,最方便使用,最简单的 VPN 解决方案”。

之前的解决方案,比如 OpenVPN,或者 IPSec 都被认为又重又复杂,并且性能也不是很好。所有现存的 VPN tunneling 方案都会导致网络延迟增大。WireGuard 是第一个实现了几乎接近有线连接网络速度的 VPN,可以看到 WireGuard 对现有网络连接几乎没有影响。随着 WireGuard 的发布,没有任何理由去使用其他隧道加密技术了。

Mesh Network

当提到 mesh network (网状网络)的时候通常也会说 「full mesh」。一个 full mesh network 指的是网络中的任何节点都可以相互直接连接。

比如在路由器后面的家庭网络,所有的电脑都会通过私有局域网地址相互连接。

Mesh network 通常会和 hub-and-spoke (中心辐射) 网络放到一起对比,中心辐射的网络中,一个节点必须通过 relay server 才能和另外一个节点进行通信。

在一些场景中,你可以需要部分的 mesh network,网络中只有部分设备需要相互直接通信,而其他设备都需要将流量转发给一个 relay/gateway 。Netmaker 在某些时候也可以实现这类模型。在第一张图片中,这个设置就是一个部分的 mesh network,因为节点A-D 是网状网络,而其他的客户端通过 gateway 连接。

Mesh networks 通常比其他拓扑的网络更快,但通常设置也会更加复杂。WireGuard 提供了在设备之间创建加密隧道的方法,但是它不提供设置完整网络的方法。这是 Netmaker 诞生的理由。

Netmaker

Netmaker 是一个建立在 WireGuard 上的平台,允许用户在设备之间构建 mesh networks。Netmaker 可以根据需要创建完全的、或部分的 mesh network。

当我们提及 Netmaker 整体的时候,通常指的是 Netmaker 以及 netclient, 以及其他辅助的服务,比如 CoreDNS,rqlite 和 UI 服务。

从终端用户来看,通常会和 Netmaker UI 交互,或会直接在终端节点中直接运行脚本。而其他部分都会在后台默默地执行。

Netmaker 做了非常多的配置相关的工作,简化了用户的配置。包括了 WireGuard 的端口,endpoints( 终端) , public IPs(公网IP),keys(密钥) 和 peers(节点)。Netmaker 尽可能多地抽象了网络管理,只需简单的在界面点击创建网络,然后点击将计算机添加到网络。也就是说,每一个机器都是不同的,可能需要不同的配置。这就是为什么,Netmaker 使用一套默认设置,则网格内的所有内容都是完全可配置的。

SystemD

SystemD 是一个被 Linux 广泛使用的系统服务器管理器。尽管没有被所有发行版采用,但是不管如何,它已经成为了 Linux 世界的事实标准。非 Linux 可能没有 systemd,而 Linux/Unix 发行版有可代替的 system service managers。

Netmaker 的 netclient (客户端) 会控制节点上的网络,可以通过命令行运行,或者通过作为 system 守护进程(daemon),在 Linux 上会默认以 daemon 运行(依赖于 systemd)。

从 0.8 版本开始,支持了 macOS 和 Windows,在这些操作系统中,netclient 使用 LaunchD 来启动 netclient 守护进程。

Ingress Gateways

在 Netmaker 网络中的任何节点都可以成为 Ingress Gateway,Ingress Gateway 可以接受 Netmaker(WireGuard)网络外部的流量。

Egress Gateways

Egress Gateway 出口网关,允许将内部网络流量转发到外部指定 IP。

Netmaker 安装

硬件要求

服务器:

  • 一台可用的 VPS(最好比较干净,没有占用端口,否则需要根据自己的需要自行调整),不推荐 Oracle Cloud 的机器,网络接口有问题
  • 公开的 IP 地址
  • 至少 1GB RAM,1CPU(4GB RAM,2 CPU 生产环境)
  • 2GB+ 存储
  • Ubuntu 20.04

软件要求

域名:

  • 一个可用的域名(可选)
  • 可以操作管理 DNS 服务(53端口)
  • 保证 443(tcp), 53(tcp udp), 51821-518XX(udp) 端口可用
    • 443 端口,Dashboard,REST API 和 gRPC
    • 53 端口,CoreDNS
    • 51821-518XX,WireGuard,每一个网络需要一个端口,起始端口会使用 51821,可以根据自己的网络端数量需要设定端口范围
    • 允许防火墙 sudo ufw allow proto tcp from any to any port 443 && sudo ufw allow 53/udp && sudo ufw allow 53/tcp && sudo ufw allow 51821:51830/udp

一键安装

如果想使用自己的域名,比如 dashboard.netmaker.example.com 这样,可以参考官网。这里为了演示方便,就使用一键脚本。

Netmaker 官方已经提供了一个 Docker 镜像,并且也提供了安装脚本:

sudo wget -qO - https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/nm-quick.sh | bash

如果没有使用自己的域名,一键脚本会使用一个 nip.io 的泛域名解析映射工具根据 IP 自动获取一个域名,用来访问后台地址。

首次登录后台会要求设定用户名和密码。登录后台之后,左侧的 Networks、 Nodes、 Access Keys 是比较重要的菜单。

在 Network 选项中选择创建 Network,设定 IP 段范围,然后在其他机器上依次安装客户端,添加节点到网络中即可。

在添加到之后网络之后,可以运行 sudo wg show 查看信息:

❯ sudo wg show
interface: nm-k3s
  public key: PGeGQKOlJt4zZJX2axf15dRsWvs6QaFRF/j/fJUfnjw=
  private key: (hidden)
  listening port: 51821

peer: Cjbp/IeTEFgPEJpOldjkaleUvlNjqg+y75hiI/Sq61Q=
  endpoint: 140.XXX.XXX.XXX:51821
  allowed ips: 10.10.11.8/32
  latest handshake: 2 seconds ago
  transfer: 6.74 KiB received, 1.88 KiB sent
  persistent keepalive: every 20 seconds

通常会看到 interface 和 peer 信息。

手动安装

如果需要手动安装,也不是特别麻烦,从官网下载 docker-compose.yml 文件:

wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.contained.yml
sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' docker-compose.yml
sed -i 's/SERVER_PUBLIC_IP/<your server ip>/g' docker-compose.yml
sed -i 's/COREDNS_IP/<default interface ip>/g' docker-compose.yml

生成唯一的 master key:

tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo ''
sed -i 's/REPLACE_MASTER_KEY/<your generated key>/g' docker-compose.yml

配置 Caddy

wget -O /root/Caddyfile https://raw.githubusercontent.com/gravitl/netmaker/master/docker/Caddyfile

sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' /root/Caddyfile
sed -i 's/YOUR_EMAIL/<your email>/g' /root/Caddyfile

然后启动:

sudo docker-compose up -d

然后可以访问 dashboard.nm.example.com 后台。

需要注意的是,如果使用自己的域名需要添加一个泛域名 A 记录(wildcard A record),比如想要后台访问地址是 dashboard.nm.example.com 那么需要添加 *.nm.example.com

Caddy 会创建三个子域名:

  • dashboard.nm.example.com
  • api.nm.example.com
  • grpc.nm.example.com

netclient 使用

netclient 是一个简单的 CLI,用于创建 WireGuard 配置和接口。netclient 可以管理任意私有网络。

macOS 安装

首先安装依赖:

brew install wireguard-tools

外延

Nebula 是另外一个选择,同样基于 WireGuard。

更多资料可以查看 Gravitl 官网:https://gravitl.com/resources

reference


2021-12-10 netmaker , wireguard , mesh-network , linux , vpn , network , tunnel , secure

每天学习一个命令:mysqlbinlog 命令使用

MySQL 或 MariaDB 中,对数据库做的任何操作都会被记录到 Binary Log 日志文件中。

二进制日志文件在主从复制中非常重要。恢复 MySQL 时也会使用到二进制日志文件。

但是 Binary Log 而二进制文件,所以无法直接使用文本查看工具打开看,所以 MySQL 提供了 mysqlbinlog 命令。

mysqlbinlog 命令是一个以友好可读方式查看 MySQL Binary log 的命令行工具。也可以使用 mysqlbinlog 命令来读取内容并用管道传给其他 MySQL 工具集。

MySQL 的 binary log 文件包含了对数据库文件操作的事件。MySQL 服务器会以二进制文件写入。

举例

获取二进制文件列表

在 MySQL 中执行:

mysql> SHOW BINARY LOGS;

如果没有开启二进制文件,则会报错 ERROR 1381 (HY000): You are not using binary logging

二进制日志文件默认会存放在 /var/lib/mysql 目录下

使用 mysqlbinlog 命令

使用:

mysqlbinlog log_file

mysqlbinlog 常用的参数有:

  • -d, --database=db_name 指定数据库
  • -o, --offset=n 忽略日志前 n 行
  • -v, -vv-v 从 binlog 中重建 SQL 语句,-vv 增加了注释
  • --start-datetime=datatime, --stop-datetime=datetime 指定日期间隔内的所有日志
  • --start-position=position, --stop-position=position 指定位置间隔内的所有日志

常用方法

通过 binlog 查看 delete 语句的执行:

mysqlbinlog /data/mysql_data/bin.000008 --database EpointFrame --base64-output=decode-rows -vv --skip-gtids=true |grep -C 1 -i "delete from Audit_Orga_Specialtype" > /opt/sql.log

说明:

  • /data/mysql_data/bin.000008:需要解析的 binlog 日志。
  • database:只列出该数据库下的行数据,但无法过滤 Rows_query_event。
  • base64-output=decode-rows -vv:显示具体 SQL 语句。
  • skip-gtids=true:忽略 GTID 显示。
  • grep -C 1 -i "delete from dataex_trigger_record":通过管道命令筛选出所需 SQL 及执行时间。
  • /opt/sql.log:将结果导入到日志文件,方便查看。

限定时间范围

设定范围

mysqlbinlog --start-datetime='2021-12-06 12:00:00' --stop-datetime='2021-12-06 16:00:00' mysql-bin.0043* |grep 'admin_user' -B 6 A6

设定位置

mysqlbinlog --start-position=120 --stop-position=330 /path/to/binlog.00001

查看特定数据的 log

可以使用 -d 参数来指定特定数据库上的日志:

mysqlbinlog -d gogs mysqld-bin.000001
mysqlbinlog --database gogs mysqld-bin.000001

reference


2021-12-07 mysql , mysqlbinlog , linux , database , cli , binary-log

OmniEdge 虚拟组网工具使用及原理简介

[[OmniEdge]] 是一个可以用来快速组建点对点私有网络的工具,也可以用来做内网穿透。

官方提供 Starter 套餐,可以供一个用户,最多创建 1 个虚拟网络,连接 20台设备。

2023 年更新

OmniEdge 已经停止运营。

安装

一键安装脚本:

curl https://omniedge.io/install/omniedge-install.sh | bash

Linux

curl https://omniedge.io/install/omniedge-install.sh | bash
omniedge login -u yourname@youremail.com
omniedge login -s yoursecuritykey
omniedge join -n 'virtual-network-id'

Run OmniEdge as a Service

在用 CLI 登录 OmniEdge 之后,推荐在后台运行。

创建 service:

vi /etc/systemd/system/omniedge.service

填入信息:

#/etc/systemd/system/omniedge.service
[Unit]
Description=omniedge process
After=network-online.target syslog.target nfw.target
Wants=network-online.target

[Service]
Type=simple
ExecStartPre=
#Replace to your real virtual network id(can be found by run omniedge join) and auth.json path
ExecStart=/usr/local/bin/omniedge join -n "your_virtual_network_id" -f your_auth_file_path
Restart=on-abnormal
RestartSec=5

[Install]
WantedBy=multi-user.target
Alias=

上面的配置中有两个地方需要修改一下:

  • 一个是网络ID,可以通过命令 omniedge join 获取,或者直接在管理后台获取
  • 一个是 auth.json 在登录成功之后会在 /root/.omniedge/auth.json 目录中

激活服务:

systemctl daemon-reload
systemctl enable omniedge.service
systemctl enable omniedge.service

为什么不使用 WireGuard

[[WireGuard]] 作为一个现代的 VPN 解决方案,简单,快速,并且易于维护,OmniEdge 官方的博客 也说过曾经尝试过使用 WireGuard,但是 WireGuard 存在的一个问题是,当构建一个具有庞大数量节点的网络的时候,管理和维护成本会成倍增加。

为什么不选择 n2n

[[n2n]] 1 是一个轻量、开源的用来组件点对点网络的工具,n2n 让 Super Node 处理节点的管理工作,这也就意味着这些节点可能需要处理大量流量,并且可能影响网络的性能。这使得 n2n 不适合构建一个完善的稳定的企业网络。

架构

OmniEdge 为了解决上面的问题,指定了一些基本的原则:

  • 足够简单,对于用户和网络管理都要足够简单
  • 基于 Zero-trust security model,用户可以通过类似于 Okta, G Suite 等等的验证工具来组件安全的网络
  • 使用 Peer-to-peer 网络通信,提升网络速度,避免单点故障

基于上面的设计目标,收到 n2n 架构的影响,设计了如下的 OmniEdge 架构。

Super Node: 用来协调虚拟网络节点和节点之间的通信

  • 协调节点和节点之间的网络通信
  • 舱室在节点和节点之间建立直接连接;如果不行,则作为节点和节点通信的 relay 节点

Node: 虚拟网络中的具体的节点

  • 保存、管理虚拟网络的信息,比如 keys, network node public keys 等等
  • 在虚拟网络上直接或间接转发 TCP 和 UDP 流量
  • 提供本地的 DNS 解析

Manager: 管理虚拟网络

  • 管理网络节点数据,包括设备ID,公钥,IP 数据,网关,路由表等等其他信息
  • 验证节点,返回网络信息给节点
  • 管理网络的改变,比如节点加入,节点删除
  • 管理节点的生命周期
  • 和用户验证服务交互,管理 ACL 信息

Client: 这是用户用来管理虚拟网络的工具

  • 和节点通信,配置管理节点
  • 处理用户注册,登录流程

利用 supernode 加速

前两天看到 omniedge GitHub 发布了 supernode ,可以用来加速虚拟网络的网络状况。

有兴趣可以自行编译 Docker 镜像:

需要注意的是如果要使用 Sueprnode 必须使用 Pro 或者 Team 套餐。

reference


2021-11-29 omniedge , tailscale , network , private-network , n2n , mesh-network

Linux 下 journal 日志清理

Linux 在运行的过程中会产生很多日志文件,一般存放在 /var/log 目录下,而其中 journal 目录中存放的是 journald daemon 程序生成的日志,其中包括了所有 kernel, initrd, services 等等产生的日志。这些日志在系统发生状况排查问题的时候非常有用。

jounrnald daemon 程序会收集系统运行的日志并存储到二进制文件中。为了查看这些二进制文件通常会使用到 journalctl 命令。但是默认情况下这些日志文件会占用磁盘空间的 10%,而大部分情况下这些日志文件是不需要查看的。所以可以配置减小一些 journal 日志的占用。

默认的日志文件保存在 /var/log/journal 下,可以使用 du 查看。不过我个人推荐使用可视化的 gdu查看

  • du -sh /var/log/journal 查看占用磁盘空间

查看 journal 日志占用大小

可以使用 journalctl 命令查看日志占用:

sudo journalctl --disk-usage

手动清理 journal 日志

如果要去清理 journal 日志,可以先执行 rotate 命令:

journalctl --rotate && \
systemctl restart systemd-journald

删除两天前的日志:

journalctl --vacuum-time=2days

删除两个礼拜前的日志:

journalctl --vacuum-time=2weeks

或者删除超出文件大小的日志:

journalctl --vacuum-size=20M
journalctl --disk-usage
# OR
du -sh /run/log/journal
journalctl --verify
ls -l /run/log/journal/*
systemctl status systemd-journald

修改配置文件限制 journal 日志最大占用

修改配置文件:

sudo vi /etc/systemd/journald.conf

修改其中的两项:

SystemMaxUse=100M
RuntimeMaxUse=100M

SystemMaxUse 设置 /var/log/journal RuntimeMaxUse 设置 /run/log/journal

然后使设置生效:

sudo systemctl daemon-reload

journal 日志过大可能产生的问题

问题

Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.

原因是:

the disk usage of the log files for journald journal 日志空间达到了上限


2021-11-29 linux , journal , systemd , journalctl , gdu , du

Proxmox VE 备份和恢复虚拟机

数据是最重要的,本着系统可以挂,但是数据不能丢的原则,这里就整理一下在 Proxmox VE 系统中,直接备份虚拟机,和恢复虚拟机的过程。

为什么需要备份

  • 保证数据的安全性
  • 硬件故障
  • 服务器升级或迁移
  • 恶意软件破坏了系统

准备工作

设置备份存储

设置 Storage,允许保存 VZDump backup 文件:

  • 转到 Datacenter > Storage。
  • 选择备份存储位置。
  • 单击编辑选项卡。
  • 确保有一个 Storage 已经选择了 Content 下的 VZDump backup file
  • 单击确定。

在执行备份之前,需要通过上面的设置设定一个允许备份的 Storage,然后之后的备份文件会存放到该 Storage 中。备份文件以文件形式存储。在大部分的情况下,可以使用 NFS 服务器作为存储备份。

Backup Modes

Proxmox VE 备份服务提供了三种不同的备份模式,在备份菜单中可以看到:

  • stop mode,这个模式以短暂停止 VM 的代价提供了高一致性备份。这个模式会先关闭 VM,然后在后台执行 Qemu 进程来备份 VM 数据,一旦备份开始,如果之前 VM 在运行会继续 VM 的运行状态
  • suspend mode,因兼容原因提供,在调用 snapshot mode 之前 suspend VM,因为 suspend VM 会导致较长时间的停机时间,所以建议使用 snapshot mode
  • snapshot mode,不需要很长的停机时间,代价为可能的一小部分数据不一致,执行 Proxmox VE Live backup,当 VM 在运行的时候拷贝 data blocks

Back File Compression

对于备份的文件,Proxmox VE 提供了多种压缩算法,lzo, gzip, zstd

目前来说,Zstandard(zstd) 是三种算法中最快的,多线程也是 zstd 优于 lzo 和 gzip 的地方。但 lzo 和 gzip 通常来说更加常用。可以安装 pigz 来无缝替换 gzip 以提供更好的性能。

使用了不同的压缩算法的备份文件的扩展名如下:

file extension algorithms
.zst Zstandard(zstd) compression
.gz or .tgz gzip compression
.lzo .zo compression

Backup

备份可以通过 GUI 或者 命令行工具来进行。

备份虚拟机

首先关闭虚拟机

CLI

通过命令行备份:

cd /var/lib/vz/dump
vzdump 101

说明:

  • 以上的命令会在 /var/lib/vz/dump 目录中备份 101 号虚拟机

GUI

通过 UI 界面备份数据:

  • 数据中心> Backup。
  • 转到 添加>创建备份作业。
  • 选择详细信息,例如节点,目标存储,星期几,时间等。
  • 确保备份作业已启用。

备份时跳过特定的目录

在备份虚拟机时有些时候不想要备份虚拟机中的特定目录,比如说缓存目录,这样可以加快备份的速度,以及减小备份文件的体积。

在 Datacenter -> Backup 中建立备份任务之后,会在系统中新建一个 cron,在 /etc/pve/vzdump.cron 文件中:

PATH="/usr/sbin:/usr/bin:/sbin:/bin"

15 2 * * 6           root vzdump 100 101 102 --mailnotification always --compress zstd --mode snapshot --quiet 1 --storage local --exclude-path /mnt/ --exclude-path '/dev/disk/by-id/ata-HGST*'

可以看到,实际使用了 vzdump 命令,直接在后面添加 --exclude-path 并加上不需要备份的目录即可。

更多的用法可以参考 vzdump 命令的使用。

备份时跳过 Disk

配置了备份之后查看日志可以看到:

INFO: Backup started at 2021-10-23 16:59:05
INFO: status = running
INFO: VM Name: ubuntu20.04
INFO: include disk 'scsi0' 'local:101/vm-101-disk-0.qcow2' 64G
INFO: include disk 'scsi1' '/dev/disk/by-id/ata-HGST_HUS726020ALA610_K5HWJ6NG' 1953514584K
INFO: include disk 'scsi2' '/dev/disk/by-id/ata-HGST_HUS726020ALA610_K5J0ZUWA' 1953514584K
INFO: include disk 'scsi3' '/dev/disk/by-id/ata-HGST_HUS726020ALA610_K5HW9RJG' 1953514584K
INFO: backup mode: snapshot
INFO: ionice priority: 7
INFO: creating vzdump archive '/var/lib/vz/dump/vzdump-qemu-101-2021_10_23-16_59_05.vma.zst'

我的虚拟机挂载了三块硬盘,而备份的时候会包括这三块 2T 的硬盘,这是没有必要的,可以通过如下的方法跳过备份挂载而硬盘。

在虚拟机的设置中,点击 Hard Disk,在 Advance 高级选项中可以将 Backup 取消选中,然后保存,在备份的时候就不会保存该设备了。

proxmox ve hard disk backup

定时清理过期的备份

随着虚拟机备份文件的增多,可以占用的本地文件会越来越多,所以定时清理必不可少。

在界面上设置

在 Datacenter -> Storage 在备份的 Storage 中双击进行设置,在 Backup Retention 中可以去掉勾选 Keep all backups 然后进行设置。

proxmox ve backup retention

执行命令

crontab -e 然后编辑:

10 2 * * * find /var/lib/vz/dump/ -mtime +14 -delete

Restore

我们使用 qmrestore 命令从备份中还原 KVM VM 101。

pct restore 600 /mnt/backup/vzdump-lxc-777.tar
qmrestore vzdump-qemu-019-2018_10_14-15_13_31.vma 101

要从GUI还原VM,请执行以下步骤。

  • 浏览到要移动的VM。
  • 单击 Backup。
  • 选择生成的备份文件,然后单击“还原”。
  • 在 Restore 字段中,指定还原虚拟机的位置。
  • 单击 restore 。

reference


2021-11-25 proxmox , pve , vm , backup , data-backup

Linux 虚拟化技术 OpenVZ KVM LXC 对比

介绍一下 Linux 下常见的虚拟化技术。

  • OpenVZ
  • KVM
  • LXC
  • Xen

OpenVZ

OpenVZ 是一种基于 Linux 内核的虚拟化技术,它允许在单个物理服务器上运行多个独立的 Linux 系统实例,每个实例都可以拥有自己的 IP 地址、文件系统、进程等。OpenVZ 使用容器技术实现虚拟化,相比于传统的虚拟机技术,它的性能更高、开销更小,因为它不需要模拟硬件,而是直接利用宿主机的资源。OpenVZ 还提供了一些管理工具,如 vzctl 和 vzlist,方便用户管理和监控容器。

OpenVZ(通常简写成 [[OVZ]]) 只能虚拟化 Linux 操作系统,但是 KVM 可以虚拟化 Linux,Windows,和其他操作系统。

OpenVZ 使用共享的 kernel,所有虚拟化 VPS 中的用户都使用同一个 kernel,因此 kernel 是不可自定义的。

一旦你使用的 RAM 达到了 host 分配的额度,那么剩下的 RAM 就是自由竞争的。如果你运行一些小型程序可能不是问题,但是一定你运行资源密集型程序就可能产生问题。

KVM

KVM 是 Kernel-based Virtual Machine 的缩写,是一个基于内核的虚拟化技术。借助 KVM 可以将 Linux 主机隔离成多个可以独立运行的虚拟环境,即虚拟机。

KVM 允许在单个物理服务器上运行多个独立的虚拟机,每个虚拟机都可以运行不同的操作系统。KVM 使用硬件辅助虚拟化技术,即 Intel VT 或 AMD-V,来提高虚拟机的性能和安全性。KVM 还提供了一些管理工具,如 virt-manager 和 virsh,方便用户管理和监控虚拟机。由于 KVM 是一种完全虚拟化技术,因此它可以运行几乎所有的操作系统,包括 Windows 和其他非 Linux 操作系统。

KVM 是 Linux 的一部分,Linux 2.6.20 版本及之后的版本包含了 KVM。KVM 在 2006 年首次公布,并且之后持续在更新和维护。

与 VMwareESX/ESXi、微软 Hyper-V 和 Xen 等虚拟化产品不同,KVM 的思想是在 Linux 内核的基础上添加虚拟机管理模块,重用 Linux 内核中已经完善的进程调度、内存管理、IO 管理等代码,使之成为一个可以支持运行虚拟机的 Hypervisor。因此,KVM 并不是一个完整的模拟器,而只是一个提供了虚拟化功能的内核插件,具体的模拟器工作需要借助 QEMU 来完成。

KVM 允许你设置使用资源的最小和最大值,这样虚拟化的系统就只能使用这些资源。并且在 KVM 下,RAM,CPU 和硬盘资源都是直接分配给用户,用户可以完全使用这些资源,而不用担心其他虚拟化机器的竞争。

KVM 提供了一个隔离的环境,用户可以自行替换 kernel。

QEMU

KVM 不是一个完整的虚拟机,而是借助 QEMU 来完成虚拟化过程。KVM 是 Linux kernel 的一个模块,通过命令 modprobe 去加载 KVM 模块。加载模块之后,才能通过其他工具创建虚拟机。仅有 KVM 模块不行,用户还需要开源的虚拟化软件 QEMU。

LXC

LXC,一般指 Linux Container,即内核容器技术的简称。LXC 将 Linux 进程沙盒化,使得进程之间相互隔离,并且能够控制各进程的资源分配。

LXC(Linux Containers)是一种基于 Linux 内核的容器化技术,它允许在单个物理服务器上运行多个独立的 Linux 系统实例,每个实例都可以拥有自己的文件系统、进程等,但它们共享宿主机的内核。LXC 使用轻量级的虚拟化技术,相比于传统的虚拟机技术,它的性能更高、开销更小,因为它不需要模拟硬件,而是直接利用宿主机的资源。LXC 还提供了一些管理工具,如 lxc-start 和 lxc-stop,方便用户管理和监控容器。LXC 可以用于构建轻量级的虚拟化环境,比如用于开发、测试、部署等场景。

Linux 容器项目(LXC)提供了一组工具、模板、库和语言绑定。LXC 采用简单的命令行界面,可改善容器启动时的用户体验。

LXC 提供了一个操作系统级的虚拟化环境,可在许多基于 Linux 的系统上安装。在 Linux 发行版中,可能会通过其软件包存储库来提供 LXC。

在 Linux 内核中,提供了 cgroups 功能,来达成资源的区隔化。它同时也提供了名称空间区隔化的功能,使应用程序看到的操作系统环境被区隔成独立区间,包括进程树,网络,用户 id,以及挂载的文件系统。但是 cgroups 并不一定需要引导任何虚拟机。

LXC 利用 cgroups 与名称空间的功能,提供应用软件一个独立的操作系统环境。LXC 不需要 Hypervisor 这个软件层,软件容器(Container)本身极为轻量化,提升了创建虚拟机的速度。软件 Docker 被用来管理 LXC 的环境。

Xen

Xen 最初是剑桥大学 Xensource 的开源项目,2003 年发布首个版本,2007 年 Xensource 被 Citrix 公司收购,开源 Xen 由 xen.org 继续维护。

Xen 是一种基于虚拟机监控器(Hypervisor)的虚拟化技术,它可以在一台物理服务器上运行多个独立的虚拟机,每个虚拟机都可以运行不同的操作系统。Xen 使用硬件辅助虚拟化技术,即 Intel VT 或 AMD-V,来提高虚拟机的性能和安全性。Xen 的虚拟机监控器可以直接访问物理硬件,而虚拟机则运行在虚拟化的环境中,因此可以获得接近于原生系统的性能。Xen 还提供了一些管理工具,如 xm 和 xl,方便用户管理和监控虚拟机。Xen 可以用于构建高性能、高可用性的虚拟化环境,比如用于云计算、虚拟桌面、数据库等场景。

我所购买的 servaRICA 就是 Xen 的虚拟化计数。

Xen 是运行在裸机上的虚拟化管理程序(HyperVisor)。

Xen 会在 Guest VM 边上运行着管理端 VM,Xen 称这个 VM 为 Dom0,虚拟机操作系统叫做 DomU。这个管理 VM 会负责管理整个硬件平台的所有输入输出设备,半虚拟化中 Hypervisor 不对 IO 设备做模拟,只对 CPU 和内存做模拟。

半虚拟化还有一个叫法:操作系统辅助虚拟化(OS Assisted Virtualization),这是因为 Guest VM 自身不带设备驱动,需要向“管理 VM”寻求帮助。这种虚拟化技术允许虚拟化操作系统感知到自己运行在 XEN HyperVisor 上而不是直接运行在硬件上,同时也可以识别出其他运行在相同环境中的虚拟机。


2021-11-18 linux , linux-virtualization , ovz , kvm , lxc

使用 Ansible Roles 结构化并复用 playbook

之前简单的了解过一下 Ansible,但没怎么具体使用起来,这两天因为要管理的机器多了起来,所以又把 Ansible 学了起来。这篇文章就主要了解一下 Ansible Roles 的使用。

之前的文章简单的知道在 Ansible 中可以使用 playbook 来组织一系列的任务。但如果要复用这些任务,并且更加模块化的花,那就离不开 Ansible Roles。

Role 用来解决的问题

之前的文章中也说过可以使用 playbook 来管理一系列的任务,但随着使用 playbook 就不可以免的膨胀,可能会出现上百行的 playbook,那为了复用和结构化地组织 playbook, Ansible 在 1.2 版本引入了 Roles 的概念。

  • 层次化、结构化组织 playbook
  • 复用任务

Roles

Ansible 中的 Roles 是 Ansible 的另一个重要的概念,通过 Roles 可以通过文件结构自动加载相关的 vars, files, tasks, handlers, 或者其他 Ansible 组件。这样说可能比较抽象,可以理解成通过在文件系统上的文件分类,可以自动让 Ansible Roles 去加载相关的内容。一旦通过 Roles 组织了内容就可以非常简单地复用和分享给其他人。

Role directory structure

Ansible Role 定义了一个目录结构,包括了8大类标准的结构,一个 Role 必须包含至少其中一个文件夹,其他没有使用的文件夹可以省略:

# playbooks
site.yml
webservers.yml
fooservers.yml
roles/
    common/
        tasks/
        handlers/
        library/
        files/
        templates/
        vars/
        defaults/
        meta/
    webservers/
        tasks/
        defaults/
        meta/

默认情况下 Ansible 会自动寻找每一个目录下的 main.yml 文件(main.yaml 或者 main)。

  • tasks/main.yml,role 需要执行的主要任务
  • handlers/main.yml,可能会被使用的 handlers,可以由该 role 使用,也可以被 role 之外的其他任务使用
  • library/my_module.py modules
  • defaults/main.yml 默认变量
  • vars/main.yml role 的其他变量
  • files/main.yml files that the role deploys,role 需要使用的文件
  • templates/main.yml templates that the role deploys
  • meta/main.yml metadata,角色依赖

Storing and finding roles

默认情况下 Ansible 会在下面两个位置寻找 Roles:

  • 相对于 playbook 的目录 roles
  • /etc/ansible/roles

也可以通过 roles_path 的方式指定 Role 的位置。更多可以参考 Configuring Ansible

ansible.cfg 中定义:

roles_path    = /etc/ansible/roles:/usr/share/ansible/roles

或者也可以直接指定具体的 path:

---
- hosts: webservers
  roles:
    - role: '/path/to/my/roles/common'

使用 Roles

可以通过三种方式使用 Roles:

  • 在 play 层级使用 roles 选项,最常用的方式
  • 在 tasks 级别使用 include_role,可以动态使用
  • 在 tasks 级别使用 import_role,静态使用

Using roles at the play level

在 playbook 中,可以这样使用role:

- hosts: webserver
 roles:
   - common 
   - webserver

可以传递参数:

---
- hosts: webservers
  roles:
    - common
    - role: foo_app_instance
      vars:
        dir: '/opt/a'
        app_port: 5000
      tags: typeA
    - role: foo_app_instance
      vars:
        dir: '/opt/b'
        app_port: 5001
      tags: typeB

也可以向 roles 传递参数,例如:

- hosts: webserver
 roles:
   - common
   - { role: foo_app_instance, dir:'/opt/a',port:5000}
   - { role: foo_app_instance, dir:'/opt/b',port:5001}

甚至也可以条件式地使用roles,例如:

- hosts:webserver
 roles:
   - { role: some_role, when: "ansible_so_family == 'RedHat" }

Including roles: dynamic reuse

include_role 会按照定义的顺序执行,如果之前有定义其他的任务,会先执行其他任务。

---
- hosts: webservers
  tasks:
    - name: Print a message
      ansible.builtin.debug:
        msg: "this task runs before the example role"

    - name: Include the example role
      include_role:
        name: example

    - name: Print a message
      ansible.builtin.debug:
        msg: "this task runs after the example role"

Importing roles: static reuse

行为和上面的一样。

---
- hosts: webservers
  tasks:
    - name: Print a message
      ansible.builtin.debug:
        msg: "before we run our role"

    - name: Import the example role
      import_role:
        name: example

    - name: Print a message
      ansible.builtin.debug:
        msg: "after we ran our role"

使用 ansible-galaxy 创建 role

可以使用 ansible-galaxy role init role_name 来创建 role,这个命令会创建一个目录结构。

  • 创建以roles命名的目录
  • 在roles目录中分别创建以各角色命名的目录,如webserver等
  • 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建

使用 ansible-galaxy 创建的 role 会有一些初始化的设定,在 meta/main.yml 中可以看到基础的 galaxy_info 配置,包括了作者信息,协议等等。

role内各目录中可应用的文件

  • task目录:至少应该包含一个为main.yml的文件,其定义了此角色的任务列表;此文件可以使用include包含其它的位于此目录中的task文件;
  • file目录:存放由copy或script等模板块调用的文件;
  • template目录:template模块会自动在此目录中寻找jinja2模板文件;
  • handlers目录:此目录中应当包含一个main.yml文件,用于定义此角色用到的各handlers,在handler中使用include包含的其它的handlers文件也应该位于此目录中;
  • vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量
  • meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;ansible1.3及其以后的版本才支持;
  • default目录:应当包含一个main.yml文件,用于为当前角色设定默认变量时使用此目录;

通过 ansible-galaxy 认识 Roles

ansible-galaxy list  # 列出已经安装的galaxy
ansible-galaxy install geerlingguy.redis  # 安装一个galaxy role
ansible-galaxy remove geerlingguy.redis  # 删除一个galaxy role

reference


2021-11-10 ansible , ansible-playbook , ansible-role , linux , python

如何发现 CPU steal 并解决

什么是 CPU 窃取

CPU 窃取(CPU steal)指的是一个虚拟 CPU 核心必须等待物理 CPU 的时间百分比。通常 CPU 窃取发生在共享主机上,简短地来说就说当共享主机去处理一个请求时发生延迟。这种情况通常会发生在资源争夺的时候,当处理 CPU 密集型任务时。

为什么会发生 CPU 窃取

在共享主机、或云主机中,虚拟机管理程序会安装在物理硬件和虚拟机化化境之间,然后将 CPU 时间、内存等等资源分配给虚拟机。

当进程准备好由虚拟 CPU 执行时,等待管理程序分配物理 CPU,而如果管理程序将此 CPU 已经分配给了另一个虚拟机时,就会发生等待。

CPU 窃取时间长的原因:

  • 虚拟机进程计算任务繁重,分配的 CPU 周期不足以处理工作负载
  • 物理服务器被虚拟机超载,云服务器提供商超额出售了虚拟机,使得物理 CPU 无法处理进程

当发生请求处理缓慢时如何查看 CPU streal

当检测到共享主机性能无故受到影响时,怀疑可能出现 CPU steal。最好的排查方法就是使用 iostat 命令。

iostat 1 10
for x in `seq 1 1 30`; do ps -eo state,pid,cmd | grep "^D"; echo "-"; sleep 2; done
top -bn 1 | head -15

拆分开每一行命令进行解释:

iostat 1 10

每隔 1s 执行一次 iostat 命令,一共执行 10 次。

其结果可能是这样的:

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           5.29    2.12   12.17   46.03    0.53   33.86

Device             tps    kB_read/s    kB_wrtn/s    kB_dscd/s    kB_read    kB_wrtn    kB_dscd
dm-0              1.00         4.00         0.00         0.00          4          0          0
dm-1             19.00       760.00      6144.00         0.00        760       6144          0
loop0             0.00         0.00         0.00         0.00          0          0          0
loop1             0.00         0.00         0.00         0.00          0          0          0
loop2             0.00         0.00         0.00         0.00          0          0          0
loop3             0.00         0.00         0.00         0.00          0          0          0
loop4             0.00         0.00         0.00         0.00          0          0          0
loop5             0.00         0.00         0.00         0.00          0          0          0
loop6             0.00         0.00         0.00         0.00          0          0          0
loop7             0.00         0.00         0.00         0.00          0          0          0
loop8             0.00         0.00         0.00         0.00          0          0          0
loop9             0.00         0.00         0.00         0.00          0          0          0
xvda             34.00      1412.00         0.00         0.00       1412          0          0
xvdb             30.00      1124.00         0.00         0.00       1124          0          0
xvdc            161.00       964.00      5440.00         0.00        964       5440          0

从结果上来看,上面的结果只有一点儿的 CPU steal,来看看一个存在 CPU steal 的结果。

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.39    0.00   12.74    0.00   37.84   49.03

注意到 %steal 值,这么高的值则表示正在发生 CPU steal。一般来说这个值低于 15% 算是比较正常,如果一直比较偏高则需要 open a ticket 给虚拟机提供商请求调查了。

for x in `seq 1 1 30`; do ps -eo state,pid,cmd | grep "^D"; echo "-"; sleep 2; done

这一行命令则是检查状态在 D 状态的进程,D 状态意味着进程在 uninterruptible sleep,这一行命令每隔 1s 执行一次,执行 30 次。

正常的结果应该是只输出 - 行。而如果输出的结果中包含 D 状态的进程:

# for x in `seq 1 1 30`; do ps -eo state,pid,cmd | grep "^D"; echo "-"; sleep 2; done
-
D  2169 [jbd2/sda-8]
-
D  2169 [jbd2/sda-8]
-
D  2169 [jbd2/sda-8]

这意味着特定的进程在 uninterruptible sleep。调查该特定的进程,查看是否因为其他的,比如 IO 等待而造成系统卡顿。

D 状态进程通常在等待 IO,但这也常常意味着会发生 CPU steal,所有的系统资源都会被绑定到 D 状态的进程上,导致系统无法处理其他任务。

D 状态的进程无法被通常的方法 kill,因此一个完整的系统重启才可能清除掉此类进程。另一个方法就是等待 IO ,直到进程自己解决问题。但缺点也是在整个等待 IO 的过程中会持续造成系统问题。

top -bn 1 | head -15

top 命令是用来监控系统进程资源使用情况的命令,上面的命令则是打印资源使用最多的 15 个进程。

注意:超出 100% 使用率的进程不是问题,一个 8 CPU 核心的虚拟机可能会有 800% 的 CPU 使用率

在查看 top 的结果时,如果 top 命令结果中有占用 CPU 异常的进程,可以进行相关的处理。

mpstat

另外一个查看的命令是 mpstat

mpstat -P ALL 1 10

每隔 1s 时间打印一次,在结果中可以查看 %steal 的数值。

sar

在 sysstat 包中的 sar 命令也可以查看 steal 情况。

reference


2021-11-05 cpu , linux , vps , cpu-steal , virtual-machine

自行搭建 ZeroTier Network Controller 组件虚拟局域网

之前的一篇文章简单的通过内网穿透,异地组网的概念介绍过 ZeroTier,过去几年里面几台设备也一直陆陆续续地在使用着,虽然中间也短暂切换成 frp,也尝试过 [[Tailscale]],但 ZeroTier 一直是候选方案中排名在前的。

ZeroTier 官方默认免费的方案可以支持最多 50 台设备的连接,我陆陆续续也用不超过 20 台。所以使用官方提供的基本服务是丝毫没有任何问题的。但就是本着折腾的态度,也是学习一下 ZeroTier network controller 相关的内容,记录一下如何自建 ZeroTier network controller。

概念介绍

ZeroTier

ZeroTier 是一个虚拟组网工具,他可以让设备和设备之间通过互联网的帮助,就像是在局域网(LAN)之间通信一样。通过 安装 ZeroTier One 客户端,并加入一个 16 位数字的 ZeroTier 网络就能实现。

ZeroTier network controller

ZeroTier 网络是通过 ZeroTier network controller 来完成配置的。用户既可以使用 ZeroTier 官方 提供的 network controller,也可以使用自己搭建的独立网络控制器(standalone network controller)。

如何设置自己独立的网络控制器就是这篇文章的重点。

ztncui

ztncui 是一个开源的 ZeroTier 网络控制中心的用户界面。

代码地址:https://github.com/key-networks/ztncui

ZeroTier 网络实现原理

ZeroTier 的网络 Controller 是一个控制节点,该节点会通过 roots (根节点)来发现彼此。可以和 DNS 根服务器类比。

ZeroTier 的 Network ID 由两部分组成:节点 ID + 其他字符。

每一个 ZeroTier 节点(Nodes)会通过 Network ID 的前 10 位来发现 network controller,然后通过 networking controller 来发现局域网中的其他节点。

然后每一个节点可以通过 zerotier-cli peers 来查看匹配网络中的节点。

如果 network controller 离线了,那些已经建立连接的节点会保持连线,但是无法再往网络中添加新的节点。

如何搭建独立的 ZeroTier 网络控制器

上文提及的 ztncui 就是一个开源的 ZeroTier 网络控制器界面,通过他可以快速搭建自己的 ZeroTier 网络控制器,这里我们使用 Docker 镜像快速搭建。如果需要手工搭建,可以直接参考官网

本文使用的镜像是:

这里直接贴出 docker-compose.yml 文件:

version: '3.3'

services:
  ztncui:
    container_name: ztncui
    image: keynetworks/ztncui
    restart: always
    volumes:
      - ~/ztncui/ztncui:/opt/key-networks/ztncui/etc
      - ~/ztncui/zt1:/var/lib/zerotier-one
    environment:
      - NODE_ENV=${NODE_ENV}
      - HTTP_PORT=${HTTP_PORT}
      - HTTP_ALL_INTERFACES=yes
      - ZTNCUI_PASSWD=${ZTNCUI_PASSWORD}
      - MYADDR=${MYADDR}
    ports:
      - '3443:3443'
      - '3180:3180'

说明:

  • HTTP_PORT:后台端口
  • ZTNCUI_PASSWD:后台默认密码
  • MYADDR: VPS 的网络地址,公网 IP 地址

然后在同级目录新建文件 .env:

# more https://github.com/key-networks/ztncui-aio
NODE_ENV=production
HTTP_PORT=3443
ZTNCUI_PASSWD=
MYADDR=your.ip

后续更新会在 dockerfile

然后使用 docker-compose up -d 启动。

启动之后可以访问 IP:3443 可以访问管理后台。

独立网络控制器的优劣

优点

自建 ZeroTier network controller 可以提升节点建立连接的稳定性,同时也解除了官网的设备连接数限制。

但 network controller 自身并不能提升节点和节点之间的连接速度。

缺点

一旦使用了自建的 ZeroTier 网络,便需要一定精力去维护 network controller 的稳定性。

并且如果 network controller 挂掉可能无法再新增加节点。不过新增节点的操作也不是高频操作,对我个人使用而言问题不大。

外延

除了 ztncui 这一个用户界面,还有一些在逐渐发展的,可以根据自己需要挑选:

reference


2021-11-04 zerotier , linux , networking

究竟什么是「内卷」

过去的这一年里,不断的有人在我耳边说起一个词「内卷」,但是我让说这个词的人解释一下自己所说的这个词的含义,却没有人能够用一句话解释清楚这个词。所以在我的笔记中就一直留着这一个词条,让我不断的去思考「内卷」一词的含义。一般来说,我在没有弄明白某一个概念之前,不会在日常生活中反复的去使用。但周围反复在用的人实在太多了,所以整理一下过去我听到的,以及看到的。

内卷的几个表达场景

我周围的人通常在这几个场景中会用到「内卷」这个词:

  • 在大多数的语境中,我们会说互联网行业的竞争,以及在这个竞争下的程序员为主体的人形成了内卷的趋势,表现形式就是加班越来越严重
  • 我也听到有人形容《鱿鱼游戏》说是反应韩国的内卷
  • 同样在学习,比如高考的竞争中也有「内卷」的趋势

但究竟什么是内卷,如果是恶性竞争,那么我们为什么要发明一个词来表达重复的含义?

什么是内卷

那接下来我们就从最原本的含义来探究一下「内卷」。

字典上的定义

内卷对应的英文单词是 involution。involution 在 American Heritage English 上的解释:

  • the state of being involved 被卷入的状态
  • intricacy, 复杂性,复杂化的状态和过程
  • 在医学上:
    • A decrease in size of an organ, as of the uterus following childbirth.(器官在大小上的萎缩,例如生育之后女性子宫的萎缩。)
    • A progressive decline or degeneration of normal physiological functioning occurring as a result of the aging process.(因年龄增长而出现的身体正常功能的持续衰退或退化。)
  • 在植物学上:
    • Having the margins rolled inward,边缘内卷,形容植物枝叶内卷的特性

英文单词 involution 有内卷,退化的含义。

哲学定义

在哲学领域,内卷化一词最早被提及是 18 世纪德国哲学家 [[康德]] 的《批判力批判》,康德将 involution 和 Entwicklung(演化)进行了区分。

他在《批判力批判》中将「内卷化」定义成与「演化」相对的概念,「演化」形容事物从无到有、从低级到高级的发展过程,而「内卷化」则指的是事物在原有的基础之上,不断向内发展,不断复杂化的过程,这个过程中,并没有新事物诞生。1

人类学家定义

美国人类学家 Goldennweiser(Alexander Aleksandrovich Goldenweiser) 将内卷化定义成在某一个状态下,无法稳定,也无法转变为新的状态,只能不断内部运动,变得复杂的文化模式。2

农业领域

美国人类学家 Clifford Geertz ,在《农业内卷化——印度尼西亚的生态变化过程》(Agricultural Involution: The Processes of Ecological Change in Indonesia)中,借用 Goldenweiser 内卷化的概念研究爪哇岛的水稻农业,提出了 agricultural involution(农业化内卷)的概念。他认为水稻种植造成了社会复杂性,但没有促成技术或政治的变革,这个过程被他称为「内卷化」,Geertz 的使用,使得「内卷化」一词在人类学家和社会学家之间广为流传。

Geertz 在书中提到,1830 年以后爪哇受到了两方面的限制:

  • 增长的人口压力
  • 阻碍本地经济作物种植和商业部门发展的帝国主义

面对土地短缺采用了共同分担贫穷的模式,引起工业变革的失败3

国内学者的研究

而在国内对「内卷」一词的引用则是在黄宗智的《长江三角洲小农家庭与乡村发展》中,作者把内卷化这一概念用于中国经济发展与社会变迁的研究,他把通过在有限的土地上投入大量的劳动力来获得总产量增长的方式,即边际效益递减的方式,将一种没有发展的增长称为「内卷化」。

内卷化含义的扩大

但是在「内卷化」一词进入公众领域之后,其含义发生了巨大变化,在网络上,随着传播,内卷一词的语义发生了偏差。人们往往用其来指代恶性竞争、过度竞争,底层淘汰等现象。

内卷和形式主义的关系

形式主义是严格意义上的内卷,即通过做没有实际意义的事情对有限资源进行零和博弈,形式主义的唯一产出是上位者的情绪价值。所以,反对形式主义的本质是减少上位者获得的情绪价值。这就是为什么反对形式主义很难。

fslC

总结

总结上面的这些定义,尽管在哲学、社会学等等不同领域中,不同学者都对内卷化展开了研究,但是对内卷化都有各自不同的定义,这些定义不尽相同,目前也没有一个统一的定义。

但是能看到一些统一性的地方:

  • 复杂化,相同的一件事情不断发展越来越复杂
  • 不断发展,却不会产生新的事物、思想

对于社会整体而言,内卷是一个停滞不前,无法转变的状态,虽然看着再不断发展,但是无法产生新的事物。而对于社会中的个体而言,内卷则使得个体投入更多,但却收获相同的结果,在边际效应上退化,对个体而言不管如何努力、改变都无法促进变革。

造成内卷的原因

信息不对称

在这里我无法再进一步探究内卷的原因,我也无法得知为什么整个社会会掉进这样的陷阱,我知道只有当市场上的人能够充分的去发明新的事物,能够自由的表达自己的观点,即使这个事物的发明可能带来灾难,即使这个观点可能是错误的,但只有这样的自由,才能不让社会陷入一潭死水,只有自由的讨论才能使得真理在辩论中脱颖而出。在信息公开透明、可以自由交流的社会中,信息的流动会弥补信息的不对称,从而使得社会中的个体能够根据自己所获得的信息做出决策,从而提高生产效率,从而发展出新的理论。就像[[密尔]]在[[论自由]]一书中所说,迫使意见不能被表达这是对整个人类的掠夺。

内卷化的误读

在我们日常生活中所讨论的内卷一词早已超出了其原本的含义,甚至在某一些地方的使用是错误的,只掩盖了原来的一些问题。很多人所说的「内卷」,其实并不是「内卷」。

就像之前看到的豆瓣短文

有人将职场学历要求越来越高视为内卷。事实上,这并不是内卷。例如一个工程师、银行经理的招聘要求从本科到硕士,从硕士到名校硕士,这其实是社会对岗位人才的要求越来越高,而不是内卷。 一个单位加班越来越严重,只要加班是有效的,这也不叫内卷,这属于劳动剥削。 将资本、风投偏爱低技术含量产业(例如共享单车、社区团购、滴滴这种的),而非原研药、精密机床、机器人这些高技术产业视为内卷。其实这也不是内卷。热钱真正偏爱的,是收益周期短的服务行业,“共享经济”、滴滴、美团、拼多多、游戏产业……这些看上去是互联网科技产业,其实它们是互联网加持的服务业,它们提供的是交通、配送、游戏娱乐、餐饮、购物等等服务。资本热钱真正偏爱的收益周期短、好讲故事的服务业。而这些生活服务产业又都是大众化服务,所以我们经常会在媒体宣传上、身边生活中看到这些服务产品(例如共享单车、美团骑手、游戏广告等),于是就会形成了资本只喜欢这种产业的错觉。实际上,高技术产业——造精密机床、造飞机、造机器人……这些技术产业都有它们自己的体系,只是它们离我们的生活较远,我们不太了解而已。所以这也算不上内卷。这属于是风投资本倾向于收益周期短、曝光率较高的服务业。如果真要靠投资共享单车那点钱去研究飞机、造芯片,那国家怎么可能发展呢?高科技企业自有其发展的政策、金融、市场体系。 将所有的加班都视为「内卷」这实际上掩盖了劳动法保障不健全的问题。假如劳动法保障够刚性,当暗示加班成为一种人人鄙视的违法行为时,加班生态是绝对可以好转的。而乱用内卷概念,则会把责任归于员工身上,反而忽略了法律制度、企业的问题,这就掩盖了真实的问题所在。

正确的使用「内卷」一词,才能让我们有针对性的解决问题,而不是像现在这样任其随意被滥用,从而掩盖真正能够被解决的问题。

  • [[躺平]]

reference

  1. 康德.判断力批判·第 2 版[M].北京:人民出版社,2002. 

  2. McGee, R. Jon; Warms, Richard L. Critical Contributions to Anthropology. Theory in Social and Cultural Anthropology: An Encyclopedia. SAGE Publications. 2013-08-28. ISBN 9781506314617 

  3. Cohen, Jeffrey H.; Dannhaeuser, Norbert. Involution and modernisation. Economic Development: An Anthropological Approach. Rowman Altamira. 2002-04-23. ISBN 9780759116696 


2021-11-03 thinking , involution

电子书

本站提供服务

最近文章

  • Dinox 又一款 AI 语音实时转录工具 前两天介绍过 [[Voicenotes]],也是一款 AI 转录文字的笔记软件,之前在调查 Voicenotes 的时候就留意到了 Dinox,因为是在小红书留意到的,所以猜测应该是国内的某位独立开发者的作品,整个应用使用起来也比较舒服,但相较于 Voicenotes,Dinox 更偏向于一个手机端的笔记软件,因为他整体的设计中没有将语音作为首选,用户也可以添加文字的笔记,反而在 Voicenotes 中,语音作为了所有笔记的首选,当然 Voicenotes 也可以自己编辑笔记,但是语音是它的核心。
  • 音流:一款支持 Navidrom 兼容 Subsonic 的跨平台音乐播放器 之前一篇文章介绍了Navidrome,搭建了一个自己在线音乐流媒体库,把我本地通过 [[Syncthing]] 同步的 80 G 音乐导入了。自己也尝试了 Navidrome 官网列出的 Subsonic 兼容客户端 [[substreamer]],以及 macOS 上面的 [[Sonixd]],体验都还不错。但是在了解的过程中又发现了一款中文名叫做「音流」(英文 Stream Music)的应用,初步体验了一下感觉还不错,所以分享出来。
  • 泰国 DTV 数字游民签证 泰国一直是 [[Digital Nomad]] 数字游民青睐的选择地,尤其是清迈以其优美的自然环境、低廉的生活成本和友好的社区氛围而闻名。许多数字游民选择在泰国清迈定居,可以在清迈租用廉价的公寓或民宿,享受美食和文化,并与其他数字游民分享经验和资源。
  • VoceChat 一款可以自托管的在线聊天室 VoceChat 是一款使用 Rust(后端),React(前端),Flutter(移动端)开发的,开源,支持独立部署的在线聊天服务。VoceChat 非常轻量,后端服务只有 15MB 的大小,打包的 Docker 镜像文件也只有 61 MB,VoceChat 可部署在任何的服务器上。
  • 结合了 Google 和 AI 的对话搜索引擎:Perplexity AI 在日本,因为 SoftBank 和 Perplexity AI 开展了合作 ,所以最近大量的使用 Perplexity ,这一篇文章就总结一下 Perplexity 的优势和使用技巧。