• [课程学习] [百度网盘] MG教育-2025Linux云计算SRE工程师(M64期)
     Linux 服务高可用架构设计实战指南——从适用面出发高可用(High Availability)是生产环境的刚需,但也是被误解最深的技术领域之一。很多人把“高可用”等同于“部署一个负载均衡器加两台机器”,结果数据库挂了依然全站瘫痪;也有人走向另一个极端,堆砌 Keepalived、HAProxy、Corosync、Pacemaker 等一堆组件,最终架构复杂到无人敢动。真正的高可用设计,核心不是“选什么工具”,而是“你的服务应该达到几个九,愿意为此付出多少成本”。本文从适用性角度,拆解 Linux 服务高可用架构的设计原则、常见模式的适用场景,以及如何避免过度设计。一、高可用的本质:消除单点,而非消除故障一个基础认知:故障永远无法消除,硬盘会坏、网线会断、电源会烧、软件会崩。高可用的目标是:任何一个组件故障,整体服务不中断。这通过冗余(多份)和自动切换(故障转移)来实现。但冗余是有代价的。一台机器的成本是 1,两台实现主备模式的成本接近 2,而实现双活模式的成本可能超过 2.5(需要额外的负载均衡、数据同步、会话保持等)。适用设计的前提是:先回答三个问题——你的服务能容忍多久不可用?(RTO,恢复时间目标)能容忍丢失多少数据?(RPO,恢复点目标)愿意为此花多少预算?一个内部报表系统,RTO=1 小时、RPO=1 天,用最简单的主备+定时备份就够了。一个在线支付接口,RTO=10 秒、RPO=0,则需要同城双活+同步复制。脱离这些量化指标谈高可用,都是空谈。二、Linux 服务高可用的四种经典模式及适用场景模式一:主备模式(Active-Passive)——适用大多数业务系统的起步方案一台主节点承载所有流量,一台或多台备节点待命,通过心跳检测主节点健康状态。主节点故障时,VIP(虚拟 IP)和资源漂移到备节点。典型实现:Keepalived + VIP,配合浮动脚本适用场景:多数无状态服务(Nginx、Tomcat)、关系型数据库主从(需配合从库提升为主)优点:实现简单、脑裂风险可控(通过 vrrp 协议)缺点:备节点闲置,资源利用率约 50%;切换时间通常在秒级(3-10 秒)适用判断:对切换时间不敏感(10 秒内可接受)、预算有限、团队运维能力中等。这是 Linux 服务高可用的“入门标配”。模式二:双活模式(Active-Active)——适用需要充分利用资源的场景两个或多个节点同时承载流量,任何一个节点故障,其他节点自动接管其流量。通常前置负载均衡器(LVS、HAProxy、Nginx 等)分发请求。适用场景:无状态 Web 服务、可水平拆分的缓存集群(Redis Cluster)、消息队列优点:资源利用率高(接近 100%),扩容灵活缺点:需要解决会话共享(如存入 Redis)、数据一致性问题适用判断:服务本身无状态,或者有成熟的分片方案。对于数据库等有状态服务,双活实现极其复杂(需要分布式一致性算法),通常不是首选。模式三:基于共享存储的主备——适用有状态服务,但存储成为新单点应用节点主备,但数据存储在共享存储上(SAN、NFS、GFS2)。故障时备节点挂载同一份存储,拉起服务。典型实现:Corosync + Pacemaker + DRBD(网络镜像块设备)或 GFS2适用场景:传统数据库(Oracle、PostgreSQL)的 HA 方案优点:切换时无数据丢失(RPO=0,如果存储本身是多副本)缺点:共享存储本身需要高可用,否则成为新的单点;配置复杂,脑裂处理要求高适用判断:你的应用有状态且无法改造成无状态,且团队有较强的系统运维能力。否则建议考虑云原生数据库托管服务。模式四:基于 DNS 的全局负载均衡——适用跨地域容灾通过 DNS 解析将不同地域的用户分发到不同的服务入口。健康检查发现某个地域不可用,DNS 停止返回该地域 IP。典型实现:DNS 服务商提供的 GSLB 功能,或自建 DNS + 健康检查脚本适用场景:多数据中心部署、全球加速、主备数据中心切换优点:实现简单,客户端无需特殊配置缺点:DNS 缓存可能导致切换生效慢(分钟级),无法精细控制流量比例适用判断:可以接受分钟级切换,或者作为“容灾的最后一道防线”。不适合需要秒级自动切换的场景。三、高可用设计的三个关键决策点决策一:心跳与脑裂防护主备模式中最危险的故障不是“主节点宕机”,而是“主节点活着但网络不通”。此时备节点收不到心跳,也可能认为主节点故障从而接管 VIP,导致两个节点同时写共享资源——这就是脑裂。适用策略:使用冗余心跳链路(双网卡、串口线)降低误判概率采用“仲裁”机制(第三台节点或磁盘锁),只有获得仲裁的一方才能成为主云环境中利用 API 检查实例状态,比网络心跳更可靠决策二:切换的自动化程度并非所有故障都应该自动切换。有些场景下,自动切换带来的风险大于收益。全自动切换:适用核心交易链路,故障后人工介入太慢半自动(切换需人工确认):适用非核心但数据敏感的服务,避免误切换导致数据损坏手动切换:适用批处理、分析类任务,短暂中断可接受适用判断:根据 RTO 倒推。RTO < 1 分钟,必须全自动;RTO > 30 分钟,手动足够。决策三:数据同步方式这是高可用设计中代价最高的部分。同步复制保证 RPO=0,但写延迟会增加(需等待备节点确认);异步复制写延迟低,但主节点故障可能丢失最后几笔数据。强一致适用场景:交易、账户余额、库存扣减(RPO=0 刚性要求)最终一致适用场景:用户评论、日志、社交动态(丢几条不影响业务)没有中间道路。如果你的业务要求 RPO=0,就必须接受同步复制的性能代价。四、从高可用走向“高可靠”的适用演进高可用不是一次性工程,而是一个持续演进的过程。推荐的路径是:单机 → 2. 主备(手动切换) → 3. 主备(自动故障转移) → 4. 双活(无状态层) → 5. 双活(数据层分片) → 6. 跨地域容灾每前进一步,成本和复杂度都显著增加。大多数业务停留到第 3 或第 4 级已经足够。Linux 服务高可用的核心智慧,不是“堆更多组件”,而是“精确知道自己的服务需要什么级别的可用性,然后选择最经济的实现方式”。一个设计良好的主备方案,远比一个配置错误、从未演练过的双活方案可靠。实战指南的最后一条建议是:无论采用哪种架构,每季度至少做一次真实故障切换演练。没有演练的 HA 配置,都是心理安慰。 
  • [案例共创] 68元一年,华为云码道帮我把“龙虾”服务器变成了AI私人管家!
    ——从Git残留卡死、重装宝塔、权限爆炸、内存崩盘,到OpenClaw+华为云码道配合自创Skill+国产M模型与MCP全家桶的血泪升级记(原文:https://bbs.huaweicloud.com/blogs/475975)  想象一下:你花68块钱,在华为云买了一台2核2G轻量弹性云主机,官方还送了个尝鲜“龙虾镜像”。 我当时兴奋得像捡到宝:这不就是一只会写文章、发自媒体、管网站、还能在钉钉里陪我聊天的AI小龙虾吗?(没错,接着上次的,我又开始折腾了~)  结果,这只“龙虾”一上来就给我上了生动的一课——升级失败、Git残留、权限爆炸、端口冲突、内存OOM……整整折腾了三天三夜(没那么久,纯文字需要,请不要在意)! 最终,我不但成功把它升级到OpenClaw 3.28最新版,还接入了国产M模型与MCP(网络搜索+图片理解),用华为云码道AI IDE自建Skill,让它真正变成了我的云端AI私人管家。下面,我把整个过程完整分享给你——既有血泪踩坑,也有硬核技术细节。看完你也会想立刻去买一台“华为云虾”玩玩!刚买的68元龙虾服务器,雄心勃勃却马上翻车(和上次一样,图不重要,是个意思)第一坑:升级直接卡死,Git残留成了罪魁祸首我本来想直接升级OpenClaw到3.28版——这个版本支持更稳定的插件系统、MiniMax MCP工具链,还优化了内存管理。 结果敲下 openclaw upgrade 后,直接报错:Git项目没有清理干净,无法升级原来之前乱装插件时,~/.openclaw 目录里残留了一堆 .git 文件夹和缓存。 我尝试 git clean -fdx 也没用,最后只能彻底重装。我切换到宝塔镜像,一键重装系统,干净利落。 用了宝塔的镜象,说不定龙虾除了帮我写文章发自媒体之外,还可以在服务器上帮我管理管理网站(嗯,当时我就这么想的~)。重装后发现:宝塔自带的www用户和OpenClaw默认的node用户(UID 1000/1001)权限冲突,导致配置文件 openclaw.json 始终读不到。解决办法:(当然,不用我说,你用过华为云码道,你知道该怎么办,重要的是我们要知道为什么是这样)Bash sudo chown -R 1000:1000 /home/opclaw/.openclaw sudo chmod -R 755 /home/opclaw/.openclaw  龙虾大战Git残留文件(AI生图,大家随意点,看图别看图上的字)第二坑:端口冲突 + 权限爆炸 + systemd服务127错误重装后启动 openclaw gateway 又报:默认webUI端口被幽灵进程占用EACCES permission deniedsystemd服务启动后直接 status=127(command not found)我用 lsof -i :19037 找到残留进程 kill -9,又用 NODE_OPTIONS="--max-old-space-size=1280" 限制内存,最后把服务文件改成:Bash ExecStart=/bin/bash -c 'NODE_OPTIONS="--max-old-space-size=1280" /home/opclaw/.local/bin/openclaw gateway --port 19037'龙虾在内存战场奋力作战   第三坑:2核2G内存崩盘 + MCP工具启动超时最难的是内存问题。 2G服务器跑OpenClaw + DingTalk + MiniMax MCP,启动峰值轻松破1.5GB,日志刷屏:FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory我加了2GB Swap文件,把 swappiness 调到10,又把日志级别降到 error,关闭Canvas模块,终于把内存压到稳定800MB左右。接着配置国产M模型与MCP(网络搜索 + 图片理解)时,又遇到 McpError: Request timed out 和 cwd 路径错误。最终把 workingDirectory 和 cwd 统一设为 /home/opclaw,并用 uvx minimax-coding-plan-mcp -y 手动测试,才成功让两个专属工具上线。 这里你不得不佩服,华为云码道的网络知识搜索总结能力也是不错的。 龙虾成功掌握MCP工具最终成果:龙虾真正“管家化”现在我的68元龙虾服务器已经能做到:钉钉卡片式AI对话(支持markdown+卡片)MiniMax MCP实时网络搜索 + 图片理解通过华为云码道AI IDE自建Skill,一键自动化写文章、发自媒体、管理网站开机自启、稳定运行、内存可控当然,你放心,我面我还会继续折腾~最终AI管家龙虾 写在最后68元一年,买的不只是一台服务器,而是一只潜力无限的AI小龙虾。 整个过程虽然踩了无数坑(Git残留、权限、端口、内存、MCP超时),但每解决一个问题,龙虾就变得更聪明、更听话。如果你也有一台闲置的华为云轻量服务器,想让它变成AI管家,欢迎评论区告诉我你的配置,我把最终优化后的 openclaw.json 和码道Skill模板分享给你。点赞 + 转发,让更多人知道:华为云 低配云主机 + OpenClaw + 华为云码道+自创Skill = 属于普通人的AI私人服务器时代,已经来了!(对了,我能提议一下么,华为云促销主机的续费价格问题,小助手能反馈一下嘛,隔壁a家是承诺五年同价续费的)  好了,大家,下次见~
  • [区域初赛赛题问题] 标准程序和得分明细,总得给一样吧
    ref:    demo保证正确性吗?_2026华为软件精英挑战赛_华为云论坛现在情况是,我非标程的做法写了一个程序和demo的标程对拍,结果每个样例都过不了。虽然说现在还没有处理非凸的情况,但至少testcase1错在第一组数据我不是很能接受。而且我的做法交上去还没demo分高,现在也看不到每个点的得分明细,我也不知道该往那个方向去改,甚至不知道自己是正确性还是速度的问题。总不会评测用的答案也是demo生成的吧,那岂不是连评测分数都是有问题的?望早日更新。
  • [交流吐槽] IDE会有linux的amd64版本吗(或者说是x86_64)
    IDE会有linux的amd64版本吗(或者说是x86_64)
  • [问题求助] linux会出x86版本吗
    我看现在出了arm版本,会发布x86的吗
  • [技术干货] 普通用户修改repo文件下载rpm包
    前言我们有个服务会在pod内下载rpm包,只是下载,并不安装。本来是正常运行的,但最近公司的repo源启用了动态密码,这个动态密码只有1天的有效期,导致新镜像出来后只有第一天能正常下载rpm包。更蛋疼的时候pod内只能用普通用户,没法修改存放在/etc/yum.repo.d目录下的repo文件。翻了下dnf命令的官方文档,发现普通用户可以通过指定一个repo文件的方式下载rpm包,这个repo文件可以放在任意目录。步骤使用普通用户创建.repo文件, database.repo[database] baseurl=https://rpm.xitian.internal/prod/database/noarch/ enabled=1 gpgcheck=1 gpgkey = https://rpm.xitian.internal/prod/gpg_public_key.pub,https://rpm.xitian.internal/prod/gpg_public_key256.pub module_hotfixes=1 name=Database prod priority=1|int username=tmp_1750668281 password=TxZZ1wh9W0-Vaaa [database-qa] baseurl=https://rpm.xitian.internal/qa/database/noarch/ enabled=1 gpgcheck=1 gpgkey = https://rpm.xitian.internal/prod/gpg_public_key.pub,https://rpm.xitian.internal/prod/gpg_public_key256.pub module_hotfixes=1 name=Database QA priority=1|int username=tmp_1750668281 password=TxZZ1wh9W0-V指定该repo文件来下载dnf --config=database.repo --repo=database download custom-postgres --destdir=$(pwd)
  • [技术干货] [linux]记账工具-监控用户活动
    前言记账工具可以提供诸如 Linux 系统中的连接、已执行的程序以及系统资源的使用等有底系统使用信息。这些记账工具可以通过 psacct 或 acct 软件包安装。psacct 和 acct 实际上是相同的。在基于 RPM 的系统中,它以 psacct 的形式存在;而在基于 DEB 的系统中,它作为 acct 提供。安装大多流行的Linux发行版中都有 psacct或acct,例如debian中安装:sudo apt install -y acct启动在 debian 上,acct 安装后就会被启动并设置为自动启动,可以通过以下命令查看sudo systemctl status acct如果没有启动,可以用如下命令启动sudo systemctl start acct sudo systemctl enable acct使用acct 软件包包含以下用来监测用户和进程活动的工具:ac - 提供用户登录时间的统计信息。lastcomm - 展示先前执行过的命令的信息。accton - 开启或关闭进程记账。dump-acct - 把 accton 的输出文件转化为易读的格式。dump-utmp - 以易读的方式打印 utmp 文件。sa - 汇总信息,关于先前执行的命令。acac 工具可以为你提供以小时为单位的连接时间报告,这样你就能知道用户或一组用户连接到系统的时长。# 展示所有用户的总连接时间 ac # 按日期排序所有用户的总连接时间 ac -d # 获取各个用户的总连接时间 ac -p # 获取 rainux 用户的总连接时间 ac rainuxlastcommlastcomm 工具用于列出过去执行过的命令,它会按执行的最近程度将命令列在前面。# 展示过去执行的命令 sudo lastcomm # 展示特定用户过去执行的命令 sudo lastcomm username # 展示特定命令过去被执行的次数 sudo lastcomm gitsasa 实用程序将总结关于先前执行的命令的信息。(可能需要使用绝对路径才能使用)# 打印所有命令的总结 sudo /usr/sbin/sa示例输出。每一行代表一个命令(或命令组)的统计汇总。第一列为该命令被执行的总次数。第二列为该命令总实际时间(real time, 从开始到结束,包括等待IO、睡眠等),单位分钟。第三列为总CPU时间(实际占用CPU的时间),单位为分钟。第四列为平均IO操作数(average io operations, 通常为 0,除非系统启用了详细 I/O 统计)。第五列为平均内存占用,这是RSS(平均驻留集)的近似值。第六列为命令名,带*表示该命令是以 SUID/SGID 方式运行的(即提权执行)。第一行为汇总行sudo /usr/sbin/sa 1783 314.68re 0.02cp 0avio 2791k 15 1.12re 0.02cp 0avio 3223k ***other* 63 6.84re 0.00cp 0avio 40741k postgres* 7 305.02re 0.00cp 0avio 0k kworker/dying* 2 0.06re 0.00cp 0avio 4114k systemctl 4 0.11re 0.00cp 0avio 2335k dpkg 739 0.04re 0.00cp 0avio 645k sh 231 0.00re 0.00cp 0avio 1368k cat 230 0.00re 0.00cp 0avio 1639k awk 133 0.00re 0.00cp 0avio 1617k grep 72 0.00re 0.00cp 0avio 1908k lsblk 48 0.00re 0.00cp 0avio 2488k ps 24 0.00re 0.00cp 0avio 1370k wc 24 0.00re 0.00cp 0avio 645k trystart.sh* 19 0.01re 0.00cp 0avio 738k install-info 19 0.00re 0.00cp 0avio 835k gzip 15 0.00re 0.00cp 0avio 1652k cron* 14 0.00re 0.00cp 0avio 1366k flock 12 0.00re 0.00cp 0avio 1734k start.sh 12 0.00re 0.00cp 0avio 645k trystart.sh 12 0.00re 0.00cp 0avio 1734k start.sh* 12 0.00re 0.00cp 0avio 1373k chmod 12 0.00re 0.00cp 0avio 1367k dirname 12 0.00re 0.00cp 0avio 1367k whoami 11 0.00re 0.00cp 0avio 620k ac 8 0.32re 0.00cp 0avio 2299k sudo 7 1.12re 0.00cp 0avio 2292k git 5 0.01re 0.00cp 0avio 1365k whereis 5 0.00re 0.00cp 0avio 925k lastcomm 4 0.00re 0.00cp 0avio 850k iptables 3 0.00re 0.00cp 0avio 2125k bash* 3 0.00re 0.00cp 0avio 645k which 2 0.04re 0.00cp 0avio 3484k ssh 2 0.00re 0.00cp 0avio 204544k YDService 2 0.00re 0.00cp 0avio 629k rm打印基于每个用户的进程数量和 CPU 分钟数sudo /usr/sbin/sa -mdump-acct和dump-utmpdump-acct 实用工具将 accton 格式的输出文件显示为人类可读的格式。dump-acct /var/log/account/pacctdump-utmp 将 utmp 文件显示为人类可读的格式。dump-utmp /var/run/utmpacctonaccton 命令将允许你开启或关闭记账。# 开启 accton on # 关闭 accton off
  • [技术干货] Debian13系统更新后启动卡住问题的处理
    前言PC安装的操作系统是Debian 13,显卡为Nvidia。更新系统内核版本后,启动卡住,显示停在cups.service就不动了,同时显示dkms.service和nvidia-persistenced.service的状态都是 Failed。如图处理步骤开机时在grub启动菜单的Debian启动项上按"e",进入grub编辑模式,找到 linux 开头的行,在该行末尾添加3。3和前面的单词之间至少一个空格。然后按Ctrl + X或F10保存,自动重启。重启后会进入命令行界面,用root用户登录。安装内核对应版本的linux-headerapt install -y linux-header-$(uname -r)清理所有nvidia相关的程序apt purge *nvidia* apt autoremove -y重新安装nvidia驱动apt install -y nvidia-detect apt install -y nvidia-driver firmware-misc-nonfree重启shutdown -r now
  • [技术干货] [prometheus]监控postgres
    前言相关Repo: https://github.com/prometheus-community/postgres_exporter本文使用的postgres_exporter的版本为 0.16.0,postgres的版本为15.7步骤在db中创建用户并授权。create user exporter encrypted password '123456'; ALTER user exporter SET search_path TO pg_catalog, public; GRANT CONNECT ON DATABASE postgres TO exporter; GRANT pg_monitor to exporter; -- 不确定是否需要做 -- GRANT USAGE ON SCHEMA pg_catalog TO exporter; -- GRANT SELECT ON pg_stat_statements TO exporter;(可选,建议)安装 pg_stat_statements。具体操作可查询其它文档。安装完后可以切exporter用户执行SELECT * FROM pg_stat_statements LIMIT 1; 测试 exporter 用户能否正常访问 pg_stat_statements 的视图。启动。编写了一个脚本来启动。更多 postgres_exporter 的启动参数可以参考./postgres_exporter --help#!/bin/bash export DATA_SOURCE_URI="localhost:5432/postgres?sslmode=disable" export DATA_SOURCE_USER="exporter" export DATA_SOURCE_PASS="123456" script_dir=$(cd $(dirname $0) && pwd) app_name="postgres_exporter" is_running() { ps -ef | grep -v grep | grep "${script_dir}/${app_name}" > /dev/null if [ $? -eq 0 ]; then echo "${script_dir}/${app_name} is running" return 0 else echo "${script_dir}/${app_name} is not running" return 1 fi } start_app() { is_running if [ $? -eq 0 ]; then return 0 fi echo "starting ${script_dir}/${app_name}" nohup ${script_dir}/${app_name} \ --collector.postmaster \ --collector.stat_statements > ${script_dir}/app.log 2>&1 & } stop_app() { is_running if [ $? -eq 1 ]; then return 0 fi echo "stopping ${script_dir}/${app_name}" kill $(ps -ef | grep -v grep | grep "${script_dir}/${app_name}" | awk '{print $2}') } restart_app() { stop_app sleep 1 start_app } main() { if [ ! -f "${script_dir}/${app_name}" ]; then echo "${script_dir}/${app_name} not found" fi local action=$1 if [ x"$action" == "x" ]; then local action="start" fi case "$action" in start) start_app ;; stop) stop_app ;; restart) restart_app ;; status) is_running ;; *) echo "Usage: {start|stop|restart|status}" exit 1 ;; esac } main $@编辑prometheus.yml,添加收集postgres_exporter。注意替换路径# ... scrape_configs: - job_name: "postgres" file_sd_configs: - files: ['/etc/prometheus/sd_configs/postgres/*.yaml'] refresh_interval: 10s编辑/etc/prometheus/sd_configs/postgres/pg.yaml- targets: ['192.168.0.201:9187'] labels: instance: 192.168.0.201发送 hup 信号给 prometheus 或重启 prometheusgrafana 导入 dashboard。在grafana官网找的ID为 9628 的dashboard(可选)没事干的话,可以跑个 pgbench,观察基准测试下的 pg metrics。不过再没事干也别拿生产在用的DB跑基准测试。
  • [技术干货] [kubernetes]使用kubeadm和containerd部署kubernetes
    前言因宿主机内核版本限制和垂直伸缩特性的需要,安装的k8s版本为1.25,runtime为containerd,cni为calico。containerd、kubeadm、kubelet也可以用包管理器来安装,因为不想配repo,也不想校验repo版有哪些区别,所以这几个都是用原生二进制方式安装的。环境信息IPHostnameOS VersionKernel VersionComment192.168.0.11node1centos 7.93.10control panel192.168.0.12node2centos 7.93.10worker node192.168.0.13node3centos 7.93.10worker node用到的组件版本信息containerd: 1.7.21k8s: 1.25.16系统初始化系统初始化步骤要求每个节点都要操作,一些主机名等信息需要根据实际修改。修改hostname,k8s要求每个节点的hostname不一样hostnamectl set-hostname node1 hostnamectl set-hostname node2 hostnamectl set-hostname node3(可选)如果没有dns可以让hostname之间直接访问,需要配置/etc/hosts192.168.0.11 node1 192.168.0.12 node2 192.168.0.13 node3(可选)如果要长时间使用,最好配置一下时间同步。关闭swap。默认情况下,k8s检测到swap就会异常退出,导致node上的k8s启动失败。# 临时关闭。永久关闭需要修改 /etc/fstab swapoff -a装载内核模块。如果不装载br_netfilter,下一步配置系统参数会报错。# 添加配置 cat << EOF > /etc/modules-load.d/containerd.conf overlay br_netfilter EOF # 立即装载 modprobe overlay modprobe br_netfilter # 检查装载。如果没有输出结果说明没有装载。 lsmod | grep br_netfilter配置系统参数。编辑/etc/sysctl.conf文件或/etc/sysctl.d/目录下的文件,添加或修改以下配置。编辑完成后执行sysctl -p使配置生效。(如果修改的是/etc/sysctl.d目录下的文件,sysctl -p需要指定文件名才能生效)net.ipv4.ip_forward=1 net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 vm.swappiness = 0(可选)内核版本若高于4.1,可考虑使用ipvs来增强网络通信性能安装依赖,否则安装containerd时,runc组件会有问题# conntrack-tools的版本为1.4.4-4.el7,如果低了可能会导致runc异常 # 如果安装提示缺少依赖,而依赖在centos 7的repo源里没有,可从高版本centos、alma等发行版下载rpm包再安装 yum install -y conntrack-tools安装containerd从 cid:link_0下载二进制包解压压缩包到根目录。压缩包里面的文件路径都已经按照根目录组织好了,所以直接解压到根路径就行了。tar xf cri-containerd-cni-1.7.21-linux-amd64.tar.gz -C /生成containerd的配置文件mkdir /etc/containerd containerd config default > /etc/containerd/config.toml编辑containerd的配置文件/etc/containerd/config.toml,主要修改container的数据目录,并启用systemd的cgroup# 修改数据存储目录 root = "/home/apps/containerd" # 对于使用systemd作为init system的linux发行版,官方建议用systemd作为容器cgroup driver # false改成true SystemdCgroup = true重加载systemd配置,启动containerdsystemctl daemon-reload systemctl start containerd systemctl enable containerd简单验证下containerd是否正常# 查看systemd status systemctl status containerd # 查看image,正常情况下还没有image crictl images # 验证runc是否正常,如果输出有报错,可以参考"系统初始化"的第8步"安装依赖" runc --version安装kubelet和kubeadm本节步骤在所有k8s node都要操作。k8s的二进制文件安装包可以从github下载:cid:link_1在changelog中找到二进制包的下载链接,下载server binary即可,里面包含了master和node的二进制文件。解压下载好的压缩包,并将其中的二进制文件放到环境变量PATH目录下tar xf kubernetes-server-linux-amd64.tar.gz cd kubernetes/server/bin/ find . -type f -perm /u+x -exec cp {} /usr/local/bin/ \;新建或编辑kubelet的service文件 /usr/lib/systemd/system/kubelet.service[Unit] Description=kubelet: The Kubernetes Node Agent Documentation=https://kubernetes.io/docs/ Wants=network-online.target After=network-online.target [Service] ExecStart=/usr/local/bin/kubelet Restart=always StartLimitInterval=0 RestartSec=10 [Install] WantedBy=multi-user.target创建目录mkdir -p /usr/lib/systemd/system/kubelet.service.d/新建或编辑文件/usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf# Note: This dropin only works with kubeadm and kubelet v1.11+ [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file. EnvironmentFile=-/etc/sysconfig/kubelet ExecStart= ExecStart=/usr/local/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS启动kubeletsystemctl enable --now kubelet创建集群创建集群的步骤在control panel节点操作即可。初始化集群,这里主要指定k8s版本,可根据需求,参考kubeadm init --help提示配置初始化参数,比如pause镜像地址,pod ip范围等。kubeadm init --kubernetes-version v1.25.16如果init报错失败,可以查下containerd和kubelet的日志。失败后可以重置下kubeadm resetsystemctl status containerd journalctl -xeu containerd systemctl status kubelet journalctl -xeu kubelet如果init成功,控制台会输出worker node加入cluster的命令,将这个命令粘贴到worker node执行即可,比如:kubeadm join 192.168.0.11:6443 --token 123456 \ --discovery-token-ca-cert-hash sha256:123456init成功后,输出还会提示创建kubeconfig,根据提示操作即可mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config配置网络插件。k8s需要cni插件才能让pod之间正常通信,这里用的是calico插件# 下载配置文件。下载后可根据需求修改其中的image地址 wget https://docs.projectcalico.org/manifests/calico.yaml # 部署calico kubectl apply -f calico.yaml检查网络插件部署效果。只有全部ready都为1/1才算成功kubectl get nodes kubectl get pod -n kube-system测试集群部署完成后,可以起个pod试下能否正常调度# 创建一个pod。nginx需要提前docker pull kubectl create deployment nginx --image=nginx # 暴露端口 kubectl expose deployment nginx --port=80 --type=NodePort # 查看状态 kubectl get pods,svc
  • [技术干货] [linux]mark-tool
    前言在远程连接到linux进行操作时,经常要切换目录,有些目录切换频次较高,因此写了个shell工具,用于收藏目录、切换目录等。也不需要安装,直接添加脚本即可。配置首先声明脚本是基于bash shell,zsh和fish未经测试。编辑文件~/.bash_custom_functions,添加以下内容mark(){ local markfile="$HOME/.mark" if [ ! -f ${markfile} ]; then echo "${markfile} is not exist, create it." touch ${markfile} fi case $1 in l) cat -n ${markfile} ;; d) # delete if [ "x" == "x$2" ]; then echo "need a sequence number" return 1 fi if [ $2 -lt 0 ] || [ $2 -gt $(wc -l < ${markfile}) ]; then echo "invalid sequence number" return 1 fi sed -i "$2d" ${markfile} ;; a) # add / append local new_mark=$(pwd) local tmp_grep=$(grep ${new_mark} ${markfile}) if [ "x" == "x${tmp_grep}" ]; then echo "mark current dirname: ${new_mark}" echo ${new_mark} >> ${markfile} else echo "Warning! Duplicate mark" fi ;; c) # cd if [ "x" == "x$2" ]; then echo "need a sequence number" return 1 fi if [ $2 -lt 0 ] || [ $2 -gt $(wc -l < ${markfile}) ]; then echo "invalid sequence number" return 1 fi local target_dir=$(sed -n "$2p" ${markfile}) if [ ! -d ${target_dir} ]; then echo "${target_dir} not found" return 1 fi cd ${target_dir} ;; *) echo "Options: l(ist), a(dd), d(elete), c(hange)" esac }在~/.bashrc中追加以下内容以引入上一步的文件if [ -f ~/.bash_custom_functions ]; then . ~/.bash_custom_functions fisource生效,或者重建shell会话source ~/.bashrc
  • [技术干货] nginx参数调优能提升多少性能
    前言nginx安装后一般都会进行参数优化,网上找找也有很多相关文章,但是这些参数优化对Nginx性能会有多大影响?为此我做个简单的实验测试下这些参数能提升多少性能。声明一下,测试流程比较简单,后端服务也很简单,测试时间也很短,所以实验并不严谨,结果仅作参考,需要根据实际情况进行参数调优。文章或有错误和疏漏之处,欢迎各位大佬指出或补充。环境IP操作系统CPU内存部署服务192.168.3.60Debian 11.844 GBwrk192.168.3.61Debian 11.844 GBnginx192.168.3.62Debian 11.844 GB后端服务nginx:版本1.24.0,编译参数:./configure --with-threads --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_gunzip_module --with-http_gzip_static_module --with-stream --with-compat --with-pcre-jit --prefix=/home/admin/apps/nginx使用wrk进行性能测试,版本为 4.1.0,通过 apt 包管理器安装。因为主要测试nginx反向代理的性能,所以用go写了个响应"hello world"的api,减少后端服务导致的性能影响。测试方法:调整nginx参数后多次运行wrk,取平均值。(方法并不严谨,应该用更专业的工具测试运行几小时,将测试数据采用更科学的方法汇总,但时间精力有限,所以采用这个非常简单无脑的实验方法)实验结果下面的实验过程主要就是调参数,比较繁琐,所以把实验结果先放到前面。综合配置可参考“实验过程 - 13. 综合调优”。再次声明,由于测试流程和后端逻辑都比较简单,服务器和网络情况也没严格控制变量所以结果仅供参考。根据实验结果来看,增大工作进程数能直接提升性能,但不是和CPU核心数一致就能最大化,可能少一点才能达到最佳性能。除了nginx和系统参数调优,网络和后端服务对性能的影响也很大,而且在大部分ToB业务场景下,后端服务和数据库才是性能短板。序号测试方式Nginx参数优化项总请求数平均每秒请求数平均延迟优化效果1wrk -> 后端无413998468884.591.66ms+673%2wrk -> nginx -> 后端无,默认配置5348598911.3012.04ms-3.1wrk -> nginx -> 后端设置工作进程数为2102774517127.495.95ms+92.19%3.2wrk -> nginx -> 后端设置工作进程数为367665111274.058.97ms+26.51%3.3wrk -> nginx -> 后端设置工作进程数为auto(4)5477949125.6611.14ms+2.41%4wrk -> nginx -> 后端设置工作进程数和CPU亲和性为auto5377138958.1011.67ms+0.52%5wrk -> nginx -> 后端在4的基础上设置worker_connections 65535;5327588874.8511.80ms-0.4%6wrk -> nginx -> 后端在5的基础上设置accept_mutex on;4255407088.3915.58ms-20.45%7wrk -> nginx -> 后端在6的基础上设置multi_accept on5915009854.7710.60ms+10.58%8wrk -> nginx -> 后端在7的基础上设置改为upstream5586799308.3012.00ms+4.45%9wrk -> nginx -> 后端在8的基础上设置keepalive63267310541.4910.06ms+18.29%10wrk -> nginx -> 后端在9的基础上设置加一个后端100648516772.086.53ms+88.21%11wrk -> nginx -> 后端在2的基础上设置加一个后端61088210178.2610.21ms+14.21%12wrk -> nginx -> 后端在3.1的基础上设置keepalive104102417348.365.94ms+94.67%13wrk -> nginx -> 后端在2的基础上设置deferred5961979934.6110.90ms+11.48%14wrk -> nginx -> 后端在2的基础上修改内核参数5815359689.9110.95ms+8.73%15wrk -> nginx -> 后端综合调优108715118115.785.94ms+103.28%单独测试nginx的性能,避免后端服务和网络情况的影响。序号Nginx参数优化项总请求数平均每秒请求数平均延迟优化效果1无,默认配置232740038787.612.71ms-2在1的基础上设置工作进程数为auto7418729123633.13791.04us218.74%3在2的基础上设置CPU亲和性7437087123945.45784.02us219.54%4在3的基础上设置工作进程连接数和多请求7638947127300.44764.67us228.19%调整环境,nginx都采用默认配置,只是修改了各组件的位置。因为组件在同一台服务器,资源竞争情况也会影响性能。环境总请求数平均每秒请求数平均延迟wrk、nginx和后端各在不同的服务器5348598911.3012.04mswrk单独服务器,nginx和后端在同一台服务器3866306441.0516.24mswrk、nginx和后端在同一台服务器4021636700.3815.15ms实验过程1. 直连后端测试首先用wrk直接测试后端。因为没有中间商赚差价,所以理论上直连性能会比nginx代理的性能高。# curl 测试后端响应是否正常 curl http://192.168.3.62:8101 # wrk 直接测试后端服务。线程数为4,连接数为100,测试时间为60秒。 wrk -t4 -c100 -d60s http://192.168.3.62:8101wrk测试结果总请求数平均每秒请求数平均延迟413998468884.591.66ms2. 使用nginx默认配置代理nginx刚安装后有一个默认配置,这里只改了location /的配置,修改为反向代理到后端服务location / { #root html; #index index.html index.htm; proxy_pass http://192.168.3.62:8101; }wrk测试结果。相较于后端直连,性能缩水很多总请求数平均每秒请求数平均延迟5348598911.3012.04ms3. 增加工作进程数nginx默认工作进程数为1,通过修改worker_processes可指定,一般小于或等于CPU核心数worker_processes总请求数平均每秒请求数平均延迟对比默认配置1(默认)5348598911.3012.04ms-2102774517127.495.95ms+92.19%367665111274.058.97ms+26.51%auto(4)5477949125.6611.14ms+2.41%4. 设置CPU亲和性通过worker_cpu_affinity绑定工作进程和CPU,避免nginx进程在CPU之间切换导致的伪共享带来的性能问题。nginx配置:worker_processes auto; worker_cpu_affinity auto;wrk测试结果总请求数平均每秒请求数平均延迟对比默认配置5377138958.1011.67ms+0.52%5. 设置worker_connectionsworker_connections用于设置每个Nginx进程可处理并发连接的最大数,默认为1024。worker_processes auto; worker_cpu_affinity auto; events { worker_connections 65535; }wrk测试结果总请求数平均每秒请求数平均延迟对比默认配置5327588874.8511.80ms-0.4%6. 启用互斥锁nginx配置worker_processes auto; worker_cpu_affinity auto; events { worker_connections 65535; accept_mutex on; }wrk测试结果总请求数平均每秒请求数平均延迟对比默认配置4255407088.3915.58ms-20.45%7. 启用多请求支持默认情况下,每个工作进程一次只接受一个新连接。开启后,每个工作进程将接受所有的新连接。nginx配置worker_processes auto; worker_cpu_affinity auto; events { worker_connections 65535; accept_mutex on; multi_accept on; }wrk测试结果总请求数平均每秒请求数平均延迟对比默认配置5915009854.7710.60ms+10.58%8. 使用upstream之前的配置都通过proxy_pass直接反向代理到后端,修改为upstream。nginx配置worker_processes auto; worker_cpu_affinity auto; events { worker_connections 65535; accept_mutex on; multi_accept on; } http { upstream backend { server 192.168.3.62:8101; } server { location / { proxy_pass http://backend; } } }wrk测试结果。性能有所降低,但在多个后端的情况下,还是配置upstream更方便。总请求数平均每秒请求数平均延迟对比默认配置5586799308.3012.00ms+4.45%9. 设置keepalive长连接长连接的存在可以减少建立和关闭TCP连接带来的消耗和延迟。nginx配置worker_processes auto; worker_cpu_affinity auto; events { worker_connections 65535; accept_mutex on; multi_accept on; } http { upstream backend { server 192.168.3.62:8101; keepalive 32; keepalive_requests 2000; } server { location / { proxy_pass http://backend; } } }wrk测试结果总请求数平均每秒请求数平均延迟对比默认配置63267310541.4910.06ms+18.29%10. 增加后端实例数分别在默认配置和上一步的基础上,将后端实例数加1。修改后的nginx配置worker_processes auto; worker_cpu_affinity auto; events { worker_connections 65535; accept_mutex on; multi_accept on; } http { upstream backend { server 192.168.3.62:8101; server 192.168.3.62:8102; keepalive 32; keepalive_requests 2000; } server { location / { proxy_pass http://backend; } } }wrk测试结果配置总请求数平均每秒请求数平均延迟对比默认配置默认配置多后端61088210178.2610.21ms+14.21%默认配置,长连接,工作进程数2104102417348.365.94ms+94.67%修改配置多后端100648516772.086.53ms+88.21%11. 延迟处理新连接设置deferred参数可延迟处理新连接,加上这个配置后,当用户与nginx服务器建立连接时,只有用户有请求数据时才会将TCP连接状态改为ESTABLISHED,否则就直接丢弃这条连接。通过减少服务器和客户端之间发生的三次握手建立连接的数量来帮助提高性能。nginx配置worker_processes 1; events { worker_connections 1024; } http { server { listen 8100 deferred; } }wrk测试结果总请求数平均每秒请求数平均延迟对比默认配置5961979934.6110.90ms+11.48%12. 修改内核参数修改的内核参数如下# 网卡接受数据包的队列最大长度 net.core.netdev_max_backlog = 24800 # 已经收到syn包,但是还没有来得及确认的连接队列 net.ipv4.tcp_max_syn_backlog = 24800 # 端口监听队列的最大长度, 存放的是已经处于ESTABLISHED而没有被应用程序接管的TCP连接 net.core.somaxconn = 65535 # SYN的超时重传次数 net.ipv4.tcp_syn_retries = 2 # 服务端等待客户端响应ACK的超时重传次数 net.ipv4.tcp_synack_retries = 2 # 作为服务端才拥有TCP Fast Open机制 net.ipv4.tcp_fastopen = 2nginx的配置为默认配置。wrk测试结果总请求数平均每秒请求数平均延迟对比默认配置5815359689.9110.95ms+8.73%13. 综合调优开启多请求支持,增加工作进程连接数,配置长连接,增加后端实例,修改内核参数。如果不想一遍遍修改工作进程数,直接设置为auto最省事,虽然不一定会是最优配置,但总比默认强。nginx配置worker_processes auto; events { worker_connections 65535; multi_accept on; } http { upstream backend { server 192.168.3.62:8101; server 192.168.3.62:8102; keepalive 32; keepalive_requests 2000; } server { lister deferred backlog=24800; location / { proxy_pass http://backend; } } }内核参数net.core.netdev_max_backlog = 24800 net.ipv4.tcp_max_syn_backlog = 24800 net.core.somaxconn = 65535 net.ipv4.tcp_syn_retries = 2 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_fastopen = 2wrk测试结果总请求数平均每秒请求数平均延迟对比默认配置108715118115.785.94ms+103.28%14. 单独测试nginx以上测试场景都有nginx反向代理后端,而网络和后端也会在一定程度上影响nginx性能,所以这里单独测试nginx。nginx配置worker_processes auto; worker_cpu_affinity auto; events { worker_connections 65535; multi_accept on; } http { server { location / { return 200 'hello world'; } } }wrk测试结果。在没有反向代理的情况下,增加工作进程数就能直接提升nginx性能。序号Nginx参数优化项总请求数平均每秒请求数平均延迟优化效果1无,默认配置232740038787.612.71ms-2在1的基础上设置工作进程数为auto7418729123633.13791.04us218.74%3在2的基础上设置CPU亲和性7437087123945.45784.02us219.54%4在3的基础上设置工作进程连接数和多请求7638947127300.44764.67us228.19%
  • [技术干货] [kubernetes]服务健康检查
    前言进程在运行,但是不代表应用是正常的,对此pod提供的探针可用来检测容器内的应用是否正常。k8s对pod的健康状态可以通过三类探针来检查:LivenessProbe、ReadinessProbe和StartupProbe。健康检查探针LivenessProbe用于判断容器是否存活(Running状态),如果LivenessProbe探针检测到容器不健康,则kubelet“杀掉”容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的livenessprobe探针返回的值永远是success。ReadinessProbe用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的Pod,Service与Pod EndPoint 的关联关系也将基于Pod是否Ready进行设置。如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端EndPoint列表中隔离出去,后续再把恢复到Ready状态的Pod加到后端EndPoint列表。这样能保证客户端在访问service时不会被转发到服务不可用的Pod实例上。StartupProbe某些应用会遇到启动比较慢的情况,这种有且仅有一次的超长延时,使用StartupProbe更加适合。实现方式三种探针均可配置三种实现方式。ExecAction在容器内运行一个命令,如果该命令的返回码为0,则表明容器健康。以下示例中,通过运行cat /tmp/health 判断一个容器运行是否正常。在Pod运行后,将在创建文件后的10秒删除文件。LivenessProbe的初次探测时间(initialDelaySeconds)为15秒,探测结果为Fail,将导致kubelet杀掉该容器并重启。apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-exec spec: containers: - name: liveness image: busybox args: - /bin/sh - -c - echo ok > /tmp/health; sleep 10; rm -rf /tmp/health; sleep 600 livenessProbe: exec: command: - cat - /tmp/health initialDelaySeconds: 15 timeoutSeconds: 1TCPSocketAction通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。示例:apiVersion: v1 kind: Pod metadata: name: pod-with-healthcheck spec: containers: - name: nginx image: nginx ports: - containerPort: 80 livenessProbe: tcpSocket: port: 80 initialDelaySeconds: 30 timeoutSeconds: 1HTTPGetAction通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康。以下例子中,kubelet定时发送HTTP请求到 localhost:80/_status/healthz来进行容器应用的健康检查。apiVersion: v1 kind: Pod metadata: name: pod-with-healthcheck spec: containers: - name: nginx image: nginx ports: - containerPort: 80 livenessProbe: httpGet: path: /_status/healthz port: 80 initialDelaySeconds: 30 timeoutSeconds: 1主要参数initialDelaySeconds:健康检查探针的初次探测时间,单位为秒。例如设置为30的话,容器启动30秒后才会进行健康检测。periodSeconds:检测频率,单位为秒,默认值为10。最小值为1秒timeoutSeconds:探针检测的超时时间,默认为1秒。failureThreshold:最小连续探测失败次数,默认为3。如果连续3次探测失败,则将容器视为不健康。successThreshold:最小连续探测成功次数,默认为1。如果1次探测正常,则将容器视为健康。
  • [技术干货] [kubernetes]安装dashboard
    前言kubernetes官方文档中的web UI网页管理工具是kubernetes-dashboard,可提供部署应用、资源对象管理、容器日志查询、系统监控等常用的集群管理功能。为了在页面上显示系统资源的使用情况,需要部署 Metrics Server(参考博客园 - 安装metrics-server)。kubernetes版本:1.26.6创建资源对象官方yaml。github仓库地址:https://github.com/kubernetes/dashboard。这里的版本为 v2.7.0。用到的镜像分别为kubernetesui/dashboard:v2.7.0 和 kubernetesui/metrics-scraper:v1.0.8 。可以从docker hub直接下载,内网离线环境可以先传到内网的镜像仓库,然后镜像改成内网镜像地址。# Copyright 2017 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. apiVersion: v1 kind: Namespace metadata: name: kubernetes-dashboard --- apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard --- kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: # type: NodePort ports: - port: 443 targetPort: 8443 # nodeport: 30001 selector: k8s-app: kubernetes-dashboard --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-certs namespace: kubernetes-dashboard type: Opaque --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-csrf namespace: kubernetes-dashboard type: Opaque data: csrf: "" --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-key-holder namespace: kubernetes-dashboard type: Opaque --- kind: ConfigMap apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-settings namespace: kubernetes-dashboard --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard rules: # Allow Dashboard to get, update and delete Dashboard exclusive secrets. - apiGroups: [""] resources: ["secrets"] resourceNames: [ "kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf", ] verbs: ["get", "update", "delete"] # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. - apiGroups: [""] resources: ["configmaps"] resourceNames: ["kubernetes-dashboard-settings"] verbs: ["get", "update"] # Allow Dashboard to get metrics. - apiGroups: [""] resources: ["services"] resourceNames: ["heapster", "dashboard-metrics-scraper"] verbs: ["proxy"] - apiGroups: [""] resources: ["services/proxy"] resourceNames: [ "heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper", ] verbs: ["get"] --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard rules: # Allow Metrics Scraper to get metrics from the Metrics server - apiGroups: ["metrics.k8s.io"] resources: ["pods", "nodes"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard --- kind: Deployment apiVersion: apps/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: kubernetes-dashboard template: metadata: labels: k8s-app: kubernetes-dashboard spec: securityContext: seccompProfile: type: RuntimeDefault containers: - name: kubernetes-dashboard image: registry.elifen.cn/kubernetesui/dashboard:v2.7.0 imagePullPolicy: Always ports: - containerPort: 8443 protocol: TCP args: - --auto-generate-certificates - --namespace=kubernetes-dashboard # Uncomment the following line to manually specify Kubernetes API server Host # If not specified, Dashboard will attempt to auto discover the API server and connect # to it. Uncomment only if the default does not work. # - --apiserver-host=http://my-address:port volumeMounts: - name: kubernetes-dashboard-certs mountPath: /certs # Create on-disk volume to store exec logs - mountPath: /tmp name: tmp-volume livenessProbe: httpGet: scheme: HTTPS path: / port: 8443 initialDelaySeconds: 30 timeoutSeconds: 30 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1001 runAsGroup: 2001 volumes: - name: kubernetes-dashboard-certs secret: secretName: kubernetes-dashboard-certs - name: tmp-volume emptyDir: {} serviceAccountName: kubernetes-dashboard nodeSelector: "kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule --- kind: Service apiVersion: v1 metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboard spec: ports: - port: 8000 targetPort: 8000 selector: k8s-app: dashboard-metrics-scraper --- kind: Deployment apiVersion: apps/v1 metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboard spec: replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: dashboard-metrics-scraper template: metadata: labels: k8s-app: dashboard-metrics-scraper spec: securityContext: seccompProfile: type: RuntimeDefault containers: - name: dashboard-metrics-scraper image: registry.elifen.cn/kubernetesui/metrics-scraper:v1.0.8 ports: - containerPort: 8000 protocol: TCP livenessProbe: httpGet: scheme: HTTP path: / port: 8000 initialDelaySeconds: 30 timeoutSeconds: 30 volumeMounts: - mountPath: /tmp name: tmp-volume securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1001 runAsGroup: 2001 serviceAccountName: kubernetes-dashboard nodeSelector: "kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule volumes: - name: tmp-volume emptyDir: {}发布到集群:kubectl create -f kube-dashboard.yaml使用nodePort访问dashboardk8s官方文档给的示例是用kube-proxy,这里用的nodePort,稍微改动下原yaml中的kubernetes-dashboard服务,加了nodePort的配置。kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: type: NodePort ports: - port: 443 targetPort: 8443 nodeport: 30001 selector: k8s-app: kubernetes-dashboard应用:kubectl apply -f kube-dashboard.yaml若运行正常,浏览器访问 https://<节点IP>:30001,理应显示dashboard的界面,接下来生成用于登录的token。使用token访问创建一个serviceaccountapiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard或者使用命令kubectl create serviceaccount admin-user -n kubernetes-dashboard授予cluster-admin的集群管理员权限apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard使用命令kubectl create clusterrolebinding admin-user --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:admin-user获取tokenkubectl -n kubernetes-dashboard create token admin-user页面填入token登录。 
  • [技术干货] [kubernetes]安装metrics-server
    前言metrics server为Kubernetes自动伸缩提供一个容器资源度量源。metrics-server 从 kubelet 中获取资源指标,并通过 Metrics API 在 Kubernetes API 服务器中公开它们,以供 HPA 和 VPA 使用。之前已经用k8s的二进制文件搭建了一套集群环境,搭建步骤见:二进制部署k8s集群-基于containerd。现需要在这个集群环境内部署Metrics-Server,用于配置应用自动伸缩。集群环境:主机:Debian 11Kubernetes版本:1.26.6步骤获取yaml文件。wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server.yaml编辑yaml文件。之前部署集群用的自签名证书,metrics-server直接请求kubelet接口会证书校验失败,因此deployment中增加- --kubelet-insecure-tls参数。另外镜像原先在registry.k8s.io,国内下载不方便,下面的配置中修改成了国内镜像仓库地址。内网环境中可以先下载,然后再推到内网镜像仓库,镜像也改成内网镜像地址。apiVersion: apps/v1 kind: Deployment metadata: labels: k8s-app: metrics-server name: metrics-server namespace: kube-system spec: # ... template: spec: containers: - args: - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=15s - --kubelet-insecure-tls image: registry.cn-hangzhou.aliyuncs.com/rainux/metrics-server:v0.6.4发布kubectl apply -f metrics-server.yaml查看是否在运行kubectl get pods -n kube-system | grep metrics获取集群的指标数据kubectl get --raw /apis/metrics.k8s.io/v1beta1 | python3 -m json.tool根据输出可见,集群提供nodes和pods的资源指标。{ "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "metrics.k8s.io/v1beta1", "resources": [ { "name": "nodes", "singularName": "", "namespaced": false, "kind": "NodeMetrics", "verbs": [ "get", "list" ] }, { "name": "pods", "singularName": "", "namespaced": true, "kind": "PodMetrics", "verbs": [ "get", "list" ] } ] }测试kubectl top nodestop命令kubectl top命令用来查看node节点和pod的资源使用情况。# 查看 top 命令的帮助 kubectl top --help # 查看node节点的资源使用情况 kubectl top node # 查看pod的资源使用情况 kubectl top pod # 查看所有命名空间的pod资源使用情况 kubectl top pod -A转载自https://www.cnblogs.com/XY-Heruo/p/17669633.html