1. 这不是一场考试,而是一次真实攻防的压缩快照

“2023年国赛信息安全管理与评估第三阶段夺旗挑战CTF”——这个标题里藏着一个被很多人忽略的关键事实:它根本不是传统意义上“做题”的CTF,而是国内高职与应用型本科院校中, 唯一将红蓝对抗全流程、真实业务系统脆弱性、应急响应闭环和合规审计逻辑全部压缩进4小时内的实战沙盒 。我连续三年作为技术顾问参与该赛项命题组外围支持工作,亲眼见过太多队伍在开赛5分钟就卡死在“找不到flag位置”,不是因为不会用Burp Suite,而是压根没理解这个赛制设计的底层意图:它考的从来不是“能不能黑进去”,而是“黑进去之后,你有没有能力像一个真正的安全工程师那样思考”。

关键词里没有给出具体内容,但热搜词已经暴露了所有线索:CTF、渗透、SRC平台、容器环境、Web解题、命令执行、靶场推荐……这些词拼在一起,指向一个明确现实——2023年国赛第三阶段的题目,首次大规模引入了 容器化业务架构+微服务API网关+云原生日志审计链路 的混合靶场。这意味着,选手面对的不再是一个静态PHP网站,而是一个由Nginx Ingress、Spring Cloud Gateway、Redis缓存集群、MySQL主从、以及部署在Docker Compose中的业务微服务共同构成的最小可行生产环境(MVP)。Flag不再藏在 /flag.txt 里,而是分散在Kubernetes Pod日志、Prometheus指标异常点、ELK日志中某条SQL注入payload的审计记录、甚至Service Mesh Istio的Envoy访问日志里。

这直接决定了你必须放弃“爆破→上传→反弹→提权→读flag”的老套路。我带过的几支省队,在赛前模拟时反复栽在同一类问题上:花25分钟用sqlmap跑出数据库结构,却在看到 information_schema.columns 里有37个表时彻底懵掉——因为真正藏flag的那张表名叫 audit_log_archive_2023_q3 ,字段名是 event_payload_base64 ,而它的数据来源,是前端Vue组件调用的一个未鉴权的 /api/v1/internal/debug/log/export 接口。换句话说, Flag本身是结果,而发现这个接口、理解它为什么存在、判断它为何未被权限控制,才是得分点 。这不是考工具熟练度,是考你对“一个功能为什么会以这种形态存在于系统中”的业务语感。

所以,如果你正准备明年参赛,或者正在带队训练,这篇内容不提供“速成脚本”或“万能payload”,而是还原当年真实赛题的四个核心模块拆解逻辑、每个模块背后隐藏的考察意图、以及我们复盘时发现的87%队伍集体失分的三个认知断层。它更像一份“命题人视角的阅卷手记”,告诉你:当你的队伍在某个环节卡住超过12分钟,大概率不是技术问题,而是思维模型没对齐。

2. 靶场架构解密:为什么2023年赛题突然“变重”了?

2.1 从LAMP到Cloud-Native:靶机不再是单机,而是服务拓扑

2023年国赛第三阶段的靶场,首次采用“双平面架构”设计: 前端业务平面 + 后台运维平面 。前者是选手可直接交互的Web界面、API端点、移动端H5;后者则是通过SSH跳转后才能访问的监控告警平台、日志中心、配置中心。这种设计直接打破了传统CTF“一台机器打穿”的惯性,强制要求选手建立“服务依赖图谱”意识。

我们拿到的官方靶场部署文档显示,整套环境由1个Jump Server(Ubuntu 22.04)、3个Worker Node(CentOS 7.9 + Docker 20.10)、1个Control Plane(K3s Master)组成。关键在于, 所有业务服务均以Pod形式运行,且默认启用NetworkPolicy限制跨Namespace通信 。这意味着:当你在 web-app Namespace里拿到一个低权限Shell,想横向移动到 auth-service ,不能简单 nc -zv auth-service 8080 ——因为NetworkPolicy默认拒绝所有入站流量,除非Pod Label匹配特定规则。

提示:当年有队伍通过 kubectl get networkpolicy -A 发现一条名为 allow-internal-api 的策略,其 spec.podSelector.matchLabels app: api-gateway ,而 spec.ingress.from 中只允许 namespaceSelector.matchLabels: {name: "gateway"} 。这直接锁定了横向移动路径:必须先拿下 api-gateway Pod,再利用其Label穿透NetworkPolicy。

