恢复 OCI Terraform 与站点网络 IaC

This commit is contained in:
2026-09-17 13:22:49 +00:00
parent a08c8a7303
commit 71eea7d8fc
41 changed files with 1786 additions and 10 deletions
+9
View File
@@ -0,0 +1,9 @@
.terraform/
*.tfstate*
*.tfplan
*.tfvars
*.tfvars.json
*.auto.tfvars*
crash.log
crash.*.log
.recovery/
+23
View File
@@ -0,0 +1,23 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/oracle/oci" {
version = "9.1.0"
hashes = [
"h1:luO69Wv8J0GKbkd+hr2UbouenTZBAPhyAxTQacJAeGU=",
"zh:0343d74d10e8c0b803874a303bea5b6619e76762ace8fdafb1bae6d867c3ece0",
"zh:077ac3c561c1b9af97c9325900b65825279537a8f85074adcf3f11af151e387e",
"zh:2571fc3f274fb081aae27d7b9fd150e3ab39309fa15241bf48b8877b8f8d8529",
"zh:26e16906006b6cb3022a06abc21884f08e1b35696bb7259b92d4aaf0e8056a17",
"zh:3882078acbfddb13a5b64d37afcded15ca56d3381f46314e4869e68dfc7f2759",
"zh:3d9b6c5e1362abbb7469cd096e68a7c1bf642959621784b6b096f0fae97dcf89",
"zh:462ef1bb079e78aadd50377fde647144c8bb0da324c314e997f4d15af81991f4",
"zh:510f88ab1592960c73fc004de8329ceff26803d470e22522623aefb99e917163",
"zh:573a7139600f21d5ae1e733317948b6f352a5434d7d06e0d3910211f79d4f286",
"zh:647b750d4fa8d982cbeef73d2beeec1dc7076ee32ee8833d0ff634e2f7ccdad0",
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
"zh:b1539e73622d3ee4fe11c951c11063341b8b302a167a9bad6712bb0e075ccdb7",
"zh:d4f1012d1a62bdc69230d7e3adc5f3bcb78a755adb858d7e6cd6af0200255828",
"zh:fa11dc03a714e8f7056bb5ff92646f1f34dea74339650b5fafdd923a5bcc5864",
]
}
+45
View File
@@ -0,0 +1,45 @@
# E2 Micro 使用独立的 x86_64 镜像;固定版本以免镜像目录更新触发重建。
resource "oci_core_instance" "amd" {
availability_domain = oci_core_instance.vm.availability_domain
compartment_id = var.compartment_ocid
display_name = "homelab-amd"
shape = "VM.Standard.E2.1.Micro"
create_vnic_details {
subnet_id = oci_core_subnet.public.id
skip_source_dest_check = true
nsg_ids = [oci_core_network_security_group.wireguard.id]
assign_public_ip = true
hostname_label = "homelab-amd"
display_name = "homelab-amd"
}
# 仅复用登录公钥,不复制原实例可能新增的 user_data 等初始化内容。
metadata = {
ssh_authorized_keys = var.instance_metadata["ssh_authorized_keys"]
}
source_details {
source_type = "image"
source_id = "ocid1.image.oc1.ap-osaka-1.aaaaaaaap3ki4u45x7acf3q3upe6sudoe4l3ogin55dmgp3gye6lvhhjg6mq"
boot_volume_size_in_gbs = 50
boot_volume_vpus_per_gb = 10
}
lifecycle {
prevent_destroy = true
}
}
output "amd_instance_id" {
value = oci_core_instance.amd.id
}
output "amd_private_ip" {
value = oci_core_instance.amd.private_ip
}
output "amd_public_ip" {
value = oci_core_instance.amd.public_ip
}
output "amd_ssh_command" {
value = "ssh ubuntu@${oci_core_instance.amd.public_ip}"
}
@@ -0,0 +1,8 @@
# versions.tf 已配置相同的 OCI backend;此文件保留为参数参考。
# 只连接已有对象,禁止把恢复副本迁移覆盖远端。
bucket = "oci-k8s-free-tier-tfstate"
namespace = "axckv9ylwqxr"
key = "terraform.tfstate"
region = "ap-osaka-1"
auth = "APIKey"
config_file_profile = "DEFAULT"
+53
View File
@@ -0,0 +1,53 @@
resource "oci_core_instance" "vm" {
agent_config {
are_all_plugins_disabled = false
is_management_disabled = false
is_monitoring_disabled = false
}
availability_config {
is_live_migration_preferred = false
recovery_action = "RESTORE_INSTANCE"
}
availability_domain = "diPX:AP-OSAKA-1-AD-1"
compartment_id = var.compartment_ocid
create_vnic_details {
assign_private_dns_record = false
assign_public_ip = "true"
display_name = "homelab-vm"
hostname_label = "homelab-vm"
private_ip = "10.0.0.124"
skip_source_dest_check = false
subnet_id = oci_core_subnet.public.id
}
display_name = "homelab-vm"
fault_domain = "FAULT-DOMAIN-1"
instance_options {
are_legacy_imds_endpoints_disabled = false
}
launch_options {
boot_volume_type = "PARAVIRTUALIZED"
firmware = "UEFI_64"
is_consistent_volume_naming_enabled = true
is_pv_encryption_in_transit_enabled = false
network_type = "PARAVIRTUALIZED"
remote_data_volume_type = "PARAVIRTUALIZED"
}
metadata = var.instance_metadata
shape = "VM.Standard.A1.Flex"
shape_config {
memory_in_gbs = 12
ocpus = 2
}
source_details {
boot_volume_size_in_gbs = "100"
boot_volume_vpus_per_gb = "10"
source_id = var.image_ocid
source_type = "image"
}
# 原生命周期配置不可恢复;保护现有 VM,避免重建丢失系统盘数据。
lifecycle {
prevent_destroy = true
}
}
+13
View File
@@ -0,0 +1,13 @@
data "oci_core_images" "ubuntu" {
compartment_id = var.compartment_ocid
operating_system = "Canonical Ubuntu"
operating_system_version = "24.04"
shape = "VM.Standard.A1.Flex"
sort_by = "TIMECREATED"
sort_order = "DESC"
}
data "oci_identity_availability_domains" "ads" {
compartment_id = var.compartment_ocid
}
+103
View File
@@ -0,0 +1,103 @@
resource "oci_core_internet_gateway" "igw" {
compartment_id = var.compartment_ocid
display_name = "homelab-igw"
enabled = true
vcn_id = oci_core_vcn.vcn.id
}
resource "oci_core_route_table" "public" {
compartment_id = var.compartment_ocid
display_name = "homelab-public-rt"
route_rules {
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
network_entity_id = oci_core_internet_gateway.igw.id
}
dynamic "route_rules" {
for_each = toset(local.wireguard_home_prefixes)
content {
destination = route_rules.value
destination_type = "CIDR_BLOCK"
network_entity_id = var.amd_router_private_ip_ocid
}
}
vcn_id = oci_core_vcn.vcn.id
}
resource "oci_core_security_list" "public" {
compartment_id = var.compartment_ocid
display_name = "homelab-public-sl"
egress_security_rules {
description = ""
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
protocol = "all"
stateless = false
}
ingress_security_rules {
description = ""
icmp_options {
code = 4
type = 3
}
protocol = "1"
source = "0.0.0.0/0"
source_type = "CIDR_BLOCK"
stateless = false
}
ingress_security_rules {
description = ""
protocol = "17"
source = "0.0.0.0/0"
source_type = "CIDR_BLOCK"
stateless = false
udp_options {
max = 41641
min = 41641
}
}
ingress_security_rules {
description = ""
protocol = "6"
source = "0.0.0.0/0"
source_type = "CIDR_BLOCK"
stateless = false
tcp_options {
max = 22
min = 22
}
}
# 内层源地址保持家中网段;OCI 安全列表须允许这些已路由的流量。
dynamic "ingress_security_rules" {
for_each = toset(local.wireguard_home_prefixes)
content {
protocol = "all"
source = ingress_security_rules.value
source_type = "CIDR_BLOCK"
stateless = false
description = "WireGuard routed homelab traffic"
}
}
vcn_id = oci_core_vcn.vcn.id
}
resource "oci_core_subnet" "public" {
cidr_block = "10.0.0.0/24"
compartment_id = var.compartment_ocid
dhcp_options_id = oci_core_vcn.vcn.default_dhcp_options_id
display_name = "homelab-public-subnet"
dns_label = "public"
prohibit_public_ip_on_vnic = false
route_table_id = oci_core_route_table.public.id
security_list_ids = [oci_core_security_list.public.id]
vcn_id = oci_core_vcn.vcn.id
}
resource "oci_core_vcn" "vcn" {
cidr_blocks = ["10.0.0.0/16"]
compartment_id = var.compartment_ocid
display_name = "homelab-vcn"
dns_label = "homelab"
is_ipv6enabled = false
}
+16
View File
@@ -0,0 +1,16 @@
output "instance_id" {
value = oci_core_instance.vm.id
}
output "instance_private_ip" {
value = oci_core_instance.vm.private_ip
}
output "instance_public_ip" {
value = oci_core_instance.vm.public_ip
}
output "ssh_command" {
value = "ssh ubuntu@${oci_core_instance.vm.public_ip}"
}
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
"""从已下载的 state 初始化本地恢复环境,不输出 metadata,也不覆盖现有文件。"""
import json
import os
from pathlib import Path
import sys
os.umask(0o077)
source = Path(sys.argv[1])
raw = source.read_bytes()
state = json.loads(raw)
vm = next(r for r in state['resources'] if r['mode'] == 'managed'
and r['type'] == 'oci_core_instance' and r['name'] == 'vm')
root = Path(__file__).resolve().parent
local = root / '.recovery' / 'terraform.tfstate'
variables = root / 'terraform.tfvars.json'
if local.exists() or variables.exists():
sys.exit('本地 state 或 tfvars 已存在;请先核对并自行备份,脚本不会覆盖。')
local.parent.mkdir(mode=0o700, exist_ok=True)
with local.open('xb') as f:
f.write(raw)
with variables.open('x') as f:
json.dump({'instance_metadata': vm['instances'][0]['attributes']['metadata']}, f, indent=2)
f.write('\n')
print('已准备本地 state 和 metadata 变量;未修改远端。')
@@ -0,0 +1,4 @@
provider "oci" {
region = var.region
config_file_profile = var.oci_config_profile
}
+7
View File
@@ -0,0 +1,7 @@
resource "oci_limits_quota" "free_tier_quota" {
compartment_id = var.compartment_ocid
description = "Enforce Always Free tier compliance for compute and storage."
name = "always-free-tier-quota"
statements = ["set compute-core quota standard-a1-core-count to 4 in tenancy", "set compute-memory quota standard-a1-memory-count to 24 in tenancy", "set block-storage quota volume-count to 10 in tenancy", "set block-storage quota total-storage-gb to 200 in tenancy"]
}
+22
View File
@@ -0,0 +1,22 @@
variable "region" {
type = string
default = "ap-osaka-1"
}
variable "oci_config_profile" {
type = string
default = "DEFAULT"
}
variable "compartment_ocid" {
type = string
default = "ocid1.tenancy.oc1..aaaaaaaalncmdinfnljot5oh7rqleavphhsa6jpyurfu4luztcct3tp5gsfa"
}
# 固定现有启动镜像;查询最新 Ubuntu 镜像不应触发现有实例重建。
variable "image_ocid" {
type = string
default = "ocid1.image.oc1.ap-osaka-1.aaaaaaaayniglvbm5xyligxib2nk3jz3zendq6ywckp4gppteii4tg7wzhua"
}
variable "instance_metadata" {
description = "从受限 state 副本提取的原实例 metadata;仅存于忽略的本地 tfvars。"
type = map(string)
sensitive = true
}
+18
View File
@@ -0,0 +1,18 @@
terraform {
required_version = ">= 1.15.8, < 2.0.0"
required_providers {
oci = {
source = "oracle/oci"
version = "= 9.1.0"
}
}
# 已停用旧执行流程,当前根模块直接管理既有对象;不迁移本地恢复副本。
backend "oci" {
bucket = "oci-k8s-free-tier-tfstate"
namespace = "axckv9ylwqxr"
key = "terraform.tfstate"
region = "ap-osaka-1"
auth = "APIKey"
config_file_profile = "DEFAULT"
}
}
+48
View File
@@ -0,0 +1,48 @@
locals {
wireguard_home_prefixes = ["192.168.10.0/24", "10.60.0.0/24", "10.61.0.0/24"]
}
# route table -> subnet -> instance 已存在依赖,不能反向引用实例的私有 IP。
# 此值从现有 AMD VNIC 核对;重建实例后必须重新查询,禁止继续使用旧 OCID。
variable "amd_router_private_ip_ocid" {
type = string
default = "ocid1.privateip.oc1.ap-osaka-1.abvwsljrhxq2cw46zhjyrnn5zbz4rrynjbzlynkz6ubhiedadr72zcaideaq"
}
resource "oci_core_network_security_group" "wireguard" {
compartment_id = var.compartment_ocid
vcn_id = oci_core_vcn.vcn.id
display_name = "homelab-amd-wireguard"
}
resource "oci_core_network_security_group_security_rule" "wireguard" {
network_security_group_id = oci_core_network_security_group.wireguard.id
direction = "INGRESS"
protocol = "17"
source = "0.0.0.0/0"
source_type = "CIDR_BLOCK"
stateless = false
description = "WireGuard NAT traversal; peer public key authenticates clients"
udp_options {
destination_port_range {
min = 51820
max = 51820
}
}
}
resource "oci_core_network_security_group_security_rule" "dn42_first_peer" {
network_security_group_id = oci_core_network_security_group.wireguard.id
direction = "INGRESS"
protocol = "17"
source = "0.0.0.0/0"
source_type = "CIDR_BLOCK"
stateless = false
description = "DN42 first external WireGuard peer; public key authentication"
udp_options {
destination_port_range {
min = 51821
max = 51821
}
}
}