refactor: 更新项目结构和文档,移除不再使用的配置文件

- 修改README.md,更新项目特性和目录结构说明
- 重命名基础设施代码目录为tofu,并添加Docker Swarm配置目录
- 移除不再使用的Docker Compose和Traefik配置文件
- 更新Terraform配置,专注于Oracle Cloud支持,移除华为云相关配置
- 清理开发环境变量和示例文件
This commit is contained in:
Houzhong Xu 2025-09-20 16:49:32 +00:00
parent 7eb4a33523
commit 377f176501
No known key found for this signature in database
GPG Key ID: B44BEB1438F1B46F
45 changed files with 3278 additions and 69 deletions

View File

@ -1,13 +1,13 @@
# 🏗️ 基础设施管理项目
这是一个现代化的多云基础设施管理平台,集成 OpenTofu、Ansible、Docker Swarm 和 Gitea CI/CD
这是一个现代化的多云基础设施管理平台,专注于 OpenTofu、Ansible 和 Docker Swarm 的集成管理
## 🎯 项目特性
- **🌩️ 多云支持**: Oracle Cloud, 华为云, Google Cloud, AWS, DigitalOcean
- **🏗️ 基础设施即代码**: 使用 OpenTofu 管理云资源
- **⚙️ 配置管理**: 使用 Ansible 自动化配置和部署
- **🐳 容器编排**: Docker Swarm 集群管理
- **🐳 容器编排**: Docker Swarm 集群管理和服务编排
- **🔄 CI/CD**: Gitea Actions 自动化流水线
- **📊 监控**: Prometheus + Grafana 监控体系
- **🔐 安全**: 多层安全防护和合规性
@ -17,23 +17,25 @@
```
mgmt/
├── .gitea/workflows/ # CI/CD 工作流
├── infrastructure/ # OpenTofu 基础设施代码
├── tofu/ # OpenTofu 基础设施代码
│ ├── environments/ # 环境配置 (dev/staging/prod)
│ ├── modules/ # 可复用模块
│ ├── providers/ # 云服务商配置
│ └── shared/ # 共享配置
├── swarm/ # Docker Swarm 配置
│ ├── stacks/ # Docker Stack 配置文件
│ ├── configs/ # Traefik 等基础设施配置
│ └── scripts/ # Swarm 管理脚本
├── configuration/ # Ansible 配置管理
│ ├── inventories/ # 主机清单
│ ├── playbooks/ # 剧本
│ ├── roles/ # 角色
│ └── group_vars/ # 组变量
├── containers/ # 容器化应用
│ ├── applications/ # 应用容器
│ ├── infrastructure/ # 基础设施容器
│ └── compose/ # Docker Compose 文件
├── monitoring/ # 监控配置
├── scripts/ # 自动化脚本
├── docs/ # 文档
│ ├── setup/ # 环境设置脚本
│ └── utilities/ # 实用工具脚本
├── mgmt.sh # 项目管理主脚本
└── Makefile # 项目管理命令
```
@ -46,56 +48,60 @@ mgmt/
git clone <repository-url>
cd mgmt
# 设置开发环境
make setup
# 检查环境状态
./mgmt.sh status
# 快速部署(适用于开发环境)
./mgmt.sh deploy
```
### 2. 配置云服务商
```bash
# 复制配置模板
cp infrastructure/environments/dev/terraform.tfvars.example infrastructure/environments/dev/terraform.tfvars
cp tofu/environments/dev/terraform.tfvars.example tofu/environments/dev/terraform.tfvars
# 编辑配置文件,填入你的云服务商凭据
vim infrastructure/environments/dev/terraform.tfvars
vim tofu/environments/dev/terraform.tfvars
```
### 3. 初始化基础设施
```bash
# 初始化 OpenTofu
make init
./mgmt.sh tofu init
# 查看执行计划
make plan
./mgmt.sh tofu plan
# 应用基础设施变更
make apply
cd tofu/environments/dev && tofu apply
```
### 4. 部署应用
### 4. 部署 Docker Swarm 服务
```bash
# 检查 Ansible 配置
make ansible-check
# 初始化 Docker Swarm
./mgmt.sh swarm init
# 部署应用
make ansible-deploy
# 部署 Traefik 反向代理
./mgmt.sh swarm deploy traefik swarm/stacks/traefik-swarm-stack.yml
# 部署示例服务
./mgmt.sh swarm deploy demo swarm/stacks/demo-services-stack.yml
```
## 🛠️ 常用命令
| 命令 | 描述 |
|------|------|
| `make help` | 显示所有可用命令 |
| `make setup` | 设置开发环境 |
| `make init` | 初始化 OpenTofu |
| `make plan` | 生成基础设施执行计划 |
| `make apply` | 应用基础设施变更 |
| `make ansible-deploy` | 部署应用 |
| `make docker-up` | 启动开发环境 |
| `make test` | 运行测试 |
| `make clean` | 清理临时文件 |
| `./mgmt.sh status` | 显示项目状态总览 |
| `./mgmt.sh deploy` | 快速部署所有服务 |
| `./mgmt.sh cleanup` | 清理所有部署的服务 |
| `./mgmt.sh swarm <cmd>` | Docker Swarm 管理命令 |
| `./mgmt.sh tofu <cmd>` | OpenTofu 管理命令 |
| `swarm/scripts/swarm-manager.sh help` | Swarm 管理帮助 |
| `scripts/setup/setup-opentofu.sh help` | OpenTofu 设置帮助 |
## 🌩️ 支持的云服务商

View File

@ -0,0 +1,95 @@
---
- name: Gitea Runner Management
hosts: hcp
become: yes
vars:
gitea_runner_user: "gitea-runner"
gitea_runner_data_dir: "/var/lib/gitea-runner"
gitea_runner_log_dir: "/var/log/gitea-runner"
tasks:
- name: Check gitea-runner service status
systemd:
name: gitea-runner
register: service_status
- name: Display service status
debug:
msg: |
Service: {{ service_status.status.ActiveState }}
Enabled: {{ service_status.status.UnitFileState }}
Main PID: {{ service_status.status.MainPID | default('N/A') }}
- name: Show recent logs
command: journalctl -u gitea-runner --no-pager -n 20
register: recent_logs
changed_when: false
- name: Display recent logs
debug:
var: recent_logs.stdout_lines
- name: Check runner registration
stat:
path: "{{ gitea_runner_data_dir }}/.runner"
register: runner_registered
- name: Display registration status
debug:
msg: "Runner registered: {{ runner_registered.stat.exists }}"
- name: Show runner configuration (if registered)
command: cat {{ gitea_runner_data_dir }}/.runner
register: runner_config
become_user: "{{ gitea_runner_user }}"
when: runner_registered.stat.exists
changed_when: false
- name: Display runner configuration
debug:
var: runner_config.stdout_lines
when: runner_registered.stat.exists
- name: Check Docker access for runner user
command: docker ps
become_user: "{{ gitea_runner_user }}"
register: docker_access
changed_when: false
failed_when: false
- name: Display Docker access status
debug:
msg: |
Docker access: {{ 'OK' if docker_access.rc == 0 else 'FAILED' }}
{% if docker_access.rc != 0 %}
Error: {{ docker_access.stderr }}
{% endif %}
# 单独的任务用于管理服务
- name: Service Management Tasks
hosts: hcp
become: yes
tasks:
- name: Start gitea-runner service
systemd:
name: gitea-runner
state: started
when: ansible_run_tags is defined and 'start' in ansible_run_tags
- name: Stop gitea-runner service
systemd:
name: gitea-runner
state: stopped
when: ansible_run_tags is defined and 'stop' in ansible_run_tags
- name: Restart gitea-runner service
systemd:
name: gitea-runner
state: restarted
when: ansible_run_tags is defined and 'restart' in ansible_run_tags
- name: Reload gitea-runner service
systemd:
name: gitea-runner
state: reloaded
when: ansible_run_tags is defined and 'reload' in ansible_run_tags

View File

@ -0,0 +1,157 @@
---
- name: Setup Gitea Runner on HCP nodes
hosts: hcp
become: yes
vars:
gitea_runner_token: "vOrrQda6Qiet9YOj4waZVU5QgLig2J3rKp2RfoN7"
gitea_server_url: "http://gitea:3000"
gitea_runner_user: "gitea-runner"
gitea_runner_home: "/home/{{ gitea_runner_user }}"
gitea_runner_config_dir: "/etc/gitea-runner"
gitea_runner_data_dir: "/var/lib/gitea-runner"
gitea_runner_log_dir: "/var/log/gitea-runner"
gitea_runner_binary: "/usr/bin/act_runner"
tasks:
- name: Check if gitea-runner binary exists
stat:
path: "{{ gitea_runner_binary }}"
register: runner_binary
- name: Fail if act_runner binary not found
fail:
msg: "Act runner binary not found at {{ gitea_runner_binary }}. Please install it first."
when: not runner_binary.stat.exists
- name: Create gitea-runner user
user:
name: "{{ gitea_runner_user }}"
system: yes
shell: /bin/bash
home: "{{ gitea_runner_home }}"
create_home: yes
comment: "Gitea Runner Service User"
- name: Create gitea-runner directories
file:
path: "{{ item }}"
state: directory
owner: "{{ gitea_runner_user }}"
group: "{{ gitea_runner_user }}"
mode: '0755'
loop:
- "{{ gitea_runner_config_dir }}"
- "{{ gitea_runner_data_dir }}"
- "{{ gitea_runner_log_dir }}"
- name: Create gitea-runner configuration file
template:
src: gitea-runner-config.yml.j2
dest: "{{ gitea_runner_config_dir }}/config.yml"
owner: "{{ gitea_runner_user }}"
group: "{{ gitea_runner_user }}"
mode: '0600'
notify: restart gitea-runner
- name: Create gitea-runner systemd service file
template:
src: gitea-runner.service.j2
dest: /etc/systemd/system/gitea-runner.service
owner: root
group: root
mode: '0644'
notify:
- reload systemd
- restart gitea-runner
- name: Create gitea-runner environment file
template:
src: gitea-runner.env.j2
dest: /etc/default/gitea-runner
owner: root
group: root
mode: '0600'
notify: restart gitea-runner
- name: Create runner registration script
template:
src: register-runner.sh.j2
dest: "{{ gitea_runner_home }}/register-runner.sh"
owner: "{{ gitea_runner_user }}"
group: "{{ gitea_runner_user }}"
mode: '0755'
- name: Check if runner is already registered
stat:
path: "{{ gitea_runner_data_dir }}/.runner"
register: runner_registered
- name: Register gitea runner
command: "{{ gitea_runner_home }}/register-runner.sh"
become_user: "{{ gitea_runner_user }}"
when: not runner_registered.stat.exists
register: registration_result
- name: Display registration result
debug:
var: registration_result.stdout_lines
when: registration_result is defined and registration_result.stdout_lines is defined
- name: Create runner startup script
template:
src: start-runner.sh.j2
dest: "{{ gitea_runner_home }}/start-runner.sh"
owner: "{{ gitea_runner_user }}"
group: "{{ gitea_runner_user }}"
mode: '0755'
- name: Create logrotate configuration for gitea-runner
template:
src: gitea-runner.logrotate.j2
dest: /etc/logrotate.d/gitea-runner
owner: root
group: root
mode: '0644'
- name: Install Docker (required for runner)
package:
name: docker.io
state: present
- name: Add gitea-runner user to docker group
user:
name: "{{ gitea_runner_user }}"
groups: docker
append: yes
- name: Start and enable Docker service
systemd:
name: docker
state: started
enabled: yes
- name: Start and enable gitea-runner service
systemd:
name: gitea-runner
state: started
enabled: yes
daemon_reload: yes
- name: Check gitea-runner service status
systemd:
name: gitea-runner
register: service_status
- name: Display service status
debug:
msg: "Gitea Runner service is {{ service_status.status.ActiveState }}"
handlers:
- name: reload systemd
systemd:
daemon_reload: yes
- name: restart gitea-runner
systemd:
name: gitea-runner
state: restarted

View File

@ -0,0 +1,50 @@
# Gitea Runner Configuration
log:
level: info
file: {{ gitea_runner_log_dir }}/runner.log
runner:
# Runner name (will be auto-generated if not specified)
name: "{{ inventory_hostname }}-runner"
# Runner capacity (number of concurrent jobs)
capacity: 2
# Runner timeout
timeout: 3600
# Runner labels (for job targeting)
labels:
- "ubuntu-latest:docker://ubuntu:22.04"
- "ubuntu-20.04:docker://ubuntu:20.04"
- "ubuntu-18.04:docker://ubuntu:18.04"
- "node:docker://node:18"
- "python:docker://python:3.11"
- "ansible:docker://quay.io/ansible/ansible-runner:latest"
- "opentofu:docker://opentofu/opentofu:latest"
cache:
enabled: true
dir: {{ gitea_runner_data_dir }}/cache
host: ""
port: 0
container:
# Docker network for runner containers
network: "gitea-runner"
# Enable privileged containers (needed for Docker-in-Docker)
privileged: false
# Container options
options: "--rm --pull=always"
# Valid platforms
valid_volumes:
- "/tmp"
- "{{ gitea_runner_data_dir }}"
docker_host: "unix:///var/run/docker.sock"
host:
workdir_parent: {{ gitea_runner_data_dir }}/work

View File

@ -0,0 +1,18 @@
# Gitea Runner Environment Variables
# Gitea server configuration
GITEA_INSTANCE_URL={{ gitea_server_url }}
GITEA_RUNNER_REGISTRATION_TOKEN={{ gitea_runner_token }}
# Runner configuration
GITEA_RUNNER_NAME={{ inventory_hostname }}-runner
GITEA_RUNNER_LABELS=ubuntu-latest,ubuntu-20.04,ubuntu-18.04,node,python,ansible,opentofu
# Docker configuration
DOCKER_HOST=unix:///var/run/docker.sock
# Logging
GITEA_RUNNER_LOG_LEVEL=info
# Security
GITEA_RUNNER_SECURITY_PRIVILEGED=false

View File

@ -0,0 +1,12 @@
{{ gitea_runner_log_dir }}/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 644 {{ gitea_runner_user }} {{ gitea_runner_user }}
postrotate
systemctl reload gitea-runner || true
endscript
}

View File

@ -0,0 +1,39 @@
[Unit]
Description=Gitea Actions Runner
Documentation=https://docs.gitea.io/en-us/actions/
After=network.target docker.service
Wants=docker.service
[Service]
Type=simple
User={{ gitea_runner_user }}
Group={{ gitea_runner_user }}
WorkingDirectory={{ gitea_runner_data_dir }}
ExecStart={{ gitea_runner_binary }} daemon --config {{ gitea_runner_config_dir }}/config.yml
ExecReload=/bin/kill -HUP $MAINPID
KillMode=mixed
KillSignal=SIGINT
TimeoutStopSec=5
Restart=always
RestartSec=10
StartLimitInterval=0
# Security settings
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths={{ gitea_runner_data_dir }} {{ gitea_runner_log_dir }} /var/run/docker.sock
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
# Environment
EnvironmentFile=-/etc/default/gitea-runner
# Logging
StandardOutput=append:{{ gitea_runner_log_dir }}/gitea-runner.log
StandardError=append:{{ gitea_runner_log_dir }}/gitea-runner-error.log
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,46 @@
#!/bin/bash
# Gitea Runner Registration Script
set -e
echo "🚀 注册 Gitea Runner..."
# 配置变量
GITEA_URL="{{ gitea_server_url }}"
REGISTRATION_TOKEN="{{ gitea_runner_token }}"
RUNNER_NAME="{{ inventory_hostname }}-runner"
RUNNER_LABELS="ubuntu-latest,ubuntu-20.04,ubuntu-18.04,node,python,ansible,opentofu"
# 切换到数据目录
cd {{ gitea_runner_data_dir }}
# 检查是否已经注册
if [ -f ".runner" ]; then
echo "✅ Runner 已经注册"
exit 0
fi
echo "📝 注册 Runner: $RUNNER_NAME"
echo "🔗 Gitea URL: $GITEA_URL"
echo "🏷️ Labels: $RUNNER_LABELS"
# 注册 Runner
{{ gitea_runner_binary }} register \
--instance "$GITEA_URL" \
--token "$REGISTRATION_TOKEN" \
--name "$RUNNER_NAME" \
--labels "$RUNNER_LABELS"
if [ $? -eq 0 ]; then
echo "✅ Runner 注册成功!"
# 设置文件权限
chown {{ gitea_runner_user }}:{{ gitea_runner_user }} .runner .credentials
chmod 600 .runner .credentials
echo "📋 Runner 信息:"
cat .runner
else
echo "❌ Runner 注册失败"
exit 1
fi

View File

@ -0,0 +1,20 @@
#!/bin/bash
# Gitea Runner Startup Script
set -e
echo "🚀 启动 Gitea Runner..."
# 切换到数据目录
cd {{ gitea_runner_data_dir }}
# 检查注册状态
if [ ! -f ".runner" ]; then
echo "❌ Runner 未注册,请先运行注册脚本"
exit 1
fi
echo "✅ Runner 已注册,启动守护进程..."
# 启动 Runner
exec {{ gitea_runner_binary }} daemon --config {{ gitea_runner_config_dir }}/config.yml

View File

@ -0,0 +1,50 @@
# Gitea Runner Configuration
log:
level: info
file: {{ gitea_runner_log_dir }}/runner.log
runner:
# Runner name (will be auto-generated if not specified)
name: "{{ inventory_hostname }}-runner"
# Runner capacity (number of concurrent jobs)
capacity: 2
# Runner timeout
timeout: 3600
# Runner labels (for job targeting)
labels:
- "ubuntu-latest:docker://ubuntu:22.04"
- "ubuntu-20.04:docker://ubuntu:20.04"
- "ubuntu-18.04:docker://ubuntu:18.04"
- "node:docker://node:18"
- "python:docker://python:3.11"
- "ansible:docker://quay.io/ansible/ansible-runner:latest"
- "opentofu:docker://opentofu/opentofu:latest"
cache:
enabled: true
dir: {{ gitea_runner_data_dir }}/cache
host: ""
port: 0
container:
# Docker network for runner containers
network: "gitea-runner"
# Enable privileged containers (needed for Docker-in-Docker)
privileged: false
# Container options
options: "--rm --pull=always"
# Valid platforms
valid_volumes:
- "/tmp"
- "{{ gitea_runner_data_dir }}"
docker_host: "unix:///var/run/docker.sock"
host:
workdir_parent: {{ gitea_runner_data_dir }}/work

View File

@ -0,0 +1,18 @@
# Gitea Runner Environment Variables
# Gitea server configuration
GITEA_INSTANCE_URL={{ gitea_server_url }}
GITEA_RUNNER_REGISTRATION_TOKEN={{ gitea_runner_token }}
# Runner configuration
GITEA_RUNNER_NAME={{ inventory_hostname }}-runner
GITEA_RUNNER_LABELS=ubuntu-latest,ubuntu-20.04,ubuntu-18.04,node,python,ansible,opentofu
# Docker configuration
DOCKER_HOST=unix:///var/run/docker.sock
# Logging
GITEA_RUNNER_LOG_LEVEL=info
# Security
GITEA_RUNNER_SECURITY_PRIVILEGED=false

View File

@ -0,0 +1,12 @@
{{ gitea_runner_log_dir }}/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 644 {{ gitea_runner_user }} {{ gitea_runner_user }}
postrotate
systemctl reload gitea-runner || true
endscript
}

View File

@ -0,0 +1,39 @@
[Unit]
Description=Gitea Actions Runner
Documentation=https://docs.gitea.io/en-us/actions/
After=network.target docker.service
Wants=docker.service
[Service]
Type=simple
User={{ gitea_runner_user }}
Group={{ gitea_runner_user }}
WorkingDirectory={{ gitea_runner_data_dir }}
ExecStart={{ gitea_runner_binary }} daemon --config {{ gitea_runner_config_dir }}/config.yml
ExecReload=/bin/kill -HUP $MAINPID
KillMode=mixed
KillSignal=SIGINT
TimeoutStopSec=5
Restart=always
RestartSec=10
StartLimitInterval=0
# Security settings
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths={{ gitea_runner_data_dir }} {{ gitea_runner_log_dir }} /var/run/docker.sock
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
# Environment
EnvironmentFile=-/etc/default/gitea-runner
# Logging
StandardOutput=append:{{ gitea_runner_log_dir }}/gitea-runner.log
StandardError=append:{{ gitea_runner_log_dir }}/gitea-runner-error.log
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,46 @@
#!/bin/bash
# Gitea Runner Registration Script
set -e
echo "🚀 注册 Gitea Runner..."
# 配置变量
GITEA_URL="{{ gitea_server_url }}"
REGISTRATION_TOKEN="{{ gitea_runner_token }}"
RUNNER_NAME="{{ inventory_hostname }}-runner"
RUNNER_LABELS="ubuntu-latest,ubuntu-20.04,ubuntu-18.04,node,python,ansible,opentofu"
# 切换到数据目录
cd {{ gitea_runner_data_dir }}
# 检查是否已经注册
if [ -f ".runner" ]; then
echo "✅ Runner 已经注册"
exit 0
fi
echo "📝 注册 Runner: $RUNNER_NAME"
echo "🔗 Gitea URL: $GITEA_URL"
echo "🏷️ Labels: $RUNNER_LABELS"
# 注册 Runner
{{ gitea_runner_binary }} register \
--instance "$GITEA_URL" \
--token "$REGISTRATION_TOKEN" \
--name "$RUNNER_NAME" \
--labels "$RUNNER_LABELS"
if [ $? -eq 0 ]; then
echo "✅ Runner 注册成功!"
# 设置文件权限
chown {{ gitea_runner_user }}:{{ gitea_runner_user }} .runner .credentials
chmod 600 .runner .credentials
echo "📋 Runner 信息:"
cat .runner
else
echo "❌ Runner 注册失败"
exit 1
fi

View File

@ -0,0 +1,20 @@
#!/bin/bash
# Gitea Runner Startup Script
set -e
echo "🚀 启动 Gitea Runner..."
# 切换到数据目录
cd {{ gitea_runner_data_dir }}
# 检查注册状态
if [ ! -f ".runner" ]; then
echo "❌ Runner 未注册,请先运行注册脚本"
exit 1
fi
echo "✅ Runner 已注册,启动守护进程..."
# 启动 Runner
exec {{ gitea_runner_binary }} daemon --config {{ gitea_runner_config_dir }}/config.yml

View File

@ -0,0 +1,198 @@
# Consul + Terraform 集成指南
本指南介绍如何使用 Consul 安全地管理 Terraform 中的敏感配置信息,特别是 Oracle Cloud 的凭据。
## 概述
我们使用 Consul 作为安全的密钥存储,避免在 Terraform 配置文件中直接暴露敏感信息。
## 架构
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Terraform │───▶│ Consul │───▶│ Oracle Cloud │
│ │ │ (密钥存储) │ │ │
│ consul provider │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
## 前提条件
1. Consul 集群正在运行
2. 可以访问 Consul API (默认: http://localhost:8500)
3. 已安装 curl 和 Terraform
## 快速开始
### 1. 启动 Consul 集群
```bash
# 进入 swarm 目录
cd swarm
# 启动 Consul 集群
docker-compose -f configs/traefik-consul-setup.yml up -d
```
### 2. 设置 Oracle Cloud 配置
```bash
# 使用密钥管理脚本设置配置
./scripts/utilities/consul-secrets-manager.sh set-oracle
```
脚本会提示你输入:
- 租户 OCID
- 用户 OCID
- API 密钥指纹
- 私钥文件路径
- 区间 OCID
### 3. 配置 Terraform
```bash
# 设置 Terraform Consul Provider
./scripts/utilities/terraform-consul-provider.sh setup
```
### 4. 验证配置
```bash
# 查看存储在 Consul 中的配置
./scripts/utilities/consul-secrets-manager.sh get-oracle
```
### 5. 运行 Terraform
```bash
cd infrastructure/environments/dev
# 初始化 Terraform
terraform init
# 规划部署
terraform plan
# 应用配置
terraform apply
```
## 详细说明
### Consul 密钥存储结构
```
config/
└── dev/
└── oracle/
├── tenancy_ocid
├── user_ocid
├── fingerprint
├── private_key
└── compartment_ocid
```
### 脚本功能
#### consul-secrets-manager.sh
- `set-oracle`: 设置 Oracle Cloud 配置到 Consul
- `get-oracle`: 从 Consul 获取配置信息
- `delete-oracle`: 删除 Consul 中的配置
- `generate-vars`: 生成临时 Terraform 变量文件
- `cleanup`: 清理临时文件
#### terraform-consul-provider.sh
- `setup`: 创建 Terraform Consul Provider 配置文件
### 安全特性
1. **敏感信息隔离**: 私钥等敏感信息只存储在 Consul 中
2. **临时文件**: 私钥文件只在 Terraform 运行时临时创建
3. **权限控制**: 临时私钥文件设置为 600 权限
4. **自动清理**: 提供清理脚本删除临时文件
## 环境变量
```bash
# Consul 地址
export CONSUL_ADDR="http://localhost:8500"
# Consul ACL Token (如果启用了 ACL)
export CONSUL_TOKEN="your-token"
# 环境名称
export ENVIRONMENT="dev"
```
## 故障排除
### Consul 连接问题
```bash
# 检查 Consul 状态
curl http://localhost:8500/v1/status/leader
# 检查 Consul 服务
docker ps | grep consul
```
### 配置验证
```bash
# 验证 Consul 中的配置
curl http://localhost:8500/v1/kv/config/dev/oracle?recurse
# 检查 Terraform 配置
terraform validate
```
### 清理和重置
```bash
# 清理临时文件
./scripts/utilities/consul-secrets-manager.sh cleanup
# 删除 Consul 中的配置
./scripts/utilities/consul-secrets-manager.sh delete-oracle
```
## 最佳实践
1. **定期轮换密钥**: 定期更新 Oracle Cloud API 密钥
2. **备份配置**: 定期备份 Consul 数据
3. **监控访问**: 监控 Consul 密钥访问日志
4. **环境隔离**: 不同环境使用不同的 Consul 路径
## 扩展其他云服务商
可以类似地为其他云服务商添加 Consul 集成:
```bash
# 华为云配置路径
config/dev/huawei/access_key
config/dev/huawei/secret_key
# AWS 配置路径
config/dev/aws/access_key
config/dev/aws/secret_key
# Google Cloud 配置路径
config/dev/gcp/service_account_key
```
## 相关文件
- `infrastructure/environments/dev/terraform.tfvars` - Terraform 变量配置
- `scripts/utilities/consul-secrets-manager.sh` - Consul 密钥管理脚本
- `scripts/utilities/terraform-consul-provider.sh` - Terraform Consul Provider 配置脚本
- `swarm/configs/traefik-consul-setup.yml` - Consul 集群配置
## 支持
如有问题,请检查:
1. Consul 集群是否正常运行
2. 网络连接是否正常
3. 权限设置是否正确
4. 环境变量是否正确设置

View File

@ -0,0 +1,86 @@
# Oracle Cloud 凭据配置指南
## 凭据文件位置
### 1. OpenTofu 配置文件
**文件位置**: `infrastructure/environments/dev/terraform.tfvars`
这是主要的配置文件,需要填入你的 OCI 凭据:
```hcl
# Oracle Cloud 配置
oci_config = {
tenancy_ocid = "ocid1.tenancy.oc1..aaaaaaaa_你的租户ID"
user_ocid = "ocid1.user.oc1..aaaaaaaa_你的用户ID"
fingerprint = "aa:bb:cc:dd:ee:ff:gg:hh:ii:jj:kk:ll:mm:nn:oo:pp"
private_key_path = "~/.oci/oci_api_key.pem"
region = "ap-seoul-1"
compartment_ocid = "ocid1.compartment.oc1..aaaaaaaa_你的区间ID"
}
```
### 2. OCI 私钥文件
**文件位置**: `~/.oci/oci_api_key.pem`
这是你的 API 私钥文件,内容类似:
```
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC...
你的私钥内容
-----END PRIVATE KEY-----
```
### 3. OCI 配置文件 (可选)
**文件位置**: `~/.oci/config`
这是 OCI CLI 的配置文件,可以作为备用:
```ini
[DEFAULT]
user=ocid1.user.oc1..aaaaaaaa_你的用户ID
fingerprint=aa:bb:cc:dd:ee:ff:gg:hh:ii:jj:kk:ll:mm:nn:oo:pp
tenancy=ocid1.tenancy.oc1..aaaaaaaa_你的租户ID
region=ap-seoul-1
key_file=~/.oci/oci_api_key.pem
```
## 设置步骤
### 步骤 1: 创建 .oci 目录
```bash
mkdir -p ~/.oci
chmod 700 ~/.oci
```
### 步骤 2: 保存私钥文件
```bash
# 将你的私钥内容保存到文件
nano ~/.oci/oci_api_key.pem
# 设置正确的权限
chmod 400 ~/.oci/oci_api_key.pem
```
### 步骤 3: 编辑 terraform.tfvars
```bash
# 编辑配置文件
nano infrastructure/environments/dev/terraform.tfvars
```
## 安全注意事项
1. **私钥文件权限**: 确保私钥文件权限为 400 (只有所有者可读)
2. **不要提交到 Git**: `.gitignore` 已经配置忽略 `*.tfvars` 文件
3. **备份凭据**: 建议安全备份你的私钥和配置信息
## 验证配置
配置完成后,可以运行以下命令验证:
```bash
# 检查配置
./scripts/setup/setup-opentofu.sh check
# 初始化 OpenTofu
./scripts/setup/setup-opentofu.sh init