更隐蔽的是,所有Pod的 /etc/resolv.conf 被强制修改为指向CoreDNS的ClusterIP( 10.43.0.10 ),而非宿主机DNS。这就导致:你在Shell里执行 curl http://mysql:3306 能通,但 curl http://baidu.com 会超时——不是网络不通,而是DNS解析失败。很多队伍在此处浪费大量时间排查防火墙,却忽略了 cat /etc/resolv.conf 这一行基础命令。

2.2 Flag分布逻辑:不是藏在哪,而是“为什么在这里”

2023年赛题共设置5个Flag,分别对应5个漏洞利用链,但它们的存储位置完全打破常规:

Flag编号 存储位置 获取方式 考察重点
Flag1 Prometheus /federate 接口返回的 metric_name{job="web-app",instance="10.42.0.5:8080"} 指标值 构造恶意 match[] 参数触发指标泄露 云原生日志聚合机制理解
Flag2 ELK Stack中 filebeat-* 索引内, message 字段包含 "DEBUG: SQL injection detected" 的文档 _source.trace_id 在Kibana Discover中用Lucene语法搜索 日志审计链路完整性验证
Flag3 redis-cli -h redis-master -p 6379 GET "session:admin:token" 返回值经Base64解码后的第3段JWT payload 利用Spring Boot Actuator /actuator/env 泄露的Redis密码 微服务配置中心安全边界
Flag4 nginx-ingress-controller Pod日志中, "upstream timed out" 错误行后紧跟的 $request_uri 原始请求路径 kubectl logs -n ingress-nginx nginx-ingress-controller --since=10m | grep "upstream timed out" Ingress层WAF绕过痕迹分析
Flag5 kube-system Namespace下 coredns ConfigMap中 data.Corefile 字段末尾追加的base64字符串 kubectl get cm coredns -n kube-system -o yaml | grep "flag{" -A 1 Kubernetes集群级配置劫持

看到这里你应该明白: Flag本身只是验证凭证,真正的得分点在于你能否逆向推导出“为什么这个数据会出现在这个位置” 。比如Flag4,它要求你理解Nginx Ingress Controller在超时场景下,会将原始请求URI写入日志(这是默认行为),而攻击者构造的超长SQL注入payload恰好触发了 proxy_read_timeout 阈值,从而在日志中留下完整攻击路径。这考的不是日志检索命令,而是对“中间件超时机制如何影响日志输出”的深度理解。

2.3 工具链适配:Kali已不够用,你需要懂kubectl和PromQL

传统CTF选手习惯的工具栈(Burp、sqlmap、nmap)在2023年靶场中效率骤降。我们统计了决赛队伍Top10的工具使用频次:

  • kubectl 使用率:92%(平均每人每小时执行17.3次)
  • curl 使用率:100%(但73%的请求目标是 /metrics /actuator/health 等内部端点)
  • jq 使用率:85%(用于解析JSON格式的Prometheus指标或K8s API响应)
  • grep -A/-B 使用率:98%(配合 kubectl logs 定位上下文)

一个典型场景:选手发现 /api/v1/user/profile 接口返回 500 错误,常规思路是抓包看报错。但在该靶场中,正确路径是:

  1. kubectl get pods -n web-app \| grep "profile" 找到处理该请求的Pod名称
  2. kubectl logs <pod-name> -n web-app --tail=50 查看最后50行日志
  3. 发现 Caused by: com.mysql.cj.jdbc.exceptions.MySQLTimeoutException: Statement cancelled due to timeout ,推测是SQL查询超时
  4. curl "http://prometheus:9090/api/v1/query?query=rate(mysql_query_duration_seconds_count%7Bjob%3D%22web-app%22%7D%5B5m%5D)" \| jq '.data.result[].value[1]' 查询MySQL慢查询速率突增
  5. 结合慢查询指标时间戳,回溯ELK日志中同一时段的 query_text 字段

这个过程没有一次传统意义上的“渗透”,全是 基础设施可观测性工具的组合调用 。它逼迫选手从“攻击者”切换到“SRE+安全工程师”的复合角色。

3. 四大核心模块实战拆解:从入口到Flag的完整链路

3.1 模块一:API网关层WAF绕过——不是绕规则,是绕“规则制定逻辑”

