静态与动态 Agent:执行环境和隔离
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
Agent 是执行构建的节点;Pod 是 Kubernetes 的工作负载单元。前置 生产部署;不可信测试与可信发布使用独立 Controller,不能只靠 label 隔离。
1. 先建立一台可复现的 Linux Agent#
在独立 Linux 虚拟机创建 jenkins-agent 用户、持久 home 和工作目录,安装与 Controller 兼容的 Java、Git,以及项目要求的 Go/Node.js。固定工具版本并在镜像构建时运行 java -version、go version、node --version;应用 JDK 和 Agent 的 Java 可以不同。
- 在凭据库保存该节点专用 SSH(Secure Shell,安全远程登录)私钥,服务器仅允许 Controller 来源登录。
- Manage Jenkins → Nodes → New Node,设置工作目录
/home/jenkins-agent/work、执行器 1、labellinux-test、Usage 为 Only build jobs with label expressions matching this node。 - Launch method 选择 SSH;指定专用凭据和已核验主机公钥,禁止使用不验证 host key 的策略。
- 启动节点,执行 Pipeline 篇测试;检查日志中的节点名称、工作目录与实际工具版本。
节点磁盘与缓存按信任域独立。断开 SSH 后任务应失败/受控重试,不能被误判成功;修复后以新 workspace 重新测试。Agent 文档
2. Kubernetes 动态 Agent#
适合已有运行在 Kubernetes 中的 Controller。外部 Controller 不直接复制集群管理员 kubeconfig;先建立可轮换的专属认证与网络,再配置 Kubernetes cloud。本实验采用 in-cluster ServiceAccount(服务账号)身份,示例 Controller 的 SA 名为 jenkins-controller,实际名称先查询。
工具镜像如何选、Agent Pod 的 ServiceAccount 与 Controller RBAC 如何分开、EKS IAM 如何只绑定受信 Agent,见Kubernetes Agent 深入实操。
保存 agent-rbac.yaml:
apiVersion: v1
kind: Namespace
metadata: {name: ci-agents}
---
apiVersion: v1
kind: ServiceAccount
metadata: {name: ci-test, namespace: ci-agents}
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: {name: jenkins-pods, namespace: ci-agents}
rules:
- apiGroups: ['']
resources: [pods]
verbs: [get, list, watch, create, delete, patch, update]
- apiGroups: ['']
resources: [pods/exec]
verbs: [get, create]
- apiGroups: ['']
resources: [pods/log]
verbs: [get, list, watch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata: {name: jenkins-pods, namespace: ci-agents}
subjects:
- {kind: ServiceAccount, name: jenkins-controller, namespace: jenkins}
roleRef: {apiGroup: rbac.authorization.k8s.io, kind: Role, name: jenkins-pods}kubectl create namespace ci-agents --dry-run=client -o yaml | kubectl apply -f -
kubectl apply --dry-run=server -f agent-rbac.yaml
kubectl apply -f agent-rbac.yaml
kubectl auth can-i create pods -n ci-agents --as=system:serviceaccount:jenkins:jenkins-controller
kubectl auth can-i get secrets -n orders --as=system:serviceaccount:jenkins:jenkins-controller预期第一项 yes、第二项 no;执行 impersonation(模拟身份)检查需要管理员权限。创建 Pod 的权限本身很强:ci-agents 不放生产秘密,准入策略禁止挂其他身份、hostPath、特权和宿主机命名空间。
Manage Jenkins → Clouds → Kubernetes:名称 k8s-test,API 地址 https://kubernetes.default.svc,namespace ci-agents,使用 Pod 内身份;Jenkins URL 填 Agent 可达的服务地址,启用 WebSocket 连接。验证连接后,在 Pipeline 中使用:
podTemplate(cloud: 'k8s-test', yaml: '''
apiVersion: v1
kind: Pod
spec:
serviceAccountName: ci-test
automountServiceAccountToken: false
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
runAsNonRoot: true
seccompProfile: {type: RuntimeDefault}
containers:
- name: jnlp
image: jenkins/inbound-agent:REPLACE_COMPATIBLE_TAG
resources:
requests: {cpu: 100m, memory: 256Mi}
limits: {cpu: '1', memory: 512Mi}
securityContext:
allowPrivilegeEscalation: false
capabilities: {drop: [ALL]}
- name: node
image: node:24-bookworm-slim
command: [sleep]
args: [99d]
resources:
requests: {cpu: 500m, memory: 512Mi}
limits: {cpu: '2', memory: 2Gi}
securityContext:
allowPrivilegeEscalation: false
capabilities: {drop: [ALL]}
''') {
node(POD_LABEL) {
checkout scm
container('node') { sh 'npm ci && npm run lint && npm test' }
}
}替换 Agent 兼容版本,生产把两个镜像都固定 digest。命名空间增加资源配额、网络默认拒绝、允许 DNS/Controller/只读依赖仓库的出口;拒绝云元数据地址与生产网络。Pod 内没有 SA token 不代表没有云权限,还需限制节点角色元数据访问。
验收:每次构建创建新 Pod,结束后删除;失败日志可查看(测试报告按 Pipeline 篇配置);删除构建 Pod 只影响该次测试;Pod 不能读取 orders 秘密。缓存仅在同一信任域复用,不把 workspace 当共享持久卷。Kubernetes 插件
3. 镜像构建不挂宿主 Docker socket#
综合项目在独立可信虚拟机 Agent使用 rootless Podman(非 root 容器构建),不在上面的测试 Pod 临时开放特权。Ubuntu 实验节点由管理员安装:
sudo apt-get update
sudo apt-get install -y podman uidmap slirp4netns fuse-overlayfs
# 确认 jenkins-agent 在 /etc/subuid、/etc/subgid 各有独占映射范围。
grep '^jenkins-agent:' /etc/subuid /etc/subgid
sudo loginctl enable-linger jenkins-agent若没有映射,管理员先分配未占用范围再用 usermod --add-subuids START-END --add-subgids START-END jenkins-agent 配置。通过该用户的真实登录会话执行 podman info,确认 rootless=true、存储目录可写;不要以 sudo podman 掩盖配置错误。按版本固定包,预装扫描器 Trivy、AWS CLI 和语言工具链,记录到 Agent 镜像清单。Rootless 要求