View File

@ -0,0 +1,153 @@
# Oracle Cloud 配置指南
## 概述
本指南将帮助你配置 Oracle Cloud Infrastructure (OCI) 以便与 OpenTofu 一起使用。
## 前提条件
1. Oracle Cloud 账户(可以使用免费层)
2. 已安装 OpenTofu
3. 已安装 OCI CLI可选但推荐
## 步骤 1: 创建 Oracle Cloud 账户
1. 访问 [Oracle Cloud](https://cloud.oracle.com/)
2. 点击 "Start for free" 创建免费账户
3. 完成注册流程
## 步骤 2: 获取必要的 OCID
### 获取 Tenancy OCID
1. 登录 Oracle Cloud Console
2. 点击右上角的用户图标
3. 选择 "Tenancy: <your-tenancy-name>"
4. 复制 OCID 值
### 获取 User OCID
1. 在 Oracle Cloud Console 中
2. 点击右上角的用户图标
3. 选择 "User Settings"
4. 复制 OCID 值
### 获取 Compartment OCID
1. 在导航菜单中选择 "Identity & Security" > "Compartments"
2. 选择你要使用的 compartment通常是 root compartment
3. 复制 OCID 值
## 步骤 3: 创建 API 密钥
### 生成密钥对
```bash
# 创建 .oci 目录
mkdir -p ~/.oci
# 生成私钥
openssl genrsa -out ~/.oci/oci_api_key.pem 2048
# 生成公钥
openssl rsa -pubout -in ~/.oci/oci_api_key.pem -out ~/.oci/oci_api_key_public.pem
# 设置权限
chmod 400 ~/.oci/oci_api_key.pem
chmod 400 ~/.oci/oci_api_key_public.pem
```
### 添加公钥到 Oracle Cloud
1. 在 Oracle Cloud Console 中,进入 "User Settings"
2. 在左侧菜单中选择 "API Keys"
3. 点击 "Add API Key"
4. 选择 "Paste Public Key"
5. 复制 `~/.oci/oci_api_key_public.pem` 的内容并粘贴
6. 点击 "Add"
7. 复制显示的 fingerprint
## 步骤 4: 配置 terraform.tfvars
编辑 `infrastructure/environments/dev/terraform.tfvars` 文件:
```hcl
# Oracle Cloud 配置
oci_config = {
tenancy_ocid = "ocid1.tenancy.oc1..aaaaaaaa_your_actual_tenancy_id"
user_ocid = "ocid1.user.oc1..aaaaaaaa_your_actual_user_id"
fingerprint = "aa:bb:cc:dd:ee:ff:gg:hh:ii:jj:kk:ll:mm:nn:oo:pp"
private_key_path = "~/.oci/oci_api_key.pem"
region = "ap-seoul-1" # 或你选择的区域
compartment_ocid = "ocid1.compartment.oc1..aaaaaaaa_your_compartment_id"
}
```
## 步骤 5: 验证配置
```bash
# 检查配置
./scripts/setup/setup-opentofu.sh check
# 初始化 OpenTofu
./scripts/setup/setup-opentofu.sh init
# 生成计划
./scripts/setup/setup-opentofu.sh plan
```
## 可用区域
常用的 Oracle Cloud 区域:
- `ap-seoul-1` - 韩国首尔
- `ap-tokyo-1` - 日本东京
- `us-ashburn-1` - 美国弗吉尼亚州
- `us-phoenix-1` - 美国亚利桑那州
- `eu-frankfurt-1` - 德国法兰克福
## 免费层资源
Oracle Cloud 免费层包括:
- 2 个 AMD 计算实例VM.Standard.E2.1.Micro
- 4 个 Arm 计算实例VM.Standard.A1.Flex
- 200 GB 块存储
- 10 GB 对象存储
- 负载均衡器
- 数据库等
## 故障排除
### 常见错误
1. **401 Unauthorized**: 检查 API 密钥配置
2. **404 Not Found**: 检查 OCID 是否正确
3. **权限错误**: 确保用户有足够的权限
### 验证连接
```bash
# 安装 OCI CLI可选
pip install oci-cli
# 配置 OCI CLI
oci setup config
# 测试连接
oci iam compartment list
```
## 安全最佳实践
1. 定期轮换 API 密钥
2. 使用最小权限原则
3. 不要在代码中硬编码凭据
4. 使用 compartment 隔离资源
5. 启用审计日志
## 参考资料
- [Oracle Cloud Infrastructure 文档](https://docs.oracle.com/en-us/iaas/)
- [OCI Terraform Provider](https://registry.terraform.io/providers/oracle/oci/latest/docs)
- [Oracle Cloud 免费层](https://www.oracle.com/cloud/free/)

View File

@ -1,8 +1,30 @@
#
#
module "shared" {
source = "../../shared"
#
terraform {
required_version = ">= 1.6"
required_providers {
# Oracle Cloud Infrastructure
oci = {
source = "oracle/oci"
version = "~> 5.0"
}
}
#
backend "local" {
path = "terraform.tfstate"
}
}
# Oracle Cloud
provider "oci" {
tenancy_ocid = var.oci_config.tenancy_ocid
user_ocid = var.oci_config.user_ocid
fingerprint = var.oci_config.fingerprint
private_key_path = var.oci_config.private_key_path
region = var.oci_config.region
}
# Oracle Cloud
@ -23,27 +45,8 @@ module "oracle_cloud" {
instance_size = "VM.Standard.E2.1.Micro" #
}
# ()
module "huawei_cloud" {
source = "../../providers/huawei-cloud"
count = contains(var.cloud_providers, "huawei") ? 1 : 0
environment = var.environment
project_name = var.project_name
owner = var.owner
vpc_cidr = "10.1.0.0/16" # CIDR
availability_zones = var.availability_zones
common_tags = var.common_tags
huawei_config = var.huawei_config
}
#
output "oracle_cloud_outputs" {
description = "Oracle Cloud 基础设施输出"
value = module.oracle_cloud
}
output "huawei_cloud_outputs" {
description = "华为云基础设施输出"
value = length(module.huawei_cloud) > 0 ? module.huawei_cloud[0] : null
}

61
key.md Normal file
View File

@ -0,0 +1,61 @@
oci usa
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDiDwCO56943GNv
rg2WYQCZTpdgA1YfdDcM6AXugzwGm6zQwuhuDdTABwJj0PfB7q5s0MZFqwpVW+MS
IkTQsk8r+8gBo9FBtH4nneBfXgqjiKhlHhcgqHWALXm8AzDq6MJ+lCDwjgi5PsID
5jbnBUBXRpVXlkEDMZj5yTNiRfLMlFZiqc4mv1j1RSIQeuptt7l2AnXhKSuW2FL3
aQNWspUylIs9IDXuC490r04/fZmX0Iw7Crb4yWWFem1e1x0g6qDiAizwpE3FF0No
AqkH+p+y3Qe7Pew2/UUS4VNRyoGBstpbBJMQ8dXRER9M4KTEdLnSG2EzdM5IGupj
Gwo9PnPPAgMBAAECggEAChaP+HtPvLMJH6NtfnfXEQBi3P6zyd+OfV2gC3mBJO0E
P09ovqXmB/5ywDBD05G/6EyWLJG/ek5eycu3CnaKoJ8x2RuNwRg5m7GooQOPXKZC
mDtJiO7mSia9YgM6caFFh2SQ5mtQPwQVSxtA+U+mBBRlocJWJbsBj/7HSOwaM8BC
wl19kZiW0aOkoGidxvjlJfkPiNer/jTy5RMNKruDpaF8PsF7xIMLwuxT5VQ/gyYA
frXsWfQp+sve/XfUg9/RGP9jJQHNppL56YWYPa8XusC2nJCym9RLDlK56jF9jhYM
iQThksG3TzOXjdGM7MP5Q/SfNckQWy0KTOu7h+N98QKBgQD9l7SFypX5Mgn2PC1A
U3lwiLCvviaKSNbzNXc6pnijbGEEvNpUGRyGwmjXItGLiEoAky0eu42Ipult6PB+
WsjCIGTGI0UBObrjbWfaj+vt6zCcI653tgvrQO97t+F6xTHiQyGRDqIlFQcE9ZKO
EJ+wuC+MbBFGPSc/Zw43/twpzQKBgQDkNGHiuoGvoSuRPpMIB82IsMmtOlzymk8B
ZZMNzHfxFyf7a/1NUhc3UvmZdE67MS4cmoY0LCY4HBW2zxxsnX0cA+vRNLFneJMC
oH2XgQs+mi1Dgem+N6EYO/5PJZqeyUJ5x5WFGrULvsL2GKcSeSp2o2nkFyKSHfhD
7zWSQyNICwKBgQD1lDZD4n3+BxFSndAMnUnbSuQgLPrRq9xNRpeh+piVWl1R4zlj
e7X+YsJ4pMVcZK2VhPGK84IKtekUgSJ0mqIULJ6qqnkmyKtNlyOdqwaFLt+yNXO9
hlRgjE/e9aGr7M90GCKngQ5Q7t4PVWmJnlunHZceW4EXDh217qz8WRkIeQKBgGV0
JFB4Ok+qh4P7HcLkNSwf7Ilm+QuiLp2gWtA3pts4QD42tFY7uLaP3Qer/ZSbOLTe
vetT9WnckorDaQ+gtI5P7/cCRhyKLlFsqGlCpY0fXiA1EYXPlX8ArP7i6OrO7w7U
/FRAm1ytYl+mdiBwXcCAxgLxhh0P1d/d6SMtVfIhAoGBALdQ9tPSkFsJiDJi+d1u
SwPauzmr8O0geaLuey9WxVAxm5DR7eTJTUswZJGqadAZlnDr/H+7YU6lEBRI224Q
0ApgIIeGpMsTZFetRsOq+TUoNQcGVCtspOckCbElW6NMSzuAlf7aI+VqKM3uwlAn
FiTDYcmZIE1yNjYi+uaD8vkU
-----END PRIVATE KEY-----
OCI_API_KEY
oci kr
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCXpRaddq1RzS0J
cBAGHh94DJyqOBti+ASs6Abv1v3gyXu0ssNSe/g/ZBe+aDIIBisL/5nRLDZfeNZg
S5azKgPFPPlukTKVAfatQrgsaCC3uNm4D0NfGSINY90HcpZwX5GCZbUIFZuBZBac
33ze+RXoEo/QJFqniiUh/19A1R6mO2oJchgcXYv3+Fe8db35Fb9HDt6tg8+maO5R
8W149SpQUlU9JWCWuRV2cdKSXP1/z3JH3bq7hezD5qkZrcwt+4e+Pj9moYyA+O8i
n9Z9yQUeipp+HR3SdM++pzUhc1E/NNrgNTKQJi3OvrUx41jc00/5KwZUYyOtvJa3
/GBzycKNAgMBAAECggEAFiooGw3cmWc+3PFHNk2y1c4qG+slfZq4vDkRwn6PDwsE
DM5QJD9AcquDmO4L2gZkxlUuu1cV/3BfDSYfOcK7WFnoL1QDq6nkz0BAQSVbGt9m
2zNH6p92zbQ5+zuxZ21gjEmnYy4dU5U4hOdZjhGkNQ55fLfDlFdpxAVae9RqrWsp
8/9SiuD1G+fgNKbe8x+ASd8Y4rP9gjItDUCqmi2rnJJsR8i1PHMZiLC0S3FbcUo6
R7kwO0dGaXYFWtPUlMB/OPx172HM6yfE+lDmT6gKfWJ2dOKvu7mOtXTGSBIGMREV
MpC9ZhYBsk3jvZKlEju0sEATg3tdDBeX3xRNOkPFFQKBgQDVrmuAOS/Xrz5ZGzwl
nRzgtR02EjdQ+wJrfyJoufmJWZQlC6cAe3RyCBs8c7YiSyvTL773ZW/v9RoVln0R
WDaEdw7L+YLjdv51Dzy3KVY9A4HX1s+xhP5zG2C24Rp5ALwfS6Qf2JDGtAlm821J
z5kwEcY2sSOxGqL8MTA9gysmqwKBgQC1rXBNsW4BVhbqOXMC6ZpwQ/n6BEdHGl8g
1nNonznnZ6ECI/G/TBYA5Pb23FslpQAaFaYgg6pY1FisnIVUpjk23xKd193zY7P4
8Ah7D/gcAtloXeJ6sknaWjkBBYRRyZhlG3M428kKoIgxQveokGZiLvF4xB9/NBM3
oCepbq6bpwKBgQC8KWFEghcdCJYQhSkLvjQls5bLfHL1fnN9EXDNY6bXSehoTsB6
bjv2BillrEcgH62xxAOXet19IgocJG5xjYpET0raVxbpEmmzzv0aFO55v9Lgq6os
mf4ugldB8ysKjpkZvdQCrwOd1f/JhmYgbwxoBd7TXl0doWUQSog+QnkHDQKBgDMd
jDZf0GqR1TqrVT+hiDFD/uYoJAHOWqt7itcJzZnc30Eh6dd/ycUQpqeIEiECTogI
RUhqoxgBDr3p/910My7MDonYfXsIN0+4ATrWoGEJMDAcEiehWAQWVGmEKtl0FeuE
kKOTuvnBdvAdPl7v2c6QFKJ807vPZATHi8ExAfGLAoGBALuFCz/9Xlw5legmGJxP
IgbhcmSFCw9OmGRA6KdRZUN+Zsb6FVj9eCcF1My13iw359xFaYdhBD6hnbPIe3XS
bzVMczdiuRAI9LijXhzGWmw5hlkumaVDqZI3+Sy5lohLhOsV4Erss1vqL3R40zjk
fk2tnbktORYd6/Q0i0FJdO/H
-----END PRIVATE KEY-----
OCI_API_KEY

162
mgmt.sh Executable file
View File

@ -0,0 +1,162 @@
#!/bin/bash
# 项目管理主脚本
set -euo pipefail
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 项目根目录
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 显示项目状态
show_status() {
log_info "=== 项目状态总览 ==="
echo ""
# Docker Swarm 状态
log_info "Docker Swarm 状态:"
if docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q "active"; then
log_success "✓ Docker Swarm 已激活"
docker node ls 2>/dev/null | head -n 5
else
log_warning "✗ Docker Swarm 未激活"
fi
echo ""
# OpenTofu 状态
log_info "OpenTofu 状态:"
if command -v tofu &> /dev/null; then
local version=$(tofu version | head -n1)
log_success "✓ OpenTofu 已安装: $version"
else
log_warning "✗ OpenTofu 未安装"
fi
echo ""
# 部署的堆栈
log_info "已部署的 Docker Stack:"
if docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q "active"; then
docker stack ls 2>/dev/null || log_warning "无堆栈部署"
else
log_warning "Swarm 未激活,无法查看堆栈"
fi
echo ""
}
# 快速部署
quick_deploy() {
log_info "=== 快速部署 ==="
# 检查 Swarm
if ! docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q "active"; then
log_info "初始化 Docker Swarm..."
"${PROJECT_ROOT}/swarm/scripts/swarm-manager.sh" init
fi
# 部署 Traefik
log_info "部署 Traefik 反向代理..."
"${PROJECT_ROOT}/swarm/scripts/swarm-manager.sh" deploy traefik "${PROJECT_ROOT}/swarm/stacks/traefik-swarm-stack.yml"
# 等待 Traefik 启动
log_info "等待 Traefik 启动..."
sleep 10
# 部署示例服务
log_info "部署示例服务..."
"${PROJECT_ROOT}/swarm/scripts/swarm-manager.sh" deploy demo "${PROJECT_ROOT}/swarm/stacks/demo-services-stack.yml"
log_success "快速部署完成!"
echo ""
log_info "访问地址:"
echo " - Traefik Dashboard: http://localhost:8080"
echo " - 示例应用: 请查看 demo 堆栈的服务配置"
}
# 清理环境
cleanup() {
log_info "=== 清理环境 ==="
# 停止所有堆栈
log_info "停止所有 Docker Stack..."
docker stack ls --format "{{.Name}}" 2>/dev/null | while read -r stack; do
if [[ -n "$stack" ]]; then
log_info "删除堆栈: $stack"
docker stack rm "$stack"
fi
done
# 等待服务清理
log_info "等待服务清理..."
sleep 5
log_success "环境清理完成"
}
# 显示帮助
show_help() {
echo "项目管理脚本"
echo ""
echo "用法: $0 [命令]"
echo ""
echo "命令:"
echo " status - 显示项目状态总览"
echo " deploy - 快速部署所有服务"
echo " cleanup - 清理所有部署的服务"
echo " swarm - 打开 Swarm 管理工具"
echo " tofu - 打开 OpenTofu 管理工具"
echo " help - 显示此帮助信息"
echo ""
echo "子工具:"
echo " ./swarm/scripts/swarm-manager.sh - Docker Swarm 管理"
echo " ./scripts/setup/setup-opentofu.sh - OpenTofu 设置"
echo ""
}
# 主函数
main() {
cd "$PROJECT_ROOT"
case "${1:-help}" in
"status")
show_status
;;
"deploy")
quick_deploy
;;
"cleanup")
cleanup
;;
"swarm")
exec "${PROJECT_ROOT}/swarm/scripts/swarm-manager.sh" "${@:2}"
;;
"tofu")
exec "${PROJECT_ROOT}/scripts/setup/setup-opentofu.sh" "${@:2}"
;;
"help"|*)
show_help
;;
esac
}
main "$@"

