479 lines
21 KiB
Python
479 lines
21 KiB
Python
#!/usr/bin/env python3
|
||
"""Generate cumulative 04-02..04-11 nodejs-demo YAML (Core→Plus→Pro doc order)."""
|
||
from pathlib import Path
|
||
from textwrap import dedent
|
||
|
||
DIR = Path(__file__).resolve().parents[1] / "labs/nodejs/manifests"
|
||
|
||
CM = dedent(
|
||
"""\
|
||
apiVersion: v1 # ConfigMap API 版本
|
||
kind: ConfigMap # 配置资源:ConfigMap
|
||
metadata: # ConfigMap 元信息
|
||
name: nodejs-demo-config # ConfigMap 名称
|
||
namespace: default # 命名空间
|
||
data: # 配置键值
|
||
APP_MSG: "Hello from ConfigMap" # 注入给应用的消息内容
|
||
"""
|
||
).strip()
|
||
|
||
SVC_8080 = dedent(
|
||
"""\
|
||
apiVersion: v1 # Service API 版本
|
||
kind: Service # Service 资源
|
||
metadata: # Service 元信息
|
||
name: nodejs-demo # Service 名称
|
||
namespace: default # 命名空间
|
||
spec: # Service 规格
|
||
selector: # 选择后端 Pod
|
||
app: nodejs-demo # 选中 app=nodejs-demo
|
||
ports: # 端口映射
|
||
- port: 80 # Service 暴露端口
|
||
targetPort: 8080 # 转发到容器端口
|
||
"""
|
||
).strip()
|
||
|
||
ING_NODE = dedent(
|
||
"""\
|
||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||
kind: Ingress # Ingress 资源
|
||
metadata: # Ingress 元信息
|
||
name: nodejs-demo # Ingress 名称
|
||
namespace: default # 命名空间
|
||
annotations: # Traefik 注解
|
||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||
spec: # Ingress 规则
|
||
rules: # 规则列表
|
||
- http: # HTTP 路由
|
||
paths: # 路径列表
|
||
- path: /node # 匹配路径前缀
|
||
pathType: Prefix # 前缀匹配
|
||
backend: # 后端目标
|
||
service: # 后端 Service
|
||
name: nodejs-demo # Service 名称
|
||
port: # Service 端口
|
||
number: 80 # 端口号
|
||
"""
|
||
).strip()
|
||
|
||
ING_HOST = dedent(
|
||
"""\
|
||
apiVersion: networking.k8s.io/v1 # Ingress API 版本
|
||
kind: Ingress # Ingress 资源
|
||
metadata: # Ingress 元信息
|
||
name: nodejs-demo # Ingress 名称
|
||
namespace: default # 命名空间
|
||
annotations: # Traefik 注解
|
||
traefik.ingress.kubernetes.io/router.entrypoints: web # 使用 web(HTTP) 入口
|
||
spec: # Ingress 规则
|
||
rules: # 规则列表
|
||
- host: app.example.local # 主机名匹配
|
||
http: # HTTP 路由
|
||
paths: # 路径列表
|
||
- path: /api # 匹配 API 路径前缀
|
||
pathType: Prefix # 前缀匹配
|
||
backend: # 后端目标
|
||
service: # 后端 Service
|
||
name: nodejs-demo # Service 名称
|
||
port: # Service 端口
|
||
number: 80 # 端口号
|
||
"""
|
||
).strip()
|
||
|
||
# 与 Deployment 模板中 ` ports:` 同级(勿对整段 dedent,否则会剥掉缩进)
|
||
PROBES = (
|
||
" livenessProbe: # 存活探针\n"
|
||
" httpGet: # HTTP 探测\n"
|
||
" path: / # 探测路径\n"
|
||
" port: 8080 # 探测端口\n"
|
||
" initialDelaySeconds: 3 # 初始延迟\n"
|
||
" periodSeconds: 10 # 探测周期\n"
|
||
" readinessProbe: # 就绪探针\n"
|
||
" httpGet: # HTTP 探测\n"
|
||
" path: / # 探测路径\n"
|
||
" port: 8080 # 探测端口\n"
|
||
" initialDelaySeconds: 2 # 初始延迟\n"
|
||
" periodSeconds: 5 # 探测周期\n"
|
||
)
|
||
|
||
RES = (
|
||
" resources: # 资源请求与限制\n"
|
||
" requests: # 最小资源请求\n"
|
||
" cpu: \"50m\" # 请求 CPU\n"
|
||
" memory: \"64Mi\" # 请求内存\n"
|
||
" limits: # 资源上限\n"
|
||
" cpu: \"500m\" # CPU 限制\n"
|
||
" memory: \"256Mi\" # 内存限制\n"
|
||
)
|
||
|
||
|
||
def main() -> None:
|
||
# 04-02: 01 + 仅改监听 8080(无 ConfigMap)
|
||
doc2 = dedent(
|
||
"""\
|
||
# 对应文档:docs/04-02-nodejs-端口与Service.md
|
||
# 累积:04-01 + 容器与 Service 改监听 8080(与后续探针一致)
|
||
apiVersion: apps/v1 # Deployment API 版本
|
||
kind: Deployment # 工作负载:Deployment
|
||
metadata: # Deployment 元信息
|
||
name: nodejs-demo # Deployment 名称
|
||
namespace: default # 命名空间
|
||
spec: # Deployment 规格
|
||
replicas: 1 # 副本数
|
||
selector: # Deployment 选择器
|
||
matchLabels: # 标签匹配集合
|
||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||
template: # Pod 模板
|
||
metadata: # Pod 元信息
|
||
labels: # Pod 标签
|
||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||
spec: # Pod 规格
|
||
containers: # 容器列表
|
||
- name: nodejs-demo # 容器名
|
||
image: node:18-alpine # Node.js 镜像
|
||
command: ["node", "-e", "require('http').createServer((req,res)=>res.end('Hello World from Node.js')).listen(8080)"] # 内联 HTTP 服务改监听 8080
|
||
ports: # 容器端口
|
||
- containerPort: 8080 # 应用监听端口
|
||
---
|
||
"""
|
||
) + SVC_8080 + "\n---\n" + ING_NODE + "\n"
|
||
|
||
# 04-03: + 固定镜像 tag、command/args(与旧 04-02 等价,端口 8080)
|
||
doc3 = dedent(
|
||
"""\
|
||
# 对应文档:docs/04-03-nodejs-镜像与运行命令.md
|
||
# 累积:04-02 + 固定镜像 tag、imagePullPolicy、command/args
|
||
apiVersion: apps/v1 # Deployment API 版本
|
||
kind: Deployment # 工作负载:Deployment
|
||
metadata: # Deployment 元信息
|
||
name: nodejs-demo # Deployment 名称
|
||
namespace: default # 命名空间
|
||
spec: # Deployment 规格
|
||
replicas: 1 # 副本数
|
||
selector: # Deployment 选择器
|
||
matchLabels: # 标签匹配集合
|
||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||
template: # Pod 模板
|
||
metadata: # Pod 元信息
|
||
labels: # Pod 标签
|
||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||
spec: # Pod 规格
|
||
containers: # 容器列表
|
||
- name: nodejs-demo # 容器名
|
||
image: node:18.20-alpine # 固定 tag 的 Node.js 镜像
|
||
imagePullPolicy: IfNotPresent # 拉取策略:本地有则不重复拉取
|
||
command: ["node"] # 主命令
|
||
args: # 命令参数
|
||
- "-e" # 执行内联脚本
|
||
- "require('http').createServer((req,res)=>res.end('Hello from pinned image')).listen(8080)" # Node.js 内联服务逻辑
|
||
ports: # 容器端口
|
||
- containerPort: 8080 # 应用监听端口
|
||
---
|
||
"""
|
||
) + SVC_8080 + "\n---\n" + ING_NODE + "\n"
|
||
|
||
# 04-04: + ConfigMap(等同旧 04-04 主体)
|
||
doc4 = (
|
||
f"# 对应文档:docs/04-04-nodejs-环境变量与配置注入.md\n"
|
||
f"# 累积:04-03 + ConfigMap + 通过 env 注入 APP_MSG\n---\n{CM}\n---\n"
|
||
+ dedent(
|
||
"""\
|
||
apiVersion: apps/v1 # Deployment API 版本
|
||
kind: Deployment # 工作负载:Deployment
|
||
metadata: # Deployment 元信息
|
||
name: nodejs-demo # Deployment 名称
|
||
namespace: default # 命名空间
|
||
spec: # Deployment 规格
|
||
replicas: 1 # 副本数
|
||
selector: # Deployment 选择器
|
||
matchLabels: # 标签匹配集合
|
||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||
template: # Pod 模板
|
||
metadata: # Pod 元信息
|
||
labels: # Pod 标签
|
||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||
spec: # Pod 规格
|
||
containers: # 容器列表
|
||
- name: nodejs-demo # 容器名
|
||
image: node:18.20-alpine # Node.js 镜像
|
||
imagePullPolicy: IfNotPresent # 拉取策略
|
||
env: # 环境变量注入
|
||
- name: APP_MSG # 环境变量名
|
||
valueFrom: # 从资源引用取值
|
||
configMapKeyRef: # 从 ConfigMap key 读取
|
||
name: nodejs-demo-config # ConfigMap 名称
|
||
key: APP_MSG # ConfigMap 键名
|
||
command: # 启动命令
|
||
- node # 运行 node
|
||
- "-e" # 执行内联脚本
|
||
- | # 多行 JS 脚本(内部内容不改动)
|
||
const http=require('http');
|
||
const msg=process.env.APP_MSG||'no env';
|
||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||
ports: # 容器端口
|
||
- containerPort: 8080 # 应用监听端口
|
||
---
|
||
"""
|
||
)
|
||
+ SVC_8080
|
||
+ "\n---\n"
|
||
+ ING_NODE
|
||
+ "\n"
|
||
)
|
||
|
||
# 04-05: + 探针(无 resources)
|
||
doc5 = (
|
||
f"# 对应文档:docs/04-05-nodejs-探针与健康检查.md\n"
|
||
f"# 累积:04-04 + livenessProbe/readinessProbe(端口 8080,路径 /)\n---\n{CM}\n---\n"
|
||
+ dedent(
|
||
"""\
|
||
apiVersion: apps/v1 # Deployment API 版本
|
||
kind: Deployment # 工作负载:Deployment
|
||
metadata: # Deployment 元信息
|
||
name: nodejs-demo # Deployment 名称
|
||
namespace: default # 命名空间
|
||
spec: # Deployment 规格
|
||
replicas: 1 # 副本数
|
||
selector: # Deployment 选择器
|
||
matchLabels: # 标签匹配集合
|
||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||
template: # Pod 模板
|
||
metadata: # Pod 元信息
|
||
labels: # Pod 标签
|
||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||
spec: # Pod 规格
|
||
containers: # 容器列表
|
||
- name: nodejs-demo # 容器名
|
||
image: node:18.20-alpine # Node.js 镜像
|
||
imagePullPolicy: IfNotPresent # 拉取策略
|
||
env: # 环境变量注入
|
||
- name: APP_MSG # 环境变量名
|
||
valueFrom: # 从资源引用取值
|
||
configMapKeyRef: # 从 ConfigMap key 读取
|
||
name: nodejs-demo-config # ConfigMap 名称
|
||
key: APP_MSG # ConfigMap 键名
|
||
command: # 启动命令
|
||
- node # 运行 node
|
||
- "-e" # 执行内联脚本
|
||
- | # 多行 JS 脚本(内部内容不改动)
|
||
const http=require('http');
|
||
const msg=process.env.APP_MSG||'no env';
|
||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||
ports: # 容器端口
|
||
- containerPort: 8080 # 应用监听端口
|
||
"""
|
||
).rstrip()
|
||
+ "\n"
|
||
+ PROBES
|
||
+ "\n"
|
||
+ dedent(
|
||
"""\
|
||
---
|
||
"""
|
||
)
|
||
+ SVC_8080
|
||
+ "\n---\n"
|
||
+ ING_NODE
|
||
+ "\n"
|
||
)
|
||
|
||
# 04-06: + replicas:3 + RollingUpdate,Ingress 仍为 /node
|
||
doc6 = (
|
||
f"# 对应文档:docs/04-06-nodejs-副本与滚动发布.md\n"
|
||
f"# 累积:04-05 + replicas: 3 + RollingUpdate(maxSurge:1 maxUnavailable:0)\n---\n{CM}\n---\n"
|
||
+ dedent(
|
||
"""\
|
||
apiVersion: apps/v1 # Deployment API 版本
|
||
kind: Deployment # 工作负载:Deployment
|
||
metadata: # Deployment 元信息
|
||
name: nodejs-demo # Deployment 名称
|
||
namespace: default # 命名空间
|
||
spec: # Deployment 规格
|
||
replicas: 3 # 副本数(高可用)
|
||
strategy: # 更新策略
|
||
type: RollingUpdate # 滚动更新
|
||
rollingUpdate: # 滚动更新参数
|
||
maxSurge: 1 # 更新时最多额外增加 1 个 Pod
|
||
maxUnavailable: 0 # 更新时不可用 Pod 数为 0
|
||
selector: # Pod 选择器
|
||
matchLabels: # 标签匹配集合
|
||
app: nodejs-demo # 匹配 app=nodejs-demo 的 Pod
|
||
template: # Pod 模板
|
||
metadata: # Pod 元信息
|
||
labels: # Pod 标签
|
||
app: nodejs-demo # 与 selector.matchLabels 对齐
|
||
spec: # Pod 规格
|
||
containers: # 容器列表
|
||
- name: nodejs-demo # 容器名
|
||
image: node:18.20-alpine # Node.js 镜像
|
||
imagePullPolicy: IfNotPresent # 拉取策略
|
||
env: # 环境变量注入
|
||
- name: APP_MSG # 环境变量名
|
||
valueFrom: # 从资源引用取值
|
||
configMapKeyRef: # 从 ConfigMap key 读取
|
||
name: nodejs-demo-config # ConfigMap 名称
|
||
key: APP_MSG # ConfigMap 键名
|
||
command: # 启动命令
|
||
- node # 运行 node
|
||
- "-e" # 执行内联脚本
|
||
- | # 多行 JS 脚本(内部内容不改动)
|
||
const http=require('http');
|
||
const msg=process.env.APP_MSG||'no env';
|
||
http.createServer((q,s)=>s.end(msg)).listen(8080);
|
||
ports: # 容器端口
|
||
- containerPort: 8080 # 应用监听端口
|
||
"""
|
||
).rstrip()
|
||
+ "\n"
|
||
+ PROBES
|
||
+ "\n"
|
||
+ dedent(
|
||
"""\
|
||
---
|
||
"""
|
||
)
|
||
+ SVC_8080
|
||
+ "\n---\n"
|
||
+ ING_NODE
|
||
+ "\n"
|
||
)
|
||
|
||
# 04-07: Ingress host + /api
|
||
doc7 = doc6.replace(
|
||
"# 对应文档:docs/04-06-nodejs-副本与滚动发布.md\n"
|
||
"# 累积:04-05 + replicas: 3 + RollingUpdate(maxSurge:1 maxUnavailable:0)\n",
|
||
"# 对应文档:docs/04-07-nodejs-Ingress与Traefik.md\n"
|
||
"# 累积:04-06 + Ingress 增加 host、path 改为 /api(访问需 Host: app.example.local)\n",
|
||
)
|
||
doc7 = doc7.replace("---\n" + ING_NODE + "\n", "---\n" + ING_HOST + "\n")
|
||
|
||
# 04-08: + resources
|
||
c8 = (
|
||
" ports: # 容器端口\n"
|
||
" - containerPort: 8080 # 应用监听端口\n"
|
||
)
|
||
c8r = (
|
||
" ports: # 容器端口\n"
|
||
" - containerPort: 8080 # 应用监听端口\n" + RES
|
||
)
|
||
doc8 = doc7.replace(
|
||
"# 对应文档:docs/04-07-nodejs-Ingress与Traefik.md\n"
|
||
"# 累积:04-06 + Ingress 增加 host、path 改为 /api(访问需 Host: app.example.local)\n",
|
||
"# 对应文档:docs/04-08-nodejs-资源请求与限制.md\n"
|
||
"# 累积:04-07 + resources.requests/limits\n",
|
||
).replace(c8, c8r)
|
||
|
||
# 04-09: + nodeSelector
|
||
doc9 = doc8.replace(
|
||
"# 对应文档:docs/04-08-nodejs-资源请求与限制.md\n"
|
||
"# 累积:04-07 + resources.requests/limits\n",
|
||
"# 对应文档:docs/04-09-nodejs-调度与亲和.md\n"
|
||
"# 累积:04-08 + nodeSelector(默认 ylc62,请改为本集群节点短主机名)\n",
|
||
).replace(
|
||
" spec: # Pod 规格\n containers: # 容器列表\n",
|
||
" spec: # Pod 规格\n nodeSelector: # 调度到指定节点\n"
|
||
" kubernetes.io/hostname: ylc62 # 节点主机名(按实际修改)\n"
|
||
" containers: # 容器列表\n",
|
||
)
|
||
|
||
# 04-10: + securityContext + tmp volume
|
||
doc10 = doc9.replace(
|
||
"# 对应文档:docs/04-09-nodejs-调度与亲和.md\n"
|
||
"# 累积:04-08 + nodeSelector(默认 ylc62,请改为本集群节点短主机名)\n",
|
||
"# 对应文档:docs/04-10-nodejs-安全上下文.md\n"
|
||
"# 累积:04-09 + pod securityContext.fsGroup、容器 securityContext、只读根、/tmp emptyDir\n",
|
||
).replace(
|
||
" spec: # Pod 规格\n nodeSelector: # 调度到指定节点\n"
|
||
" kubernetes.io/hostname: ylc62 # 节点主机名(按实际修改)\n"
|
||
" containers: # 容器列表\n",
|
||
" spec: # Pod 规格\n nodeSelector: # 调度到指定节点\n"
|
||
" kubernetes.io/hostname: ylc62 # 节点主机名(按实际修改)\n"
|
||
" securityContext: # Pod 级安全上下文\n"
|
||
" fsGroup: 1000 # 挂载卷文件组 ID\n"
|
||
" containers: # 容器列表\n",
|
||
)
|
||
doc10 = doc10.replace(
|
||
" - name: nodejs-demo # 容器名\n image: node:18.20-alpine # Node.js 镜像\n"
|
||
" imagePullPolicy: IfNotPresent # 拉取策略\n env:",
|
||
" - name: nodejs-demo # 容器名\n image: node:18.20-alpine # Node.js 镜像\n"
|
||
" imagePullPolicy: IfNotPresent # 拉取策略\n"
|
||
" securityContext: # 容器级安全上下文\n"
|
||
" allowPrivilegeEscalation: false # 禁止提权\n"
|
||
" runAsNonRoot: true # 强制非 root 运行\n"
|
||
" runAsUser: 1000 # 运行用户 UID\n"
|
||
" readOnlyRootFilesystem: true # 根文件系统只读\n"
|
||
" env:",
|
||
)
|
||
doc10 = doc10.replace(
|
||
" periodSeconds: 5 # 探测周期\n\n---\n",
|
||
" periodSeconds: 5 # 探测周期\n"
|
||
" volumeMounts: # 卷挂载\n"
|
||
" - name: tmp # 引用临时卷\n"
|
||
" mountPath: /tmp # 容器内临时目录\n"
|
||
" volumes: # 卷定义\n"
|
||
" - name: tmp # 临时卷名称\n"
|
||
" emptyDir: {} # 空目录卷(Pod 生命周期内)\n\n---\n",
|
||
)
|
||
|
||
pvc = dedent(
|
||
"""\
|
||
apiVersion: v1 # PVC API 版本
|
||
kind: PersistentVolumeClaim # 持久卷声明
|
||
metadata: # PVC 元信息
|
||
name: nodejs-demo-data # PVC 名称
|
||
namespace: default # 命名空间
|
||
spec: # PVC 规格
|
||
accessModes: # 访问模式
|
||
- ReadWriteOnce # RWO:同一时间仅单节点挂载读写
|
||
storageClassName: local-path # 存储类(按集群可改)
|
||
resources: # 资源请求
|
||
requests: # 配额请求
|
||
storage: 1Gi # 申请容量
|
||
---
|
||
"""
|
||
).strip()
|
||
doc11 = doc10.replace(
|
||
"# 对应文档:docs/04-10-nodejs-安全上下文.md\n"
|
||
"# 累积:04-09 + pod securityContext.fsGroup、容器 securityContext、只读根、/tmp emptyDir\n",
|
||
"# 对应文档:docs/04-11-nodejs-存储与卷.md\n"
|
||
"# 累积:04-10 + PVC nodejs-demo-data(默认 storageClassName: local-path)+ 挂载 /data\n",
|
||
)
|
||
doc11 = doc11.replace(
|
||
"---\n" + CM + "\n---\n",
|
||
"---\n" + pvc + "\n" + CM + "\n---\n",
|
||
1,
|
||
)
|
||
doc11 = doc11.replace(
|
||
" volumeMounts: # 卷挂载\n"
|
||
" - name: tmp # 引用临时卷\n"
|
||
" mountPath: /tmp # 容器内临时目录\n",
|
||
" volumeMounts: # 卷挂载\n"
|
||
" - name: tmp # 临时卷名称\n"
|
||
" mountPath: /tmp # 容器内临时目录\n"
|
||
" - name: data # 数据卷名称\n"
|
||
" mountPath: /data # 容器内数据目录\n",
|
||
)
|
||
doc11 = doc11.replace(
|
||
" volumes: # 卷定义\n - name: tmp # 临时卷名称\n"
|
||
" emptyDir: {} # 空目录卷(Pod 生命周期内)\n",
|
||
" volumes: # 卷定义\n - name: tmp # 临时卷\n emptyDir: {} # 空目录卷\n"
|
||
" - name: data # 数据卷\n persistentVolumeClaim: # 卷来源为 PVC\n"
|
||
" claimName: nodejs-demo-data # 绑定 PVC 名称\n",
|
||
)
|
||
|
||
DIR.mkdir(parents=True, exist_ok=True)
|
||
(DIR / "04-02-nodejs-demo.yaml").write_text(doc2, encoding="utf-8")
|
||
(DIR / "04-03-nodejs-demo.yaml").write_text(doc3, encoding="utf-8")
|
||
(DIR / "04-04-nodejs-demo.yaml").write_text(doc4, encoding="utf-8")
|
||
(DIR / "04-05-nodejs-demo.yaml").write_text(doc5, encoding="utf-8")
|
||
(DIR / "04-06-nodejs-demo.yaml").write_text(doc6, encoding="utf-8")
|
||
(DIR / "04-07-nodejs-demo.yaml").write_text(doc7, encoding="utf-8")
|
||
(DIR / "04-08-nodejs-demo.yaml").write_text(doc8, encoding="utf-8")
|
||
(DIR / "04-09-nodejs-demo.yaml").write_text(doc9, encoding="utf-8")
|
||
(DIR / "04-10-nodejs-demo.yaml").write_text(doc10, encoding="utf-8")
|
||
(DIR / "04-11-nodejs-demo.yaml").write_text(doc11, encoding="utf-8")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|