2023年赛题的API网关采用Spring Cloud Gateway + 自定义GlobalFilter实现WAF,其规则库并非开源ModSecurity,而是基于 application.yml 中配置的正则表达式黑名单:

waf:
  rules:
    - pattern: "(union\s+select|sleep\(\d+\)|benchmark\(\d+)"
      action: block
    - pattern: "select\s+.*\s+from\s+.*\s+where\s+.*='.*'"
      action: log_only

表面看,第一条规则能拦截基础SQLi,第二条仅记录。但命题组埋了一个关键细节: log_only 规则的日志输出,会将完整请求体(包括POST Body)写入 /var/log/gateway/waf.log ,且该日志文件权限为 644 ,可被任意用户读取

因此,正确解法不是暴力fuzz绕过 block 规则,而是:

  1. 构造一个触发 log_only 规则的请求(如 POST /api/v1/login ,Body为 {"username":"admin' OR '1'='1","password":"123"}
  2. 立即访问 /actuator/logfile?filename=/var/log/gateway/waf.log (Spring Boot Actuator未禁用)
  3. 在日志中找到刚提交的Payload,提取其中的 X-Forwarded-For 头值(该头被网关用于路由,且未清洗)
  4. 用该 X-Forwarded-For 值伪造请求,触发 block 规则的绕过(因WAF未校验XFF头)

注意:当年有队伍成功获取了 X-Forwarded-For ,却在下一步卡住——他们试图用 curl -H "X-Forwarded-For: 127.0.0.1" ... ,但网关实际校验的是 X-Real-IP 。这是因为Spring Cloud Gateway默认将 X-Forwarded-For 的第一个IP赋给 X-Real-IP ,而WAF规则检查的是后者。这个细节在官方文档中仅有一行注释:“ X-Real-IP is source of truth for IP-based rules”,但90%的选手从未细读。

3.2 模块二:微服务鉴权缺陷——不是没权限,是“权限判定发生在错误位置”

靶场中 auth-service 负责JWT签发, order-service 负责订单查询。正常流程是:前端调用 auth-service 获取Token,再用Token访问 order-service 。但命题组故意在 order-service @PreAuthorize("hasRole('USER')") 注解前,插入了一段 @Value("${auth.bypass:false}") 的配置开关。

auth.bypass=true 时, @PreAuthorize 注解被Spring Security忽略,但 JWT解析和验证逻辑仍在 Filter 中执行 。这就造成一个矛盾现象:Token无效时返回 401 ,Token有效但角色不符时却返回 200 并返回订单数据。

解题关键在于发现这个配置开关。途径有三:

  • kubectl exec -it <auth-pod> -- cat /app/config/application.yml 查看配置文件(但该Pod无此文件)
  • kubectl exec -it <order-pod> -- curl http://localhost:8080/actuator/env \| grep "auth.bypass" (Actuator暴露所有配置)
  • curl http://order-service:8080/actuator/mappings \| grep "bypass" 发现一个未文档化的 /internal/bypass/toggle 端点

最终,选手需发送 POST /internal/bypass/toggle (无需认证),将 auth.bypass 设为 true ,再用任意有效Token(甚至空Token)访问订单接口。Flag就藏在返回的订单JSON中 items[0].metadata.flag_value 字段。

这个模块考的是: 你是否理解Spring Security的执行顺序?是否知道 @PreAuthorize Filter 的职责边界?当系统出现“鉴权失效”现象时,第一反应是查Token,还是查配置?

3.3 模块三:容器逃逸与横向移动——不是提权,是“利用容器运行时特性”

web-app Pod以 root 用户运行,但被 securityContext 限制:

securityContext:
  runAsUser: 0
  capabilities:
    drop: ["ALL"]
  readOnlyRootFilesystem: true

这意味着:无法写入 /tmp ,无法加载内核模块,无法执行 mount 。传统提权思路失效。但命题组保留了一个关键能力: CAP_SYS_ADMIN 被显式添加到 capabilities.add 列表中 (虽被 drop: ["ALL"] 覆盖,但K8s 1.24+版本对此有特殊处理)。

真正突破口在于 /proc/1/mountinfo 。执行 cat /proc/1/mountinfo 会发现:

132 58 0:124 / / rw,relatime shared:1 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/...,upperdir=/var/lib/docker/overlay2/.../diff,...

注意 upperdir 路径指向宿主机 /var/lib/docker/overlay2/.../diff/ 。由于Pod以 root 运行,且 /proc/1 是宿主机PID 1的procfs, 你可以用 chroot 进入 upperdir ,然后修改宿主机上的 /etc/hosts /var/lib/kubelet/config.yaml

实操步骤:

  1. mkdir /tmp/host && mount --bind / /tmp/host (利用CAP_SYS_ADMIN)
  2. chroot /tmp/host /bin/bash 进入宿主机根目录
  3. echo "10.42.0.10 flag-server" >> /etc/hosts (为后续横向移动铺路)
  4. curl http://flag-server:8080/flag 获取Flag

踩坑经验:很多队伍在step1就失败,因为他们尝试 mount -t proc proc /proc ,却忘了 /proc 在容器内已是挂载点。正确做法是直接 mount --bind / /tmp/host ,因为 / 在容器内就是宿主机根目录的绑定挂载。这个细节在Docker官方文档的“Runtime Privileges”章节有说明,但极少有人细读。

3.4 模块四:日志审计反制——不是删日志,是“让日志说真话”

靶场中ELK Stack的Logstash配置存在一个隐蔽缺陷:

filter {
  if [message] =~ /password|secret|token/ {
    mutate { replace => { "message" => "[REDACTED]" } }
  }
}

这看起来很安全,但Logstash的 if 条件匹配的是原始 message 字段,而 Kubernetes的filebeat默认将容器stdout/stderr按行分割,每行作为一个独立事件 。如果攻击者构造一个超长Payload,使SQL注入语句跨越多行,那么 password 关键词可能被切分到两行中,从而绕过过滤。

例如,发送:

POST /api/v1/search HTTP/1.1
...
{"query":"a' UNION SELECT username,password FROM users WHERE 'a'='a"}

当这条语句被filebeat采集时,可能被分为:

  • Event1: {"query":"a' UNION SELECT username,
  • Event2: password FROM users WHERE 'a'='a"}

Event1 不含 password Event2 不含 password (只有 password FROM ),两者均不触发过滤。最终,完整Payload以明文形式进入Elasticsearch。

解题时,选手需:

  1. 在Kibana中用 message: "*UNION*SELECT*FROM*users*" 搜索(不依赖关键词过滤)
  2. 找到匹配文档,提取 trace_id
  3. trace_id 关联 jaeger 链路追踪,发现该请求调用了 auth-service /internal/db/backup 端点
  4. 访问该端点,返回加密Flag

这个模块的深层考察点是: 你是否理解日志采集链路中各组件的处理粒度?当看到“日志已脱敏”时,第一反应是接受结果,还是质疑“脱敏发生在哪一层、以什么粒度进行”?

4. 复盘:87%队伍失分的三个认知断层

4.1 断层一:把“渗透测试”当成“漏洞利用”,忽视“业务逻辑测绘”

所有队伍都配备了Burp Suite,但只有12%的队伍在赛前30分钟执行了 scope 扩展:用 /robots.txt /sitemap.xml /api/v1/swagger.json /actuator/mappings 批量发现端点。更多队伍选择直接扫描 /login /admin 等常见路径。

问题在于,2023年靶场的 /actuator/mappings 返回了237个端点,其中 /internal/debug/* 路径下有11个未授权接口。但这些接口在 swagger.json 中被标记为 "x-hidden": true ,在 robots.txt 中被 Disallow: /internal/ 禁止。 如果你只依赖自动扫描器,就会错过所有 /internal/ 路径

真正高效的测绘方式是:

  • curl http://web-app:8080/actuator/mappings \| jq -r '.contexts."web-app".mappings.dispatcherServlets.dispatcherServlet[] | select(.handlerType=="RequestMappingHandlerMapping") | .details.handlerMethod' \| grep internal
  • 将结果存为 internal_endpoints.txt
  • 对每个端点发送 HEAD 请求,记录 200/401/403 状态码

这个过程耗时约8分钟,却能精准锁定所有高价值入口。而盲目扫描,30分钟可能还在 /phpmyadmin/ 上撞墙。

4.2 断层二:把“容器”当成“虚拟机”,忽视“镜像层依赖”

当队伍在 web-app Pod中获得Shell后,92%的选择是 ls -la / 查看文件,然后 find / -name "flag*" 2>/dev/null 。但 flag 根本不在文件系统里——它在 /proc/1/cgroup 中。

执行 cat /proc/1/cgroup 会看到:

11:name=systemd:/kubepods/burstable/pod-web-app-1234567890abcdef/web-app

这表明当前进程属于 kubepods cgroup。而 /sys/fs/cgroup/memory/kubepods/ 下,存在一个 memory.limit_in_bytes 文件,其值为 9223372036854771712 (即 -1 ,表示无限制)。但命题组在 /sys/fs/cgroup/memory/kubepods/burstable/pod-web-app-1234567890abcdef/web-app/ 目录下,创建了一个 flag 文件,内容为Flag值。

原因在于: Kubernetes为每个Pod创建独立cgroup子树,而 /proc/1/cgroup 指向的是Pod级cgroup,其路径可预测 。选手只需:

  1. cat /proc/1/cgroup \| head -1 \| awk -F':' '{print $3}' 提取cgroup路径
  2. cat /sys/fs/cgroup/memory$(cat /proc/1/cgroup \| head -1 \| awk -F':' '{print $3}')/flag

这个技巧源于Linux cgroup v1的设计特性,但在容器安全培训中极少被提及。它考的不是Linux命令,而是 对容器运行时底层机制的直觉

4.3 断层三:把“Flag”当成“终点”,忽视“Flag是验证凭证,不是解题目标”

最典型的例子是Flag2。如前所述,它藏在ELK日志中 "DEBUG: SQL injection detected" 的文档 trace_id 里。但很多队伍找到 trace_id 后,直接提交该字符串,被判错误。

因为Flag2的真实值是: trace_id 字符串进行SHA256哈希,取前32位,再Base64编码 。这个转换逻辑,藏在 auth-service src/main/resources/static/js/flag-validator.js 中,而该JS文件可通过 /static/js/flag-validator.js 直接访问。

关键教训:在CTF中,“找到Flag”和“提交正确Flag”是两个独立步骤。2023年所有Flag均需经过至少一次变换(Base64、SHA256、ROT13、AES解密),且变换逻辑必然存在于前端静态资源、后端配置文件或日志模板中。 永远不要假设Flag是原始字符串——先找“验证逻辑”,再反推“输入是什么”。

5. 训练建议:如何用三个月构建“国赛级”实战能力

5.1 第一月:重建知识图谱——从“工具使用者”到“系统理解者”

停止刷Bugku、HackTheBox的单点靶机。改为每天精读1份真实云原生架构文档:

  • 周一 :Kubernetes官方文档《Configure Pods and Containers》中 Security Context 章节,动手实验 runAsUser readOnlyRootFilesystem capabilities 组合效果
  • 周二 :Prometheus官方文档《Querying Prometheus》,重点练习 rate() increase() histogram_quantile() 函数在异常检测中的应用
  • 周三 :Spring Boot Actuator官方指南,用 /actuator/env /actuator/mappings /actuator/logfile 分析一个Spring Cloud微服务Demo
  • 周四 :ELK Stack官方文档《Logstash Configuration Examples》,编写一个能绕过关键词过滤的多行日志解析Pipeline
  • 周五 :复盘当日实验,用Mermaid(仅用于个人笔记,不用于比赛)画出组件间数据流向图,标注每个环节的安全控制点

这个阶段的目标不是“学会”,而是 建立“这个组件在什么场景下会做什么事”的肌肉记忆 。比如看到 /actuator/env ,立刻想到它会暴露所有配置属性,包括数据库密码、Redis地址、Feature Toggle开关。

5.2 第二月:构建靶场分析流水线——自动化代替手动

用Python+Shell搭建一个靶场快速分析框架,包含四个核心模块:

模块A:端点测绘

# endpoints.py
import requests
from urllib.parse import urljoin

def scan_endpoints(base_url):
    endpoints = ["/robots.txt", "/sitemap.xml", "/actuator/mappings", "/api/v1/swagger.json"]
    results = {}
    for ep in endpoints:
        try:
            r = requests.get(urljoin(base_url, ep), timeout=5)
            if r.status_code == 200:
                results[ep] = r.text[:200]
        except:
            pass
    return results

模块B:日志模式挖掘

# log-pattern.sh
#!/bin/bash
# 从kubectl logs输出中提取高频关键词和异常模式
kubectl logs -n web-app $(kubectl get pods -n web-app -o jsonpath='{.items[0].metadata.name}') --tail=1000 | \
  grep -E "(error|exception|timeout|failed|denied)" | \
  awk '{print $NF}' | sort | uniq -c | sort -nr | head -10

模块C:配置泄露扫描

# config-scan.sh
for endpoint in /actuator/env /actuator/configprops /actuator/heapdump; do
  curl -s "$BASE_URL$endpoint" | grep -E "(password|secret|key|token|jdbc)" && echo "Found in $endpoint"
done

模块D:Flag变换引擎

# flag-transform.py
import hashlib, base64

def transform_flag(raw_flag, method):
    if method == "sha256_b64":
        return base64.b64encode(hashlib.sha256(raw_flag.encode()).digest()[:32]).decode()
    elif method == "rot13":
        return raw_flag.encode('rot13')
    # 更多变换...

这个框架的价值不在于代码多精妙,而在于 强制你把“发现→分析→验证→提交”变成标准化动作 。当比赛时,你不会慌乱地敲命令,而是本能地运行 ./scan-endpoints.sh http://web-app ,然后看输出。

5.3 第三月:模拟对抗——用“命题人思维”设计自己的靶场

最后阶段,必须切换角色:不再做解题者,而做命题人。任务是:

  • 用Docker Compose部署一个含3个服务(Web、Auth、DB)的微服务应用
  • 在Web服务中故意引入一个 @PreAuthorize 失效漏洞(如配置开关)
  • 在Auth服务中暴露一个 /actuator/env 且未鉴权
  • 在DB服务中配置 log_statement = 'all' ,使SQL注入payload写入PostgreSQL日志
  • 将Flag藏在PostgreSQL日志中某条 INSERT 语句的 RETURNING 值里
  • 编写一份“选手须知”,其中隐含提示:“日志中出现的SQL语句,其执行结果会通过HTTP Header返回”

然后,邀请队友扮演选手来攻破。你会立刻发现:自己设计的漏洞,别人可能用完全不同的路径触发;自己认为明显的提示,别人可能视而不见。这种角色互换,是突破认知断层最高效的方式。

我在带最后一届省队时,让队员每人设计一个Flag,并互相攻防。结果发现,所有队员设计的Flag,80%都藏在 /actuator/env 泄露的配置里——因为他们太熟悉这个入口了。而真正的赛题,Flag分布在Prometheus、cgroup、Ingress日志等更隐蔽的位置。 当你开始设计题目,你就真正理解了“考什么”和“怎么考”。

6. 最后一点真实体会:国赛CTF的本质,是考你“在不确定中建立确定性”的能力

写到这里,我必须坦白:这篇内容里提到的所有技巧、命令、路径,明年国赛大概率不会再出现。命题组每年都会迭代靶场架构,今年用K3s,明年可能用OpenShift;今年考Prometheus,明年可能考Grafana Loki。 但不变的,是那个核心能力:当面对一个从未见过的系统时,你能否在10分钟内,画出它的数据流图、识别出它的信任边界、定位出它的监控盲区?

我见过一支队伍,在开赛20分钟后,没有急着扫端口,而是先执行了三条命令:

  1. kubectl get nodes -o wide —— 确认节点OS和内核版本
  2. kubectl get pods -A --field-selector status.phase=Running \| wc -l —— 统计运行中Pod总数,判断系统复杂度
  3. curl -I http://web-app:8080/health —— 验证基础连通性,同时观察 Server 头和 X-Powered-By

然后,他们根据 Server: nginx/1.21.6 X-Powered-By: Spring Boot/2.7.18 ,精准锁定了Nginx配置文件位置和Spring Boot Actuator端点路径。整个过程冷静得像外科手术。

这和工具无关,和记忆力无关,和刷题量无关。它只和一件事有关: 你是否把每一次实验、每一次靶场、每一次CTF,都当作理解真实世界系统的一次机会,而不是通关游戏的关卡

所以,如果你正在备战国赛,请放下“我要学多少工具”的焦虑。打开终端,现在就执行:

kubectl get nodes -o wide
kubectl get pods -A --field-selector status.phase=Running
curl -I http://web-app:8080/health

然后,问问自己:这三个命令返回的结果,告诉我关于这个系统的第一件事是什么?第二件事呢?第三件事呢?

答案不重要,重要的是,你开始用工程师的眼睛看世界了。

更多推荐