174
scripts/setup/setup-opentofu.sh Executable file
View File

@ -0,0 +1,174 @@
#!/bin/bash
# OpenTofu 设置脚本
set -euo pipefail
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 OpenTofu 是否已安装
check_opentofu() {
log_info "检查 OpenTofu 安装状态..."
if command -v tofu &> /dev/null; then
local version=$(tofu version | head -n1)
log_success "OpenTofu 已安装: $version"
return 0
else
log_error "OpenTofu 未安装"
return 1
fi
}
# 检查配置文件
check_config() {
log_info "检查配置文件..."
local config_file="tofu/environments/dev/terraform.tfvars"
if [[ ! -f "$config_file" ]]; then
log_error "配置文件不存在: $config_file"
log_info "请复制 terraform.tfvars.example 并填入实际配置"
return 1
fi
# 检查是否包含示例值
if grep -q "your_tenancy_id_here\|your_user_id_here\|your:key:fingerprint:here" "$config_file"; then
log_warning "配置文件包含示例值,请填入实际的 Oracle Cloud 配置"
log_info "需要配置以下项目:"
echo " - tenancy_ocid: Oracle Cloud 租户 OCID"
echo " - user_ocid: 用户 OCID"
echo " - fingerprint: API 密钥指纹"
echo " - private_key_path: 私钥文件路径"
echo " - compartment_ocid: 区间 OCID"
return 1
fi
log_success "配置文件检查通过"
return 0
}
# 初始化 OpenTofu
init_opentofu() {
log_info "初始化 OpenTofu..."
cd tofu/environments/dev
# 清理旧的状态文件
if [[ -d ".terraform" ]]; then
log_info "清理旧的 .terraform 目录..."
rm -rf .terraform
fi
# 初始化
if tofu init; then
log_success "OpenTofu 初始化成功"
else
log_error "OpenTofu 初始化失败"
return 1
fi
cd - > /dev/null
}
# 验证配置
validate_config() {
log_info "验证 OpenTofu 配置..."
cd tofu/environments/dev
if tofu validate; then
log_success "配置验证通过"
else
log_error "配置验证失败"
return 1
fi
cd - > /dev/null
}
# 生成计划
plan_infrastructure() {
log_info "生成基础设施计划..."
cd tofu/environments/dev
if tofu plan -var-file="terraform.tfvars" -out=tfplan; then
log_success "计划生成成功"
log_info "计划文件已保存为 tfplan"
else
log_error "计划生成失败"
return 1
fi
cd - > /dev/null
}
# 显示帮助信息
show_help() {
echo "OpenTofu 设置脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " init - 初始化 OpenTofu"
echo " validate - 验证配置"
echo " plan - 生成执行计划"
echo " check - 检查环境和配置"
echo " help - 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 check # 检查环境"
echo " $0 init # 初始化项目"
echo " $0 plan # 生成计划"
}
# 主函数
main() {
case "${1:-help}" in
"check")
check_opentofu
check_config
;;
"init")
check_opentofu || exit 1
check_config || exit 1
init_opentofu
;;
"validate")
validate_config
;;
"plan")
check_opentofu || exit 1
check_config || exit 1
plan_infrastructure
;;
"help"|*)
show_help
;;
esac
}
# 运行主函数
main "$@"

