chore(infra): 新增 Gitea+Jenkins CI/CD 部署与凭据整改

- infra/cicd:docker-compose(gitea/jenkins)、JCasC(凭据统一 ${ENV} 注入,无硬编码)、
  备份/恢复、健康检查、凭据轮换与 git 历史清除脚本
- docs/deployment/cicd:安装、高可用备份监控、凭据事故复盘
- .env.example 仅为占位模板;真实 .env 由 .gitignore 排除
This commit was merged in pull request #27.
This commit is contained in:
2026-09-20 10:37:57 +08:00
parent 7df2dde438
commit 4ab2f3cd8e
15 changed files with 2092 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
# ============================================================
# Jenkins 生产环境编排(加固版)
# 部署位置: 139.155.109.62:/home/novalon/docker-app/jenkins/
# 访问地址: https://ci.f.novalon.cn
#
# 相对现状(2026-09-14 实测)的修复点:
# 1. user: root -> 1000:1000(现状以 root 运行,容器内即宿主 root)
# 2. 摘掉 /var/run/docker.sock(作业 config.xml 实测 0 处 docker 调用,纯多余风险;
# 挂载 docker.sock = 容器内任意用户可直接拿到宿主 root)
# 3. 摘掉 /root/.ssh 全量挂载 -> 改为专用部署密钥只读挂载
# 4. 补日志轮转(现状无 logging 配置,jenkins_home 已 430MB 且裸奔)
# 5. 补资源限制、cap_drop、CSRF、JCasC 声明式配置
#
# ⚠️ 首次切换到非 root 前必须先改卷属主(否则 Jenkins 起不来):
# docker stop jenkins
# docker run --rm -v jenkins_jenkins_home:/v alpine chown -R 1000:1000 /v
# docker compose -f docker-compose.jenkins.yml up -d
#
# 用法:
# cp .env.example .env && vim .env
# docker compose -f docker-compose.jenkins.yml up -d
# ============================================================
services:
jenkins:
# 锁定 LTS 大版本;升级走镜像 tag 变更 + 蓝绿验证,不要用 latest 漂移
image: jenkins/jenkins:2.568.1-lts-jdk17
container_name: jenkins
restart: unless-stopped
stop_grace_period: 60s
# 不再以 root 运行
user: "1000:1000"
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
environment:
- TZ=Asia/Shanghai
- JAVA_OPTS=-Xmx1024m -Xms256m -Duser.timezone=Asia/Shanghai -Djenkins.install.runSetupWizard=false
# 关闭 Jenkins 2.3xx 之后默认禁用的入站代理(JNLP)端口,减少攻击面
- JENKINS_OPTS=--httpPort=8080
# JCasC:声明式安全域 / 授权 / 凭据,杜绝手工漂移
- CASC_JENKINS_CONFIG=/var/jenkins_config/casc.yaml
- ADMIN_USER=${JENKINS_ADMIN_USER}
- ADMIN_PASSWORD=${JENKINS_ADMIN_PASSWORD}
- GITEA_TOKEN=${GITEA_TOKEN}
- DEPLOY_SSH_KEY_PASSPHRASE=${DEPLOY_SSH_KEY_PASSPHRASE}
volumes:
- jenkins_home:/var/jenkins_home
# JCasC 只读挂载
- ./jenkins/casc.yaml:/var/jenkins_config/casc.yaml:ro
# 专用部署密钥(仅含 id_ed25519_deploy / known_hosts),不再暴露宿主 /root/.ssh
- ./jenkins-ssh:/var/jenkins_home/.ssh:ro
tmpfs:
- /tmp:size=200m,mode=1777
ports:
# 只监听本机,由 nginx 终止 TLS;50000 为 JNLP 入站代理,无 agent 时可整段删除
- "127.0.0.1:8080:8080"
- "127.0.0.1:50000:50000"
cpus: 2.0
mem_limit: 2g
mem_reservation: 512m
networks:
- novalon-network
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 90s
logging:
driver: json-file
options:
max-size: "20m"
max-file: "5"
compress: "true"
volumes:
jenkins_home:
driver: local
networks:
novalon-network:
external: true