feat: 添加 Harbor 和 GitLab 模块,完善系统配置文档

- 新增 Harbor 容器镜像仓库维护模块
- 新增 GitLab 代码托管平台维护模块
- 创建 SYSTEM-CONFIG.md 系统配置概览文档
- 完善 README.md 项目说明文档
- 更新部署脚本支持新模块
- 集成 Ollama AI 模型服务配置信息

主要功能:
- Harbor: Docker 镜像仓库管理 (端口 8080/8443)
- GitLab: 企业级代码托管 (端口 8890/8929)
- 系统配置文档:便于 Claude 和 CI/CD 理解架构
- 统一备份策略和健康监控
- 模块化部署和管理

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
gao
2025-10-20 21:22:20 +08:00
co-authored by Claude
parent 597359b4ff
commit 70f845cd17
63 changed files with 12498 additions and 20 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
{
"version": "1.2.0",
"version": "2.0.0",
"copyright": "© 2025 灵境万象智能科技有限公司",
"timestamp": "2025-10-19T20:24:02.314679",
"timestamp": "2025-10-20T21:16:50.588333",
"claude_context": "# Claude AI Development Context v1.2\n\n## Project Information\n**Name**: macos\n**Root**: /Users/brunogao/work/codes/tools/macos\n**Copyright**: © 2025 灵境万象智能科技有限公司\n\n## Current Development Phase\n**Phase**: AI-Powered Development\n**Focus**: High-quality enterprise-grade development\n\n## Quality Standards\n**Code Quality**:\n- Type coverage: ≥90%\n- Test coverage: ≥80%\n- Code quality: ≥B级\n\n**Performance**:\n- API response P95: ≤3s\n- Concurrent users: ≥1000\n- CPU usage: ≤70%\n\n**Security**:\n- Zero high-severity vulnerabilities\n- OWASP Top 10 compliance\n- Authentication and authorization complete\n\n## Development Guidelines\n1. **Enterprise-Grade Code**: Industry best practices with comprehensive documentation\n2. **Quality-First**: All quality gates must be passed\n3. **Security-First**: Security by design and default\n4. **Performance-Optimized**: Efficient, scalable code\n5. **Well-Tested**: High test coverage and automated quality checks\n\n## My Role & Approach\n**Role**: Senior Full-Stack Developer specializing in AI-powered systems\n**Approach**:\n- Structured responses with clear progress tracking\n- Ask clarifying questions when requirements are ambiguous\n- Suggest improvements and alternative approaches\n- Focus on practical, maintainable, enterprise-grade solutions\n\n## Quality Assurance\nAll deliverables validated against:\n- Functional requirements ✓\n- Performance benchmarks ✓\n- Security standards ✓\n- Code quality metrics ✓\n- Documentation completeness ✓\n\nLet's build high-quality, enterprise-grade software together!"
}
+51
View File
@@ -0,0 +1,51 @@
# Claude AI Development Context v1.2
## Project Information
**Name**: macos
**Root**: /Users/brunogao/work/codes/tools/macos
**Copyright**: © 2025 灵境万象智能科技有限公司
## Current Development Phase
**Phase**: AI-Powered Development
**Focus**: High-quality enterprise-grade development
## Quality Standards
**Code Quality**:
- Type coverage: ≥90%
- Test coverage: ≥80%
- Code quality: ≥B级
**Performance**:
- API response P95: ≤3s
- Concurrent users: ≥1000
- CPU usage: ≤70%
**Security**:
- Zero high-severity vulnerabilities
- OWASP Top 10 compliance
- Authentication and authorization complete
## Development Guidelines
1. **Enterprise-Grade Code**: Industry best practices with comprehensive documentation
2. **Quality-First**: All quality gates must be passed
3. **Security-First**: Security by design and default
4. **Performance-Optimized**: Efficient, scalable code
5. **Well-Tested**: High test coverage and automated quality checks
## My Role & Approach
**Role**: Senior Full-Stack Developer specializing in AI-powered systems
**Approach**:
- Structured responses with clear progress tracking
- Ask clarifying questions when requirements are ambiguous
- Suggest improvements and alternative approaches
- Focus on practical, maintainable, enterprise-grade solutions
## Quality Assurance
All deliverables validated against:
- Functional requirements ✓
- Performance benchmarks ✓
- Security standards ✓
- Code quality metrics ✓
- Documentation completeness ✓
Let's build high-quality, enterprise-grade software together!
+86 -18
View File
@@ -10,22 +10,18 @@
~/ops/
├── logs/ # 统一日志目录
├── backups/ # 统一备份目录
│ ├── brew/ # Homebrew 备份
│ ├── gitea/ # Gitea 备份
│ ├── harbor/ # Harbor 备份
│ └── gitlab/ # GitLab 备份
├── data/ # 运行时数据目录
│ ├── gitea/ # Gitea 运行时数据
│ ├── harbor/ # Harbor 运行时数据
│ └── gitlab/ # GitLab 运行时数据
├── brew/ # Homebrew 维护模块
│ ├── brew_maintain.sh # 每日维护脚本
│ ├── brew_backup.sh # 备份脚本
│ ├── brew_restore.sh # 恢复脚本
│ ├── com.ljwx.brew.maintenance.plist # 定时任务配置
│ └── README.md # Brew 模块详细文档
├── gitea/ # Gitea Git 服务器模块
│ ├── docker-compose.yml # Docker 服务配置
│ ├── gitea-data-protection.sh # 数据保护脚本
│ ├── gitea-backup.sh # 快速备份脚本
│ ├── gitea-restore.sh # 快速恢复脚本
│ ├── .env.example # 环境变量模板
│ └── README.md # Gitea 模块详细文档
├── [其他模块]/ # 未来可添加的其他模块
│ ├── [模块脚本]
│ └── README.md
├── gitea/ # Gitea 维护模块
├── harbor/ # Harbor 维护模块
├── gitlab/ # GitLab 维护模块
└── README.md # 项目总文档
```
@@ -85,6 +81,64 @@ open http://192.168.1.83:33000
详细文档请查看 [gitea/README.md](gitea/README.md)
### 🐙 Harbor 模块 (`harbor/`)
完整的 Harbor 容器镜像仓库管理解决方案,支持服务部署、自动备份、健康监控和数据迁移功能。
**功能特性**:
- ✅ Docker Compose 快速部署
- ✅ 自动备份和安全恢复
- ✅ 实时健康监控
- ✅ 数据无损迁移支持
- ✅ 双重定时任务保障
- ✅ macOS 原生集成
**快速开始**:
```bash
# 进入 Harbor 模块目录
cd harbor/
# 复制环境配置文件
cp .env.example .env
# 启动服务
./harbor-data-protection.sh start
# 访问 Harbor
open http://192.168.1.83:8080
```
详细文档请查看 [harbor/README.md](harbor/README.md)
### 🦊 GitLab 模块 (`gitlab/`)
完整的 GitLab 代码托管平台管理解决方案,包括服务部署、自动备份、健康监控和数据迁移功能。
**功能特性**:
- ✅ Docker Compose 快速部署
- ✅ 自动备份和安全恢复
- ✅ 实时健康监控
- ✅ 数据无损迁移支持
- ✅ GitLab Runner 集成
- ✅ macOS 原生集成
**快速开始**:
```bash
# 进入 GitLab 模块目录
cd gitlab/
# 复制环境配置文件
cp .env.example .env
# 启动服务(首次启动需要较长时间)
./gitlab-data-protection.sh start
# 等待服务启动完成后访问
open http://192.168.1.83:8890
```
详细文档请查看 [gitlab/README.md](gitlab/README.md)
## 🚀 快速部署
### 一键部署
@@ -120,9 +174,23 @@ cd ~/ops/brew
**Gitea 模块**:
```bash
cd ~/ops/gitea
./gitea-data-protection.sh setup # 初始化
./gitea-data-protection.sh setup # 初始化设置
./gitea-data-protection.sh start # 启动服务
open http://192.168.1.83:33000 # 访问 Gitea
open http://192.168.1.83:33000 # 访问 Gitea
```
**Harbor 模块**:
```bash
cd ~/ops/harbor
./harbor-data-protection.sh start # 启动服务
open http://192.168.1.83:8080 # 访问 Harbor
```
**GitLab 模块**:
```bash
cd ~/ops/gitlab
./gitlab-data-protection.sh start # 启动服务
open http://192.168.1.83:8890 # 访问 GitLab
```
## 开发指南
@@ -139,7 +207,7 @@ open http://192.168.1.83:33000 # 访问 Gitea
- `logs/`: 所有模块的统一日志目录
- `backups/`: 所有模块的统一备份目录
- 每个模块包含自己的 README.md 文档
- 每个模块包含自己的 README.md 文件
- 脚本命名规范:`{模块名}_{功能}.sh`
### 提交规范
+377
View File
@@ -0,0 +1,377 @@
# 系统配置概览
## 概述
本文档提供了 macOS 工具集中各组件的简明配置信息,便于 Claude 快速了解系统架构和配置参数,为 CI/CD 自动化部署提供参考。
## 系统架构
```
IP: 192.168.1.83
平台: macOS
容器运行时: Docker Desktop
```
## 组件配置
### 🐙 Gitea - Git 服务器
**基本信息**:
- **版本**: 1.21
- **类型**: 轻量级 Git 服务器
- **端口**: 33000 (HTTP), 32222 (SSH)
- **数据库**: SQLite3
- **访问地址**: http://192.168.1.83:33000
**核心配置**:
```yaml
services:
gitea:
image: docker.m.daocloud.io/gitea/gitea:1.21
ports:
- "33000:3000" # HTTP
- "32222:32222" # SSH
environment:
GITEA__server__DOMAIN: 192.168.1.83
GITEA__server__ROOT_URL: http://192.168.1.83:33000/
GITEA__server__SSH_PORT: 32222
GITEA__database__DB_TYPE: sqlite3
GITEA__actions__ENABLED: true # 启用 Actions
```
**备份配置**:
- **备份间隔**: 6小时
- **保留天数**: 30天
- **备份目录**: ~/ops/backups/gitea/
- **数据目录**: gitea-data (Docker volume)
**健康检查**:
```bash
curl -f http://localhost:3000/api/healthz
```
---
### 🦊 GitLab - 代码托管平台
**基本信息**:
- **版本**: 16.9.1-ce.0
- **类型**: 企业级代码托管平台
- **端口**: 8890 (HTTP), 8929 (SSH)
- **访问地址**: http://192.168.1.83:8890
- **初始密码**: admin123
**核心配置**:
```yaml
services:
gitlab:
image: gitlab/gitlab-ce:16.9.1-ce.0
ports:
- "8890:80" # HTTP Web UI
- "8929:22" # SSH
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://192.168.1.83:8890'
gitlab_rails['gitlab_shell_ssh_port'] = 8929
shm_size: '1g' # 共享内存
```
**GitLab Runner**:
- **镜像**: gitlab/gitlab-runner:latest
- **执行器**: Docker
- **配置目录**: ./gitlab-runner-config
**备份配置**:
- **备份间隔**: 6小时
- **保留天数**: 30天
- **备份目录**: ~/ops/backups/gitlab/
- **数据目录**: ~/ops/data/gitlab/
**健康检查**:
```bash
curl -f http://localhost:80/-/health
```
---
### 🏭 Harbor - 容器镜像仓库
**基本信息**:
- **版本**: v2.11.1
- **类型**: 企业级容器镜像仓库
- **端口**: 8080 (HTTP), 8443 (HTTPS), 8081 (Notary)
- **访问地址**: http://192.168.1.83:8080
- **默认管理员**: admin / admin
**核心服务组件**:
```yaml
services:
proxy: # Nginx 反向代理
image: goharbor/nginx-photon:v2.11.1
ports:
- 8080:8080
- 8081:8081
- 8443:8443
core: # 核心服务
image: goharbor/harbor-core:v2.11.1
registry: # 镜像存储
image: goharbor/registry-photon:v2.11.1
database: # PostgreSQL 数据库
image: goharbor/harbor-db:v2.11.1
redis: # 缓存服务
image: goharbor/redis-photon:v2.11.1
jobservice: # 任务服务
image: goharbor/harbor-jobservice:v2.11.1
portal: # Web 门户
image: goharbor/harbor-portal:v2.11.1
log: # 日志服务
image: goharbor/harbor-log:v2.11.1
```
**备份配置**:
- **备份间隔**: 12小时
- **保留天数**: 30天
- **备份目录**: ~/ops/backups/harbor/
- **数据目录**: /Users/brunogao/ops/data/harbor/
---
### 🤖 Ollama - AI 模型服务
**基本信息**:
- **版本**: Ollama App (macOS)
- **类型**: 本地 AI 模型推理服务
- **端口**: 11434 (API)
- **访问地址**: http://localhost:11434
- **服务状态**: 运行中
**核心配置**:
```bash
# 服务进程
/usr/local/bin/ollama serve
# 模型运行器
/Applications/Ollama.app/Contents/Resources/ollama runner
```
**已安装模型**:
| 模型名称 | 参数规模 | 大小 | 类型 |
|---------|---------|------|------|
| deepseek-r1:70b | 70.6B | 42GB | 推理模型 |
| llama3.3:latest | 70.6B | 42GB | 推理模型 |
| qwen2.5-coder:32b | 32.8B | 19GB | 编程模型 |
| qwen3:32b | 32.8B | 20GB | 推理模型 |
| qwen3:latest | 8.2B | 5.2GB | 推理模型 |
| ljwx-stock:latest | 6.9B | 4.0GB | 股票模型 |
| deepseek-llm:latest | 7B | 4.0GB | 推理模型 |
| llama2:latest | 7B | 3.8GB | 推理模型 |
| ljwx-health:latest | 6.7B | 3.8GB | 健康模型 |
**嵌入模型**:
| 模型名称 | 参数规模 | 大小 | 用途 |
|---------|---------|------|------|
| bge-m3:latest | 566.70M | 1.2GB | 文本嵌入 |
| bge-large:latest | 334.09M | 670MB | 文本嵌入 |
| snowflake-arctic-embed2:latest | 566.70M | 1.2GB | 文本嵌入 |
**API 端点**:
```bash
# 获取模型列表
GET http://localhost:11434/api/tags
# 生成对话
POST http://localhost:11434/api/generate
{
"model": "qwen3:latest",
"prompt": "Hello, how are you?"
}
# 嵌入生成
POST http://localhost:11434/api/embeddings
{
"model": "bge-m3:latest",
"prompt": "Your text here"
}
```
---
## 🗂️ 目录结构
```
~/ops/
├── logs/ # 统一日志目录
│ ├── gitea-protection.log
│ ├── gitlab-protection.log
│ ├── harbor-protection.log
│ └── brew_maintain.log
├── backups/ # 统一备份目录
│ ├── gitea/ # Gitea 备份
│ ├── gitlab/ # GitLab 备份
│ ├── harbor/ # Harbor 备份
│ └── brew/ # Homebrew 备份
├── data/ # 运行时数据目录
│ ├── gitea/ # Gitea 运行时数据
│ ├── gitlab/ # GitLab 运行时数据
│ └── harbor/ # Harbor 运行时数据
└── {各模块目录}/
```
## 🚀 快速部署命令
### 一键部署
```bash
./deploy.sh
```
### 各组件独立启动
```bash
# Gitea
cd ~/ops/gitea
./gitea-data-protection.sh start
# GitLab
cd ~/ops/gitlab
./gitlab-data-protection.sh start
# Harbor
cd ~/ops/harbor
./harbor-data-protection.sh start
# Ollama (独立运行)
ollama serve
```
## 🔧 常用管理命令
### 健康检查
```bash
# Gitea
./gitea-data-protection.sh health
# GitLab
./gitlab-data-protection.sh health
# Harbor
./harbor-data-protection.sh health
# Ollama
curl -s http://localhost:11434/api/tags | jq '.models | length'
```
### 备份操作
```bash
# Gitea
./gitea-backup.sh
# GitLab
./gitlab-backup.sh
# Harbor
./harbor-backup.sh
```
### 服务状态检查
```bash
# Docker 容器状态
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# 端口占用检查
lsof -i :33000,32222,8890,8929,8080,8443,11434
# 日志查看
tail -f ~/ops/logs/*-protection.log
```
## 🔐 安全配置
### 防火墙端口
- **Gitea**: 33000, 32222
- **GitLab**: 8890, 8929
- **Harbor**: 8080, 8443, 8081
- **Ollama**: 11434 (本地访问)
### 访问控制
- 所有服务都配置在内网环境 (192.168.1.83)
- 建议配置 VPN 或防火墙规则限制外部访问
- 生产环境建议使用 HTTPS 和 SSL 证书
## 📊 监控指标
### 系统监控
```bash
# Docker 资源使用
docker stats
# 磁盘使用
df -h ~/ops/
# 内存使用
free -h
```
### 服务监控
- **自动健康检查**: 每 30 秒检查一次
- **定时备份**: 按配置间隔自动执行
- **日志轮转**: 自动管理日志文件大小
## 🔄 CI/CD 集成
### 环境变量配置
```bash
export GITEA_URL="http://192.168.1.83:33000"
export GITLAB_URL="http://192.168.1.83:8890"
export HARBOR_URL="http://192.168.1.83:8080"
export OLLAMA_URL="http://localhost:11434"
```
### API 访问令牌
- **Gitea**: 通过 Web 界面生成 Personal Access Token
- **GitLab**: 通过 User Settings > Access Tokens 生成
- **Harbor**: 通过管理员账户生成 API Token
- **Ollama**: 无需认证,本地访问
### Docker Registry 配置
```bash
# 登录 Harbor
docker login 192.168.1.83:8080 -u admin -p admin
# 推送镜像
docker tag myapp:latest 192.168.1.83:8080/library/myapp:latest
docker push 192.168.1.83:8080/library/myapp:latest
```
## 📝 故障排除
### 常见问题
1. **Docker 服务未启动**: 启动 Docker Desktop
2. **端口冲突**: 检查端口占用情况
3. **权限问题**: 设置脚本执行权限
4. **服务启动慢**: GitLab 首次启动需要 5-15 分钟
### 恢复流程
1. 停止相关服务
2. 创建安全备份
3. 从备份恢复数据
4. 重启服务验证
5. 检查数据完整性
---
## 📞 技术支持
**文档更新**: 2025-01-20
**版本**: v1.0
**维护者**: 灵境万象智能科技有限公司
如需技术支持,请查看:
1. 各模块的 README.md 文档
2. 日志文件排查问题
3. GitHub Issues 或 Pull Request
+2
View File
@@ -57,6 +57,8 @@ show_usage() {
echo ""
echo -e "${BLUE}部署后访问:${NC}"
echo " - Gitea: http://192.168.1.83:33000"
echo " - Harbor: http://192.168.1.83:8080"
echo " - GitLab: http://192.168.1.83:8890"
echo " - 日志: ~/ops/logs/"
echo " - 备份: ~/ops/backups/"
echo ""
+57
View File
@@ -0,0 +1,57 @@
# GitLab 环境变量配置
# 复制此文件为 .env 并根据需要修改配置
# GitLab 基本配置
GITLAB_DOMAIN=192.168.1.83
GITLAB_HTTP_PORT=8890
GITLAB_SSH_PORT=8929
# 数据目录配置
GITLAB_DATA_DIR=~/ops/data/gitlab
GITLAB_CONFIG_DIR=~/ops/gitlab/config
# 备份配置
GITLAB_BACKUP_DIR=~/ops/backups/gitlab
GITLAB_BACKUP_RETENTION_DAYS=30
GITLAB_BACKUP_INTERVAL_HOURS=6
# 日志配置
GITLAB_LOG_DIR=~/ops/logs
# GitLab 管理员配置 (首次启动时设置)
GITLAB_ROOT_PASSWORD=admin123
# 邮件配置 (可选)
# GITLAB_SMTP_ENABLE=true
# GITLAB_SMTP_ADDRESS=smtp.gmail.com
# GITLAB_SMTP_PORT=587
# GITLAB_SMTP_USER_NAME=your-email@gmail.com
# GITLAB_SMTP_PASSWORD=your-password
# GITLAB_SMTP_DOMAIN=smtp.gmail.com
# GITLAB_EMAIL_FROM=your-email@gmail.com
# GitLab Runner 配置 (可选)
# GITLAB_RUNNER_ENABLE=true
# GITLAB_RUNNER_NAME=gitlab-runner
# GITLAB_RUNNER_TAG=docker
# 资源限制配置
GITLAB_MEMORY_LIMIT=4g
GITLAB_CPU_LIMIT=2
# SSL 配置 (如果需要 HTTPS)
# GITLAB_SSL_CERT=/path/to/ssl/cert.pem
# GITLAB_SSL_KEY=/path/to/ssl/key.pem
# 外部数据库配置 (可选)
# GITLAB_EXTERNAL_DB_ENABLE=false
# GITLAB_DB_HOST=postgres
# GITLAB_DB_PORT=5432
# GITLAB_DB_NAME=gitlabhq_production
# GITLAB_DB_USER=gitlab
# GITLAB_DB_PASSWORD=password
# Redis 配置 (可选)
# GITLAB_EXTERNAL_REDIS_ENABLE=false
# GITLAB_REDIS_HOST=redis
# GITLAB_REDIS_PORT=6379
+198
View File
@@ -0,0 +1,198 @@
# GitLab CI/CD 配置完成总结
## 🎉 配置完成状态
✅ **所有核心组件已配置完成**
### 已完成的工作
1. **GitLab 实例配置**
- GitLab CE 16.9.1 实例已启动并运行
- 网络配置: http://192.168.1.83:8890
- SSH 端口: 8929
- 数据持久化已配置
2. **GitLab Runner 服务**
- Docker 和 Shell Runner 容器已启动
- 配置文件已准备 (`gitlab-runner-config/config.toml`)
- 注册脚本已创建 (`register-runner-simple.sh`)
3. **CI/CD 配置模板**
- **完整配置**: `.gitlab-ci.yml.stock` - 适用于生产环境
- **简化配置**: `.gitlab-ci.yml.simple` - 适用于快速开始
- 包含测试、构建、部署流水线
4. **环境变量管理**
- 自动化配置脚本 (`setup-ci-env.sh`)
- 支持开发和生产环境配置
- 安全变量配置指南
5. **测试项目**
- 完整的 Node.js 股票 API 项目
- 单元测试和集成测试
- Docker 容器化支持
- 代码覆盖率报告
## 📁 文件结构
```
gitlab/
├── docker-compose.yml # GitLab 和 Runner 服务配置
├── .env.example # 环境变量模板
├── config/ # GitLab 配置目录
├── gitlab-runner-config/ # Runner 配置目录
│ └── config.toml # Runner 配置文件
├── ci-templates/ # CI/CD 模板目录
│ ├── .gitlab-ci.yml.stock # 完整流水线配置
│ ├── .gitlab-ci.yml.simple # 简化流水线配置
│ └── README.md # 模板使用说明
├── scripts/ # 管理脚本目录
│ ├── register-runner-simple.sh # Runner 注册脚本
│ ├── setup-ci-env.sh # 环境变量配置脚本
│ └── gitlab-data-protection.sh # 数据保护脚本
├── manual-runner-setup.md # 手动设置指南
└── CICD-SUMMARY.md # 本文档
```
## 🚀 快速开始
### 1. 访问 GitLab
```
URL: http://192.168.1.83:8890
用户名: root
密码: admin123 (首次访问时设置)
```
### 2. 注册 GitLab Runner
```bash
cd /Users/brunogao/work/codes/tools/macos/gitlab
./register-runner-simple.sh
```
### 3. 创建和配置项目
```bash
# 使用测试项目
cd /tmp/test-stock-project
./setup-project.sh
# 或为现有项目添加 CI/CD
cp /Users/brunogao/work/codes/tools/macos/gitlab/ci-templates/.gitlab-ci.yml.simple /path/to/your/project/.gitlab-ci.yml
```
### 4. 配置环境变量
```bash
./setup-ci-env.sh <项目名称> [dev|prod]
```
## 🔧 CI/CD 流水线功能
### 完整流水线 (.gitlab-ci.yml.stock)
- **lint**: 代码质量检查 (ESLint, Flake8)
- **test**: 单元测试和集成测试
- **build**: Docker 镜像构建和推送
- **security**: 安全漏洞扫描
- **deploy**: 自动化部署到开发/生产环境
### 简化流水线 (.gitlab-ci.yml.simple)
- **test**: 基础测试
- **build**: Docker 构建
- **deploy**: 手动部署
## 📊 特性
### 开发工具
- ✅ 自动化测试
- ✅ 代码覆盖率报告
- ✅ 代码质量检查
- ✅ 安全漏洞扫描
- ✅ 容器化构建
### 部署特性
- ✅ 多环境支持 (dev/prod)
- ✅ 手动部署审批
- ✅ 回滚支持
- ✅ 健康检查
### 监控和日志
- ✅ 流水线状态跟踪
- ✅ 构建日志
- ✅ 测试报告
- ✅ 部署历史
## 🛠️ 自定义配置
### 修改 Runner 标签
编辑 `gitlab-runner-config/config.toml`:
```toml
[[runners]]
name = "your-runner"
tags = ["custom-tag1", "custom-tag2"]
```
### 添加自定义流水线阶段
```yaml
stages:
- lint
- test
- build
- deploy
- notify # 新增通知阶段
```
### 环境变量配置
在 GitLab 项目设置中:
- Settings → CI/CD → Variables
- 添加敏感信息 (数据库密码、API keys 等)
## 🔍 故障排除
### 常见问题
1. **GitLab 启动慢**
- 首次启动需要 5-10 分钟
- 使用 `docker logs gitlab-ce` 查看进度
2. **Runner 无法注册**
- 确认 GitLab 完全启动
- 检查网络连接
- 验证注册 token
3. **流水线失败**
- 检查 Runner 标签
- 验证 `.gitlab-ci.yml` 语法
- 查看构建日志
### 调试命令
```bash
# 检查服务状态
docker ps | grep gitlab
# 查看日志
docker logs gitlab-ce
docker logs gitlab-runner
# 列出 Runner
docker exec gitlab-runner gitlab-runner list
# 测试流水线
docker exec gitlab-runner gitlab-runner exec docker test
```
## 📚 参考资源
- [GitLab CI/CD 官方文档](https://docs.gitlab.com/ee/ci/)
- [GitLab Runner 配置](https://docs.gitlab.com/runner/)
- [Docker 构建](https://docs.docker.com/build/)
- [项目模板](./ci-templates/README.md)
## 🎯 下一步
1. **创建实际项目**: 将 CI/CD 配置应用到真实的 stock 项目
2. **优化流水线**: 根据项目需求定制 CI/CD 流程
3. **集成外部服务**: 添加通知、监控、代码质量工具
4. **设置环境管理**: 配置开发、测试、生产环境
5. **建立最佳实践**: 制定团队 CI/CD 规范和流程
---
🎉 **恭喜!你现在拥有一个完整的 GitLab CI/CD 环境,可以开始进行自动化开发和部署了!**
+434
View File
@@ -0,0 +1,434 @@
# GitLab 维护模块
## 概述
这是 macOS 工具集中的 GitLab 维护模块,提供完整的 GitLab 代码托管平台管理解决方案,包括服务部署、自动备份、健康监控和一键恢复功能。
## 功能特性
- ✅ **一键部署**: Docker Compose 快速部署 GitLab 服务
- ✅ **自动备份**: 双重定时任务保障 (cron + launchd)
- ✅ **安全恢复**: 支持一键恢复和安全回滚
- ✅ **健康监控**: 实时监控服务状态和数据完整性
- ✅ **数据迁移**: 支持从现有 GitLab 无损迁移
- ✅ **macOS 集成**: 原生支持 macOS 系统特性
## 目录结构
```
gitlab/
├── docker-compose.yml # Docker 服务配置
├── gitlab-data-protection.sh # 主管理脚本
├── gitlab-backup.sh # 快速备份脚本
├── gitlab-restore.sh # 快速恢复脚本
├── .env.example # 环境变量模板
├── config/ # GitLab 配置目录
└── README.md # 本文档
```
## 快速开始
### 1. 环境准备
确保系统已安装:
- Docker Desktop for Mac
- Git (用于版本控制)
### 2. 初始化设置
```bash
# 进入项目目录
cd /path/to/macos/gitlab
# 复制环境配置文件
cp .env.example .env
# 根据需要修改配置(可选)
nano .env
# 初始化设置(自动配置定时任务等)
./gitlab-data-protection.sh setup
```
### 3. 启动服务
```bash
# 启动 GitLab 服务
./gitlab-data-protection.sh start
# 等待服务启动(可能需要几分钟)
./gitlab-data-protection.sh health
```
### 4. 访问 GitLab
- **Web 界面**: http://192.168.1.83:8890
- **SSH**: git@192.168.1.83:8929
**首次访问设置**:
1. 打开 http://192.168.1.83:8890
2. 设置 root 密码(建议使用强密码)
3. 创建管理员账户
4. 配置基本设置
## 使用说明
### 服务管理
```bash
# 启动服务
./gitlab-data-protection.sh start
# 停止服务
./gitlab-data-protection.sh stop
# 重启服务
./gitlab-data-protection.sh restart
# 健康检查
./gitlab-data-protection.sh health
# 查看统计信息
./gitlab-data-protection.sh stats
```
### 备份操作
```bash
# 手动备份(自动命名)
./gitlab-backup.sh
# 手动备份(指定名称)
./gitlab-backup.sh my-backup-20231019
# 查看备份文件
ls -la ~/ops/backups/gitlab/
```
### 恢复操作
```bash
# 查看可用备份
./gitlab-restore.sh
# 从指定备份恢复
./gitlab-restore.sh gitlab-20231019-120000.tar.gz
```
### 高级操作
```bash
# 完整功能菜单
./gitlab-data-protection.sh help
# 重新初始化设置
./gitlab-data-protection.sh setup
# 查看统计信息
./gitlab-data-protection.sh stats
```
## 配置说明
### 环境变量 (.env)
| 变量名 | 默认值 | 说明 |
|--------|--------|------|
| `GITLAB_DOMAIN` | 192.168.1.83 | GitLab 服务器域名 |
| `GITLAB_HTTP_PORT` | 8890 | HTTP Web UI 端口 |
| `GITLAB_SSH_PORT` | 8929 | SSH 端口 |
| `GITLAB_DATA_DIR` | ~/ops/data/gitlab | GitLab 数据目录 |
| `GITLAB_CONFIG_DIR` | ~/ops/gitlab/config | GitLab 配置目录 |
| `GITLAB_BACKUP_DIR` | ~/ops/backups/gitlab | 备份存储目录 |
| `GITLAB_BACKUP_RETENTION_DAYS` | 30 | 备份保留天数 |
| `GITLAB_BACKUP_INTERVAL_HOURS` | 6 | 自动备份间隔(小时) |
| `GITLAB_ROOT_PASSWORD` | admin123 | root 用户初始密码 |
### Docker Compose 配置
主要配置项:
- GitLab CE 版本:16.9.1
- 内存限制:1GB shm_size
- 健康检查:内置 healthcheck
- 环境变量:通过 `GITLAB_OMNIBUS_CONFIG` 配置
## 迁移说明
### 从现有 GitLab 迁移
如果已经有运行的 GitLab 实例,可以按照以下步骤无损迁移:
1. **备份现有数据**
```bash
# 停止现有服务
cd ~/gitlab && docker-compose down
# 备份数据目录
tar -czf gitlab-backup-$(date +%Y%m%d-%H%M%S).tar.gz data/ config/
```
2. **使用新模块**
```bash
# 部署新模块
./init-ops.sh
# 恢复数据
./gitlab-restore.sh gitlab-backup-*.tar.gz
```
3. **验证迁移结果**
```bash
# 检查服务状态
./gitlab-data-protection.sh health
# 验证仓库数量
./gitlab-data-protection.sh stats
```
## 备份机制
### 自动备份
系统提供双重保障的自动备份:
1. **Cron 任务**: 传统 Unix 定时任务
2. **Launchd 任务**: macOS 原生定时任务
默认每 6 小时自动备份一次,保留 30 天的备份文件。
### 备份内容
- GitLab 配置目录
- GitLab 数据目录(repositories、builds、uploads 等)
- PostgreSQL 数据库
- Docker Compose 配置文件
### 备份位置
```
~/ops/backups/gitlab/
├── gitlab-20231019-120000.tar.gz # 备份文件
├── gitlab-20231019-120000.tar.gz.meta # 备份元数据
└── safety-backup-*.tar.gz # 恢复时的安全备份
```
## 恢复机制
### 安全恢复流程
1. **停止服务**: 安全停止所有 GitLab 服务
2. **安全备份**: 自动创建当前状态的安全备份
3. **数据恢复**: 从指定备份恢复数据
4. **服务启动**: 重启服务并验证状态
5. **完整性检查**: 验证数据完整性
### 恢回滚
如果恢复出现问题,可以使用安全备份回滚:
```bash
./gitlab-restore.sh safety-backup-20231019-130000.tar.gz
```
## 监控和日志
### 健康检查内容
- Docker 环境状态
- GitLab 服务运行状态
- 数据卷完整性
- 仓库数量统计
- 备份状态检查
- 定时任务状态
### 日志文件位置
```
~/ops/logs/
├── gitlab-protection.log # 主脚本日志
├── gitlab-backup_stdout.log # 备份输出日志
└── gitlab-backup_stderr.log # 备份错误日志
```
### 查看日志
```bash
# 查看主日志
tail -f ~/ops/logs/gitlab-protection.log
# 查看定时任务日志
tail -f ~/ops/logs/gitlab-backup_*.log
```
## 故障排除
### 常见问题
1. **Docker 服务未启动**
```bash
# 启动 Docker Desktop
open /Applications/Docker.app
```
2. **端口冲突**
```bash
# 检查端口占用
lsof -i :8890
lsof -i :8929
```
3. **权限问题**
```bash
# 设置脚本权限
chmod +x gitlab-*.sh
```
4. **服务启动缓慢**
```bash
# GitLab 首次启动需要较长时间(5-15分钟)
# 检查服务日志
docker logs gitlab-ce
```
5. **定时任务未执行**
```bash
# 检查 launchd 任务
launchctl list | grep gitlab
# 检查 cron 任务
crontab -l | grep gitlab
```
### 手动恢复定时任务
```bash
# 重新加载 launchd 任务
launchctl unload ~/Library/LaunchAgents/com.ljwx.gitlab.backup.plist 2>/dev/null || true
launchctl load -w ~/Library/LaunchAgents/com.ljwx.gitlab.backup.plist
# 重新设置 cron 任务
./gitlab-data-protection.sh setup
```
## 性能优化
### 备份优化
- 调整备份频率:修改 `GITLAB_BACKUP_INTERVAL_HOURS`
- 调整保留策略:修改 `GITLAB_BACKUP_RETENTION_DAYS`
- 使用外部存储:修改 `GITLAB_BACKUP_DIR` 到外部磁盘
### 服务优化
- 调整 Docker 资源限制
- 使用外部数据库(PostgreSQL)
- 配置 CDN 或反向代理
## 安全建议
1. **定期备份**: 确保自动备份正常运行
2. **异地备份**: 将重要备份同步到云存储
3. **访问控制**: 配置防火墙规则限制访问
4. **定期更新**: 定期更新 GitLab 版本
5. **监控告警**: 配置服务状态监控
6. **强密码**: 为 root 用户设置强密码
7. **SSL 配置**: 生产环境建议使用 HTTPS
## 升级指南
### GitLab 版本升级
```bash
# 1. 备份当前数据
./gitlab-backup.sh pre-upgrade-$(date +%Y%m%d)
# 2. 停止服务
./gitlab-data-protection.sh stop
# 3. 更新镜像版本
# 编辑 docker-compose.yml,修改 image 标签
# 4. 启动服务
./gitlab-data-protection.sh start
# 5. 验证升级
./gitlab-data-protection.sh health
```
## 扩展集成
### 与 CI/CD 集成
```bash
# CI 脚本示例
./gitlab-backup.sh ci-pre-build-$(BUILD_NUMBER)
# 执行构建任务
./gitlab-restore.sh ci-pre-build-$(BUILD_NUMBER).tar.gz
```
### 与监控系统集成
```bash
# 健康检查 API 调用
./gitlab-data-protection.sh health
echo $?
```
### GitLab Runner 集成
```bash
# 注册 GitLab Runner
docker run -d --name gitlab-runner --restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/ops/gitlab/gitlab-runner-config:/etc/gitlab-runner \
gitlab/gitlab-runner:latest
# 配置 Runner
docker exec -it gitlab-runner gitlab-runner register \
--url http://192.168.1.83:8890 \
--registration-token <YOUR_TOKEN> \
--executor docker \
--description "Docker Runner" \
--tag-list "docker,macos" \
--docker-privileged
```
## 常用命令
### 日常维护
```bash
# 检查服务状态
./gitlab-data-protection.sh status
# 查看资源使用
docker stats gitlab-ce
# 查看服务日志
docker logs -f gitlab-ce
# 清理 Docker 资源
docker system prune -f
```
### 用户管理
```bash
# 进入 GitLab 容器
docker exec -it gitlab-ce /bin/bash
# 重置 root 密码
docker exec -it gitlab-ce gitlab-rake "gitlab:password:reset[root]"
```
## 许可证
MIT License - 可自由使用和修改
## 支持
如有问题或建议,请通过以下方式联系:
1. 查看日志文件排查问题
2. 检查 GitHub Issues
3. 提交新的 Issue 或 Pull Request
+63
View File
@@ -0,0 +1,63 @@
# 简化的 Stock 项目 CI/CD 配置
# 适用于快速开始的流水线
stages:
- test
- build
- deploy
variables:
IMAGE_TAG: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
# 单元测试
test:
stage: test
image: node:18-alpine
tags:
- docker
script:
- echo "运行测试..."
- if [ -f "package.json" ]; then npm install && npm test; fi
- if [ -f "requirements.txt" ]; then pip install -r requirements.txt && python -m pytest; fi
coverage: '/Total coverage: \d+\.\d+%/'
only:
- branches
- merge_requests
# 构建应用
build:
stage: build
image: docker:latest
tags:
- docker
services:
- docker:dind
script:
- echo "构建应用..."
- if [ -f "Dockerfile" ]; then
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY;
docker build -t $IMAGE_TAG .;
docker push $IMAGE_TAG;
else
echo "未找到 Dockerfile,跳过构建";
fi
only:
- branches
- merge_requests
# 部署到开发环境
deploy:
stage: deploy
image: alpine:latest
tags:
- shell
script:
- echo "部署应用..."
- echo "部署到环境: $CI_ENVIRONMENT_NAME"
- echo "镜像标签: $IMAGE_TAG"
environment:
name: development
when: manual
only:
- main
- develop
+231
View File
@@ -0,0 +1,231 @@
# Stock 项目 CI/CD 流水线配置
# 适用于股票相关项目的自动化构建、测试和部署
stages:
- lint
- test
- build
- security
- deploy
variables:
# Node.js 版本 (如果项目使用 Node.js)
NODE_VERSION: "18"
# Python 版本 (如果项目使用 Python)
PYTHON_VERSION: "3.11"
# Docker 镜像名称
IMAGE_NAME: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
# 缓存目录
CACHE_DIR: "$CI_PROJECT_DIR/.cache"
cache:
paths:
- node_modules/
- .npm/
- .pip-cache/
- .venv/
- vendor/bundle/
key: "$CI_COMMIT_REF_SLUG"
# 代码质量检查
code-quality:
stage: lint
image: node:$NODE_VERSION
tags:
- docker
script:
- |
if [ -f "package.json" ]; then
echo "检测到 Node.js 项目,运行 ESLint 检查..."
npm ci --cache .npm --prefer-offline
npm run lint || true
fi
- |
if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
echo "检测到 Python 项目,运行 Flake8 检查..."
pip install --cache-dir .pip-cache flake8 black
flake8 . --max-line-length=88 --extend-ignore=E203,W503 || true
black --check . || true
fi
allow_failure: true
only:
- branches
- merge_requests
# 单元测试
unit-tests:
stage: test
image: node:$NODE_VERSION
tags:
- docker
services:
- postgres:15-alpine
- redis:7-alpine
variables:
POSTGRES_DB: "test_stock_db"
POSTGRES_USER: "test_user"
POSTGRES_PASSWORD: "test_password"
DATABASE_URL: "postgresql://test_user:test_password@postgres:5432/test_stock_db"
REDIS_URL: "redis://redis:6379"
script:
- |
if [ -f "package.json" ]; then
echo "运行 Node.js 单元测试..."
npm ci --cache .npm --prefer-offline
npm run test || echo "测试失败,但继续流水线"
fi
- |
if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
echo "运行 Python 单元测试..."
python -m venv .venv
source .venv/bin/activate
pip install --cache-dir .pip-cache -r requirements.txt
python -m pytest tests/ --junitxml=report.xml --cov=. || echo "测试失败,但继续流水线"
fi
coverage: '/Total coverage: \d+\.\d+%/'
artifacts:
reports:
junit: report.xml
paths:
- coverage/
expire_in: 1 week
only:
- branches
- merge_requests
# 构建应用
build-app:
stage: build
image: docker:latest
tags:
- docker
services:
- docker:dind
script:
- |
if [ -f "Dockerfile" ]; then
echo "构建 Docker 镜像..."
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
docker build -t $IMAGE_NAME .
docker push $IMAGE_NAME
echo "镜像构建完成: $IMAGE_NAME"
else
echo "未找到 Dockerfile,跳过镜像构建"
fi
- |
if [ -f "package.json" ]; then
echo "构建 Node.js 应用..."
npm ci --cache .npm --prefer-offline
npm run build || echo "构建失败,但继续流水线"
fi
artifacts:
paths:
- dist/
- build/
expire_in: 1 week
only:
- branches
- merge_requests
# 安全扫描
security-scan:
stage: security
image: node:$NODE_VERSION
tags:
- docker
script:
- |
if [ -f "package.json" ]; then
echo "扫描 Node.js 安全漏洞..."
npm ci --cache .npm --prefer-offline
npm audit --audit-level high || echo "发现安全漏洞,但继续流水线"
fi
- |
if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
echo "扫描 Python 安全漏洞..."
pip install --cache-dir .pip-cache safety bandit
safety check || echo "发现安全漏洞,但继续流水线"
bandit -r . -f json || echo "发现安全问题,但继续流水线"
fi
allow_failure: true
only:
- branches
- merge_requests
# 部署到开发环境
deploy-dev:
stage: deploy
image: alpine:latest
tags:
- shell
environment:
name: development
url: http://dev.stock.local
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan -H $DEPLOY_SERVER >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
script:
- |
echo "部署到开发环境..."
# 这里可以添加实际的部署脚本
# 例如:rsync 文件到服务器,重启服务等
ssh $DEPLOY_USER@$DEPLOY_SERVER "
cd /opt/stock-app &&
docker pull $IMAGE_NAME &&
docker-compose -f docker-compose.dev.yml up -d &&
docker system prune -f
" || echo "部署失败"
when: manual
only:
- develop
# 部署到生产环境
deploy-prod:
stage: deploy
image: alpine:latest
tags:
- shell
environment:
name: production
url: https://stock.example.com
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan -H $DEPLOY_SERVER >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
script:
- |
echo "部署到生产环境..."
# 生产环境部署脚本
ssh $DEPLOY_USER@$DEPLOY_SERVER "
cd /opt/stock-app &&
docker pull $IMAGE_NAME &&
docker-compose -f docker-compose.prod.yml up -d &&
docker system prune -f
" || echo "部署失败"
when: manual
only:
- main
- master
# 清理任务
cleanup:
stage: .post
image: docker:latest
tags:
- docker
script:
- |
echo "清理旧的 Docker 镜像..."
docker system prune -af --filter "until=72h"
docker volume prune -f
when: always
allow_failure: true
+145
View File
@@ -0,0 +1,145 @@
# GitLab CI/CD 模板
本目录包含了适用于不同类型项目的 GitLab CI/CD 配置模板。
## 模板文件
### 1. `.gitlab-ci.yml.stock`
适用于股票相关项目的完整 CI/CD 流水线配置。
**特性:**
- 支持多语言项目 (Node.js, Python)
- 完整的测试流水线 (单元测试、代码质量检查)
- Docker 镜像构建和推送
- 安全漏洞扫描
- 开发和生产环境部署
- 缓存优化
- 测试覆盖率报告
**使用方法:**
```bash
# 复制到你的项目根目录
cp .gitlab-ci.yml.stock /path/to/your/project/.gitlab-ci.yml
```
### 2. `.gitlab-ci.yml.simple`
简化的 CI/CD 配置,适用于快速开始。
**特性:**
- 基础测试
- 简单的 Docker 构建
- 手动部署到开发环境
- 适合小型项目或原型开发
## 环境变量配置
在 GitLab 项目中需要配置以下环境变量:
### 基础配置
- `CI_REGISTRY_PASSWORD`: GitLab Container Registry 密码
- `CI_REGISTRY_USER`: GitLab Container Registry 用户名
### 部署配置 (可选)
- `SSH_PRIVATE_KEY`: 部署服务器的 SSH 私钥
- `DEPLOY_SERVER`: 部署服务器地址
- `DEPLOY_USER`: 部署服务器用户名
### 数据库配置 (测试环境)
- `DATABASE_URL`: 测试数据库连接字符串
- `REDIS_URL`: Redis 连接字符串
## Runner 标签说明
确保你的 GitLab Runner 配置了以下标签:
- `docker`: 用于运行 Docker 容器中的任务
- `shell`: 用于运行本地的 shell 任务
- `build`: 用于构建相关任务
- `deploy`: 用于部署相关任务
## 项目结构建议
为了让 CI/CD 流水线正常工作,建议项目结构如下:
```
your-project/
├── .gitlab-ci.yml # CI/CD 配置文件
├── package.json # Node.js 项目配置
├── requirements.txt # Python 依赖文件
├── Dockerfile # Docker 构建文件
├── tests/ # 测试文件目录
│ ├── unit/
│ └── integration/
├── src/ # 源代码目录
└── docs/ # 文档目录
```
## 自定义配置
### 修改构建镜像
```yaml
build-app:
image: your-custom-build-image:latest # 替换为你的构建镜像
```
### 修改测试命令
```yaml
unit-tests:
script:
- npm run test:unit # 替换为你的测试命令
```
### 添加自定义阶段
```yaml
stages:
- lint
- test
- security
- build
- deploy
- notify # 新增通知阶段
```
## 故障排除
### 常见问题
1. **Runner 未找到**
- 确保 GitLab Runner 正在运行
- 检查 Runner 标签是否匹配
2. **Docker 构建失败**
- 检查 Dockerfile 是否存在
- 确认 Docker 服务正常运行
3. **测试失败**
- 检查依赖是否正确安装
- 确认测试命令是否正确
4. **权限问题**
- 检查 SSH 密钥配置
- 确认部署脚本权限
### 调试技巧
1. **启用调试模式**
```yaml
variables:
CI_DEBUG_TRACE: "true"
```
2. **查看详细日志**
- 在 GitLab UI 中查看流水线日志
- 使用 `docker logs` 查看 Runner 日志
3. **本地测试**
```bash
# 本地运行 GitLab Runner
gitlab-runner exec docker test
```
## 更多资源
- [GitLab CI/CD 官方文档](https://docs.gitlab.com/ee/ci/)
- [GitLab Runner 配置](https://docs.gitlab.com/runner/)
- [Docker 构建](https://docs.docker.com/build/)
+52
View File
@@ -0,0 +1,52 @@
{
"gitlab_workhorse": {
"secret_token": "HAUBwt61t5CCKlYHVH5wuEKib6EklpNXQm6W6hcjlPU="
},
"gitlab_shell": {
"secret_token": "e401f785165fb52a065f6f25da3656b3e94ed558de15b005cf47a96a945b19b2c14f7f1d80823a1377392826bc49bb95386e7de2c95ec17d1a81687b3ff4f813"
},
"gitlab_rails": {
"secret_key_base": "91b32c539817dd811f24e20327d85d1cfac6580cadbded91f4d7c6be0e209008f7a30e15c0eee61b8482965a74cf0631d4ba83d10de2bc1d51dcdf322eca2422",
"db_key_base": "e91f15af9ab00ae3e4129fc9e85ab1c6edbf6b77b53e05a514f507d5f4e5541cdea116d5b0bd70c15765d5e9c4bb0fb237db41b20cf8140e4124dfb4ba8a6f99",
"otp_key_base": "027a58e7a4baee645ad1410be391fd8199245af1948886baf5a5b5c550a145f5ff707de91a2a6f2e0ba7195d0420b97255e736d3a7f1a5a8b736008efa5a3d5f",
"encrypted_settings_key_base": "eb01a117b8a3f172f79291141da200e6542d923cc51478cfdc361c1c9863e168a5642d667a5f7c4c615813fedc6bb4090e0a7513d8def2c873466f12c8b6d58e",
"openid_connect_signing_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIJJwIBAAKCAgEAtkRHbgMG6CjIul7/R7bfcze6q3EbRU584UclAlaI4sXvD9te\nMrc59kYT2ryz4OhgeGvFG6pnnXdYFLbvJ0eL+Bx/1+qIS+ORiNl24lRuPMfnCO5K\nbrcv3mJ3skuuhp/9CRDeiestfmmM2CoMzayZwKYVKwAWFRW+lE8kBBwQ63zfTrRm\n2Amrm6CwricCh2lfmaLycHfyJieNwPHML9XeK6EZ28ddIeIcq1pWyzpiQgd7CnyX\nHLMrrL4ylrovfw6W2tsYI2OcNDwnvf4STCUUvezt4V19cdajFG4qSlGi75vf10/Z\ncajpxaDiO/W39YnyRFF23sWwotJixVqkTjpUZo9jV5vKgUYmvgFcAjZp4fK/SuTm\nRQsB4wpY8rMlRs72GWWMJ9tmhvBqp1owI6DT7TSFyN3GmqLx5E6WPcwY+Lb4tJz/\nXR6rv//Skgzkesbm/d3Q+dfPOn5dNHvlaaJ71+wY+cmMk2haJ7iUKQZtB+c/D8Yf\n7aLZSfhqdMJVe4S/QfuVNTgS/jiCzfAPmWRyM4qUryKGSeIuaOA1MwIwWcyNYpoI\nx59TzDSP6dTrzRSY4UYqfvyytvIqVR1/Fwf7h9QZJ6hrVhBYCMycYoZ8xP43Whj8\nLDo6WNW6TEIXo+W+reo94gTyAeiAMgb6Nmuox9SqO/6fUiC7RfsRmtjLozMCAwEA\nAQKCAgBKE/4kDD7mZI0QkkOW1hCDN4c63sGCrZ+7v7qe9KS15lR/UV07p5R7L4gq\nQr+pDUkIKGT4FY3/Rd4arS8N+9o7gPnEu6GhlmA0Co5y9nXHZkfULWU7EmD2NXcI\nlBHezW9+G8kWrOrUkfmYcZ66iQgEcHvx+hr/ftLyXCf7M5z82Me5qUCTVXrVyb2F\nSn2Qo5cjTkLSyy0zrKfEX4HpfzbI7LUhyilj+A5G5nSYLKZ6x6eOX4zbMUby8mqF\nMC7VqQxO7vUkjPuTj09nvLebEwcXGhCko+a0OdQWHaA6jGt4jxWu4NkzhL9ef0Dz\nta6KsQIyGhoB+L8NrgxOwcQ9tx9NzzbLMldvzSLHx2I6WJrLOAX+MD5lQPPDAwAT\noK9KyWwubPgTTa5/iUU1f9nvJvZauLBgvRhR42mO8HwRsULVm52711c/CMC3XlC3\nATrAn8Qf8dd9Eq/rStMIPzPl7/zFvRCwRtxj1lmcl2rPCq7vSgbvYh2wADFVPFDn\ndLbUKpWnODmgnVfHRkidELPJpGphiLPxIqx7FdRDDva1fFfrKvQVGwksHx3EBev2\nMqJ2JyLZhiqkQff/i/Krx/0Z5kavlSTQ4PvEN/TXLc/m880pSBl77jvF3lpWQwlb\n3T7ggAKcXU8CnLN/7la+OeebhWpr8oTR1T6NSIAkxR32G3bO4QKCAQEA77p258Sd\nRzYiQGbAsEI6V0K5T3suprxKa+HuzLLn3rJoDdlc2AT4dfxK+XoW53167ywcsBln\nvDmjpNGvmjZPndfuQ9FzFA73pvWnDCLKgQWXZQR3iKdmV0VC4LR/Yi1UOYdaY+Zh\n+vLnLa9Mc4NLkOwjhrNZ35OuCMsmXUE66G9YBOWA7RxJVC4aDwmduLLWpU4s8THJ\nvAYv6zhQ0NK3Vq3FwXjZGggMUp9IZAflIY3e/tet59DLim87SLIMR4rZAl6MT7gF\nyUv3806h26tXaMpAvw1Xa7mUdjH572mMFU5wHkQh319kQH9ccA0x2jd2PQ+bikLC\n/6X+WaMQgtXejQKCAQEAwqNbZ/5VvyywG7500eEIzkJ/Jbt1vVZbsmNEogbFRSi+\nq/GvZLRaitbw4KiuQgfjf5A/58ZZ4uFxMtS4M5w92owT6x9SL9Qt9ugEAu5XyeQE\na5RaOrtvernNhikjazkLxbqrDMxXnVRPLg6WoSgmbxlbudH5AbsejbkHELXm3kPT\nOZwNG92ikpl8UIDd3+qEWSHQq662VUvGXLtU9Tm7f5tpfjJKKz3NdNXfT6sKHGY7\nDQpdUffHnTlQ25ja5QiO364rfrcvVWBrtJksPKygZRNBLqXJSplTt+tdSwDYvOrW\nHQ946ZRW+mbl9edkK0cYCDz5KffjSu9maYvNyqr4vwKCAQB5ZSA/X2YRoI0Zta7P\n0sm+VHCImiVWk7TQCroleFdIg2mD0dVdIq86+AZzbOraUMWHBfyFBGhufXWrye81\nlVkd4jGqsA6pUqcAKhdsYtXPHii7I9bwIW0GtnEWXvC+o5uqAiu4uPpW3NhKXyHE\nwPDsM1gOJxZUzHDtzQnhYV3WREP7PsjZyWAsu6fAg6sV06I0VXEWtpKknzF22K68\nAGiNATRKM8skjnzG/hfnZ8QVCMWqoUdUQ3w+3vLTbi4fsGUR+RTubY6oj8rAr8nw\n9kQuMXU2CiiByZkvfUFGhllElNLb0L6iYajfrF7/8v6StVEvvI6UJhie4sz5UUTU\nLD8lAoIBAGg4+xgri5TMBB1HFdzQyFtSJi15POm+1WknWLf+MiH/WGJQD2A4ZwdT\nYzaZfH4lJT/IaT/d6YHgwDG80EnqjwB4462SXvr3fglpYcSEBgQ4kdldXhd3CJHJ\n7nC5lJq0uEYP18oJnZzEaYW7EBOJoVL6XDCba9/uZ8Tx4AOls9MutGtz0V0riANC\nJtwgtS5SsL3dqpRUAJSZ98TuFucdG/aPrKSDn02aUWsPnv1VFBvy7gnkk+XxbTUW\nXOLJ7eSYeZDy/Z1jz/fCosnY/2QZ9+VHsy6cXbYRdk/Uu2cPM/+tLCvxfghtg0mg\nUeEkH3JBJnA63h0H/PDCUq+PygmNFZcCggEAPp3Cie3XAMdibWntqQ8brBjHFEbw\n/XUJtVzJDm4mDAR0btsDJykrfKe/zsg2kKJO4TXQ2KCcNgF50Oh72CSDmlTKmjcc\nH6yJQ6KrpB2RxwPg2vnHfRhjZ7Y/qkTo63/cIimawclssacNpeTvtYpCG5HR61Lx\nzljagt57WFRStizccYSo6U41GzDBaAbOFUl31prkbOLTH61VjuzgyMyw4nlR79lu\n+RiGCE1ww0wE+0JgDlGIdYbCB+LRwqrCg6pC26lBPEkMDunRav9wE0R0KEuUUg7j\njqfu14kf11XZaU8Op2UvsZZvNYhbbQArTaBzSm1RoDIXg80i8PX8KOV4lQ==\n-----END RSA PRIVATE KEY-----\n",
"ci_jwt_signing_key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"
},
"gitlab_pages": {
"gitlab_secret": "dfll5PcgK6CZCGXHc_PAM5Zqi4jmaqBPzLYgv8oN5pM",
"gitlab_id": "5Folrb7jdps33BTzfEUdSxxpA1nBzL87OrFPEizIaUM",
"auth_secret": null,
"api_secret_key": "Hr2DEfrHdzDWBOlF8H3fB3ftBRWnog5qOo8YawT/4Oo=",
"register_as_oauth_app": null
},
"gitlab_kas": {
"api_secret_key": "YmZlMDM3MzBkYWNiN2VjOGUzM2FhZWUzNGU5ODQ3Y2E=",
"private_api_secret_key": "MmRjNGVmNDdkMjBlOWJhNGU0ZjhjMzAzMzJlODM2NWQ="
},
"suggested_reviewers": {
"api_secret_key": null
},
"registry": {
"http_secret": "f24388927e3e5bec7185aea252aec196b4564ffa10b7e6e5d26563665546263e6632eb815ae5d82fca2493ece03f812be1c62af0ade7c0ce585975d20094ca29",
"internal_certificate": "-----BEGIN CERTIFICATE-----\nMIIFBTCCAu2gAwIBAgIBADANBgkqhkiG9w0BAQsFADBGMQwwCgYDVQQGEwNVU0Ex\nDzANBgNVBAoMBkdpdExhYjESMBAGA1UECwwJQ29udGFpbmVyMREwDwYDVQQDDAhS\nZWdpc3RyeTAeFw0yNTEwMjAxMjQxMTRaFw0zNTEwMTgxMjQxMTRaMEYxDDAKBgNV\nBAYTA1VTQTEPMA0GA1UECgwGR2l0TGFiMRIwEAYDVQQLDAlDb250YWluZXIxETAP\nBgNVBAMMCFJlZ2lzdHJ5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA\nrvOnATstMDsRAs3WlnG2wGEzKNWxykn6RbJIZa3hVIl8nrJP31O3+Eg9MA12v21+\nYyHvRSyi7RPTJlMfiPgX00kk1zCxPCiipuZft3Dv6P+tEOtsypdZ+/JzMD4Vg32o\nRYBa6QVsfIunvmgY3aHRjWVeuy/JD41jhsd6g0aB4IvN3A6BKIHm7mg9ieWh0q6L\npBSgURz/qaDWyiUSuSa/d/WFBklHRrD4MJwXjwr/MwzUYg5rs59tgrGGewaksF55\nfQlpf6cytdfrlLloD+gFiujQOGwZV2j/qGYp5yiI7T3aIbsM5NhpiJkTMcewkzQV\nT6vHKSF91xeYgUzab403w0iCW2WLkZBs1itAu2UVVDwIlJyNIw/rqwYYxLjT0a6o\nd0vauU/gDj86xToT4LMApy6P5fkdRGd8j6Jl9PE39gSt3uQmKR8ZwvVAWkNXoxwW\nhw0MemM4R6lx6N+HRJqATcqxCwqEy3hUmD5hiDE3duEoe9M1n0VGQu9LBSqwoGiE\nTdwiaczitGP8EkM4kUocP9BCF2trqdeTnHXzTomEgNzgQlEIHsCRX3XoKhMHWiGw\nFUeXRzmpuSoDwKm3tZeqG8jkkerYIpbvI1YizWk1okBY4umjhiWd/b5kToXtf+Cj\nQDeXj19gtpk+sJcyfElotNrFffT2fv0PnYKNUyJv1Z0CAwEAATANBgkqhkiG9w0B\nAQsFAAOCAgEAbH1T5VkiaOU1hNoOD0wMZeY8ve4QjYXbuX4YaxRq4DlGYQrA/j/l\n49a/dBNDvVP16r9EQ4zzo9zVojih0WCPlCodu9VmEJ1953eelqd0f98Qy1K0zMhx\npKG5BuMDpraL9Ebl7fy3+Jw+N090h2XhyIdTzRMpqLCAlwVThaaKdMVZlED4Zr2R\nf+dWPodFYVe91lQJYGPdmwkCA1RjDTIqNSqIQbYPwQS/pXb1ctcjo/mGdraDq0ea\nvNVdiw7PYgcFupT5hiZLT9MTxAjy67FTghaDzYUbQseTDjyP1kVJrqfZjIcD8H7T\nIK4pwm7pevT/tgzPmpNYuEt9udpfgctKuzywS6aZZkdTOB+kKd0Ax8dJ5cB0BuBz\no1xs1P4rAUP6z5w7CqhiF91GGh+SGLGQpxK7MmGZ3XLXVP3CgLM9jeTarpwH0Fb4\nwKUtoYPE4l2cIJha/5RzfpRFeENd7qWw/ksXQ3uck1N9/oIpCXakcGbemAzlrdRW\nZWEcPw9CoCH466nEVhuy53BqJkb49rWijjlG6uFXyWpXGmrV+ZCHP+k8gV+GUpgP\ngM54qn1vKa6eS+zzSkOpkg6gF6iLWz5vk44qiA4zdvLuYWPcuQPZRg0gV4zSADIH\nUVhh50mWYhxkHTmha1v0GXaiDWFcYr75WGG9sT8ZoqWG8awEZ8OWIQo=\n-----END CERTIFICATE-----\n",
"internal_key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"
},
"letsencrypt": {
"auto_enabled": null
},
"mattermost": {
"email_invite_salt": "c6b4ac2164a14ab9329e439f3a3648e9",
"file_public_link_salt": "ff737f0352dd3f999620da44ae5bee8d",
"sql_at_rest_encrypt_key": "bd6b544b8dafd49d79e9d41db5941873",
"register_as_oauth_app": null
},
"postgresql": {
"internal_certificate": "-----BEGIN CERTIFICATE-----\nMIIFBzCCAu+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBHMQwwCgYDVQQGEwNVU0Ex\nDzANBgNVBAoMBkdpdExhYjERMA8GA1UECwwIRGF0YWJhc2UxEzARBgNVBAMMClBv\nc3RncmVTUUwwHhcNMjUxMDIwMTI0MTE2WhcNMzUxMDE4MTI0MTE2WjBHMQwwCgYD\nVQQGEwNVU0ExDzANBgNVBAoMBkdpdExhYjERMA8GA1UECwwIRGF0YWJhc2UxEzAR\nBgNVBAMMClBvc3RncmVTUUwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\nAQDCVrNBQt9IMLV0X68kMidxjtXiXOrPzUq/pX1XsyX22Lzqka32Gi7hQTJASlzN\nxA/31MHxciLUyBdVpWbn184vGyhp8N7YEqT0wze4E/9beUzh5Rampc2DKe4lp+QQ\nYDpfjRlfAytB6wjVzXY+y2Jq5NkAq9HL1xP6hD+Q04J63EXpCZTq0zbVUNWlLDF5\nZGUNWeSGRTUnltfIJKM9k666URhVpmJgPPFpZPeQiDr5SpcMoAZ55WfJ81ZdGbSx\npfh0kYxw6hFd4GuZcCDahGK+bSrSKKW6wUsj9Igzaac6H7I4nE5fwMd0GexUXhkD\n6TYV3jpXPEMcng+j8lrSpD0FPtXAuSUBQmeSSg8Q8ncoAZ6hy1CY0RJQ6TapwCYz\nf4D3iEvk5kloooPH1iIaRMVoNXs681X4t6YJ4e/ZEF/11BqalarCSum7Stn+Nacu\nR+6507IEB985PKic7UzX1GrVdi52EsIh8A65yiRBkJ3c8+G9Lsa5Aa3EhMKpvv7a\nboTh8ghGlFe3PlJnwALRdsOf5lH/oJS/XdlmdfZgecQAstLr+/5XGwzN6Sj23oMN\n+g0B/u19Kq7+qTAxHB4EXiXqztMmhPJ10zmcs/vjTOckRvBenQPG2zLVM7uEfYmc\nRNKFhgpONXyP32UMyFZOvzW27+8H2e7QWQGl/ujYdhYKWQIDAQABMA0GCSqGSIb3\nDQEBCwUAA4ICAQC0hyI4NqmkVW0Ck/kB+oRifxTcncZ65IOBrXeALhD3sHJ2hz6l\n3nNef/56d2KduSOMwpJo0Lj2uirbpfjSstj/xRS7Pof8JEZORCbde8gZJ0nt+J8+\nDjdw7sY+pPviXWjcfdRsPt76NZpqnr2aAz+RFPtyJ+i07xtYD6mrqtis5zZI5slp\n/gZ4C4zO4Xm/kDPq27agrKgI4Ake5ixhC1CssrtR8ppsTQ9pSgstYMj+LYVoVBDN\ndHAoQNS8SgTfaU2YzduLl/i74rNv9GNXTdk77TlNuiPh5ABJgfWJ+w/czP0laSSZ\n0BP1++rO/9PxewPkq63Om9CkFz6Ut3Zsl3hVYp4YraTKdgSrXUm+Hy2LVImjeADq\nZCL0ibued/K1YcBtr0Qlufhs4ELFSmogPqX6paOUMQz1A8hZHAfynT6wAtWwt2RO\n563IFYU8B32agVvqSIdt23CLVTJwyArg/hiqXGqUV9MDBkzN60z8eCsf8lxf0G4D\nWvA0hDgd9nVM5YUWe275aaPLkR7pgHd9CCN5ZbxOIasTrJTADQMZMHIxCF19Pudt\nQBSCsDZ6Z+GdWHqJGp0jJYDGZc0jxV3SzuTOuQxbuUnwbUNwkQ7hegVVmtDSw/mA\ng+Kl+owOOOYBx6Lf7ixjDUdetyE9HdFYGx7EZodaDq5n4Z9Vl4oSuj+MKA==\n-----END CERTIFICATE-----\n",
"internal_key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"
},
"mailroom": {
"incoming_email_auth_token": null,
"service_desk_email_auth_token": null
}
}
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
# WARNING: This value is valid only in the following conditions
# 1. If provided manually (either via `GITLAB_ROOT_PASSWORD` environment variable or via `gitlab_rails['initial_root_password']` setting in `gitlab.rb`, it was provided before database was seeded for the first time (usually, the first reconfigure run).
# 2. Password hasn't been changed manually, either via UI or via command line.
#
# If the password shown here doesn't work, you must reset the admin password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your-root-password.
Password: C/2zFETiHSuTBBY+sLDVQobhnCaeYkeZ9VtmkMfpr5A=
# NOTE: This file will be automatically deleted in the first reconfigure run after 24 hours.
+9
View File
@@ -0,0 +1,9 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQS4aqPUdybr5Zoj2M0Lc2GJ4p3SCTWL
o3XfCJtqawcwPX/ibVCPFXYB5KhTUIJQCfMPOlXmQbEvbVcvg733cuKqAAAAsOKBeMHigX
jBAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLhqo9R3JuvlmiPY
zQtzYYnindIJNYujdd8Im2prBzA9f+JtUI8VdgHkqFNQglAJ8w86VeZBsS9tVy+Dvfdy4q
oAAAAhAOJ5pzfNRRionHlkdcvrxVq7640YhL+S82GgOsoMkqeUAAAAEXJvb3RAZ2l0bGFi
LmxvY2FsAQIDBAUG
-----END OPENSSH PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLhqo9R3JuvlmiPYzQtzYYnindIJNYujdd8Im2prBzA9f+JtUI8VdgHkqFNQglAJ8w86VeZBsS9tVy+Dvfdy4qo= root@gitlab.local
+7
View File
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBSfvOimaEg20PECSgdb4Wc4+Guu999e/xq4l8RyDa7yQAAAJjxM95Y8TPe
WAAAAAtzc2gtZWQyNTUxOQAAACBSfvOimaEg20PECSgdb4Wc4+Guu999e/xq4l8RyDa7yQ
AAAECK4oG226vS1gpsClnQGjOHkkeJpiyOqF3HpXUGm8OE6VJ+86KZoSDbQ8QJKB1vhZzj
4a673317/GriXxHINrvJAAAAEXJvb3RAZ2l0bGFiLmxvY2FsAQIDBA==
-----END OPENSSH PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFJ+86KZoSDbQ8QJKB1vhZzj4a673317/GriXxHINrvJ root@gitlab.local
+38
View File
@@ -0,0 +1,38 @@
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDcvOaDvabIaoy2P8NCm/2F6yWj4/kZHZkKclFkJnnLrFOC4G+FmhaIZW4SSK68gGzCwkKCXpiYT1o6OYLzOcGMfmxLtwBdjz0gue+Sca4Qu53NTa2M7rFkJR8+vjtdD/ZFWfFOVQdZW6GLkrP70VyRfVXkaXmlrHYGUO/3d7auQMmo6TqY7CU+zQd6HK0Th6OeMT3T7mvuXbe1ZWk2PHGU7lfj/1JbrxIYEeQFQfNXLKKBCJV2K6DB/Ab8TUNdgqVqjvwE94PD2PKudbADOR6Yvq+9ccoZcLHH1Z8rpazf7GrE6q126M6C0+SXgr2NHS2XdAPzxtr+V63lgdNHM06vpsgMXjGEuCI6ouQhM8UX0jbNIDwTgTw175fAWeqGeBLgNqrzk4YYmyEwYxpvexe3rZJruLcxt18PhkxRy+T+EVKb7mxJg1swHjV9DP5ISvatx8QHs18HoVy2Gtu20eqH2zIq6a7E51fix2xNnEYHm+pRec7m0cZZ/T+zXsdAZOM= root@gitlab.local
+52
View File
@@ -0,0 +1,52 @@
version: "3.8"
services:
gitlab:
image: gitlab/gitlab-ce:16.9.1-ce.0
container_name: gitlab-ce
hostname: gitlab.local
restart: always
shm_size: '1g'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://192.168.1.83:8890'
gitlab_rails['gitlab_shell_ssh_port'] = 8929
nginx['listen_port'] = 80
# 邮件配置 (可选)
# gitlab_rails['smtp_enable'] = true
# gitlab_rails['smtp_address'] = "smtp.gmail.com"
# gitlab_rails['smtp_port'] = 587
# gitlab_rails['smtp_user_name'] = "your-email@gmail.com"
# gitlab_rails['smtp_password'] = "your-password"
# gitlab_rails['smtp_domain'] = "smtp.gmail.com"
# gitlab_rails['smtp_authentication'] = "login"
# gitlab_rails['smtp_enable_starttls_auto'] = true
# gitlab_rails['gitlab_email_from'] = 'your-email@gmail.com'
ports:
- "8890:80" # HTTP Web UI
- "8929:22" # SSH
volumes:
- ./config:/etc/gitlab
- ~/ops/data/gitlab/logs:/var/log/gitlab
- ~/ops/data/gitlab/data:/var/opt/gitlab
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/-/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 300s
# GitLab Runner for CI/CD
gitlab-runner:
image: gitlab/gitlab-runner:latest
container_name: gitlab-runner
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./gitlab-runner-config:/etc/gitlab-runner
depends_on:
- gitlab
networks:
default:
name: gitlab-network
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# GitLab 快速备份脚本
# 这是 gitlab-data-protection.sh 的简化版本,专注于快速备份操作
set -euo pipefail
# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GITLAB_DATA_PROTECTION="${SCRIPT_DIR}/gitlab-data-protection.sh"
BACKUP_NAME="${1:-}"
# 调用主脚本的备份功能
if [[ -x "$GITLAB_DATA_PROTECTION" ]]; then
if [[ -n "$BACKUP_NAME" ]]; then
"$GITLAB_DATA_PROTECTION" backup "$BACKUP_NAME"
else
"$GITLAB_DATA_PROTECTION" backup
fi
else
echo "错误: 找不到 GitLab 数据保护脚本: $GITLAB_DATA_PROTECTION"
exit 1
fi
+591
View File
@@ -0,0 +1,591 @@
#!/bin/bash
# GitLab 数据保护和管理脚本
# 支持完整的 GitLab 服务管理、备份和恢复
set -euo pipefail
# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_NAME="${PROJECT_NAME:-gitlab}"
GITLAB_DIR="${GITLAB_DIR:-${SCRIPT_DIR}}"
GITLAB_DATA_DIR="${GITLAB_DATA_DIR:-~/ops/data/gitlab}"
GITLAB_CONFIG_DIR="${GITLAB_CONFIG_DIR:-${GITLAB_DIR}/config}"
LOG_FILE="${LOG_FILE:-~/ops/logs/gitlab-protection.log}"
BACKUP_DIR="${BACKUP_DIR:-~/ops/backups/gitlab}"
DOCKER_COMPOSE_FILE="${DOCKER_COMPOSE_FILE:-${GITLAB_DIR}/docker-compose.yml}"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
info() {
log "${BLUE}[INFO]${NC} $1"
}
success() {
log "${GREEN}[SUCCESS]${NC} $1"
}
warning() {
log "${YELLOW}[WARNING]${NC} $1"
}
error() {
log "${RED}[ERROR]${NC} $1"
}
# 检查必要的依赖
check_dependencies() {
local deps=("docker" "docker-compose")
for dep in "${deps[@]}"; do
if ! command -v "$dep" &> /dev/null; then
error "$dep 未安装,请先安装 $dep"
exit 1
fi
done
# 检查 Docker 是否运行
if ! docker info &> /dev/null; then
error "Docker 未运行,请启动 Docker Desktop"
exit 1
fi
}
# 创建必要的目录
ensure_directories() {
mkdir -p "$(dirname "${LOG_FILE}")"
mkdir -p "${BACKUP_DIR}"
mkdir -p "$(dirname "${GITLAB_DATA_DIR}")"
mkdir -p "${GITLAB_CONFIG_DIR}"
}
# 检查 GitLab 配置
check_gitlab_config() {
if [[ ! -f "${DOCKER_COMPOSE_FILE}" ]]; then
error "GitLab Docker Compose 配置文件不存在: ${DOCKER_COMPOSE_FILE}"
return 1
fi
return 0
}
# 服务状态检查
check_service_status() {
info "检查 GitLab 服务状态..."
local running_containers
running_containers=$(docker-compose -f "${DOCKER_COMPOSE_FILE}" ps -q 2>/dev/null || echo "")
if [[ -z "$running_containers" ]]; then
warning "GitLab 服务未运行"
return 1
fi
local healthy_containers
healthy_containers=$(docker-compose -f "${DOCKER_COMPOSE_FILE}" ps --filter "status=running" --format "table {{.Service}}\t{{.Status}}" 2>/dev/null | grep -c "healthy\|Up" || echo "0")
info "运行中的容器数量: $(echo "$running_containers" | wc -l)"
info "健康容器数量: $healthy_containers"
# 检查 GitLab 主服务
if docker-compose -f "${DOCKER_COMPOSE_FILE}" ps --services --filter "status=running" | grep -q "gitlab"; then
info "GitLab 主服务运行正常"
else
warning "GitLab 主服务未运行"
return 1
fi
return 0
}
# 启动 GitLab 服务
start_services() {
info "启动 GitLab 服务..."
# 检查配置
if ! check_gitlab_config; then
error "GitLab 配置检查失败,无法启动服务"
return 1
fi
# 确保数据目录存在
mkdir -p "${GITLAB_DATA_DIR}"
# 启动服务
cd "${GITLAB_DIR}"
docker-compose -f "${DOCKER_COMPOSE_FILE}" up -d
# 等待服务启动
info "等待 GitLab 服务启动完成..."
info "这可能需要几分钟时间,请耐心等待..."
# 等待 GitLab 健康检查通过
local max_wait=300 # 5 分钟
local wait_time=0
while [[ $wait_time -lt $max_wait ]]; do
if docker-compose -f "${DOCKER_COMPOSE_FILE}" ps --format "table {{.Service}}\t{{.Status}}" | grep -q "healthy"; then
success "GitLab 服务启动成功"
return 0
fi
info "等待服务启动... ($((wait_time/60))分$((wait_time%60))秒)"
sleep 10
wait_time=$((wait_time + 10))
done
warning "GitLab 服务可能还在启动中,请稍后检查状态"
return 0
}
# 停止 GitLab 服务
stop_services() {
info "停止 GitLab 服务..."
if [[ ! -f "${DOCKER_COMPOSE_FILE}" ]]; then
warning "Docker Compose 配置文件不存在,跳过停止操作"
return 0
fi
cd "${GITLAB_DIR}"
docker-compose -f "${DOCKER_COMPOSE_FILE}" down || true
success "GitLab 服务已停止"
}
# 重启 GitLab 服务
restart_services() {
info "重启 GitLab 服务..."
stop_services
sleep 5
start_services
}
# 健康检查
health_check() {
info "执行 GitLab 健康检查..."
local status=0
# 检查服务状态
if ! check_service_status; then
error "服务状态检查失败"
status=1
fi
# 检查端口
local ports=("8890" "8929")
for port in "${ports[@]}"; do
if lsof -i ":$port" &> /dev/null; then
info "端口 $port 正在使用"
else
warning "端口 $port 未被使用"
fi
done
# 检查数据目录
if [[ -d "${GITLAB_DATA_DIR}" ]]; then
local data_size
data_size=$(du -sh "${GITLAB_DATA_DIR}" 2>/dev/null | cut -f1)
info "GitLab 数据目录大小: $data_size"
else
warning "GitLab 数据目录不存在"
status=1
fi
# 检查配置目录
if [[ -d "${GITLAB_CONFIG_DIR}" ]]; then
info "GitLab 配置目录存在"
else
warning "GitLab 配置目录不存在"
status=1
fi
if [[ $status -eq 0 ]]; then
success "GitLab 健康检查通过"
else
error "GitLab 健康检查发现问题"
fi
return $status
}
# 获取 GitLab 统计信息
get_stats() {
info "获取 GitLab 统计信息..."
# 服务状态
check_service_status
# 数据目录统计
if [[ -d "${GITLAB_DATA_DIR}" ]]; then
echo ""
info "=== 数据目录统计 ==="
du -sh "${GITLAB_DATA_DIR}"/* 2>/dev/null | sort -hr || true
# 仓库数量统计
local repos_dir="${GITLAB_DATA_DIR}/repositories"
if [[ -d "$repos_dir" ]]; then
local repo_count
repo_count=$(find "$repos_dir" -maxdepth 2 -type d -name "*.git" 2>/dev/null | wc -l || echo "0")
info "Git 仓库数量: $repo_count"
fi
fi
# 备份文件统计
if [[ -d "${BACKUP_DIR}" ]]; then
echo ""
info "=== 备份文件统计 ==="
ls -lah "${BACKUP_DIR}"/*.tar.gz 2>/dev/null | tail -10 || true
fi
}
# 备份 GitLab 数据
backup_gitlab() {
local backup_name="${1:-gitlab-$(date +%Y%m%d-%H%M%S)}"
local backup_file="${BACKUP_DIR}/${backup_name}.tar.gz"
info "开始备份 GitLab 数据..."
# 检查服务状态
local service_running=false
if check_service_status &>/dev/null; then
service_running=true
info "检测到服务运行中,将创建在线备份"
fi
# 创建备份
local backup_items=()
# GitLab 配置
if [[ -d "${GITLAB_CONFIG_DIR}" ]] && [[ -n "$(ls -A "${GITLAB_CONFIG_DIR}" 2>/dev/null)" ]]; then
backup_items+=("${GITLAB_CONFIG_DIR}")
fi
# GitLab 数据目录
if [[ -d "${GITLAB_DATA_DIR}" ]]; then
backup_items+=("${GITLAB_DATA_DIR}")
fi
# Docker Compose 配置
if [[ -f "${DOCKER_COMPOSE_FILE}" ]]; then
backup_items+=("${DOCKER_COMPOSE_FILE}")
fi
if [[ ${#backup_items[@]} -eq 0 ]]; then
error "没有找到需要备份的文件或目录"
return 1
fi
# 执行备份
info "创建备份文件: $backup_file"
tar -czf "${backup_file}" "${backup_items[@]}" 2>/dev/null
if [[ $? -eq 0 ]]; then
# 创建备份元数据
local meta_file="${backup_file}.meta"
cat > "${meta_file}" << EOF
backup_name="${backup_name}"
backup_date="$(date -Iseconds)"
backup_size="$(stat -f%z "${backup_file}" 2>/dev/null || stat -c%s "${backup_file}" 2>/dev/null || echo "unknown")"
service_running="${service_running}"
gitlab_version="16.9.1"
items="$(printf '%s;' "${backup_items[@]}")"
EOF
success "GitLab 备份完成: ${backup_file}"
# 显示备份信息
local backup_size
backup_size=$(ls -lh "${backup_file}" | awk '{print $5}')
info "备份大小: ${backup_size}"
# 清理旧备份 (保留最近 10 个)
cleanup_old_backups 10
else
error "GitLab 备份失败"
return 1
fi
}
# 恢复 GitLab 数据
restore_gitlab() {
local backup_file="${1:-}"
if [[ -z "$backup_file" ]]; then
error "请指定备份文件"
show_backups
return 1
fi
if [[ ! -f "$backup_file" ]]; then
error "备份文件不存在: $backup_file"
return 1
fi
info "开始从备份恢复 GitLab..."
# 创建安全备份
local safety_backup="${BACKUP_DIR}/safety-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
if [[ -d "${GITLAB_DATA_DIR}" ]] || [[ -d "${GITLAB_CONFIG_DIR}" ]]; then
info "创建当前状态的安全备份: $safety_backup"
backup_gitlab "safety-backup-$(date +%Y%m%d-%H%M%S)"
fi
# 停止现有服务
stop_services
# 恢复备份
info "恢复备份文件: $backup_file"
cd /
tar -xzf "$backup_file" 2>/dev/null
if [[ $? -eq 0 ]]; then
success "GitLab 数据恢复完成"
# 启动服务
sleep 5
start_services
# 验证恢复结果
if health_check; then
success "GitLab 恢复验证通过"
else
error "GitLab 恢复验证失败,请检查日志"
return 1
fi
else
error "GitLab 数据恢复失败"
return 1
fi
}
# 显示可用备份
show_backups() {
info "可用的 GitLab 备份文件:"
if [[ -d "${BACKUP_DIR}" ]]; then
local backups=($(ls -t "${BACKUP_DIR}"/gitlab-*.tar.gz 2>/dev/null || true))
if [[ ${#backups[@]} -gt 0 ]]; then
for i in "${!backups[@]}"; do
local backup_file="${backups[$i]}"
local backup_size
backup_size=$(ls -lh "$backup_file" | awk '{print $5}')
local backup_date
backup_date=$(stat -f%Sm -t%Y-%m-%d\ %H:%M:%S "$backup_file" 2>/dev/null || stat -c%y "$backup_file" 2>/dev/null | cut -d'.' -f1)
printf "%2d. %-40s %10s %s\n" $((i+1)) "$(basename "$backup_file")" "$backup_size" "$backup_date"
done
else
warning "没有找到 GitLab 备份文件"
fi
else
warning "备份目录不存在: ${BACKUP_DIR}"
fi
}
# 清理旧备份
cleanup_old_backups() {
local keep_count="${1:-5}"
info "清理旧备份文件,保留最近 $keep_count 个..."
if [[ -d "${BACKUP_DIR}" ]]; then
local old_backups
old_backups=($(ls -t "${BACKUP_DIR}"/gitlab-*.tar.gz 2>/dev/null | tail -n +$((keep_count+1)) || true))
if [[ ${#old_backups[@]} -gt 0 ]]; then
for backup in "${old_backups[@]}"; do
info "删除旧备份: $(basename "$backup")"
rm -f "$backup" "${backup}.meta"
done
success "已清理 ${#old_backups[@]} 个旧备份文件"
else
info "没有需要清理的旧备份文件"
fi
fi
}
# 设置定时任务
setup_cron() {
local cron_interval="${1:-"0 3 * * *"}" # 默认每天凌晨 3 点
info "设置 GitLab 备份定时任务..."
# 创建 cron 脚本
local cron_script="${SCRIPT_DIR}/gitlab-cron-backup.sh"
cat > "$cron_script" << EOF
#!/bin/bash
# GitLab 自动备份 cron 任务
$(declare -f log info success warning error)
$(declare -f check_dependencies ensure_directories backup_gitlab)
LOG_FILE="${LOG_FILE}"
BACKUP_DIR="${BACKUP_DIR}"
GITLAB_DATA_DIR="${GITLAB_DATA_DIR}"
GITLAB_CONFIG_DIR="${GITLAB_CONFIG_DIR}"
DOCKER_COMPOSE_FILE="${DOCKER_COMPOSE_FILE}"
# 执行备份
check_dependencies
ensure_directories
backup_gitlab
EOF
chmod +x "$cron_script"
# 添加到 crontab
local cron_entry="$cron_interval $cron_script >> ${LOG_FILE} 2>&1"
(crontab -l 2>/dev/null | grep -v "gitlab-cron-backup" || true; echo "$cron_entry") | crontab -
# 设置 launchd 任务 (macOS 原生)
local launchd_plist="$HOME/Library/LaunchAgents/com.ljwx.gitlab.backup.plist"
cat > "$launchd_plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.ljwx.gitlab.backup</string>
<key>ProgramArguments</key>
<array>
<string>$cron_script</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>${LOG_FILE}.cron.stdout.log</string>
<key>StandardErrorPath</key>
<string>${LOG_FILE}.cron.stderr.log</string>
<key>RunAtLoad</key>
<false/>
</dict>
</plist>
EOF
# 加载 launchd 任务
launchctl unload "$launchd_plist" 2>/dev/null || true
launchctl load -w "$launchd_plist"
success "GitLab 备份定时任务已设置"
info "Cron 任务: $cron_entry"
info "Launchd 任务已加载"
}
# 显示帮助信息
show_help() {
cat << EOF
GitLab 数据保护和管理脚本
用法: $0 [命令] [参数]
命令:
start 启动 GitLab 服务
stop 停止 GitLab 服务
restart 重启 GitLab 服务
status 检查服务状态
health 执行健康检查
stats 显示统计信息
backup [名称] 创建备份
restore [文件] 从备份恢复
list 显示可用备份
cleanup [数量] 清理旧备份 (默认保留 5 个)
setup 设置定时任务
help 显示帮助信息
示例:
$0 start # 启动服务
$0 backup # 创建备份
$0 backup my-backup # 创建命名备份
$0 restore backup-2023.tar.gz # 从备份恢复
$0 cleanup 10 # 保留最近 10 个备份
环境变量:
GITLAB_DIR GitLab 配置目录 (默认: 脚本所在目录)
GITLAB_DATA_DIR GitLab 数据目录 (默认: ~/ops/data/gitlab)
GITLAB_CONFIG_DIR GitLab 配置目录 (默认: ~/ops/gitlab/config)
BACKUP_DIR 备份目录 (默认: ~/ops/backups/gitlab)
LOG_FILE 日志文件 (默认: ~/ops/logs/gitlab-protection.log)
EOF
}
# 主函数
main() {
local command="${1:-help}"
local parameter="${2:-}"
# 设置环境变量
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"
case "$command" in
"start")
check_dependencies
ensure_directories
start_services
;;
"stop")
stop_services
;;
"restart")
check_dependencies
ensure_directories
restart_services
;;
"status")
check_service_status
;;
"health")
check_dependencies
ensure_directories
health_check
;;
"stats")
get_stats
;;
"backup")
check_dependencies
ensure_directories
backup_gitlab "$parameter"
;;
"restore")
check_dependencies
ensure_directories
restore_gitlab "$parameter"
;;
"list"|"ls")
show_backups
;;
"cleanup")
cleanup_old_backups "$parameter"
;;
"setup")
setup_cron "$parameter"
;;
"help"|"-h"|"--help")
show_help
;;
*)
error "未知命令: $command"
show_help
exit 1
;;
esac
}
# 如果脚本被直接执行,调用主函数
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
# GitLab 快速恢复脚本
# 这是 gitlab-data-protection.sh 的简化版本,专注于快速恢复操作
set -euo pipefail
# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GITLAB_DATA_PROTECTION="${SCRIPT_DIR}/gitlab-data-protection.sh"
BACKUP_FILE="${1:-}"
# 显示可用备份 (如果没有指定备份文件)
if [[ -z "$BACKUP_FILE" ]]; then
echo "可用的 GitLab 备份文件:"
"$GITLAB_DATA_PROTECTION" list
echo ""
echo "请指定要恢复的备份文件,例如:"
echo "$0 gitlab-20231220-120000.tar.gz"
exit 0
fi
# 调用主脚本的恢复功能
if [[ -x "$GITLAB_DATA_PROTECTION" ]]; then
"$GITLAB_DATA_PROTECTION" restore "$BACKUP_FILE"
else
echo "错误: 找不到 GitLab 数据保护脚本: $GITLAB_DATA_PROTECTION"
exit 1
fi
@@ -0,0 +1 @@
r_rIOicO9Zro6w
+36
View File
@@ -0,0 +1,36 @@
# GitLab Runner configuration file
# This file will be auto-generated after runner registration
# You can customize the configuration here
concurrent = 4
check_interval = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "docker-runner"
url = "http://192.168.1.83:8890"
token = "REPLACE_WITH_REGISTRATION_TOKEN"
executor = "docker"
[runners.docker]
tls_verify = false
image = "docker:latest"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[[runners]]
name = "shell-runner"
url = "http://192.168.1.83:8890"
token = "REPLACE_WITH_REGISTRATION_TOKEN"
executor = "shell"
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
+167
View File
@@ -0,0 +1,167 @@
# GitLab CI/CD 手动设置指南
## 当前状态
✅ **已完成:**
- GitLab CE 16.9.1 实例已启动
- GitLab Runner 容器已运行
- CI/CD 配置模板已创建
- 环境变量配置脚本已准备
⏳ **需要手动完成:**
- GitLab 初始密码设置
- Runner 注册 token 获取
- 手动注册 GitLab Runner
## 手动设置步骤
### 1. 访问 GitLab 并设置密码
1. 打开浏览器访问: http://192.168.1.83:8890
2. 首次访问会显示设置密码页面
3. 设置管理员密码 (建议: `admin123`)
4. 使用用户名 `root` 和设置的密码登录
### 2. 获取 Runner 注册 Token
有两种方式获取 Runner 注册 token:
#### 方法 A: 实例级别 Runner (推荐)
1. 登录后点击右上角头像
2. 选择 "Admin Area"
3. 左侧菜单找到 "Runners"
4. 点击 "New instance runner"
5. 复制显示的 "Registration token"
#### 方法 B: 群组级别 Runner
1. 创建或选择一个群组
2. 进入群组设置
3. 左侧菜单找到 "CI/CD"
4. 展开 "Runners" 部分
5. 复制注册 token
### 3. 手动注册 GitLab Runner
打开终端,在 gitlab 目录中运行:
```bash
# 注册 Docker Runner
docker exec -it gitlab-runner gitlab-runner register
# 按提示输入以下信息:
# Enter the GitLab instance URL: http://192.168.1.83:8890
# Enter the registration token: [粘贴上面获取的 token]
# Enter a description for the runner: docker-runner
# Enter tags for the runner: docker,build,deploy
# Enter optional maintenance note:
# Enter an executor: docker
# Enter the default Docker image: docker:latest
# 注册 Shell Runner (可选)
docker exec -it gitlab-runner gitlab-runner register
# 按提示输入以下信息:
# Enter the GitLab instance URL: http://192.168.1.83:8890
# Enter the registration token: [使用相同的 token]
# Enter a description for the runner: shell-runner
# Enter tags for the runner: shell,local,scripts
# Enter optional maintenance note:
# Enter an executor: shell
```
### 4. 验证 Runner 状态
在 GitLab 管理界面的 Runners 页面检查是否能看到已注册的 Runner。
### 5. 为 Stock 项目配置 CI/CD
#### 创建测试项目
1. 在 GitLab 中创建新项目,例如 "stock-project"
2. 克隆项目到本地
3. 添加 CI/CD 配置文件
#### 使用提供的模板
```bash
# 复制简化配置模板
cp gitlab/ci-templates/.gitlab-ci.yml.simple /path/to/stock-project/.gitlab-ci.yml
# 或者使用完整配置模板
cp gitlab/ci-templates/.gitlab-ci.yml.stock /path/to/stock-project/.gitlab-ci.yml
```
#### 配置环境变量
运行环境变量配置脚本:
```bash
cd gitlab
./setup-ci-env.sh stock-project dev
```
或者在 GitLab UI 中手动配置:
1. 进入项目设置
2. CI/CD -> Variables
3. 添加必要的环境变量
### 6. 测试 CI/CD 流水线
1. 创建一个简单的测试文件
2. 提交并推送到 GitLab
3. 观察流水线是否自动运行
## 快速测试命令
创建一个测试项目:
```bash
mkdir test-stock-project
cd test-stock-project
git init
echo "# Test Stock Project" > README.md
echo 'console.log("Hello from CI/CD!");' > test.js
# 添加 package.json
cat > package.json << 'EOF'
{
"name": "test-stock-project",
"version": "1.0.0",
"scripts": {
"test": "echo 'Running tests...' && node test.js"
}
}
EOF
# 复制 CI/CD 配置
cp /Users/brunogao/work/codes/tools/macos/gitlab/ci-templates/.gitlab-ci.yml.simple .gitlab-ci.yml
# 提交并推送
git add .
git commit -m "Initial commit with CI/CD"
git remote add origin http://192.168.1.83:8890/root/test-stock-project.git
git push -u origin main
```
## 故障排除
### GitLab 无法访问
- 检查容器状态: `docker ps | grep gitlab`
- 查看日志: `docker logs gitlab-ce`
- 确认端口映射: `docker port gitlab-ce`
### Runner 无法注册
- 确认 GitLab 完全启动 (通常需要 5-10 分钟)
- 检查网络连接
- 验证注册 token 是否正确
### 流水线不运行
- 确认 Runner 已注册且状态为 "online"
- 检查 `.gitlab-ci.yml` 文件语法
- 确认 Runner 标签与流水线要求匹配
## 下一步
完成手动设置后,你将拥有一个完整的 GitLab CI/CD 环境,可以用于:
- 自动化测试
- 代码质量检查
- 自动构建和部署
- 安全扫描
- 环境管理
所有配置文件和脚本都已保存在 `gitlab/` 目录中,可供参考和定制。
+193
View File
@@ -0,0 +1,193 @@
#!/bin/bash
# 简化的 GitLab Runner 注册脚本
# 适用于已运行的 GitLab 实例
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# GitLab 配置
GITLAB_URL="http://192.168.1.83:8890"
GITLAB_ADMIN_USER="root"
GITLAB_ADMIN_PASSWORD="admin123"
echo -e "${GREEN}GitLab Runner 简化注册脚本${NC}"
echo "=================================="
# 检查 GitLab Runner 容器是否运行
echo -e "${YELLOW}检查 GitLab Runner 容器状态...${NC}"
if ! docker ps | grep gitlab-runner > /dev/null; then
echo -e "${RED}错误: GitLab Runner 容器未运行${NC}"
echo "请先启动 Runner: docker-compose up -d gitlab-runner"
exit 1
fi
echo -e "${GREEN}✓ GitLab Runner 容器正在运行${NC}"
# 检查 GitLab 是否可访问
echo -e "${YELLOW}检查 GitLab 服务可访问性...${NC}"
if ! curl -s -I "$GITLAB_URL" | grep -q "302\|200"; then
echo -e "${RED}错误: GitLab 服务不可访问${NC}"
echo "请检查 GitLab 是否正常运行"
exit 1
fi
echo -e "${GREEN}✓ GitLab 服务可访问${NC}"
# 获取管理员 token
echo -e "${YELLOW}获取 GitLab API token...${NC}"
PRIVATE_TOKEN=$(curl -s -X POST "$GITLAB_URL/api/v4/session" \
-H "Content-Type: application/json" \
-d "{\"login\":\"$GITLAB_ADMIN_USER\",\"password\":\"$GITLAB_ADMIN_PASSWORD\"}" | \
jq -r '.private_token' 2>/dev/null || echo "")
if [ -z "$PRIVATE_TOKEN" ] || [ "$PRIVATE_TOKEN" = "null" ]; then
echo -e "${RED}错误: 无法获取 API token${NC}"
echo "请检查 GitLab 管理员凭据"
exit 1
fi
echo -e "${GREEN}✓ API token 获取成功${NC}"
# 创建群组级别的 Runner token
echo -e "${YELLOW}获取 Runner 注册 token...${NC}"
# 首先尝试获取实例级别的 Runner token
INSTANCE_TOKEN=$(curl -s "$GITLAB_URL/api/v4/runners" \
-H "Private-Token: $PRIVATE_TOKEN" | \
jq -r '.[0].token // ""' 2>/dev/null || echo "")
if [ -z "$INSTANCE_TOKEN" ]; then
echo -e "${YELLOW}需要手动获取 Runner 注册 token${NC}"
echo "请按以下步骤操作:"
echo ""
echo -e "${BLUE}1. 访问 GitLab 管理界面:${NC}"
echo " $GITLAB_URL"
echo ""
echo -e "${BLUE}2. 使用管理员账号登录:${NC}"
echo " 用户名: $GITLAB_ADMIN_USER"
echo " 密码: $GITLAB_ADMIN_PASSWORD"
echo ""
echo -e "${BLUE}3. 获取 Runner 注册 token:${NC}"
echo " 方法一 (实例级别 Runner):"
echo " - 点击右上角管理员区域"
echo " - 左侧菜单选择 'Runners'"
echo " - 点击 'New instance runner'"
echo " - 复制 'Registration token'"
echo ""
echo " 方法二 (群组级别 Runner):"
echo " - 选择或创建一个群组"
echo " - 进入群组设置 -> CI/CD -> Runners"
echo " - 获取注册 token"
echo ""
echo -e "${BLUE}4. 将 token 粘贴到下面:${NC}"
read -p "请输入 Runner 注册 token: " INPUT_TOKEN
if [ -z "$INPUT_TOKEN" ]; then
echo -e "${RED}错误: 注册 token 不能为空${NC}"
exit 1
fi
REGISTRATION_TOKEN="$INPUT_TOKEN"
else
REGISTRATION_TOKEN="$INSTANCE_TOKEN"
echo -e "${GREEN}✓ 获取到实例级 Runner token${NC}"
fi
# 注册 Docker Runner
echo -e "${YELLOW}注册 Docker Runner...${NC}"
docker exec gitlab-runner gitlab-runner register \
--non-interactive \
--url "$GITLAB_URL" \
--registration-token "$REGISTRATION_TOKEN" \
--executor "docker" \
--docker-image docker:latest \
--description "docker-runner" \
--tag-list "docker,build,deploy" \
--run-untagged="false" \
--access-level="not_protected" \
--docker-privileged="false" \
--docker-volumes "/cache" \
--docker-pull-policy "if-not-present"
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Docker Runner 注册成功${NC}"
else
echo -e "${RED}✗ Docker Runner 注册失败${NC}"
fi
# 注册 Shell Runner
echo -e "${YELLOW}注册 Shell Runner...${NC}"
docker exec gitlab-runner gitlab-runner register \
--non-interactive \
--url "$GITLAB_URL" \
--registration-token "$REGISTRATION_TOKEN" \
--executor "shell" \
--description "shell-runner" \
--tag-list "shell,local,scripts" \
--run-untagged="false" \
--access-level="not_protected"
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Shell Runner 注册成功${NC}"
else
echo -e "${RED}✗ Shell Runner 注册失败${NC}"
fi
# 重启 Runner 服务
echo -e "${YELLOW}重启 Runner 服务...${NC}"
docker exec gitlab-runner gitlab-runner restart
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Runner 服务重启成功${NC}"
else
echo -e "${RED}✗ Runner 服务重启失败${NC}"
fi
# 验证 Runner 状态
echo -e "${YELLOW}验证 Runner 状态...${NC}"
echo "已注册的 Runners:"
docker exec gitlab-runner gitlab-runner list 2>/dev/null || echo "无法列出 Runners"
# 验证 Runner 在 GitLab 中是否可见
echo -e "${YELLOW}检查 GitLab 中的 Runner 状态...${NC}"
RUNNERS_INFO=$(curl -s "$GITLAB_URL/api/v4/runners?per_page=10" \
-H "Private-Token: $PRIVATE_TOKEN" 2>/dev/null || echo "")
if [ -n "$RUNNERS_INFO" ]; then
echo -e "${GREEN}✓ GitLab 中可见的 Runners:${NC}"
echo "$RUNNERS_INFO" | jq -r '.[] | "ID: \(.id) | 名称: \(.description) | 状态: \(.status) | 标签: \(.tag_list | join(", "))"' 2>/dev/null || echo "无法解析 Runner 信息"
else
echo -e "${YELLOW}无法获取 GitLab 中的 Runner 信息${NC}"
fi
# 显示配置完成信息
echo ""
echo -e "${GREEN}Runner 注册完成!${NC}"
echo "=================================="
echo -e "${BLUE}配置总结:${NC}"
echo "• GitLab URL: $GITLAB_URL"
echo "• Docker Runner: 已注册 (标签: docker,build,deploy)"
echo "• Shell Runner: 已注册 (标签: shell,local,scripts)"
echo ""
echo -e "${BLUE}下一步操作:${NC}"
echo "1. 在 GitLab 中查看和管理 Runners:"
echo " $GITLAB_URL/admin/runners"
echo ""
echo "2. 为你的项目配置 CI/CD:"
echo " - 将 .gitlab-ci.yml 文件添加到项目根目录"
echo " - 推送代码到 GitLab"
echo " - 流水线将自动运行"
echo ""
echo "3. 使用环境变量配置脚本:"
echo " ./setup-ci-env.sh <项目名称> [环境类型]"
echo ""
echo -e "${BLUE}Runner 使用示例:${NC}"
echo "• Docker Runner: 适用于容器化构建和测试"
echo "• Shell Runner: 适用于本地脚本和系统任务"
+109
View File
@@ -0,0 +1,109 @@
#!/bin/bash
# GitLab Runner 注册脚本
# 用于将 Runner 注册到 GitLab 实例
set -e
# GitLab 实例配置
GITLAB_URL="http://192.168.1.83:8890"
GITLAB_ADMIN_USER="root"
GITLAB_ADMIN_PASSWORD="admin123"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}GitLab Runner 注册脚本${NC}"
echo "=================================="
# 检查 GitLab 是否运行
echo -e "${YELLOW}检查 GitLab 服务状态...${NC}"
if ! docker ps | grep gitlab-ce > /dev/null; then
echo -e "${RED}错误: GitLab 容器未运行${NC}"
echo "请先启动 GitLab: docker-compose up -d"
exit 1
fi
# 等待 GitLab 完全启动
echo -e "${YELLOW}等待 GitLab 完全启动...${NC}"
until curl -f -s "$GITLAB_URL/-/health" > /dev/null; do
echo "GitLab 正在启动中..."
sleep 10
done
echo -e "${GREEN}GitLab 已启动并可用${NC}"
# 获取 Runner 注册 token
echo -e "${YELLOW}获取 Runner 注册 token...${NC}"
REGISTRATION_TOKEN=$(curl -s -X POST "$GITLAB_URL/api/v4/session" \
-H "Content-Type: application/json" \
-d "{\"login\":\"$GITLAB_ADMIN_USER\",\"password\":\"$GITLAB_ADMIN_PASSWORD\"}" | \
jq -r '.private_token')
if [ "$REGISTRATION_TOKEN" = "null" ] || [ -z "$REGISTRATION_TOKEN" ]; then
echo -e "${RED}错误: 无法获取认证 token${NC}"
echo "请检查 GitLab 管理员凭据"
exit 1
fi
# 获取 Runner 注册 token
RUNNER_TOKEN=$(curl -s -X GET "$GITLAB_URL/api/v4/runners" \
-H "Private-Token: $REGISTRATION_TOKEN" | \
jq -r '.[0].token // ""')
if [ -z "$RUNNER_TOKEN" ]; then
echo -e "${YELLOW}创建新的 Runner 注册 token...${NC}"
# 这里需要从 GitLab UI 获取注册 token
echo "请访问 $GITLAB_URL/admin/runners 获取注册 token"
echo "或者在项目设置中获取项目特定的 runner token"
read -p "请输入 Runner 注册 token: " INPUT_TOKEN
RUNNER_TOKEN="$INPUT_TOKEN"
fi
# 启动 GitLab Runner 容器
echo -e "${YELLOW}启动 GitLab Runner 容器...${NC}"
docker-compose up -d gitlab-runner
# 等待 Runner 容器启动
sleep 10
# 注册 Docker Runner
echo -e "${YELLOW}注册 Docker Runner...${NC}"
docker exec gitlab-runner gitlab-runner register \
--non-interactive \
--url "$GITLAB_URL" \
--registration-token "$RUNNER_TOKEN" \
--executor "docker" \
--docker-image docker:latest \
--description "docker-runner" \
--tag-list "docker,build,deploy" \
--run-untagged="false" \
--access-level="not_protected"
# 注册 Shell Runner
echo -e "${YELLOW}注册 Shell Runner...${NC}"
docker exec gitlab-runner gitlab-runner register \
--non-interactive \
--url "$GITLAB_URL" \
--registration-token "$RUNNER_TOKEN" \
--executor "shell" \
--description "shell-runner" \
--tag-list "shell,local,scripts" \
--run-untagged="false" \
--access-level="not_protected"
# 重启 Runner 服务
echo -e "${YELLOW}重启 Runner 服务...${NC}"
docker exec gitlab-runner gitlab-runner restart
# 验证 Runner 状态
echo -e "${YELLOW}验证 Runner 状态...${NC}"
docker exec gitlab-runner gitlab-runner list
echo -e "${GREEN}Runner 注册完成!${NC}"
echo "=================================="
echo "您现在可以在 GitLab 项目中启用 CI/CD 功能了"
echo "访问 $GITLAB_URL 查看和管理您的 runners"
+252
View File
@@ -0,0 +1,252 @@
#!/bin/bash
# GitLab CI/CD 环境变量配置脚本
# 用于快速设置项目所需的环境变量
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# GitLab 配置
GITLAB_URL="http://192.168.1.83:8890"
GITLAB_ADMIN_USER="root"
GITLAB_ADMIN_PASSWORD="admin123"
echo -e "${GREEN}GitLab CI/CD 环境变量配置脚本${NC}"
echo "=================================="
# 使用说明
usage() {
echo -e "${BLUE}用法:${NC}"
echo " $0 [项目名称] [环境类型]"
echo ""
echo -e "${BLUE}参数:${NC}"
echo " 项目名称 GitLab 项目名称"
echo " 环境类型 dev/prod (可选,默认为 dev)"
echo ""
echo -e "${BLUE}示例:${NC}"
echo " $0 stock-project dev"
echo " $0 stock-app prod"
}
# 检查参数
if [ $# -lt 1 ]; then
usage
exit 1
fi
PROJECT_NAME="$1"
ENV_TYPE="${2:-dev}"
echo -e "${YELLOW}项目名称: $PROJECT_NAME${NC}"
echo -e "${YELLOW}环境类型: $ENV_TYPE${NC}"
echo ""
# 检查 GitLab 是否运行
echo -e "${YELLOW}检查 GitLab 服务状态...${NC}"
if ! docker ps | grep gitlab-ce > /dev/null; then
echo -e "${RED}错误: GitLab 容器未运行${NC}"
echo "请先启动 GitLab: cd gitlab && docker-compose up -d"
exit 1
fi
# 等待 GitLab 完全启动
echo -e "${YELLOW}等待 GitLab 完全启动...${NC}"
until curl -f -s "$GITLAB_URL/-/health" > /dev/null; do
echo "GitLab 正在启动中..."
sleep 10
done
echo -e "${GREEN}GitLab 已启动并可用${NC}"
# 获取 GitLab API token
echo -e "${YELLOW}获取 GitLab API token...${NC}"
PRIVATE_TOKEN=$(curl -s -X POST "$GITLAB_URL/api/v4/session" \
-H "Content-Type: application/json" \
-d "{\"login\":\"$GITLAB_ADMIN_USER\",\"password\":\"$GITLAB_ADMIN_PASSWORD\"}" | \
jq -r '.private_token')
if [ "$PRIVATE_TOKEN" = "null" ] || [ -z "$PRIVATE_TOKEN" ]; then
echo -e "${RED}错误: 无法获取 API token${NC}"
echo "请检查 GitLab 管理员凭据"
exit 1
fi
# 查找项目
echo -e "${YELLOW}查找项目: $PROJECT_NAME${NC}"
PROJECT_INFO=$(curl -s "$GITLAB_URL/api/v4/projects?search=$PROJECT_NAME" \
-H "Private-Token: $PRIVATE_TOKEN" | \
jq ".[] | select(.path_with_namespace | contains(\"$PROJECT_NAME\"))")
if [ -z "$PROJECT_INFO" ]; then
echo -e "${RED}错误: 未找到项目 '$PROJECT_NAME'${NC}"
echo "请确保项目已存在于 GitLab 中"
exit 1
fi
PROJECT_ID=$(echo "$PROJECT_INFO" | jq -r '.id')
PROJECT_PATH=$(echo "$PROJECT_INFO" | jq -r '.path_with_namespace')
echo -e "${GREEN}找到项目: $PROJECT_PATH (ID: $PROJECT_ID)${NC}"
# 环境变量配置
echo -e "${YELLOW}配置 CI/CD 环境变量...${NC}"
# 基础环境变量
VARS=(
"NODE_VERSION|18|Node.js 版本"
"PYTHON_VERSION|3.11|Python 版本"
"CI_DEBUG_TRACE|false|启用调试日志"
)
# 部署相关环境变量
if [ "$ENV_TYPE" = "prod" ]; then
VARS+=(
"DEPLOY_ENV|production|部署环境"
"ENVIRONMENT_NAME|production|环境名称"
)
else
VARS+=(
"DEPLOY_ENV|development|部署环境"
"ENVIRONMENT_NAME|development|环境名称"
)
fi
# 数据库配置 (示例)
VARS+=(
"POSTGRES_DB|${PROJECT_NAME}_db|数据库名称"
"POSTGRES_USER|${PROJECT_NAME}_user|数据库用户"
"REDIS_URL|redis://redis:6379|Redis 连接"
)
# 为每个变量创建或更新
for var in "${VARS[@]}"; do
IFS='|' read -r key value description <<< "$var"
echo -e "${BLUE}设置变量: $key${NC}"
echo -e "${BLUE}描述: $description${NC}"
echo -e "${BLUE}值: $value${NC}"
# 检查变量是否已存在
existing_var=$(curl -s "$GITLAB_URL/api/v4/projects/$PROJECT_ID/variables/$key" \
-H "Private-Token: $PRIVATE_TOKEN" || echo "")
if [ -n "$existing_var" ]; then
# 更新现有变量
result=$(curl -s -X PUT "$GITLAB_URL/api/v4/projects/$PROJECT_ID/variables/$key" \
-H "Private-Token: $PRIVATE_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"value\":\"$value\",\"description\":\"$description\"}")
else
# 创建新变量
result=$(curl -s -X POST "$GITLAB_URL/api/v4/projects/$PROJECT_ID/variables" \
-H "Private-Token: $PRIVATE_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"key\":\"$key\",\"value\":\"$value\",\"description\":\"$description\"}")
fi
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 变量设置成功${NC}"
else
echo -e "${RED}✗ 变量设置失败${NC}"
fi
echo ""
done
# 提示用户配置敏感变量
echo -e "${YELLOW}需要手动配置的敏感变量:${NC}"
echo "=================================="
echo "1. SSH_PRIVATE_KEY - 部署服务器 SSH 私钥"
echo "2. DEPLOY_SERVER - 部署服务器地址"
echo "3. DEPLOY_USER - 部署服务器用户名"
echo "4. DATABASE_PASSWORD - 数据库密码"
echo ""
echo -e "${BLUE}配置方法:${NC}"
echo "1. 访问 $GITLAB_URL"
echo "2. 进入项目: $PROJECT_PATH"
echo "3. Settings -> CI/CD -> Variables"
echo "4. 添加上述敏感变量,选择 'Protected' 和 'Masked'"
echo ""
# 创建示例 .gitlab-ci.yml 文件
echo -e "${YELLOW}创建示例 CI/CD 配置文件...${NC}"
cat > /tmp/.gitlab-ci.yml << 'EOF'
# 使用 stock 项目模板
include:
- local: 'gitlab/ci-templates/.gitlab-ci.yml.simple'
# 或者直接使用简化配置
stages:
- test
- build
- deploy
variables:
NODE_VERSION: "18"
IMAGE_TAG: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
test:
stage: test
image: node:$NODE_VERSION-alpine
script:
- echo "运行测试..."
- npm install
- npm test
coverage: '/Total coverage: \d+\.\d+%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
only:
- main
- develop
deploy:
stage: deploy
image: alpine:latest
script:
- echo "部署到 $DEPLOY_ENV 环境"
- echo "镜像: $IMAGE_TAG"
environment:
name: $ENVIRONMENT_NAME
when: manual
only:
- main
EOF
echo -e "${GREEN}示例配置文件已创建: /tmp/.gitlab-ci.yml${NC}"
echo ""
# 显示下一步操作
echo -e "${GREEN}环境变量配置完成!${NC}"
echo "=================================="
echo -e "${BLUE}下一步操作:${NC}"
echo "1. 复制示例配置文件到项目根目录:"
echo " cp /tmp/.gitlab-ci.yml /path/to/your/project/"
echo ""
echo "2. 推送代码到 GitLab:"
echo " git add .gitlab-ci.yml"
echo " git commit -m 'Add CI/CD configuration'"
echo " git push origin main"
echo ""
echo "3. 在 GitLab UI 中配置敏感变量"
echo "4. 等待流水线自动运行"
echo ""
echo -e "${BLUE}查看流水线:${NC}"
echo "$GITLAB_URL/$PROJECT_PATH/-/pipelines"
+40
View File
@@ -0,0 +1,40 @@
# Harbor 环境变量配置
# 复制此文件为 .env 并根据需要修改配置
# Harbor 基本配置
HARBOR_DOMAIN=192.168.1.83
HARBOR_HTTP_PORT=8080
HARBOR_HTTPS_PORT=8443
# Harbor 管理员密码
HARBOR_ADMIN_PASSWORD=admin
# 数据目录配置
HARBOR_DATA_DIR=~/ops/data/harbor
HARBOR_CERT_DIR=~/ops/harbor/certs
# 备份配置
HARBOR_BACKUP_DIR=~/ops/backups/harbor
HARBOR_BACKUP_RETENTION_DAYS=30
HARBOR_BACKUP_INTERVAL_HOURS=12
# 日志配置
HARBOR_LOG_DIR=~/ops/logs
# 数据库配置
HARBOR_DB_PASSWORD=root123
HARBOR_DB_MAX_IDLE_CONNS=100
HARBOR_DB_MAX_OPEN_CONNS=900
# Redis 配置
HARBOR_REDIS_HOST=redis
HARBOR_REDIS_PORT=6379
# 证书配置
HARBOR_SSL_CERT=/Users/brunogao/certs/harbor.lan.pem
HARBOR_SSL_KEY=/Users/brunogao/certs/harbor.lan-key.pem
# 代理配置 (如果需要)
# HTTP_PROXY=
# HTTPS_PROXY=
# NO_PROXY=localhost,127.0.0.1
+374
View File
@@ -0,0 +1,374 @@
# Harbor 维护模块
## 概述
这是 macOS 工具集中的 Harbor 维护模块,提供完整的 Harbor 容器镜像仓库管理解决方案,包括服务部署、自动备份、健康监控和一键恢复功能。
## 功能特性
- ✅ **一键部署**: Docker Compose 快速部署 Harbor 服务
- ✅ **自动备份**: 双重定时任务保障 (cron + launchd)
- ✅ **安全恢复**: 支持一键恢复和安全回滚
- ✅ **健康监控**: 实时监控服务状态和数据完整性
- ✅ **数据迁移**: 支持从现有 Harbor 无损迁移
- ✅ **macOS 集成**: 原生支持 macOS 系统特性
## 目录结构
```
harbor/
├── harbor.yml # Harbor 配置文件
├── docker-compose.yml # Docker 服务配置
├── harbor-data-protection.sh # 主管理脚本
├── harbor-backup.sh # 快速备份脚本
├── harbor-restore.sh # 快速恢复脚本
├── common/ # Harbor 通用配置
└── README.md # 本文档
```
## 快速开始
### 1. 环境准备
确保系统已安装:
- Docker Desktop for Mac
- Git (用于版本控制)
### 2. 初始化设置
```bash
# 进入项目目录
cd /path/to/macos/harbor
# 复制环境配置文件
cp .env.example .env
# 根据需要修改配置(可选)
nano .env
# 初始化设置(自动配置定时任务等)
./harbor-data-protection.sh setup
```
### 3. 启动服务
```bash
# 启动 Harbor 服务
./harbor-data-protection.sh start
# 检查服务状态
./harbor-data-protection.sh health
```
### 4. 访问 Harbor
- **Web 界面**: http://192.168.1.83:8080
- **Registry API**: http://192.168.1.83:8080/api/v2.0/
## 使用说明
### 服务管理
```bash
# 启动服务
./harbor-data-protection.sh start
# 停止服务
./harbor-data-protection.sh stop
# 重启服务
./harbor-data-protection.sh restart
# 健康检查
./harbor-data-protection.sh health
# 查看统计信息
./harbor-data-protection.sh stats
```
### 备份操作
```bash
# 手动备份(自动命名)
./harbor-backup.sh
# 手动备份(指定名称)
./harbor-backup.sh my-backup-20231019
# 查看备份文件
ls -la ~/ops/backups/harbor/
```
### 恢复操作
```bash
# 查看可用备份
./harbor-restore.sh
# 从指定备份恢复
./harbor-restore.sh harbor-20231019-120000.tar.gz
```
### 高级操作
```bash
# 完整功能菜单
./harbor-data-protection.sh help
# 重新初始化设置
./harbor-data-protection.sh setup
# 查看统计信息
./harbor-data-protection.sh stats
```
## 配置说明
### 环境变量 (.env)
| 变量名 | 默认值 | 说明 |
|--------|--------|------|
| `HARBOR_DOMAIN` | 192.168.1.83 | Harbor 服务器域名 |
| `HARBOR_HTTP_PORT` | 8080 | HTTP 端口 |
| `HARBOR_HTTPS_PORT` | 8443 | HTTPS 端口 |
| `HARBOR_ADMIN_PASSWORD` | admin | 管理员密码 |
| `HARBOR_DATA_DIR` | ~/ops/data/harbor | Harbor 数据目录 |
| `HARBOR_BACKUP_DIR` | ~/ops/backups/harbor | 备份存储目录 |
| `HARBOR_BACKUP_RETENTION_DAYS` | 30 | 备份保留天数 |
| `HARBOR_BACKUP_INTERVAL_HOURS` | 12 | 自动备份间隔(小时) |
### Harbor 配置 (harbor.yml)
主要配置项:
- `hostname`: Harbor 服务器地址
- `http.port`: HTTP 服务端口
- `https.port`: HTTPS 服务端口
- `harbor_admin_password`: 管理员密码
- `data_volume`: 数据存储路径
## 迁移说明
### 从现有 Harbor 迁移
如果已经有运行的 Harbor 实例,可以按照以下步骤无损迁移:
1. **备份现有数据**
```bash
# 停止现有服务
cd ~/harbor/harbor && docker-compose down
# 备份数据目录
tar -czf harbor-backup-$(date +%Y%m%d-%H%M%S).tar.gz ~/harbor-data
```
2. **使用新模块**
```bash
# 部署新模块
./init-ops.sh
# 恢复数据
./harbor-restore.sh harbor-backup-*.tar.gz
```
3. **验证迁移结果**
```bash
# 检查服务状态
./harbor-data-protection.sh health
# 验证镜像数量
./harbor-data-protection.sh stats
```
## 备份机制
### 自动备份
系统提供双重保障的自动备份:
1. **Cron 任务**: 传统 Unix 定时任务
2. **Launchd 任务**: macOS 原生定时任务
默认每 12 小时自动备份一次,保留 30 天的备份文件。
### 备份内容
- Harbor 配置文件 (harbor.yml)
- Docker Compose 配置
- Harbor 数据目录 (包括镜像数据、数据库等)
- 通用配置目录
### 备份位置
```
~/ops/backups/harbor/
├── harbor-20231019-120000.tar.gz # 备份文件
├── harbor-20231019-120000.tar.gz.meta # 备份元数据
└── safety-backup-*.tar.gz # 恢复时的安全备份
```
## 恢复机制
### 安全恢复流程
1. **停止服务**: 安全停止所有 Harbor 服务
2. **安全备份**: 自动创建当前状态的安全备份
3. **数据恢复**: 从指定备份恢复数据
4. **服务启动**: 重启服务并验证状态
5. **完整性检查**: 验证数据完整性
### 恢回滚
如果恢复出现问题,可以使用安全备份回滚:
```bash
./harbor-restore.sh safety-backup-20231019-130000.tar.gz
```
## 监控和日志
### 健康检查内容
- Docker 环境状态
- Harbor 各服务运行状态
- 数据卷完整性
- 镜像仓库数量统计
- 备份状态检查
- 定时任务状态
### 日志文件位置
```
~/ops/logs/
├── harbor-protection.log # 主脚本日志
├── harbor-backup_stdout.log # 备份输出日志
└── harbor-backup_stderr.log # 备份错误日志
```
### 查看日志
```bash
# 查看主日志
tail -f ~/ops/logs/harbor-protection.log
# 查看定时任务日志
tail -f ~/ops/logs/harbor-backup_*.log
```
## 故障排除
### 常见问题
1. **Docker 服务未启动**
```bash
# 启动 Docker Desktop
open /Applications/Docker.app
```
2. **端口冲突**
```bash
# 检查端口占用
lsof -i :8080
lsof -i :8443
```
3. **权限问题**
```bash
# 设置脚本权限
chmod +x harbor-*.sh
```
4. **定时任务未执行**
```bash
# 检查 launchd 任务
launchctl list | grep harbor
# 检查 cron 任务
crontab -l | grep harbor
```
### 手动恢复定时任务
```bash
# 重新加载 launchd 任务
launchctl unload ~/Library/LaunchAgents/com.ljwx.harbor.backup.plist 2>/dev/null || true
launchctl load -w ~/Library/LaunchAgents/com.ljwx.harbor.backup.plist
# 重新设置 cron 任务
./harbor-data-protection.sh setup
```
## 性能优化
### 备份优化
- 调整备份频率:修改 `HARBOR_BACKUP_INTERVAL_HOURS`
- 调整保留策略:修改 `HARBOR_BACKUP_RETENTION_DAYS`
- 使用外部存储:修改 `HARBOR_BACKUP_DIR` 到外部磁盘
### 服务优化
- 调整 Docker 资源限制
- 使用外部数据库(PostgreSQL)
- 配置 CDN 或反向代理
- 优化存储性能
## 安全建议
1. **定期备份**: 确保自动备份正常运行
2. **异地备份**: 将重要备份同步到云存储
3. **访问控制**: 配置防火墙规则限制访问
4. **定期更新**: 定期更新 Harbor 版本
5. **监控告警**: 配置服务状态监控
6. **SSL 证书**: 使用有效的 SSL 证书
## 升级指南
### Harbor 版本升级
```bash
# 1. 备份当前数据
./harbor-backup.sh pre-upgrade-$(date +%Y%m%d)
# 2. 停止服务
./harbor-data-protection.sh stop
# 3. 更新镜像版本
# 编辑 harbor.yml 或 docker-compose.yml,修改镜像标签
# 4. 启动服务
./harbor-data-protection.sh start
# 5. 验证升级
./harbor-data-protection.sh health
```
## 集成说明
### 与 CI/CD 集成
```bash
# CI 脚本示例
./harbor-backup.sh ci-pre-build-$(BUILD_NUMBER)
# 执行构建任务
./harbor-restore.sh ci-pre-build-$(BUILD_NUMBER).tar.gz
```
### 与监控系统集成
```bash
# 健康检查 API 调用
./harbor-data-protection.sh health
echo $?
```
## 许可证
MIT License - 可自由使用和修改
## 支持
如有问题或建议,请通过以下方式联系:
1. 查看日志文件排查问题
2. 检查 GitHub Issues
3. 提交新的 Issue 或 Pull Request
+6
View File
@@ -0,0 +1,6 @@
appname = Harbor
runmode = prod
enablegzip = true
[prod]
httpport = 8080
+51
View File
@@ -0,0 +1,51 @@
CONFIG_PATH=/etc/core/app.conf
UAA_CA_ROOT=/etc/core/certificates/uaa_ca.pem
_REDIS_URL_CORE=redis://redis:6379?idle_timeout_seconds=30
SYNC_QUOTA=true
_REDIS_URL_REG=redis://redis:6379/1?idle_timeout_seconds=30
LOG_LEVEL=info
EXT_ENDPOINT=https://192.168.1.83:8443
DATABASE_TYPE=postgresql
POSTGRESQL_HOST=postgresql
POSTGRESQL_PORT=5432
POSTGRESQL_USERNAME=postgres
POSTGRESQL_PASSWORD=root123
POSTGRESQL_DATABASE=registry
POSTGRESQL_SSLMODE=disable
POSTGRESQL_MAX_IDLE_CONNS=100
POSTGRESQL_MAX_OPEN_CONNS=900
POSTGRESQL_CONN_MAX_LIFETIME=5m
POSTGRESQL_CONN_MAX_IDLE_TIME=0
REGISTRY_URL=http://registry:5000
PORTAL_URL=http://portal:8080
TOKEN_SERVICE_URL=http://core:8080/service/token
HARBOR_ADMIN_PASSWORD=admin
MAX_JOB_WORKERS=10
CORE_SECRET=evrhBggzCUD4nZrP
JOBSERVICE_SECRET=Fz2ZivOojMGv0pN9
WITH_TRIVY=False
CORE_URL=http://core:8080
CORE_LOCAL_URL=http://127.0.0.1:8080
JOBSERVICE_URL=http://jobservice:8080
TRIVY_ADAPTER_URL=http://trivy-adapter:8080
REGISTRY_STORAGE_PROVIDER_NAME=filesystem
READ_ONLY=false
RELOAD_KEY=
REGISTRY_CONTROLLER_URL=http://registryctl:8080
REGISTRY_CREDENTIAL_USERNAME=harbor_registry_user
REGISTRY_CREDENTIAL_PASSWORD=0k8vBxdZcBoL7eYFjJiD96WzKGpIf7XN
CSRF_KEY=r7triBX5KUTSc8AQRzt8Zp3AdntdIs8j
ROBOT_SCANNER_NAME_PREFIX=8tzoAVCZ
PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE=docker-hub,harbor,azure-acr,aws-ecr,google-gcr,quay,docker-registry,github-ghcr,jfrog-artifactory
HTTP_PROXY=
HTTPS_PROXY=
NO_PROXY=.local,.internal,127.0.0.1,localhost,core,trivy-adapter,portal,registry,registryctl,nginx,jobservice,log,redis,postgresql,db,exporter
PORT=8080
QUOTA_UPDATE_PROVIDER=db
+1
View File
@@ -0,0 +1 @@
POSTGRES_PASSWORD=root123
@@ -0,0 +1,46 @@
---
#Protocol used to serve
protocol: "http"
#Server listening port
port: 8080
#Worker pool
worker_pool:
#Worker concurrency
workers: 10
backend: "redis"
#Additional config if use 'redis' backend
redis_pool:
#redis://[arbitrary_username:password@]ipaddress:port/database_index
redis_url: redis://redis:6379/2?idle_timeout_seconds=30
namespace: "harbor_job_service_namespace"
idle_timeout_second: 3600
#Loggers for the running job
job_loggers:
# The jobLoggers backend name, only support "STD_OUTPUT", "FILE" and/or "DB"
- name: "STD_OUTPUT"
level: "INFO" # INFO/DEBUG/WARNING/ERROR/FATAL
- name: "FILE"
level: "INFO"
settings: # Customized settings of logger
base_dir: "/var/log/jobs"
sweeper:
duration: 1 #days
settings: # Customized settings of sweeper
work_dir: "/var/log/jobs"
#Loggers for the job service
loggers:
- name: "STD_OUTPUT" # Same with above
level: "INFO"
reaper:
# the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24,
max_update_hours: 24
# the max time for execution in running state without new task created
max_dangling_hours: 168
# the max size of job log returned by API, default is 10M
max_retrieve_size_mb: 10
+17
View File
@@ -0,0 +1,17 @@
CORE_SECRET=evrhBggzCUD4nZrP
REGISTRY_URL=http://registry:5000
JOBSERVICE_SECRET=Fz2ZivOojMGv0pN9
CORE_URL=http://core:8080
REGISTRY_CONTROLLER_URL=http://registryctl:8080
JOBSERVICE_WEBHOOK_JOB_MAX_RETRY=3
JOBSERVICE_WEBHOOK_JOB_HTTP_CLIENT_TIMEOUT=3
HTTP_PROXY=
HTTPS_PROXY=
NO_PROXY=.local,.internal,127.0.0.1,localhost,core,trivy-adapter,portal,registry,registryctl,nginx,jobservice,log,redis,postgresql,db,exporter
REGISTRY_CREDENTIAL_USERNAME=harbor_registry_user
REGISTRY_CREDENTIAL_PASSWORD=0k8vBxdZcBoL7eYFjJiD96WzKGpIf7XN
+8
View File
@@ -0,0 +1,8 @@
/var/log/docker/*.log {
rotate 50
size 200M
copytruncate
compress
missingok
nodateext
}
@@ -0,0 +1,7 @@
# Rsyslog configuration file for docker.
template(name="DynaFile" type="string" string="/var/log/docker/%programname%.log")
if $programname != "rsyslogd" then {
action(type="omfile" dynaFile="DynaFile")
}
+156
View File
@@ -0,0 +1,156 @@
worker_processes auto;
pid /tmp/nginx.pid;
events {
worker_connections 3096;
use epoll;
multi_accept on;
}
http {
client_body_temp_path /tmp/client_body_temp;
proxy_temp_path /tmp/proxy_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
tcp_nodelay on;
include /etc/nginx/conf.d/*.upstream.conf;
# this is necessary for us to be able to disable request buffering in all cases
proxy_http_version 1.1;
upstream core {
server core:8080;
}
upstream portal {
server portal:8080;
}
log_format timed_combined '$remote_addr - '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time $pipe';
access_log /dev/stdout timed_combined;
map $http_x_forwarded_proto $x_forwarded_proto {
default $http_x_forwarded_proto;
"" $scheme;
}
include /etc/nginx/conf.d/*.server.conf;
server {
listen 8443 ssl;
# server_name harbordomain.com;
server_tokens off;
# SSL
ssl_certificate /etc/cert/server.crt;
ssl_certificate_key /etc/cert/server.key;
# Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
chunked_transfer_encoding on;
# Add extra headers
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header Content-Security-Policy "frame-ancestors 'none'";
# customized location config file can place to /etc/nginx dir with prefix harbor.https. and suffix .conf
include /etc/nginx/conf.d/harbor.https.*.conf;
location / {
proxy_pass http://portal/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $x_forwarded_proto;
proxy_cookie_path / "/; HttpOnly; Secure";
proxy_buffering off;
proxy_request_buffering off;
}
location /c/ {
proxy_pass http://core/c/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $x_forwarded_proto;
proxy_cookie_path / "/; Secure";
proxy_buffering off;
proxy_request_buffering off;
}
location /api/ {
proxy_pass http://core/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $x_forwarded_proto;
proxy_cookie_path / "/; Secure";
proxy_buffering off;
proxy_request_buffering off;
}
location /v1/ {
return 404;
}
location /v2/ {
proxy_pass http://core/v2/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $x_forwarded_proto;
proxy_buffering off;
proxy_request_buffering off;
proxy_send_timeout 900;
proxy_read_timeout 900;
}
location /service/ {
proxy_pass http://core/service/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $x_forwarded_proto;
proxy_cookie_path / "/; Secure";
proxy_buffering off;
proxy_request_buffering off;
}
location /service/notifications {
return 404;
}
}
server {
listen 8080;
#server_name harbordomain.com;
return 308 https://$host:8443$request_uri;
}
# Additional HTTP server on port 8081 for users who accidentally use HTTP on port 8443
server {
listen 8081;
#server_name harbordomain.com;
return 308 https://$host:8443$request_uri;
}
}
+42
View File
@@ -0,0 +1,42 @@
worker_processes auto;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
client_body_temp_path /tmp/client_body_temp;
proxy_temp_path /tmp/proxy_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location /devcenter-api-2.0 {
try_files $uri $uri/ /swagger-ui-index.html;
}
location / {
try_files $uri $uri/ /index.html;
}
location = /index.html {
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
}
}
+43
View File
@@ -0,0 +1,43 @@
version: 0.1
log:
level: info
fields:
service: registry
storage:
cache:
layerinfo: redis
filesystem:
rootdirectory: /storage
maintenance:
uploadpurging:
enabled: true
age: 168h
interval: 24h
dryrun: false
delete:
enabled: true
redis:
addr: redis:6379
readtimeout: 10s
writetimeout: 10s
dialtimeout: 10s
password:
db: 1
pool:
maxidle: 100
maxactive: 500
idletimeout: 60s
http:
addr: :5000
secret: placeholder
debug:
addr: localhost:5001
auth:
htpasswd:
realm: harbor-registry-basic-realm
path: /etc/registry/passwd
validation:
disabled: true
compatibility:
schema1:
enabled: true
+1
View File
@@ -0,0 +1 @@
harbor_registry_user:$2y$05$qpjbQSEnJNUHPgMZxjzE2.dbLI.bsnkpjSpJdu2J.1S24ZVF585zS
@@ -0,0 +1,5 @@
---
protocol: "http"
port: 8080
log_level: info
registry_config: "/etc/registry/config.yml"
+2
View File
@@ -0,0 +1,2 @@
CORE_SECRET=evrhBggzCUD4nZrP
JOBSERVICE_SECRET=Fz2ZivOojMGv0pN9
+258
View File
@@ -0,0 +1,258 @@
version: '2.3'
services:
log:
image: goharbor/harbor-log:v2.11.1
container_name: harbor-log
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- SETGID
- SETUID
volumes:
- /var/log/harbor/:/var/log/docker/:z
- type: bind
source: ./common/config/log/logrotate.conf
target: /etc/logrotate.d/logrotate.conf
- type: bind
source: ./common/config/log/rsyslog_docker.conf
target: /etc/rsyslog.d/rsyslog_docker.conf
ports:
- 127.0.0.1:1514:10514
networks:
- harbor
registry:
image: goharbor/registry-photon:v2.11.1
container_name: registry
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
volumes:
- /Users/brunogao/ops/data/harbor/registry:/storage:z
- ./common/config/registry/:/etc/registry/:z
- type: bind
source: /Users/brunogao/ops/data/harbor/secret/registry/root.crt
target: /etc/registry/root.crt
- type: bind
source: ./common/config/shared/trust-certificates
target: /harbor_cust_cert
networks:
- harbor
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://localhost:1514"
tag: "registry"
registryctl:
image: goharbor/harbor-registryctl:v2.11.1
container_name: registryctl
env_file:
- ./common/config/registryctl/env
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
volumes:
- /Users/brunogao/ops/data/harbor/registry:/storage:z
- ./common/config/registry/:/etc/registry/:z
- type: bind
source: ./common/config/registryctl/config.yml
target: /etc/registryctl/config.yml
- type: bind
source: ./common/config/shared/trust-certificates
target: /harbor_cust_cert
networks:
- harbor
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://localhost:1514"
tag: "registryctl"
postgresql:
image: goharbor/harbor-db:v2.11.1
container_name: harbor-db
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- SETGID
- SETUID
volumes:
- /Users/brunogao/ops/data/harbor/database:/var/lib/postgresql/data:z
networks:
harbor:
env_file:
- ./common/config/db/env
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://localhost:1514"
tag: "postgresql"
shm_size: '1gb'
core:
image: goharbor/harbor-core:v2.11.1
container_name: harbor-core
env_file:
- ./common/config/core/env
restart: always
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
volumes:
- /Users/brunogao/ops/data/harbor/ca_download/:/etc/core/ca/:z
- /Users/brunogao/ops/data/harbor/:/data/:z
- ./common/config/core/certificates/:/etc/core/certificates/:z
- type: bind
source: ./common/config/core/app.conf
target: /etc/core/app.conf
- type: bind
source: /Users/brunogao/ops/data/harbor/secret/core/private_key.pem
target: /etc/core/private_key.pem
- type: bind
source: /Users/brunogao/ops/data/harbor/secret/keys/secretkey
target: /etc/core/key
- type: bind
source: ./common/config/shared/trust-certificates
target: /harbor_cust_cert
networks:
harbor:
depends_on:
- log
- registry
- redis
- postgresql
logging:
driver: "syslog"
options:
syslog-address: "tcp://localhost:1514"
tag: "core"
portal:
image: goharbor/harbor-portal:v2.11.1
container_name: harbor-portal
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
- NET_BIND_SERVICE
volumes:
- type: bind
source: ./common/config/portal/nginx.conf
target: /etc/nginx/nginx.conf
networks:
- harbor
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://localhost:1514"
tag: "portal"
jobservice:
image: goharbor/harbor-jobservice:v2.11.1
container_name: harbor-jobservice
env_file:
- ./common/config/jobservice/env
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
volumes:
- /Users/brunogao/ops/data/harbor/job_logs:/var/log/jobs:z
- type: bind
source: ./common/config/jobservice/config.yml
target: /etc/jobservice/config.yml
- type: bind
source: ./common/config/shared/trust-certificates
target: /harbor_cust_cert
networks:
- harbor
depends_on:
- core
logging:
driver: "syslog"
options:
syslog-address: "tcp://localhost:1514"
tag: "jobservice"
redis:
image: goharbor/redis-photon:v2.11.1
container_name: redis
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
volumes:
- /Users/brunogao/ops/data/harbor/redis:/var/lib/redis
networks:
harbor:
depends_on:
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://localhost:1514"
tag: "redis"
proxy:
image: goharbor/nginx-photon:v2.11.1
container_name: nginx
restart: always
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
- NET_BIND_SERVICE
volumes:
- ./common/config/nginx:/etc/nginx:z
- /Users/brunogao/ops/data/harbor/secret/cert:/etc/cert:z
- type: bind
source: ./common/config/shared/trust-certificates
target: /harbor_cust_cert
networks:
- harbor
ports:
- 8080:8080
- 8081:8081
- 8443:8443
depends_on:
- registry
- core
- portal
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://localhost:1514"
tag: "proxy"
networks:
harbor:
external: false
+91
View File
@@ -0,0 +1,91 @@
# GitLab CI/CD 环境变量配置
# 企业级 CI/CD 蓝皮书 - Harbor 集成配置
# Harbor 容器仓库配置
HARBOR_URL="192.168.1.83:8443"
HARBOR_INSECURE="true"
# Harbor Robot Account (CI/CD)
HARBOR_DEV_USER="robot$ci"
HARBOR_DEV_PASSWORD="EhlqdiZvxAGreXaCK7faAte4kNbPymtG"
# Harbor 项目配置
HARBOR_DEV_PROJECT="ljwx-dev"
HARBOR_STAGE_PROJECT="ljwx-stage"
HARBOR_PROD_PROJECT="ljwx-prod"
# Docker 镜像仓库配置
DOCKER_REGISTRY="$HARBOR_URL"
DOCKER_REGISTRY_USER="$HARBOR_DEV_USER"
DOCKER_REGISTRY_PASSWORD="$HARBOR_DEV_PASSWORD"
# GitLab Runner 配置
RUNNER_EXECUTOR="docker"
RUNNER_DOCKER_IMAGE="docker:24.0.7"
RUNNER_DOCKER_PRIVILEGED="true"
RUNNER_DOCKER_VOLUMES="/var/run/docker.sock:/var/run/docker.sock,/cache"
# K8s 集群配置 (预留)
K8S_DEV_CLUSTER="dev-cluster.ljwx.com"
K8S_STAGE_CLUSTER="stage-cluster.ljwx.com"
K8S_PROD_CLUSTER="prod-cluster.ljwx.com"
# 应用配置
APP_NAME="ljwx-enterprise"
APP_VERSION="1.0.0"
BUILD_TARGET="linux/arm64"
# 安全配置
SECURITY_SCAN_ENABLED="true"
VULNERABILITY_THRESHOLD="high"
CONTAINER_SCAN_ENABLED="true"
# 通知配置
SLACK_WEBHOOK_URL=""
EMAIL_NOTIFY_ENABLED="false"
TEAMS_WEBHOOK_URL=""
# 备份配置
BACKUP_ENABLED="true"
BACKUP_RETENTION_DAYS="30"
BACKUP_STORAGE_LOCATION="s3://enterprise-backups"
# 监控配置
PROMETHEUS_ENABLED="true"
GRAFANA_ENABLED="true"
JAEGER_ENABLED="false"
# Git 配置
GIT_USER_EMAIL="ci@ljwx.com"
GIT_USER_NAME="LJWX CI/CD"
# 构建配置
MAVEN_OPTS="-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
NODE_OPTIONS="--max-old-space-size=4096"
PYTHON_CACHE_DIR="$CI_PROJECT_DIR/.cache/pip"
# 测试配置
TEST_TIMEOUT="30m"
COVERAGE_THRESHOLD="80"
TEST_PARALLELISM="4"
# 部署配置
DEV_DEPLOY_STRATEGY="rolling"
STAGE_DEPLOY_STRATEGY="blue-green"
PROD_DEPLOY_STRATEGY="canary"
# 回滚配置
AUTO_ROLLBACK_ENABLED="true"
ROLLBACK_TIMEOUT="10m"
HEALTH_CHECK_INTERVAL="30s"
# 资源限制
DEFAULT_CPU_LIMIT="1000m"
DEFAULT_MEMORY_LIMIT="2Gi"
BUILD_CPU_LIMIT="2000m"
BUILD_MEMORY_LIMIT="4Gi"
# 网络配置
SERVICE_MESH_ENABLED="true"
INGRESS_CLASS="nginx"
TLS_ENABLED="true"
+52
View File
@@ -0,0 +1,52 @@
{
"gitlab_workhorse": {
"secret_token": "84tABJKOYmTcKsskhWtvlIyqU/aH0+LxLNPAr27V8r4="
},
"gitlab_shell": {
"secret_token": "bbe09e3b9555f2f06d08eb4ed9c1aad18b6f836e651b427e7e4cba884184242001883b3b93044ec34210985b999779f0a161c160761f24d2fbff814e69bd1e3c"
},
"gitlab_rails": {
"secret_key_base": "6545781a75c56e2ee25d0a28eaa7e4b10a6e6ebf3d8efa278d50700f3c688969251eb141d9b29094bf2acc2b6636b3db9a20915ed7eae997374b537d072ff9b1",
"db_key_base": "336dd3ed6a763d9fc11c4609324434aa19c9585729e23930fac5238b225a4b0e9df847588d0826179e7b5deacbdf37e5adf68adcda846c307da4a227cc81d192",
"otp_key_base": "08fe9208076f8088dfdca25ff5e8933fe4a4844e344a601e042e8ae40321b97f727453e93b852f978fb20cae36ca978620bbd198bcd7a556bfc6e406ff22069c",
"encrypted_settings_key_base": "22921af55f891345dcb16e35649fd7b0cb74064c84622606badd0808325e0749ea955d679a4db995cbfb301ac3c8fdcfcdc625a10a1201841d7e0906c42d5994",
"openid_connect_signing_key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n",
"ci_jwt_signing_key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"
},
"gitlab_pages": {
"gitlab_secret": "vSGX1XT5uloQ7wX-TxFOGnJLQwCSiW2MAyyb_nKEaKw",
"gitlab_id": "MAbuRe-RicEDF-TAt0il07Ib1oa7YUq6t_X7nGk3kGI",
"auth_secret": null,
"api_secret_key": "SqhJ7Lq0fudU/dzLhxp4CVbq7sMoZR7Fcb/NsgCcH6g=",
"register_as_oauth_app": null
},
"gitlab_kas": {
"api_secret_key": "YzMxYzE1YjNmOTcwMjZiZTg0NTU2YTRlYTc5NjNmNzU=",
"private_api_secret_key": "Y2Q5OTA1ZTczOTRlYzk1ODJjNTZlMzU4MTBlZWIzMTA="
},
"suggested_reviewers": {
"api_secret_key": null
},
"registry": {
"http_secret": "ffd29c6711ed3b569366cc7b50763f031844480f360ab847cfd5f77a2bcec0b97e5fec00a64a45f15c0908ce5f8040018c666c058df9fc106708234aad4120d0",
"internal_certificate": "-----BEGIN CERTIFICATE-----\nMIIFBTCCAu2gAwIBAgIBADANBgkqhkiG9w0BAQsFADBGMQwwCgYDVQQGEwNVU0Ex\nDzANBgNVBAoMBkdpdExhYjESMBAGA1UECwwJQ29udGFpbmVyMREwDwYDVQQDDAhS\nZWdpc3RyeTAeFw0yNTEwMTkxMjEyMjBaFw0zNTEwMTcxMjEyMjBaMEYxDDAKBgNV\nBAYTA1VTQTEPMA0GA1UECgwGR2l0TGFiMRIwEAYDVQQLDAlDb250YWluZXIxETAP\nBgNVBAMMCFJlZ2lzdHJ5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA\nw45EFNG5skX7lr1+xxZNNVBQSeiNTXGYudpMBuH8vLztEvOabR1IA4OruWD5/skc\nlGZ5EIZHxmeOdINaibL87+MKdIq2JrLv8VbsuqtMxzAG7OoOexvpqrSKE8ZG02hE\n6Cw0rc43gc9oWo//qpVt5zDR7PS+X75UuKkiUyYyIP7QqdD9dc4EpVAPl1ZSEON2\nlZ46xwlVvXQKfZoe2/+BJqzxhUYXw5Qm1WRzZFe6LXUYOw5ym6DNcEKyjdSkqN0r\n8oFefJ2iAPGnjMiaUhitCwb68pPJ6qpZzkhBT5bxXu6NkISBvGXC0poX8aPTSSVe\nAFyCdhmK+RNXf/5HHNPcaxKE4C4CfDgFDvju62jwjVU9zvoQQBu7PwFZDgupCCmd\nZDpTPwHctMLfSfoROmrosTqS8LACI7VnjUTHHwncaQNcKdDrE6jQSPGk/6U39reZ\nDs785qDk1+d4j2+mnncWSyKiQm9oeZTpfqcH0IR5PXRon35EbfR+WG9jdHTYOKEq\neGys5A/ke6m8ZWf0zhpph1z8SViuKK+amTAaKkphIQ0Cv6PhTSwkZuNSSMF5FDIO\nDsz4D3kU5o6kFgGZidcb/obSrDrPNRjZtZbVtUAmfgC9xDneR1QLBcIZD9yKrFCQ\nPyLAzduyCbP0hVtK05YROTNtAE5NF90aHvn3xbRHrdMCAwEAATANBgkqhkiG9w0B\nAQsFAAOCAgEAgUbtH/tBk6NWhd6O0OxE8WiJFdgP8temB7muaha3nYDc67jPLnma\nudWXynavCp1WqqImkoO3r4bgiTJs0e90UPxKlf+nLkjziOCCwah08GfQ8lrEsY7P\nKRKjgKBTE3M3yj7ixhoPFMfOVuXGXvcDf9CEuByy3TIuAHfeOreUXOBc49eK1/i1\nYldjI7Q2jIlqJAJAI8Z9BmP47/JU0J6YJnYfsv1FxMw4icpDbvkEFuusiZcI+zkJ\nrhRqBcSQ1V+LRDYr/YMRsApOWCADsfe7wrUxvYi7ZkoDcfanxIrH2d7TaSvRayGD\n0f/AjPGDtpg9vsMI7sImyOQbccIpqwL9n3uB7QFmutHEHdf7GjKvGVdSaYMwxZyj\nTojyrEZhqn8XUjRRtsWu4yI+t2CSa3uO2IOyHaWtbhp67N3HiJUZU12SldB1mFWE\n5U3kzmT6ouNRkMd5xBdKPvrn7ahoqwgfm02NGvV4b8tFrsT5Ts3z1qEBRByJ3JnL\nB7+8e/7QXlVUrBCMKzPUU2RzR/ybVqsMtiCxteAZAamXg6BeSd1pLwgyG/guj0bo\nUx3TNTsT6a806RCBdu1GpgSA2Yehl7OFsfP9djYpOwTIX9mgrvEplb6wG1a0OoDk\n7+xhi4eVHWmAVuqCb4tHYUAZ4kLcVEhPZf0kLP6RLqlOI8trud6WU68=\n-----END CERTIFICATE-----\n",
"internal_key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"
},
"letsencrypt": {
"auto_enabled": null
},
"mattermost": {
"email_invite_salt": "aa89bd78b0cf5e7a252c006706189879",
"file_public_link_salt": "7814e1b33d5118bee79d29f26cf9dfba",
"sql_at_rest_encrypt_key": "38d36278fff3ee68f48edb732afe000a",
"register_as_oauth_app": null
},
"postgresql": {
"internal_certificate": "-----BEGIN CERTIFICATE-----\nMIIFBzCCAu+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBHMQwwCgYDVQQGEwNVU0Ex\nDzANBgNVBAoMBkdpdExhYjERMA8GA1UECwwIRGF0YWJhc2UxEzARBgNVBAMMClBv\nc3RncmVTUUwwHhcNMjUxMDE5MTIxMjIyWhcNMzUxMDE3MTIxMjIyWjBHMQwwCgYD\nVQQGEwNVU0ExDzANBgNVBAoMBkdpdExhYjERMA8GA1UECwwIRGF0YWJhc2UxEzAR\nBgNVBAMMClBvc3RncmVTUUwwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\nAQCmODHJRKX7sOYmAD8zN6Bmoi13VRhYEta9mWBRpkg1H0P41nCF9PxwVoqKqymt\nGgyZCs0wFEsPRWc0/5r3AoPBlup+eggMMvEnvr5Y9Z/vaG354rUr/tXEqma3ekwr\nVHGberXsF3+ohmctQrzxa3+3eElnL/sz9iUunPu3IZoE19OjAsCeu1kgo6af0UWe\niObQd2gvCSkRZ1t+ctvdiVS3Wblzs95disOXjhTU06Aji3868Yc1xrhI5J7WP/iS\n/z/SP2pmqGvgnMswgkrABkauuaI6WZCWj6uPEajgn+GMoXLTMKPBznDxtD6B2M9z\nS5hSHATLYnRYADeVZoXolq4s9WVDMJfOB7vnDHWbnZAA+lz66RfPMgpLH0b3C10U\n06MRyx145uXkImoYeQqEd3AWLNDXQIpZxXqN11kA9lCMqMyWPPGRgQK3oeZEzah+\n8rynoL/RS593Ne0yrCT1/hQKsmLeY8SsgmbgEAvgGIQZllwuwgUmXqwtdE8g8Md0\nlfgdqFNdJWqEjcRRQVbPVWClN3Ln4qh7IisCa9ZXVhmyhMEFgruI6C/0R6ynxPLu\nXdc8UnAPlhxt/BoC84jhv9ixkM1/ue5QZlwkbUcjqZDcMRS/91YGwPMWfuw2oALi\nSOcPMOSNJy3PRVYlAmOgS/Bq5ufdy98qNnYSCBZRVua2/QIDAQABMA0GCSqGSIb3\nDQEBCwUAA4ICAQAQ+f/zhgQvKYe8OCcr6Ri/4CYN7WtLJwSsrFSPZNofZgVpJY9e\nH3Evz/7y/1kawHDHKNDea04+5OYSpyS2DzBderDtdEJ63XQ0mHlDjsCeVXltblx+\nP80jl+a3xAp4SQ0pQJTln+9LF/tjXmuXz21XdS5fJbtrpwubYyDG7qgBANd2wtQG\njTnUJCsAUYSscYT5QrMgvHo6csxM3usios4H3u+AilzHSyigFBJgWbUEHxHBZLiq\nX3ucSKQH++5Wi/nd3KMKfbUcQdTXie1NymmiPUO4SjZKyMcVrLxb7+Ayy2F0FerT\ne7UWKgsFhiGGXXsGnSAcW8h6TmxOU4RmrTcs7McVg9dGkN+t4oeJkLTFWdzyfr/Q\nrzpZZax7tBwdnpK3OmEUZqnqccqiO/ludnDT92e1/sCK8Os+I1Ho0djyd5u88ACo\nSKGE+zFGeaCUWDutc6qtk7m4j9GI/rMHE6mrB1PPKaD3l35p2KEYORtOYNhXCgwb\nAob5UTRA+to/Q2JMTPqeYIqx86sEScoUje56deJInMB2Izle2ii2w2UtbdmRhM4J\nwrY+4zDlPbAk+oqdAVtDhyiOnxF/mrvP0i+036wJAC8eufjaJaV6+YPQvNF6mREU\nhxdWq4jgpWeV6GuUZemDYc/GUx+av+6wCyjN6mY7QLix8R4Ur4woKskwOQ==\n-----END CERTIFICATE-----\n",
"internal_key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----\n"
},
"mailroom": {
"incoming_email_auth_token": null,
"service_desk_email_auth_token": null
}
}
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
QCRhYSVZyyArPTlUAca83uMkg
+9
View File
@@ -0,0 +1,9 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQRZEGo+QqcWCpmc+5oEBY6/MVtNgO4b
/cFHVHI1jWR3DUxjy42DrQrUwTdhQP+/akzggJkeZdrMx2wYFmrSQShIAAAAsGYu4RhmLu
EYAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFkQaj5CpxYKmZz7
mgQFjr8xW02A7hv9wUdUcjWNZHcNTGPLjYOtCtTBN2FA/79qTOCAmR5l2szHbBgWatJBKE
gAAAAgVpMHrvAvegJxD7D7Pt3I6kROyh1pFuDmPRekWnepbMUAAAARcm9vdEBnaXRsYWIu
bG9jYWwBAgMEBQYH
-----END OPENSSH PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFkQaj5CpxYKmZz7mgQFjr8xW02A7hv9wUdUcjWNZHcNTGPLjYOtCtTBN2FA/79qTOCAmR5l2szHbBgWatJBKEg= root@gitlab.local
+7
View File
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAhjNhWIv6q9j6rtIRaYuIkh5Ui8Epi9CFW0gruYJwGrAAAAJhDpEc4Q6RH
OAAAAAtzc2gtZWQyNTUxOQAAACAhjNhWIv6q9j6rtIRaYuIkh5Ui8Epi9CFW0gruYJwGrA
AAAEBKZwRgwiVtu5FHHME8sh31Ah0aO/09Ec5emFSEsGn2pyGM2FYi/qr2Pqu0hFpi4iSH
lSLwSmL0IVbSCu5gnAasAAAAEXJvb3RAZ2l0bGFiLmxvY2FsAQIDBA==
-----END OPENSSH PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICGM2FYi/qr2Pqu0hFpi4iSHlSLwSmL0IVbSCu5gnAas root@gitlab.local
+38
View File
@@ -0,0 +1,38 @@
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
+1
View File
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCp0oTA3ydj0mPbLsbouE+G++M2w674cXYReJ1cpA2NCFSTzjaLo4Vh/KqpcG4IS5XaqB2kM6AtdgHc/kzZ1dBLL1wNceDWTDxJNjapKYYN0r33ujzN+7pIXJXY6ek8jbxtZfs/0UNPhU3rgbkHowNwFwiQPxY/NdpJrLntrU3Urd0sBoyVe58QzOEuaSysgfCDqw3fxEVpBGosVl70gym1r4kHtxhAm4gV9c56Tj5Pz+Z8Y4IvHRsVUA7AgmqtFzwg/Of6ComEEriJXqgbDr+g5koE/yGvAPRuwvvEa+7Na2vVuZ/e000en4rP7VJVNlL+6DW52JwZyl1Xf10Pmx6Xbkp8PHXutyFgsbMr5fjlX4qM5zhNYxpgsgwten9rDiA/F36nzdiminlIT38yHnQGqkSr40n1ePlhcywWRux3NV0VFRQVYgVWnpolGHb/3XPWiqKJrGBYJXoejC2nwQDe0r423f2G4AJgcIyRIWAmdcBnw0K26Ke5pwo153gaEsk= root@gitlab.local
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# Harbor 快速备份脚本
# 这是 harbor-data-protection.sh 的简化版本,专注于快速备份操作
set -euo pipefail
# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HARBOR_DATA_PROTECTION="${SCRIPT_DIR}/harbor-data-protection.sh"
BACKUP_NAME="${1:-}"
# 调用主脚本的备份功能
if [[ -x "$HARBOR_DATA_PROTECTION" ]]; then
if [[ -n "$BACKUP_NAME" ]]; then
"$HARBOR_DATA_PROTECTION" backup "$BACKUP_NAME"
else
"$HARBOR_DATA_PROTECTION" backup
fi
else
echo "错误: 找不到 Harbor 数据保护脚本: $HARBOR_DATA_PROTECTION"
exit 1
fi
+596
View File
@@ -0,0 +1,596 @@
#!/bin/bash
# Harbor 数据保护和管理脚本
# 支持 Docker Compose 模式的 Harbor 服务管理
set -euo pipefail
# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_NAME="${PROJECT_NAME:-harbor}"
HARBOR_DIR="${HARBOR_DIR:-${SCRIPT_DIR}}"
HARBOR_DATA_DIR="${HARBOR_DATA_DIR:-~/ops/data/harbor}"
HARBOR_CERT_DIR="${HARBOR_CERT_DIR:-${SCRIPT_DIR}/certs}"
LOG_FILE="${LOG_FILE:-~/ops/logs/harbor-protection.log}"
BACKUP_DIR="${BACKUP_DIR:-~/ops/backups/harbor}"
HARBOR_YML="${HARBOR_YML:-${HARBOR_DIR}/harbor.yml}"
DOCKER_COMPOSE_FILE="${DOCKER_COMPOSE_FILE:-${HARBOR_DIR}/docker-compose.yml}"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
info() {
log "${BLUE}[INFO]${NC} $1"
}
success() {
log "${GREEN}[SUCCESS]${NC} $1"
}
warning() {
log "${YELLOW}[WARNING]${NC} $1"
}
error() {
log "${RED}[ERROR]${NC} $1"
}
# 检查必要的依赖
check_dependencies() {
local deps=("docker" "docker-compose")
for dep in "${deps[@]}"; do
if ! command -v "$dep" &> /dev/null; then
error "$dep 未安装,请先安装 $dep"
exit 1
fi
done
# 检查 Docker 是否运行
if ! docker info &> /dev/null; then
error "Docker 未运行,请启动 Docker Desktop"
exit 1
fi
}
# 创建必要的目录
ensure_directories() {
mkdir -p "$(dirname "${LOG_FILE}")"
mkdir -p "${BACKUP_DIR}"
mkdir -p "$(dirname "${HARBOR_DATA_DIR}")"
mkdir -p "${HARBOR_CERT_DIR}"
}
# 检查 Harbor 配置
check_harbor_config() {
if [[ ! -f "${HARBOR_YML}" ]]; then
error "Harbor 配置文件不存在: ${HARBOR_YML}"
return 1
fi
if [[ ! -f "${DOCKER_COMPOSE_FILE}" ]]; then
error "Docker Compose 配置文件不存在: ${DOCKER_COMPOSE_FILE}"
return 1
fi
return 0
}
# 服务状态检查
check_service_status() {
info "检查 Harbor 服务状态..."
local running_containers
running_containers=$(docker-compose -f "${DOCKER_COMPOSE_FILE}" ps -q 2>/dev/null || echo "")
if [[ -z "$running_containers" ]]; then
warning "Harbor 服务未运行"
return 1
fi
local healthy_containers
healthy_containers=$(docker-compose -f "${DOCKER_COMPOSE_FILE}" ps --filter "status=running" --format "table {{.Service}}\t{{.Status}}" 2>/dev/null | grep -c "healthy\|Up" || echo "0")
info "运行中的容器数量: $(echo "$running_containers" | wc -l)"
info "健康容器数量: $healthy_containers"
return 0
}
# 启动 Harbor 服务
start_services() {
info "启动 Harbor 服务..."
# 检查配置
if ! check_harbor_config; then
error "Harbor 配置检查失败,无法启动服务"
return 1
fi
# 确保数据目录存在
mkdir -p "${HARBOR_DATA_DIR}"
# 启动服务
cd "${HARBOR_DIR}"
docker-compose -f "${DOCKER_COMPOSE_FILE}" up -d
# 等待服务启动
info "等待服务启动完成..."
sleep 10
# 检查服务状态
if check_service_status; then
success "Harbor 服务启动成功"
return 0
else
error "Harbor 服务启动失败"
return 1
fi
}
# 停止 Harbor 服务
stop_services() {
info "停止 Harbor 服务..."
if [[ ! -f "${DOCKER_COMPOSE_FILE}" ]]; then
warning "Docker Compose 配置文件不存在,跳过停止操作"
return 0
fi
cd "${HARBOR_DIR}"
docker-compose -f "${DOCKER_COMPOSE_FILE}" down || true
success "Harbor 服务已停止"
}
# 重启 Harbor 服务
restart_services() {
info "重启 Harbor 服务..."
stop_services
sleep 5
start_services
}
# 健康检查
health_check() {
info "执行 Harbor 健康检查..."
local status=0
# 检查服务状态
if ! check_service_status; then
error "服务状态检查失败"
status=1
fi
# 检查端口
local ports=("8080" "8081" "8443" "8444")
for port in "${ports[@]}"; do
if lsof -i ":$port" &> /dev/null; then
info "端口 $port 正在使用"
else
warning "端口 $port 未被使用"
fi
done
# 检查数据目录
if [[ -d "${HARBOR_DATA_DIR}" ]]; then
local data_size
data_size=$(du -sh "${HARBOR_DATA_DIR}" 2>/dev/null | cut -f1)
info "Harbor 数据目录大小: $data_size"
else
warning "Harbor 数据目录不存在"
status=1
fi
# 检查证书
if [[ -f "${HARBOR_CERT_DIR}/harbor.crt" ]]; then
info "SSL 证书文件存在"
# 检查证书有效期
if command -v openssl &> /dev/null; then
local cert_exp
cert_exp=$(openssl x509 -in "${HARBOR_CERT_DIR}/harbor.crt" -noout -enddate 2>/dev/null | cut -d= -f2 || echo "unknown")
info "SSL 证书有效期: $cert_exp"
fi
else
warning "SSL 证书文件不存在"
fi
if [[ $status -eq 0 ]]; then
success "Harbor 健康检查通过"
else
error "Harbor 健康检查发现问题"
fi
return $status
}
# 获取 Harbor 统计信息
get_stats() {
info "获取 Harbor 统计信息..."
# 服务状态
check_service_status
# 数据目录统计
if [[ -d "${HARBOR_DATA_DIR}" ]]; then
echo ""
info "=== 数据目录统计 ==="
du -sh "${HARBOR_DATA_DIR}"/* 2>/dev/null | sort -hr || true
# 镜像数量估算 (基于 registry 目录)
local registry_dir="${HARBOR_DATA_DIR}/registry"
if [[ -d "$registry_dir" ]]; then
local repo_count
repo_count=$(find "$registry_dir" -type d -name "*.git" 2>/dev/null | wc -l || echo "0")
info "估算的镜像仓库数量: $repo_count"
fi
fi
# 备份文件统计
if [[ -d "${BACKUP_DIR}" ]]; then
echo ""
info "=== 备份文件统计 ==="
ls -lah "${BACKUP_DIR}"/*.tar.gz 2>/dev/null | tail -10 || true
fi
}
# 备份 Harbor 数据
backup_harbor() {
local backup_name="${1:-harbor-$(date +%Y%m%d-%H%M%S)}"
local backup_file="${BACKUP_DIR}/${backup_name}.tar.gz"
info "开始备份 Harbor 数据..."
# 检查服务状态
local service_running=false
if check_service_status &>/dev/null; then
service_running=true
warning "服务正在运行,建议在备份前停止服务以获得一致性备份"
read -p "是否继续备份? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
info "备份已取消"
return 0
fi
fi
# 创建备份
local backup_items=()
# Harbor 配置
if [[ -f "${HARBOR_YML}" ]]; then
backup_items+=("${HARBOR_YML}")
fi
if [[ -f "${DOCKER_COMPOSE_FILE}" ]]; then
backup_items+=("${DOCKER_COMPOSE_FILE}")
fi
# Harbor 数据目录
if [[ -d "${HARBOR_DATA_DIR}" ]]; then
backup_items+=("${HARBOR_DATA_DIR}")
fi
# 证书目录
if [[ -d "${HARBOR_CERT_DIR}" ]] && [[ -n "$(ls -A "${HARBOR_CERT_DIR}" 2>/dev/null)" ]]; then
backup_items+=("${HARBOR_CERT_DIR}")
fi
if [[ ${#backup_items[@]} -eq 0 ]]; then
error "没有找到需要备份的文件或目录"
return 1
fi
# 执行备份
info "创建备份文件: $backup_file"
tar -czf "${backup_file}" "${backup_items[@]}" 2>/dev/null
if [[ $? -eq 0 ]]; then
# 创建备份元数据
local meta_file="${backup_file}.meta"
cat > "${meta_file}" << EOF
backup_name="${backup_name}"
backup_date="$(date -Iseconds)"
backup_size="$(stat -f%z "${backup_file}" 2>/dev/null || stat -c%s "${backup_file}" 2>/dev/null || echo "unknown")"
service_running="${service_running}"
harbor_version="$(grep "_version" "${HARBOR_YML}" 2>/dev/null | cut -d' ' -f2 || echo "unknown")"
items="$(printf '%s;' "${backup_items[@]}")"
EOF
success "Harbor 备份完成: ${backup_file}"
# 显示备份信息
local backup_size
backup_size=$(ls -lh "${backup_file}" | awk '{print $5}')
info "备份大小: ${backup_size}"
# 清理旧备份 (保留最近 10 个)
cleanup_old_backups 10
else
error "Harbor 备份失败"
return 1
fi
}
# 恢复 Harbor 数据
restore_harbor() {
local backup_file="${1:-}"
if [[ -z "$backup_file" ]]; then
error "请指定备份文件"
show_backups
return 1
fi
if [[ ! -f "$backup_file" ]]; then
error "备份文件不存在: $backup_file"
return 1
fi
info "开始从备份恢复 Harbor..."
# 创建安全备份
local safety_backup="${BACKUP_DIR}/safety-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
if [[ -d "${HARBOR_DATA_DIR}" ]] || [[ -f "${HARBOR_YML}" ]]; then
info "创建当前状态的安全备份: $safety_backup"
backup_harbor "safety-backup-$(date +%Y%m%d-%H%M%S)"
fi
# 停止现有服务
stop_services
# 恢复备份
info "恢复备份文件: $backup_file"
cd /
tar -xzf "$backup_file" 2>/dev/null
if [[ $? -eq 0 ]]; then
success "Harbor 数据恢复完成"
# 启动服务
sleep 5
start_services
# 验证恢复结果
if health_check; then
success "Harbor 恢复验证通过"
else
error "Harbor 恢复验证失败,请检查日志"
return 1
fi
else
error "Harbor 数据恢复失败"
return 1
fi
}
# 显示可用备份
show_backups() {
info "可用的 Harbor 备份文件:"
if [[ -d "${BACKUP_DIR}" ]]; then
local backups=($(ls -t "${BACKUP_DIR}"/harbor-*.tar.gz 2>/dev/null || true))
if [[ ${#backups[@]} -gt 0 ]]; then
for i in "${!backups[@]}"; do
local backup_file="${backups[$i]}"
local backup_size
backup_size=$(ls -lh "$backup_file" | awk '{print $5}')
local backup_date
backup_date=$(stat -f%Sm -t%Y-%m-%d\ %H:%M:%S "$backup_file" 2>/dev/null || stat -c%y "$backup_file" 2>/dev/null | cut -d'.' -f1)
printf "%2d. %-40s %10s %s\n" $((i+1)) "$(basename "$backup_file")" "$backup_size" "$backup_date"
done
else
warning "没有找到 Harbor 备份文件"
fi
else
warning "备份目录不存在: ${BACKUP_DIR}"
fi
}
# 清理旧备份
cleanup_old_backups() {
local keep_count="${1:-5}"
info "清理旧备份文件,保留最近 $keep_count 个..."
if [[ -d "${BACKUP_DIR}" ]]; then
local old_backups
old_backups=($(ls -t "${BACKUP_DIR}"/harbor-*.tar.gz 2>/dev/null | tail -n +$((keep_count+1)) || true))
if [[ ${#old_backups[@]} -gt 0 ]]; then
for backup in "${old_backups[@]}"; do
info "删除旧备份: $(basename "$backup")"
rm -f "$backup" "${backup}.meta"
done
success "已清理 ${#old_backups[@]} 个旧备份文件"
else
info "没有需要清理的旧备份文件"
fi
fi
}
# 设置定时任务
setup_cron() {
local cron_interval="${1:-"0 2 * * *"}" # 默认每天凌晨 2 点
info "设置 Harbor 备份定时任务..."
# 创建 cron 脚本
local cron_script="${SCRIPT_DIR}/harbor-cron-backup.sh"
cat > "$cron_script" << EOF
#!/bin/bash
# Harbor 自动备份 cron 任务
$(declare -f log info success warning error)
$(declare -f check_dependencies ensure_directories backup_harbor)
LOG_FILE="${LOG_FILE}"
BACKUP_DIR="${BACKUP_DIR}"
HARBOR_DATA_DIR="${HARBOR_DATA_DIR}"
HARBOR_CERT_DIR="${HARBOR_CERT_DIR}"
HARBOR_YML="${HARBOR_YML}"
DOCKER_COMPOSE_FILE="${DOCKER_COMPOSE_FILE}"
# 执行备份
check_dependencies
ensure_directories
backup_harbor
EOF
chmod +x "$cron_script"
# 添加到 crontab
local cron_entry="$cron_interval $cron_script >> ${LOG_FILE} 2>&1"
(crontab -l 2>/dev/null | grep -v "harbor-cron-backup" || true; echo "$cron_entry") | crontab -
# 设置 launchd 任务 (macOS 原生)
local launchd_plist="$HOME/Library/LaunchAgents/com.ljwx.harbor.backup.plist"
cat > "$launchd_plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.ljwx.harbor.backup</string>
<key>ProgramArguments</key>
<array>
<string>$cron_script</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>2</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>${LOG_FILE}.cron.stdout.log</string>
<key>StandardErrorPath</key>
<string>${LOG_FILE}.cron.stderr.log</string>
<key>RunAtLoad</key>
<false/>
</dict>
</plist>
EOF
# 加载 launchd 任务
launchctl unload "$launchd_plist" 2>/dev/null || true
launchctl load -w "$launchd_plist"
success "Harbor 备份定时任务已设置"
info "Cron 任务: $cron_entry"
info "Launchd 任务已加载"
}
# 显示帮助信息
show_help() {
cat << EOF
Harbor 数据保护和管理脚本
用法: $0 [命令] [参数]
命令:
start 启动 Harbor 服务
stop 停止 Harbor 服务
restart 重启 Harbor 服务
status 检查服务状态
health 执行健康检查
stats 显示统计信息
backup [名称] 创建备份
restore [文件] 从备份恢复
list 显示可用备份
cleanup [数量] 清理旧备份 (默认保留 5 个)
setup 设置定时任务
help 显示帮助信息
示例:
$0 start # 启动服务
$0 backup # 创建备份
$0 backup my-backup # 创建命名备份
$0 restore backup-2023.tar.gz # 从备份恢复
$0 cleanup 10 # 保留最近 10 个备份
环境变量:
HARBOR_DIR Harbor 配置目录 (默认: 脚本所在目录)
HARBOR_DATA_DIR Harbor 数据目录 (默认: ~/ops/data/harbor)
BACKUP_DIR 备份目录 (默认: ~/ops/backups/harbor)
LOG_FILE 日志文件 (默认: ~/ops/logs/harbor-protection.log)
EOF
}
# 主函数
main() {
local command="${1:-help}"
local parameter="${2:-}"
# 设置环境变量
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"
case "$command" in
"start")
check_dependencies
ensure_directories
start_services
;;
"stop")
stop_services
;;
"restart")
check_dependencies
ensure_directories
restart_services
;;
"status")
check_service_status
;;
"health")
check_dependencies
ensure_directories
health_check
;;
"stats")
get_stats
;;
"backup")
check_dependencies
ensure_directories
backup_harbor "$parameter"
;;
"restore")
check_dependencies
ensure_directories
restore_harbor "$parameter"
;;
"list"|"ls")
show_backups
;;
"cleanup")
cleanup_old_backups "$parameter"
;;
"setup")
setup_cron "$parameter"
;;
"help"|"-h"|"--help")
show_help
;;
*)
error "未知命令: $command"
show_help
exit 1
;;
esac
}
# 如果脚本被直接执行,调用主函数
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
# Harbor 快速恢复脚本
# 这是 harbor-data-protection.sh 的简化版本,专注于快速恢复操作
set -euo pipefail
# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HARBOR_DATA_PROTECTION="${SCRIPT_DIR}/harbor-data-protection.sh"
BACKUP_FILE="${1:-}"
# 显示可用备份 (如果没有指定备份文件)
if [[ -z "$BACKUP_FILE" ]]; then
echo "可用的 Harbor 备份文件:"
"$HARBOR_DATA_PROTECTION" list
echo ""
echo "请指定要恢复的备份文件,例如:"
echo "$0 harbor-20231220-120000.tar.gz"
exit 0
fi
# 调用主脚本的恢复功能
if [[ -x "$HARBOR_DATA_PROTECTION" ]]; then
"$HARBOR_DATA_PROTECTION" restore "$BACKUP_FILE"
else
echo "错误: 找不到 Harbor 数据保护脚本: $HARBOR_DATA_PROTECTION"
exit 1
fi
+316
View File
@@ -0,0 +1,316 @@
# Configuration file of Harbor
# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: 192.168.1.83
# http related config
http:
# port for http, default is 80. If https enabled, this port will redirect to https port
port: 8080
# https related config
https:
# https port for harbor, default is 443
port: 8443
# The path of cert and key files for nginx
certificate: /Users/brunogao/certs/harbor.lan.pem
private_key: /Users/brunogao/certs/harbor.lan-key.pem
# enable strong ssl ciphers (default: false)
# strong_ssl_ciphers: false
# # Harbor will set ipv4 enabled only by default if this block is not configured
# # Otherwise, please uncomment this block to configure your own ip_family stacks
# ip_family:
# # ipv6Enabled set to true if ipv6 is enabled in docker network, currently it affected the nginx related component
# ipv6:
# enabled: false
# # ipv4Enabled set to true by default, currently it affected the nginx related component
# ipv4:
# enabled: true
# # Uncomment following will enable tls communication between all harbor components
# internal_tls:
# # set enabled to true means internal tls is enabled
# enabled: true
# # put your cert and key files on dir
# dir: /etc/harbor/tls/internal
# Uncomment external_url if you want to enable external proxy
# And when it enabled the hostname will no longer used
# external_url: https://reg.mydomain.com:8433
# The initial password of Harbor admin
# It only works in first time to install harbor
# Remember Change the admin password from UI after launching Harbor.
harbor_admin_password: admin
# Harbor DB configuration
database:
# The password for the root user of Harbor DB. Change this before any production use.
password: root123
# The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained.
max_idle_conns: 100
# The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.
# Note: the default number of connections is 1024 for postgres of harbor.
max_open_conns: 900
# The maximum amount of time a connection may be reused. Expired connections may be closed lazily before reuse. If it <= 0, connections are not closed due to a connection's age.
# The value is a duration string. A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
conn_max_lifetime: 5m
# The maximum amount of time a connection may be idle. Expired connections may be closed lazily before reuse. If it <= 0, connections are not closed due to a connection's idle time.
# The value is a duration string. A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
conn_max_idle_time: 0
# The default data volume
data_volume: /Users/brunogao/ops/data/harbor
# Harbor Storage settings by default is using /data dir on local filesystem
# Uncomment storage_service setting If you want to using external storage
# storage_service:
# # ca_bundle is the path to the custom root ca certificate, which will be injected into the truststore
# # of registry's containers. This is usually needed when the user hosts a internal storage with self signed certificate.
# ca_bundle:
# # storage backend, default is filesystem, options include filesystem, azure, gcs, s3, swift and oss
# # for more info about this configuration please refer https://distribution.github.io/distribution/about/configuration/
# # and https://distribution.github.io/distribution/storage-drivers/
# filesystem:
# maxthreads: 100
# # set disable to true when you want to disable registry redirect
# redirect:
# disable: false
# Trivy configuration
#
# Trivy DB contains vulnerability information from NVD, Red Hat, and many other upstream vulnerability databases.
# It is downloaded by Trivy from the GitHub release page https://github.com/aquasecurity/trivy-db/releases and cached
# in the local file system. In addition, the database contains the update timestamp so Trivy can detect whether it
# should download a newer version from the Internet or use the cached one. Currently, the database is updated every
# 12 hours and published as a new release to GitHub.
trivy:
# ignoreUnfixed The flag to display only fixed vulnerabilities
ignore_unfixed: false
# skipUpdate The flag to enable or disable Trivy DB downloads from GitHub
#
# You might want to enable this flag in test or CI/CD environments to avoid GitHub rate limiting issues.
# If the flag is enabled you have to download the `trivy-offline.tar.gz` archive manually, extract `trivy.db` and
# `metadata.json` files and mount them in the `/home/scanner/.cache/trivy/db` path.
skip_update: false
#
# skipJavaDBUpdate If the flag is enabled you have to manually download the `trivy-java.db` file and mount it in the
# `/home/scanner/.cache/trivy/java-db/trivy-java.db` path
skip_java_db_update: false
#
# The offline_scan option prevents Trivy from sending API requests to identify dependencies.
# Scanning JAR files and pom.xml may require Internet access for better detection, but this option tries to avoid it.
# For example, the offline mode will not try to resolve transitive dependencies in pom.xml when the dependency doesn't
# exist in the local repositories. It means a number of detected vulnerabilities might be fewer in offline mode.
# It would work if all the dependencies are in local.
# This option doesn't affect DB download. You need to specify "skip-update" as well as "offline-scan" in an air-gapped environment.
offline_scan: false
#
# Comma-separated list of what security issues to detect. Possible values are `vuln`, `config` and `secret`. Defaults to `vuln`.
security_check: vuln
#
# insecure The flag to skip verifying registry certificate
insecure: false
#
# timeout The duration to wait for scan completion.
# There is upper bound of 30 minutes defined in scan job. So if this `timeout` is larger than 30m0s, it will also timeout at 30m0s.
timeout: 5m0s
#
# github_token The GitHub access token to download Trivy DB
#
# Anonymous downloads from GitHub are subject to the limit of 60 requests per hour. Normally such rate limit is enough
# for production operations. If, for any reason, it's not enough, you could increase the rate limit to 5000
# requests per hour by specifying the GitHub access token. For more details on GitHub rate limiting please consult
# https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting
#
# You can create a GitHub token by following the instructions in
# https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line
#
# github_token: xxx
jobservice:
# Maximum number of job workers in job service
max_job_workers: 10
# The jobLoggers backend name, only support "STD_OUTPUT", "FILE" and/or "DB"
job_loggers:
- STD_OUTPUT
- FILE
# - DB
# The jobLogger sweeper duration (ignored if `jobLogger` is `stdout`)
logger_sweeper_duration: 1 #days
notification:
# Maximum retry count for webhook job
webhook_job_max_retry: 3
# HTTP client timeout for webhook job
webhook_job_http_client_timeout: 3 #seconds
# Log configurations
log:
# options are debug, info, warning, error, fatal
level: info
# configs for logs in local storage
local:
# Log files are rotated log_rotate_count times before being removed. If count is 0, old versions are removed rather than rotated.
rotate_count: 50
# Log files are rotated only if they grow bigger than log_rotate_size bytes. If size is followed by k, the size is assumed to be in kilobytes.
# If the M is used, the size is in megabytes, and if G is used, the size is in gigabytes. So size 100, size 100k, size 100M and size 100G
# are all valid.
rotate_size: 200M
# The directory on your host that store log
location: /var/log/harbor
# Uncomment following lines to enable external syslog endpoint.
# external_endpoint:
# # protocol used to transmit log to external endpoint, options is tcp or udp
# protocol: tcp
# # The host of external endpoint
# host: localhost
# # Port of external endpoint
# port: 5140
#This attribute is for migrator to detect the version of the .cfg file, DO NOT MODIFY!
_version: 2.11.0
# Uncomment external_database if using external database.
# external_database:
# harbor:
# host: harbor_db_host
# port: harbor_db_port
# db_name: harbor_db_name
# username: harbor_db_username
# password: harbor_db_password
# ssl_mode: disable
# max_idle_conns: 2
# max_open_conns: 0
# Uncomment redis if need to customize redis db
# redis:
# # db_index 0 is for core, it's unchangeable
# # registry_db_index: 1
# # jobservice_db_index: 2
# # trivy_db_index: 5
# # it's optional, the db for harbor business misc, by default is 0, uncomment it if you want to change it.
# # harbor_db_index: 6
# # it's optional, the db for harbor cache layer, by default is 0, uncomment it if you want to change it.
# # cache_layer_db_index: 7
# Uncomment external_redis if using external Redis server
# external_redis:
# # support redis, redis+sentinel
# # host for redis: <host_redis>:<port_redis>
# # host for redis+sentinel:
# # <host_sentinel1>:<port_sentinel1>,<host_sentinel2>:<port_sentinel2>,<host_sentinel3>:<port_sentinel3>
# host: redis:6379
# password:
# # Redis AUTH command was extended in Redis 6, it is possible to use it in the two-arguments AUTH <username> <password> form.
# # there's a known issue when using external redis username ref:https://github.com/goharbor/harbor/issues/18892
# # if you care about the image pull/push performance, please refer to this https://github.com/goharbor/harbor/wiki/Harbor-FAQs#external-redis-username-password-usage
# # username:
# # sentinel_master_set must be set to support redis+sentinel
# #sentinel_master_set:
# # db_index 0 is for core, it's unchangeable
# registry_db_index: 1
# jobservice_db_index: 2
# trivy_db_index: 5
# idle_timeout_seconds: 30
# # it's optional, the db for harbor business misc, by default is 0, uncomment it if you want to change it.
# # harbor_db_index: 6
# # it's optional, the db for harbor cache layer, by default is 0, uncomment it if you want to change it.
# # cache_layer_db_index: 7
# Uncomment uaa for trusting the certificate of uaa instance that is hosted via self-signed cert.
# uaa:
# ca_file: /path/to/ca
# Global proxy
# Config http proxy for components, e.g. http://my.proxy.com:3128
# Components doesn't need to connect to each others via http proxy.
# Remove component from `components` array if want disable proxy
# for it. If you want use proxy for replication, MUST enable proxy
# for core and jobservice, and set `http_proxy` and `https_proxy`.
# Add domain to the `no_proxy` field, when you want disable proxy
# for some special registry.
proxy:
http_proxy:
https_proxy:
no_proxy:
components:
- core
- jobservice
- trivy
# metric:
# enabled: false
# port: 9090
# path: /metrics
# Trace related config
# only can enable one trace provider(jaeger or otel) at the same time,
# and when using jaeger as provider, can only enable it with agent mode or collector mode.
# if using jaeger collector mode, uncomment endpoint and uncomment username, password if needed
# if using jaeger agetn mode uncomment agent_host and agent_port
# trace:
# enabled: true
# # set sample_rate to 1 if you wanna sampling 100% of trace data; set 0.5 if you wanna sampling 50% of trace data, and so forth
# sample_rate: 1
# # # namespace used to differentiate different harbor services
# # namespace:
# # # attributes is a key value dict contains user defined attributes used to initialize trace provider
# # attributes:
# # application: harbor
# # # jaeger should be 1.26 or newer.
# # jaeger:
# # endpoint: http://hostname:14268/api/traces
# # username:
# # password:
# # agent_host: hostname
# # # export trace data by jaeger.thrift in compact mode
# # agent_port: 6831
# # otel:
# # endpoint: hostname:4318
# # url_path: /v1/traces
# # compression: false
# # insecure: true
# # # timeout is in seconds
# # timeout: 10
# Enable purge _upload directories
upload_purging:
enabled: true
# remove files in _upload directories which exist for a period of time, default is one week.
age: 168h
# the interval of the purge operations
interval: 24h
dryrun: false
# Cache layer configurations
# If this feature enabled, harbor will cache the resource
# `project/project_metadata/repository/artifact/manifest` in the redis
# which can especially help to improve the performance of high concurrent
# manifest pulling.
# NOTICE
# If you are deploying Harbor in HA mode, make sure that all the harbor
# instances have the same behaviour, all with caching enabled or disabled,
# otherwise it can lead to potential data inconsistency.
cache:
# not enabled by default
enabled: false
# keep cache for one day by default
expire_hours: 24
# Harbor core configurations
# Uncomment to enable the following harbor core related configuration items.
# core:
# # The provider for updating project quota(usage), there are 2 options, redis or db,
# # by default is implemented by db but you can switch the updation via redis which
# # can improve the performance of high concurrent pushing to the same project,
# # and reduce the database connections spike and occupies.
# # By redis will bring up some delay for quota usage updation for display, so only
# # suggest switch provider to redis if you were ran into the db connections spike around
# # the scenario of high concurrent pushing to same project, no improvement for other scenes.
# quota_update_provider: redis # Or db
+108
View File
@@ -75,7 +75,11 @@ create_base_structure() {
"${OPS_DIR}/data"
"${OPS_DIR}/backups/brew"
"${OPS_DIR}/backups/gitea"
"${OPS_DIR}/backups/harbor"
"${OPS_DIR}/backups/gitlab"
"${OPS_DIR}/data/gitea"
"${OPS_DIR}/data/harbor"
"${OPS_DIR}/data/gitlab"
)
for dir in "${dirs[@]}"; do
@@ -184,6 +188,110 @@ deploy_gitea_module() {
fi
}
# 部署 harbor 模块
deploy_harbor_module() {
if [[ "$DOCKER_AVAILABLE" != true ]]; then
warn "跳过 harbor 模块部署(Docker 未安装)"
return
fi
log "🐙 部署 Harbor 维护模块..."
local harbor_target_dir="${OPS_DIR}/harbor"
# 创建目录
mkdir -p "$harbor_target_dir"
# 复制文件
local files=(
"harbor/harbor.yml"
"harbor/docker-compose.yml"
"harbor/harbor-data-protection.sh"
"harbor/harbor-backup.sh"
"harbor/harbor-restore.sh"
"harbor/.env.example"
"harbor/common"
"harbor/README.md"
)
for file in "${files[@]}"; do
local src="${PROJECT_ROOT}/$file"
local dst="${harbor_target_dir}/$(basename "$file")"
if [[ -f "$src" ]] || [[ -d "$src" ]]; then
if [[ -d "$src" ]]; then
cp -r "$src" "$dst"
else
cp "$src" "$dst"
fi
chmod +x "$dst" 2>/dev/null || true # 只对脚本设置可执行权限
log "✅ 复制: $(basename "$file")"
else
warn "文件不存在: $src"
fi
done
# 创建 .env 文件(如果不存在)
local env_file="${harbor_target_dir}/.env"
if [[ ! -f "$env_file" ]] && [[ -f "${PROJECT_ROOT}/harbor/.env.example" ]]; then
cp "${PROJECT_ROOT}/harbor/.env.example" "$env_file"
log "✅ 创建环境配置文件: .env"
info "💡 请根据需要编辑 ${env_file}"
fi
}
# 部署 gitlab 模块
deploy_gitlab_module() {
if [[ "$DOCKER_AVAILABLE" != true ]]; then
warn "跳过 gitlab 模块部署(Docker 未安装)"
return
fi
log "🦊 部署 GitLab 维护模块..."
local gitlab_target_dir="${OPS_DIR}/gitlab"
# 创建目录
mkdir -p "$gitlab_target_dir"
# 复制文件
local files=(
"gitlab/docker-compose.yml"
"gitlab/gitlab-data-protection.sh"
"gitlab/gitlab-backup.sh"
"gitlab/gitlab-restore.sh"
"gitlab/.env.example"
"gitlab/README.md"
)
for file in "${files[@]}"; do
local src="${PROJECT_ROOT}/$file"
local dst="${gitlab_target_dir}/$(basename "$file")"
if [[ -f "$src" ]]; then
cp "$src" "$dst"
chmod +x "$dst" 2>/dev/null || true # 只对脚本设置可执行权限
log "✅ 复制: $(basename "$file")"
else
warn "文件不存在: $src"
fi
done
# 复制配置目录
if [[ -d "${PROJECT_ROOT}/gitlab/config" ]]; then
cp -r "${PROJECT_ROOT}/gitlab/config" "${gitlab_target_dir}/"
log "✅ 复制: config/"
fi
# 创建 .env 文件(如果不存在)
local env_file="${gitlab_target_dir}/.env"
if [[ ! -f "$env_file" ]] && [[ -f "${PROJECT_ROOT}/gitlab/.env.example" ]]; then
cp "${PROJECT_ROOT}/gitlab/.env.example" "$env_file"
log "✅ 创建环境配置文件: .env"
info "💡 请根据需要编辑 ${env_file}"
fi
}
# 创建项目总 README
create_main_readme() {
local readme_file="${OPS_DIR}/README.md"
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
Claude Bluebook Context Generator (v1.2)
自动生成Claude开发上下文
"""
import json
import os
from pathlib import Path
from datetime import datetime
def generate_context():
"""生成Claude上下文"""
project_root = Path.cwd()
context = f"""# Claude AI Development Context v1.2
## Project Information
**Name**: {project_root.name}
**Root**: {project_root}
**Copyright**: © 2025 灵境万象智能科技有限公司
## Current Development Phase
**Phase**: AI-Powered Development
**Focus**: High-quality enterprise-grade development
## Quality Standards
**Code Quality**:
- Type coverage: ≥90%
- Test coverage: ≥80%
- Code quality: ≥B级
**Performance**:
- API response P95: ≤3s
- Concurrent users: ≥1000
- CPU usage: ≤70%
**Security**:
- Zero high-severity vulnerabilities
- OWASP Top 10 compliance
- Authentication and authorization complete
## Development Guidelines
1. **Enterprise-Grade Code**: Industry best practices with comprehensive documentation
2. **Quality-First**: All quality gates must be passed
3. **Security-First**: Security by design and default
4. **Performance-Optimized**: Efficient, scalable code
5. **Well-Tested**: High test coverage and automated quality checks
## My Role & Approach
**Role**: Senior Full-Stack Developer specializing in AI-powered systems
**Approach**:
- Structured responses with clear progress tracking
- Ask clarifying questions when requirements are ambiguous
- Suggest improvements and alternative approaches
- Focus on practical, maintainable, enterprise-grade solutions
## Quality Assurance
All deliverables validated against:
- Functional requirements ✓
- Performance benchmarks ✓
- Security standards ✓
- Code quality metrics ✓
- Documentation completeness ✓
Let's build high-quality, enterprise-grade software together!
"""
return context.strip()
def main():
context = generate_context()
cache_file = Path.cwd() / ".claude-bluebook-cache.json"
cache_data = {
"version": "2.0.0",
"copyright": "© 2025 灵境万象智能科技有限公司",
"timestamp": datetime.now().isoformat(),
"claude_context": context
}
with open(cache_file, 'w', encoding='utf-8') as f:
json.dump(cache_data, f, indent=2, ensure_ascii=False)
print(f"✅ Context saved to: {cache_file}")
print("🚀 Ready for Claude AI collaboration!")
if __name__ == "__main__":
main()