View File

@ -0,0 +1,228 @@
#!/bin/bash
# Consul 密钥管理脚本
# 用于安全地管理 Oracle Cloud 和其他云服务商的敏感配置
set -euo pipefail
# 配置
CONSUL_ADDR="${CONSUL_ADDR:-http://localhost:8500}"
CONSUL_TOKEN="${CONSUL_TOKEN:-}"
ENVIRONMENT="${ENVIRONMENT:-dev}"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 Consul 连接
check_consul() {
log_info "检查 Consul 连接..."
if ! curl -s "${CONSUL_ADDR}/v1/status/leader" > /dev/null; then
log_error "无法连接到 Consul: ${CONSUL_ADDR}"
exit 1
fi
log_success "Consul 连接正常"
}
# 设置 Oracle Cloud 配置
set_oracle_config() {
log_info "设置 Oracle Cloud 配置..."
echo "请输入 Oracle Cloud 配置信息:"
read -p "租户 OCID: " tenancy_ocid
read -p "用户 OCID: " user_ocid
read -p "API 密钥指纹: " fingerprint
read -p "私钥文件路径: " private_key_path
read -p "区间 OCID: " compartment_ocid
# 验证私钥文件是否存在
if [[ ! -f "$private_key_path" ]]; then
log_error "私钥文件不存在: $private_key_path"
exit 1
fi
# 读取私钥内容
private_key_content=$(cat "$private_key_path")
# 存储到 Consul
local base_path="config/${ENVIRONMENT}/oracle"
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/tenancy_ocid" -d "$tenancy_ocid" > /dev/null
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/user_ocid" -d "$user_ocid" > /dev/null
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/fingerprint" -d "$fingerprint" > /dev/null
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/private_key" -d "$private_key_content" > /dev/null
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/compartment_ocid" -d "$compartment_ocid" > /dev/null
log_success "Oracle Cloud 配置已存储到 Consul"
}
# 获取 Oracle Cloud 配置
get_oracle_config() {
log_info "从 Consul 获取 Oracle Cloud 配置..."
local base_path="config/${ENVIRONMENT}/oracle"
echo "Oracle Cloud 配置:"
echo "租户 OCID: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/tenancy_ocid?raw" 2>/dev/null || echo "未设置")"
echo "用户 OCID: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/user_ocid?raw" 2>/dev/null || echo "未设置")"
echo "指纹: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/fingerprint?raw" 2>/dev/null || echo "未设置")"
echo "区间 OCID: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/compartment_ocid?raw" 2>/dev/null || echo "未设置")"
echo "私钥: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/private_key?raw" 2>/dev/null | head -1 || echo "未设置")"
}
# 删除 Oracle Cloud 配置
delete_oracle_config() {
log_warning "删除 Oracle Cloud 配置..."
read -p "确定要删除所有 Oracle Cloud 配置吗?(y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
log_info "操作已取消"
return
fi
local base_path="config/${ENVIRONMENT}/oracle"
curl -s -X DELETE "${CONSUL_ADDR}/v1/kv/${base_path}?recurse" > /dev/null
log_success "Oracle Cloud 配置已删除"
}
# 生成 Terraform 变量文件
generate_terraform_vars() {
log_info "生成 Terraform 变量文件..."
local base_path="config/${ENVIRONMENT}/oracle"
local output_file="infrastructure/environments/${ENVIRONMENT}/terraform.tfvars.consul"
# 从 Consul 获取配置
local tenancy_ocid=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/tenancy_ocid?raw" 2>/dev/null || echo "")
local user_ocid=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/user_ocid?raw" 2>/dev/null || echo "")
local fingerprint=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/fingerprint?raw" 2>/dev/null || echo "")
local compartment_ocid=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/compartment_ocid?raw" 2>/dev/null || echo "")
if [[ -z "$tenancy_ocid" ]]; then
log_error "Consul 中没有找到 Oracle Cloud 配置"
exit 1
fi
# 创建临时私钥文件
local temp_key_file="/tmp/oci_private_key_${ENVIRONMENT}.pem"
curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/private_key?raw" > "$temp_key_file"
chmod 600 "$temp_key_file"
# 生成 Terraform 变量文件
cat > "$output_file" << EOF
# 从 Consul 生成的 Oracle Cloud 配置
# 生成时间: $(date)
# 环境: ${ENVIRONMENT}
oci_config = {
tenancy_ocid = "$tenancy_ocid"
user_ocid = "$user_ocid"
fingerprint = "$fingerprint"
private_key_path = "$temp_key_file"
region = "ap-seoul-1"
compartment_ocid = "$compartment_ocid"
}
EOF
log_success "Terraform 变量文件已生成: $output_file"
log_warning "私钥文件位置: $temp_key_file"
log_warning "请在使用完毕后删除临时私钥文件"
}
# 清理临时文件
cleanup_temp_files() {
log_info "清理临时文件..."
rm -f /tmp/oci_private_key_*.pem
rm -f infrastructure/environments/*/terraform.tfvars.consul
log_success "临时文件已清理"
}
# 显示帮助信息
show_help() {
cat << EOF
Consul 密钥管理脚本
用法: $0 [选项]
选项:
set-oracle 设置 Oracle Cloud 配置到 Consul
get-oracle 从 Consul 获取 Oracle Cloud 配置
delete-oracle 从 Consul 删除 Oracle Cloud 配置
generate-vars 从 Consul 生成 Terraform 变量文件
cleanup 清理临时文件
help 显示此帮助信息
环境变量:
CONSUL_ADDR Consul 地址 (默认: http://localhost:8500)
CONSUL_TOKEN Consul ACL Token (可选)
ENVIRONMENT 环境名称 (默认: dev)
示例:
# 设置 Oracle Cloud 配置
$0 set-oracle
# 生成 Terraform 变量文件
$0 generate-vars
# 查看配置
$0 get-oracle
# 清理临时文件
$0 cleanup
EOF
}
# 主函数
main() {
case "${1:-help}" in
"set-oracle")
check_consul
set_oracle_config
;;
"get-oracle")
check_consul
get_oracle_config
;;
"delete-oracle")
check_consul
delete_oracle_config
;;
"generate-vars")
check_consul
generate_terraform_vars
;;
"cleanup")
cleanup_temp_files
;;
"help"|*)
show_help
;;
esac
}
main "$@"

View File

@ -0,0 +1,311 @@
#!/bin/bash
# Terraform Consul Provider 配置脚本
# 用于配置 Terraform 从 Consul 读取敏感配置
set -euo pipefail
ENVIRONMENT="${ENVIRONMENT:-dev}"
CONSUL_ADDR="${CONSUL_ADDR:-http://localhost:8500}"
# 颜色输出
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
# 创建 Terraform Consul Provider 配置
create_consul_provider() {
local tf_dir="infrastructure/environments/${ENVIRONMENT}"
log_info "创建 Terraform Consul Provider 配置..."
cat > "${tf_dir}/consul-provider.tf" << 'EOF'
# Consul Provider 配置
terraform {
required_providers {
consul = {
source = "hashicorp/consul"
version = "~> 2.18"
}
}
}
provider "consul" {
address = var.consul_config.address
token = lookup(var.consul_config, "token", null)
}
# 从 Consul 读取 Oracle Cloud 配置
data "consul_keys" "oracle_config" {
key {
name = "tenancy_ocid"
path = "config/${var.environment}/oracle/tenancy_ocid"
}
key {
name = "user_ocid"
path = "config/${var.environment}/oracle/user_ocid"
}
key {
name = "fingerprint"
path = "config/${var.environment}/oracle/fingerprint"
}
key {
name = "private_key"
path = "config/${var.environment}/oracle/private_key"
}
key {
name = "compartment_ocid"
path = "config/${var.environment}/oracle/compartment_ocid"
}
}
# 创建临时私钥文件
resource "local_file" "oci_private_key" {
content = data.consul_keys.oracle_config.var.private_key
filename = "/tmp/oci_private_key_${var.environment}.pem"
file_permission = "0600"
lifecycle {
ignore_changes = [content]
}
}
# 本地变量,用于构建完整的 OCI 配置
locals {
oci_config_from_consul = {
tenancy_ocid = data.consul_keys.oracle_config.var.tenancy_ocid
user_ocid = data.consul_keys.oracle_config.var.user_ocid
fingerprint = data.consul_keys.oracle_config.var.fingerprint
private_key_path = local_file.oci_private_key.filename
region = var.oci_config.region
compartment_ocid = data.consul_keys.oracle_config.var.compartment_ocid
}
}
EOF
log_success "Consul Provider 配置已创建: ${tf_dir}/consul-provider.tf"
}
# 创建变量定义文件
create_variables() {
local tf_dir="infrastructure/environments/${ENVIRONMENT}"
log_info "更新 Terraform 变量定义..."
cat > "${tf_dir}/variables.tf" << 'EOF'
# 基本变量
variable "environment" {
description = "环境名称"
type = string
}
variable "project_name" {
description = "项目名称"
type = string
}
variable "owner" {
description = "项目所有者"
type = string
}
variable "cloud_providers" {
description = "要启用的云服务商"
type = list(string)
default = []
}
variable "vpc_cidr" {
description = "VPC CIDR 块"
type = string
}
variable "availability_zones" {
description = "可用区列表"
type = list(string)
}
variable "common_tags" {
description = "通用标签"
type = map(string)
default = {}
}
# Consul 配置
variable "consul_config" {
description = "Consul 配置"
type = object({
address = string
token = optional(string)
})
}
# Oracle Cloud 配置(基本信息)
variable "oci_config" {
description = "Oracle Cloud 基本配置"
type = object({
region = string
tenancy_ocid = optional(string, "FROM_CONSUL")
user_ocid = optional(string, "FROM_CONSUL")
fingerprint = optional(string, "FROM_CONSUL")
private_key_path = optional(string, "FROM_CONSUL")
compartment_ocid = optional(string, "FROM_CONSUL")
})
}
# 其他云服务商配置
variable "huawei_config" {
description = "华为云配置"
type = object({
access_key = string
secret_key = string
region = string
project_id = string
})
default = {
access_key = ""
secret_key = ""
region = "cn-north-4"
project_id = ""
}
}
variable "gcp_config" {
description = "Google Cloud 配置"
type = object({
project_id = string
region = string
zone = string
credentials_file = string
})
default = {
project_id = ""
region = "asia-northeast3"
zone = "asia-northeast3-a"
credentials_file = ""
}
}
variable "aws_config" {
description = "AWS 配置"
type = object({
region = string
access_key = string
secret_key = string
})
default = {
region = "ap-northeast-2"
access_key = ""
secret_key = ""
}
}
variable "do_config" {
description = "DigitalOcean 配置"
type = object({
token = string
region = string
})
default = {
token = ""
region = "sgp1"
}
}
EOF
log_success "变量定义已更新: ${tf_dir}/variables.tf"
}
# 创建示例 main.tf
create_main_tf() {
local tf_dir="infrastructure/environments/${ENVIRONMENT}"
log_info "创建示例 main.tf..."
cat > "${tf_dir}/main.tf" << 'EOF'
# 主要 Terraform 配置文件
terraform {
required_version = ">= 1.0"
required_providers {
oci = {
source = "oracle/oci"
version = "~> 5.0"
}
}
}
# Oracle Cloud Provider
provider "oci" {
tenancy_ocid = local.oci_config_from_consul.tenancy_ocid
user_ocid = local.oci_config_from_consul.user_ocid
fingerprint = local.oci_config_from_consul.fingerprint
private_key_path = local.oci_config_from_consul.private_key_path
region = local.oci_config_from_consul.region
}
# 示例:创建 VCN
resource "oci_core_vcn" "main" {
count = contains(var.cloud_providers, "oracle") ? 1 : 0
compartment_id = local.oci_config_from_consul.compartment_ocid
cidr_block = var.vpc_cidr
display_name = "${var.project_name}-${var.environment}-vcn"
freeform_tags = var.common_tags
}
# 输出
output "vcn_id" {
description = "VCN ID"
value = try(oci_core_vcn.main[0].id, null)
}
output "oci_config_source" {
description = "OCI 配置来源"
value = "consul"
}
EOF
log_success "示例 main.tf 已创建: ${tf_dir}/main.tf"
}
# 主函数
main() {
case "${1:-help}" in
"setup")
create_consul_provider
create_variables
create_main_tf
;;
"help"|*)
cat << EOF
Terraform Consul Provider 配置脚本
用法: $0 [选项]
选项:
setup 创建 Terraform Consul Provider 配置
help 显示此帮助信息
环境变量:
ENVIRONMENT 环境名称 (默认: dev)
CONSUL_ADDR Consul 地址 (默认: http://localhost:8500)
EOF
;;
esac
}
main "$@"

View File

@ -0,0 +1,128 @@
#!/bin/bash
# 简化版 OpenTofu 密钥上传脚本
set -euo pipefail
# 配置
CONSUL_ADDR="${CONSUL_ADDR:-http://master:8500}"
ENVIRONMENT="${ENVIRONMENT:-dev}"
TFVARS_FILE="tofu/environments/${ENVIRONMENT}/terraform.tfvars"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 检查 Consul 连接
check_consul() {
log_info "检查 Consul 连接..."
if ! curl -s "${CONSUL_ADDR}/v1/status/leader" > /dev/null; then
log_error "无法连接到 Consul: ${CONSUL_ADDR}"
exit 1
fi
log_success "Consul 连接正常"
}
# 上传配置
upload_configs() {
local uploaded_count=0
log_info "开始解析并上传配置..."
# 直接解析 tfvars 文件
while IFS= read -r line; do
# 跳过注释和空行
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then
continue
fi
# 匹配变量赋值
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*\"([^\"]*)\"|^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*([^[:space:]#]+) ]]; then
local var_name="${BASH_REMATCH[1]:-${BASH_REMATCH[3]}}"
local var_value="${BASH_REMATCH[2]:-${BASH_REMATCH[4]}}"
# 跳过空值
if [[ -z "$var_value" || "$var_value" == "null" ]]; then
continue
fi
# 确定配置分类和路径
local consul_path=""
if [[ "$var_name" =~ ^oci_ ]]; then
consul_path="config/${ENVIRONMENT}/oracle/${var_name#oci_}"
elif [[ "$var_name" =~ ^huawei_ ]]; then
consul_path="config/${ENVIRONMENT}/huawei/${var_name#huawei_}"
elif [[ "$var_name" =~ ^aws_ ]]; then
consul_path="config/${ENVIRONMENT}/aws/${var_name#aws_}"
elif [[ "$var_name" =~ ^do_ ]]; then
consul_path="config/${ENVIRONMENT}/digitalocean/${var_name#do_}"
elif [[ "$var_name" =~ ^gcp_ ]]; then
consul_path="config/${ENVIRONMENT}/gcp/${var_name#gcp_}"
else
consul_path="config/${ENVIRONMENT}/general/${var_name}"
fi
# 上传到 Consul
if curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${consul_path}" -d "$var_value" > /dev/null; then
log_info "上传: ${consul_path}"
((uploaded_count++))
else
log_error "上传失败: ${consul_path}"
fi
fi
done < "$TFVARS_FILE"
log_success "总共上传了 $uploaded_count 个配置项到 Consul"
}
# 列出配置
list_configs() {
log_info "列出 Consul 中的配置..."
local keys=$(curl -s "${CONSUL_ADDR}/v1/kv/config/${ENVIRONMENT}/?keys" | jq -r '.[]' 2>/dev/null || echo "")
if [[ -z "$keys" ]]; then
log_error "没有找到配置"
return
fi
echo "=== 环境 ${ENVIRONMENT} 的配置 ==="
echo "$keys" | while read -r key; do
local value=$(curl -s "${CONSUL_ADDR}/v1/kv/${key}?raw" 2>/dev/null || echo "无法读取")
# 隐藏敏感信息
if [[ "$key" =~ (secret|key|token|password|ocid) ]]; then
echo "$key: [已隐藏]"
else
echo "$key: $value"
fi
done
}
# 主函数
main() {
if [[ ! -f "$TFVARS_FILE" ]]; then
log_error "找不到配置文件: $TFVARS_FILE"
exit 1
fi
check_consul
case "${1:-upload}" in
"upload")
upload_configs
;;
"list")
list_configs
;;
*)
echo "用法: $0 [upload|list]"
;;
esac
}
main "$@"

View File

@ -0,0 +1,495 @@
#!/bin/bash
# OpenTofu 密钥上传脚本
# 用于将 terraform.tfvars 中的敏感配置批量上传到 Consul
set -euo pipefail
# 配置
CONSUL_ADDR="${CONSUL_ADDR:-http://master:8500}"
CONSUL_TOKEN="${CONSUL_TOKEN:-}"
ENVIRONMENT="${ENVIRONMENT:-dev}"
TOFU_DIR="${TOFU_DIR:-tofu/environments/${ENVIRONMENT}}"
TFVARS_FILE="${TFVARS_FILE:-${TOFU_DIR}/terraform.tfvars}"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查依赖
check_dependencies() {
local deps=("curl" "jq")
for dep in "${deps[@]}"; do
if ! command -v "$dep" &> /dev/null; then
log_error "缺少依赖: $dep"
exit 1
fi
done
}
# 检查 Consul 连接
check_consul() {
log_info "检查 Consul 连接..."
if ! curl -s "${CONSUL_ADDR}/v1/status/leader" > /dev/null; then
log_error "无法连接到 Consul: ${CONSUL_ADDR}"
exit 1
fi
log_success "Consul 连接正常"
}
# 检查 tfvars 文件
check_tfvars_file() {
if [[ ! -f "$TFVARS_FILE" ]]; then
log_error "找不到 terraform.tfvars 文件: $TFVARS_FILE"
exit 1
fi
log_info "找到配置文件: $TFVARS_FILE"
}
# 解析 HCL 配置并转换为 JSON
parse_hcl_to_json() {
local tfvars_file="$1"
local temp_tf_file="/tmp/temp_config.tf"
local temp_json_file="/tmp/temp_config.json"
# 创建临时 .tf 文件,将变量赋值转换为输出
log_info "解析 HCL 配置..."
# 读取 tfvars 文件并转换为 output 格式
cat > "$temp_tf_file" << 'EOF'
# 临时配置文件,用于解析 tfvars
EOF
# 解析每个配置块
while IFS= read -r line; do
# 跳过注释和空行
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then
continue
fi
# 提取变量名和值
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local var_name="${BASH_REMATCH[1]}"
local var_value="${BASH_REMATCH[2]}"
echo "output \"$var_name\" {" >> "$temp_tf_file"
echo " value = $var_value" >> "$temp_tf_file"
echo "}" >> "$temp_tf_file"
fi
done < "$tfvars_file"
# 使用 terraform 解析配置
if command -v terraform &> /dev/null; then
cd "$(dirname "$temp_tf_file")"
terraform init -backend=false > /dev/null 2>&1 || true
terraform output -json > "$temp_json_file" 2>/dev/null || {
log_warning "无法使用 terraform 解析,尝试手动解析..."
manual_parse_tfvars "$tfvars_file" "$temp_json_file"
}
else
log_warning "未找到 terraform使用手动解析..."
manual_parse_tfvars "$tfvars_file" "$temp_json_file"
fi
echo "$temp_json_file"
}
# 手动解析 tfvars 文件
manual_parse_tfvars() {
local tfvars_file="$1"
local output_file="$2"
log_info "手动解析 tfvars 文件..."
# 创建基础 JSON 结构
echo "{" > "$output_file"
local first_item=true
local in_block=false
local block_name=""
local block_content=""
while IFS= read -r line; do
# 跳过注释和空行
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then
continue
fi
# 检测配置块开始
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*\{[[:space:]]*$ ]]; then
block_name="${BASH_REMATCH[1]}"
in_block=true
block_content=""
continue
fi
# 检测配置块结束
if [[ "$in_block" == true && "$line" =~ ^[[:space:]]*\}[[:space:]]*$ ]]; then
if [[ "$first_item" == false ]]; then
echo "," >> "$output_file"
fi
echo " \"$block_name\": {" >> "$output_file"
echo "$block_content" >> "$output_file"
echo " }" >> "$output_file"
first_item=false
in_block=false
continue
fi
# 处理块内容
if [[ "$in_block" == true ]]; then
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*\"([^\"]*)\"|^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*([^[:space:]]+) ]]; then
local key="${BASH_REMATCH[1]:-${BASH_REMATCH[3]}}"
local value="${BASH_REMATCH[2]:-${BASH_REMATCH[4]}}"
if [[ -n "$block_content" ]]; then
block_content+=","
fi
block_content+="\n \"$key\": \"$value\""
fi
continue
fi
# 处理简单变量
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*\"([^\"]*)\"|^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*([^[:space:]]+) ]]; then
local var_name="${BASH_REMATCH[1]:-${BASH_REMATCH[3]}}"
local var_value="${BASH_REMATCH[2]:-${BASH_REMATCH[4]}}"
if [[ "$first_item" == false ]]; then
echo "," >> "$output_file"
fi
echo " \"$var_name\": \"$var_value\"" >> "$output_file"
first_item=false
fi
done < "$tfvars_file"
echo "}" >> "$output_file"
}
# 上传配置到 Consul
upload_config_to_consul() {
local config_file="$1"
local uploaded_count=0
log_info "开始上传配置到 Consul..."
# 读取 JSON 配置
if [[ ! -f "$config_file" ]]; then
log_error "配置文件不存在: $config_file"
return 1
fi
# 上传 Oracle Cloud 配置
local oci_tenancy=$(jq -r '.oci_tenancy_ocid // empty' "$config_file")
local oci_user=$(jq -r '.oci_user_ocid // empty' "$config_file")
local oci_fingerprint=$(jq -r '.oci_fingerprint // empty' "$config_file")
local oci_private_key_path=$(jq -r '.oci_private_key_path // empty' "$config_file")
local oci_compartment=$(jq -r '.oci_compartment_ocid // empty' "$config_file")
local oci_region=$(jq -r '.oci_region // empty' "$config_file")
if [[ -n "$oci_tenancy" && "$oci_tenancy" != "null" && "$oci_tenancy" != "" ]]; then
=======
# 上传配置到 Consul
upload_config_to_consul() {
local config_file="$1"
local uploaded_count=0
log_info "开始上传配置到 Consul..."
# 读取 JSON 配置
if [[ ! -f "$config_file" ]]; then
log_error "配置文件不存在: $config_file"
return 1
fi
# 上传 Oracle Cloud 配置
local oci_tenancy=$(jq -r '.oci_tenancy_ocid // empty' "$config_file")
local oci_user=$(jq -r '.oci_user_ocid // empty' "$config_file")
local oci_fingerprint=$(jq -r '.oci_fingerprint // empty' "$config_file")
local oci_private_key_path=$(jq -r '.oci_private_key_path // empty' "$config_file")
local oci_compartment=$(jq -r '.oci_compartment_ocid // empty' "$config_file")
local oci_region=$(jq -r '.oci_region // empty' "$config_file")
if [[ -n "$oci_tenancy" && "$oci_tenancy" != "null" && "$oci_tenancy" != "" ]]; then
log_info "上传 Oracle Cloud 配置..."
local base_path="config/${ENVIRONMENT}/oracle"
local tenancy_ocid=$(jq -r '.oci_config.tenancy_ocid // empty' "$config_file")
local user_ocid=$(jq -r '.oci_config.user_ocid // empty' "$config_file")
local fingerprint=$(jq -r '.oci_config.fingerprint // empty' "$config_file")
local private_key_path=$(jq -r '.oci_config.private_key_path // empty' "$config_file")
local compartment_ocid=$(jq -r '.oci_config.compartment_ocid // empty' "$config_file")
local region=$(jq -r '.oci_config.region // "ap-seoul-1"' "$config_file")
# 上传非空配置
[[ -n "$tenancy_ocid" && "$tenancy_ocid" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/tenancy_ocid" -d "$tenancy_ocid" > /dev/null
((uploaded_count++))
}
[[ -n "$user_ocid" && "$user_ocid" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/user_ocid" -d "$user_ocid" > /dev/null
((uploaded_count++))
}
[[ -n "$fingerprint" && "$fingerprint" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/fingerprint" -d "$fingerprint" > /dev/null
((uploaded_count++))
}
[[ -n "$compartment_ocid" && "$compartment_ocid" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/compartment_ocid" -d "$compartment_ocid" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
# 上传私钥文件内容
if [[ -n "$private_key_path" && "$private_key_path" != "null" && -f "$private_key_path" ]]; then
local private_key_content=$(cat "$private_key_path")
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/private_key" -d "$private_key_content" > /dev/null
((uploaded_count++))
fi
log_success "Oracle Cloud 配置已上传"
fi
# 上传华为云配置
if jq -e '.huawei_config' "$config_file" > /dev/null 2>&1; then
log_info "上传华为云配置..."
local base_path="config/${ENVIRONMENT}/huawei"
local access_key=$(jq -r '.huawei_config.access_key // empty' "$config_file")
local secret_key=$(jq -r '.huawei_config.secret_key // empty' "$config_file")
local region=$(jq -r '.huawei_config.region // "cn-north-4"' "$config_file")
local project_id=$(jq -r '.huawei_config.project_id // empty' "$config_file")
[[ -n "$access_key" && "$access_key" != "null" && "$access_key" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/access_key" -d "$access_key" > /dev/null
((uploaded_count++))
}
[[ -n "$secret_key" && "$secret_key" != "null" && "$secret_key" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/secret_key" -d "$secret_key" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
[[ -n "$project_id" && "$project_id" != "null" && "$project_id" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/project_id" -d "$project_id" > /dev/null
((uploaded_count++))
}
log_success "华为云配置已上传"
fi
# 上传 AWS 配置
if jq -e '.aws_config' "$config_file" > /dev/null 2>&1; then
log_info "上传 AWS 配置..."
local base_path="config/${ENVIRONMENT}/aws"
local access_key=$(jq -r '.aws_config.access_key // empty' "$config_file")
local secret_key=$(jq -r '.aws_config.secret_key // empty' "$config_file")
local region=$(jq -r '.aws_config.region // "ap-northeast-2"' "$config_file")
[[ -n "$access_key" && "$access_key" != "null" && "$access_key" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/access_key" -d "$access_key" > /dev/null
((uploaded_count++))
}
[[ -n "$secret_key" && "$secret_key" != "null" && "$secret_key" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/secret_key" -d "$secret_key" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
log_success "AWS 配置已上传"
fi
# 上传 DigitalOcean 配置
if jq -e '.do_config' "$config_file" > /dev/null 2>&1; then
log_info "上传 DigitalOcean 配置..."
local base_path="config/${ENVIRONMENT}/digitalocean"
local token=$(jq -r '.do_config.token // empty' "$config_file")
local region=$(jq -r '.do_config.region // "sgp1"' "$config_file")
[[ -n "$token" && "$token" != "null" && "$token" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/token" -d "$token" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
log_success "DigitalOcean 配置已上传"
fi
# 上传 Google Cloud 配置
if jq -e '.gcp_config' "$config_file" > /dev/null 2>&1; then
log_info "上传 Google Cloud 配置..."
local base_path="config/${ENVIRONMENT}/gcp"
local project_id=$(jq -r '.gcp_config.project_id // empty' "$config_file")
local region=$(jq -r '.gcp_config.region // "asia-northeast3"' "$config_file")
local zone=$(jq -r '.gcp_config.zone // "asia-northeast3-a"' "$config_file")
local credentials_file=$(jq -r '.gcp_config.credentials_file // empty' "$config_file")
[[ -n "$project_id" && "$project_id" != "null" && "$project_id" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/project_id" -d "$project_id" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
[[ -n "$zone" && "$zone" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/zone" -d "$zone" > /dev/null
((uploaded_count++))
}
# 上传凭证文件内容
if [[ -n "$credentials_file" && "$credentials_file" != "null" && -f "$credentials_file" ]]; then
local credentials_content=$(cat "$credentials_file")
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/credentials" -d "$credentials_content" > /dev/null
((uploaded_count++))
fi
log_success "Google Cloud 配置已上传"
fi
log_success "总共上传了 $uploaded_count 个配置项到 Consul"
}
# 列出 Consul 中的配置
list_consul_configs() {
log_info "列出 Consul 中的配置..."
local base_path="config/${ENVIRONMENT}"
echo "=== Consul 中的配置 ==="
# 获取所有配置键
local keys=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/?keys" | jq -r '.[]' 2>/dev/null || echo "")
if [[ -z "$keys" ]]; then
log_warning "Consul 中没有找到配置"
return
fi
echo "$keys" | while read -r key; do
local value=$(curl -s "${CONSUL_ADDR}/v1/kv/${key}?raw" 2>/dev/null || echo "无法读取")
# 隐藏敏感信息
if [[ "$key" =~ (secret|key|token|password) ]]; then
echo "$key: [已隐藏]"
else
echo "$key: $value"
fi
done
}
# 清理 Consul 配置
cleanup_consul_configs() {
log_warning "清理 Consul 配置..."
read -p "确定要删除环境 '$ENVIRONMENT' 的所有配置吗?(y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
log_info "操作已取消"
return
fi
local base_path="config/${ENVIRONMENT}"
curl -s -X DELETE "${CONSUL_ADDR}/v1/kv/${base_path}?recurse" > /dev/null
log_success "环境 '$ENVIRONMENT' 的配置已清理"
}
# 显示帮助信息
show_help() {
cat << EOF
OpenTofu 密钥上传脚本
用法: $0 [选项]
选项:
upload 上传 terraform.tfvars 中的配置到 Consul
list 列出 Consul 中的配置
cleanup 清理 Consul 中的配置
help 显示此帮助信息
环境变量:
CONSUL_ADDR Consul 地址 (默认: http://localhost:8500)
CONSUL_TOKEN Consul ACL Token (可选)
ENVIRONMENT 环境名称 (默认: dev)
TOFU_DIR OpenTofu 目录 (默认: tofu/environments/\${ENVIRONMENT})
TFVARS_FILE 变量文件路径 (默认: \${TOFU_DIR}/terraform.tfvars)
示例:
# 上传配置到 Consul
$0 upload
# 列出 Consul 中的配置
$0 list
# 清理配置
$0 cleanup
# 指定不同环境
ENVIRONMENT=production $0 upload
EOF
}
# 主函数
main() {
check_dependencies
case "${1:-help}" in
"upload")
check_consul
check_tfvars_file
log_info "解析配置文件: $TFVARS_FILE"
local config_json=$(manual_parse_tfvars "$TFVARS_FILE" "/tmp/parsed_config.json")
upload_config_to_consul "/tmp/parsed_config.json"
# 清理临时文件
rm -f /tmp/parsed_config.json /tmp/temp_config.tf
;;
"list")
check_consul
list_consul_configs
;;
"cleanup")
check_consul
cleanup_consul_configs
;;
"help"|*)
show_help
;;
esac
}
main "$@"

184
swarm/scripts/swarm-manager.sh Executable file
View File

@ -0,0 +1,184 @@
#!/bin/bash
# Docker Swarm 管理脚本
set -euo pipefail
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查是否在 Swarm 模式
check_swarm_mode() {
if docker info --format '{{.Swarm.LocalNodeState}}' | grep -q "active"; then
log_success "Docker Swarm 模式已激活"
return 0
else
log_error "Docker Swarm 模式未激活"
return 1
fi
}
# 初始化 Swarm
init_swarm() {
log_info "初始化 Docker Swarm..."
if docker swarm init; then
log_success "Docker Swarm 初始化成功"
log_info "要添加工作节点,请在其他主机上运行:"
docker swarm join-token worker
else
log_error "Docker Swarm 初始化失败"
return 1
fi
}
# 部署堆栈
deploy_stack() {
local stack_name="$1"
local compose_file="$2"
log_info "部署堆栈: $stack_name"
if [[ ! -f "$compose_file" ]]; then
log_error "Compose 文件不存在: $compose_file"
return 1
fi
if docker stack deploy -c "$compose_file" "$stack_name"; then
log_success "堆栈 $stack_name 部署成功"
else
log_error "堆栈 $stack_name 部署失败"
return 1
fi
}
# 列出堆栈
list_stacks() {
log_info "当前部署的堆栈:"
docker stack ls
}
# 查看堆栈服务
show_stack_services() {
local stack_name="$1"
log_info "堆栈 $stack_name 的服务:"
docker stack services "$stack_name"
}
# 删除堆栈
remove_stack() {
local stack_name="$1"
log_info "删除堆栈: $stack_name"
if docker stack rm "$stack_name"; then
log_success "堆栈 $stack_name 删除成功"
else
log_error "堆栈 $stack_name 删除失败"
return 1
fi
}
# 显示节点信息
show_nodes() {
log_info "Swarm 节点信息:"
docker node ls
}
# 显示帮助信息
show_help() {
echo "Docker Swarm 管理脚本"
echo ""
echo "用法: $0 [命令] [参数]"
echo ""
echo "命令:"
echo " init - 初始化 Docker Swarm"
echo " deploy <stack> <compose-file> - 部署堆栈"
echo " list - 列出所有堆栈"
echo " services <stack> - 查看堆栈服务"
echo " remove <stack> - 删除堆栈"
echo " nodes - 显示节点信息"
echo " check - 检查 Swarm 状态"
echo " help - 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 init # 初始化 Swarm"
echo " $0 deploy traefik stacks/traefik-swarm-stack.yml"
echo " $0 deploy demo stacks/demo-services-stack.yml"
echo " $0 list # 列出堆栈"
echo " $0 services traefik # 查看 traefik 堆栈服务"
}
# 主函数
main() {
case "${1:-help}" in
"init")
init_swarm
;;
"deploy")
if [[ $# -lt 3 ]]; then
log_error "部署命令需要堆栈名称和 compose 文件"
echo "用法: $0 deploy <stack-name> <compose-file>"
exit 1
fi
check_swarm_mode || exit 1
deploy_stack "$2" "$3"
;;
"list")
check_swarm_mode || exit 1
list_stacks
;;
"services")
if [[ $# -lt 2 ]]; then
log_error "需要指定堆栈名称"
echo "用法: $0 services <stack-name>"
exit 1
fi
check_swarm_mode || exit 1
show_stack_services "$2"
;;
"remove")
if [[ $# -lt 2 ]]; then
log_error "需要指定堆栈名称"
echo "用法: $0 remove <stack-name>"
exit 1
fi
check_swarm_mode || exit 1
remove_stack "$2"
;;
"nodes")
check_swarm_mode || exit 1
show_nodes
;;
"check")
check_swarm_mode
;;
"help"|*)
show_help
;;
esac
}
# 运行主函数
main "$@"

View File

@ -0,0 +1,41 @@
version: '3.8'
services:
consul:
image: consul:latest
hostname: consul-ash3c
command: >
sh -c "
IP=$$(hostname -i | awk '{print $$1}');
consul agent -server -bootstrap-expect=2
-datacenter=dc1 -data-dir=/consul/data
-node=consul-ash3c -bind=$$IP -advertise=100.116.80.94 -client=0.0.0.0
-retry-join=100.117.106.136
-ui
-log-level=INFO
"
ports:
- "8500:8500"
- "8600:8600/udp"
volumes:
- consul_data:/consul/data
networks:
- consul-net
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == ash3c
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
volumes:
consul_data:
networks:
consul-net:
driver: overlay
attachable: true

View File

@ -0,0 +1,76 @@
version: '3.8'
services:
consul-master:
image: consul:latest
hostname: consul-master
command: >
sh -c "
IP=$$(hostname -i | awk '{print $$1}');
consul agent -server -bootstrap-expect=2
-datacenter=dc1 -data-dir=/consul/data
-node=consul-master -bind=$$IP -advertise=$$IP -client=0.0.0.0
-ui
-log-level=INFO
"
ports:
- "8500:8500"
- "8600:8600/udp"
volumes:
- consul_master_data:/consul/data
networks:
consul-net:
aliases:
- consul-master
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == master
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
consul-ash3c:
image: consul:latest
hostname: consul-ash3c
command: >
sh -c "
IP=$$(hostname -i | awk '{print $$1}');
consul agent -server -bootstrap-expect=2
-datacenter=dc1 -data-dir=/consul/data
-node=consul-ash3c -bind=$$IP -advertise=$$IP -client=0.0.0.0
-retry-join=consul-cluster_consul-master
-ui
-log-level=INFO
"
ports:
- "8501:8500"
- "8601:8600/udp"
volumes:
- consul_ash3c_data:/consul/data
networks:
consul-net:
aliases:
- consul-ash3c
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == ash3c
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
volumes:
consul_master_data:
consul_ash3c_data:
networks:
consul-net:
driver: overlay
attachable: true

View File

@ -0,0 +1,40 @@
version: '3.8'
services:
consul:
image: consul:latest
hostname: consul-master
command: >
sh -c "
IP=$$(hostname -i | awk '{print $$1}');
consul agent -server -bootstrap-expect=2
-datacenter=dc1 -data-dir=/consul/data
-node=consul-master -bind=$$IP -advertise=100.117.106.136 -client=0.0.0.0
-ui
-log-level=INFO
"
ports:
- "8500:8500"
- "8600:8600/udp"
volumes:
- consul_data:/consul/data
networks:
- consul-net
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == master
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
volumes:
consul_data:
networks:
consul-net:
driver: overlay
attachable: true

View File

@ -0,0 +1,39 @@
version: '3.8'
services:
consul:
image: consul:latest
hostname: consul
command: >
consul agent -server -bootstrap-expect=1
-datacenter=dc1 -data-dir=/consul/data
-node=consul -client=0.0.0.0
-ui
-log-level=INFO
ports:
- "8500:8500"
- "8600:8600/udp"
volumes:
- consul_data:/consul/data
networks:
- consul-net
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
labels:
- "traefik.enable=true"
- "traefik.http.routers.consul.rule=Host(`consul.local`)"
- "traefik.http.services.consul.loadbalancer.server.port=8500"
- "traefik.docker.network=consul-net"
volumes:
consul_data:
networks:
consul-net:
driver: overlay
attachable: true

View File

@ -0,0 +1,109 @@
#
#
terraform {
required_version = ">= 1.6"
required_providers {
# Oracle Cloud Infrastructure
oci = {
source = "oracle/oci"
version = "~> 5.0"
}
#
huaweicloud = {
source = "huaweicloud/huaweicloud"
version = "~> 1.60"
}
#
random = {
source = "hashicorp/random"
version = "~> 3.1"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
local = {
source = "hashicorp/local"
version = "~> 2.1"
}
}
#
backend "local" {
path = "terraform.tfstate"
}
}
# Oracle Cloud
provider "oci" {
tenancy_ocid = var.oci_config.tenancy_ocid
user_ocid = var.oci_config.user_ocid
fingerprint = var.oci_config.fingerprint
private_key_path = var.oci_config.private_key_path
region = var.oci_config.region
}
# ()
provider "huaweicloud" {
access_key = var.huawei_config.access_key
secret_key = var.huawei_config.secret_key
region = var.huawei_config.region
alias = "huawei"
}
# Oracle Cloud
module "oracle_cloud" {
source = "../../providers/oracle-cloud"
#
environment = var.environment
project_name = var.project_name
owner = var.owner
vpc_cidr = var.vpc_cidr
availability_zones = var.availability_zones
common_tags = var.common_tags
oci_config = var.oci_config
#
instance_count = 1
instance_size = "VM.Standard.E2.1.Micro" #
providers = {
oci = oci
}
}
# ()
module "huawei_cloud" {
source = "../../providers/huawei-cloud"
count = contains(var.cloud_providers, "huawei") ? 1 : 0
environment = var.environment
project_name = var.project_name
owner = var.owner
vpc_cidr = "10.1.0.0/16" # CIDR
availability_zones = var.availability_zones
common_tags = var.common_tags
huawei_config = var.huawei_config
providers = {
huaweicloud = huaweicloud.huawei
}
}
#
output "oracle_cloud_outputs" {
description = "Oracle Cloud 基础设施输出"
value = module.oracle_cloud
}
output "huawei_cloud_outputs" {
description = "华为云基础设施输出"
value = length(module.huawei_cloud) > 0 ? module.huawei_cloud[0] : null
}

View File

@ -1,4 +1,4 @@
#
#
terraform {
required_providers {
@ -9,13 +9,6 @@ terraform {
}
}
#
provider "huaweicloud" {
access_key = var.huawei_config.access_key
secret_key = var.huawei_config.secret_key
region = var.huawei_config.region
}
#
data "huaweicloud_availability_zones" "zones" {}

View File

@ -0,0 +1,54 @@
#
variable "environment" {
description = "环境名称"
type = string
}
variable "project_name" {
description = "项目名称"
type = string
}
variable "owner" {
description = "项目所有者"
type = string
}
variable "vpc_cidr" {
description = "VPC CIDR 块"
type = string
}
variable "availability_zones" {
description = "可用区列表"
type = list(string)
}
variable "common_tags" {
description = "通用标签"
type = map(string)
}
variable "huawei_config" {
description = "华为云配置"
type = object({
access_key = string
secret_key = string
region = string
project_id = string
})
sensitive = true
}
variable "instance_count" {
description = "实例数量"
type = number
default = 1
}
variable "instance_size" {
description = "实例规格"
type = string
default = "s6.small.1"
}

View File

@ -1,4 +1,4 @@
# Oracle Cloud Infrastructure
# Oracle Cloud Infrastructure
terraform {
required_providers {
@ -9,15 +9,6 @@ terraform {
}
}
# OCI
provider "oci" {
tenancy_ocid = var.oci_config.tenancy_ocid
user_ocid = var.oci_config.user_ocid
fingerprint = var.oci_config.fingerprint
private_key_path = var.oci_config.private_key_path
region = var.oci_config.region
}
#
data "oci_identity_availability_domains" "ads" {
compartment_id = var.oci_config.tenancy_ocid

View File

@ -0,0 +1,55 @@
# Oracle Cloud
variable "environment" {
description = "环境名称"
type = string
}
variable "project_name" {
description = "项目名称"
type = string
}
variable "owner" {
description = "项目所有者"
type = string
}
variable "vpc_cidr" {
description = "VPC CIDR 块"
type = string
}
variable "availability_zones" {
description = "可用区列表"
type = list(string)
}
variable "common_tags" {
description = "通用标签"
type = map(string)
}
variable "oci_config" {
description = "Oracle Cloud 配置"
type = object({
tenancy_ocid = string
user_ocid = string
fingerprint = string
private_key_path = string
region = string
compartment_ocid = string
})
}
variable "instance_count" {
description = "实例数量"
type = number
default = 1
}
variable "instance_size" {
description = "实例规格"
type = string
default = "VM.Standard.E2.1.Micro"
}