Clean repository: organized structure and GitOps setup

- Organized root directory structure
- Moved orphan files to proper locations
- Updated .gitignore to ignore temporary files
- Set up Gitea Runner for GitOps automation
- Fixed Tailscale access issues
- Added workflow for automated Nomad deployment
This commit is contained in:
2025-10-09 06:13:45 +00:00
commit 89ee6f7967
306 changed files with 30781 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
# Traefik 配置
## 部署
```bash
nomad job run components/traefik/jobs/traefik.nomad
```
## 配置特点
- 明确绑定 Tailscale IP (100.97.62.111)
- 地理位置优化的 Consul 集群顺序(北京 → 韩国 → 美国)
- 适合跨太平洋网络的宽松健康检查
- 无服务健康检查,避免 flapping
## 访问方式
- Dashboard: `http://hcp1.tailnet-68f9.ts.net:8080/dashboard/`
- 直接 IP: `http://100.97.62.111:8080/dashboard/`
- Consul LB: `http://hcp1.tailnet-68f9.ts.net:80`
## 故障排除
如果遇到服务 flapping 问题:
1. 检查是否使用了 RFC1918 私有地址
2. 确认 Tailscale 网络连通性
3. 调整健康检查间隔时间
4. 考虑地理位置对网络延迟的影响

View File

@@ -0,0 +1,28 @@
job "test-simple" {
datacenters = ["dc1"]
type = "service"
group "test" {
count = 1
constraint {
attribute = "${node.unique.name}"
value = "warden"
}
task "test" {
driver = "exec"
config {
command = "sleep"
args = ["3600"]
}
resources {
cpu = 100
memory = 64
}
}
}
}

View File

@@ -0,0 +1,213 @@
job "traefik-cloudflare-v1" {
datacenters = ["dc1"]
type = "service"
group "traefik" {
count = 1
constraint {
attribute = "${node.unique.name}"
value = "hcp1"
}
network {
mode = "host"
port "http" {
static = 80
host_network = "tailscale0"
}
port "https" {
static = 443
host_network = "tailscale0"
}
port "traefik" {
static = 8080
host_network = "tailscale0"
}
}
task "traefik" {
driver = "exec"
config {
command = "/usr/local/bin/traefik"
args = [
"--configfile=/local/traefik.yml"
]
}
template {
data = <<EOF
api:
dashboard: true
insecure: true
entryPoints:
web:
address: "0.0.0.0:80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
permanent: true
websecure:
address: "0.0.0.0:443"
traefik:
address: "0.0.0.0:8080"
providers:
consulCatalog:
endpoint:
address: "warden.tailnet-68f9.ts.net:8500"
scheme: "http"
watch: true
exposedByDefault: false
prefix: "traefik"
defaultRule: "Host(`{{ .Name }}.git4ta.me`)"
file:
filename: /local/dynamic.yml
watch: true
certificatesResolvers:
cloudflare:
acme:
email: houzhongxu.houzhongxu@gmail.com
storage: /local/acme.json
dnsChallenge:
provider: cloudflare
delayBeforeCheck: 30s
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
log:
level: DEBUG
EOF
destination = "local/traefik.yml"
}
template {
data = <<EOF
http:
serversTransports:
waypoint-insecure:
insecureSkipVerify: true
middlewares:
consul-stripprefix:
stripPrefix:
prefixes:
- "/consul"
waypoint-auth:
replacePathRegex:
regex: "^/auth/token(.*)$"
replacement: "/auth/token$1"
services:
consul-cluster:
loadBalancer:
servers:
- url: "http://warden.tailnet-68f9.ts.net:8500" # 北京,优先
- url: "http://ch4.tailnet-68f9.ts.net:8500" # 韩国,备用
- url: "http://ash3c.tailnet-68f9.ts.net:8500" # 美国,备用
healthCheck:
path: "/v1/status/leader"
interval: "30s"
timeout: "15s"
nomad-cluster:
loadBalancer:
servers:
- url: "http://warden.tailnet-68f9.ts.net:4646" # 北京,优先
- url: "http://ch4.tailnet-68f9.ts.net:4646" # 韩国,备用
- url: "http://ash3c.tailnet-68f9.ts.net:4646" # 美国,备用
healthCheck:
path: "/v1/status/leader"
interval: "30s"
timeout: "15s"
waypoint-cluster:
loadBalancer:
servers:
- url: "https://hcp1.tailnet-68f9.ts.net:9701" # hcp1 节点 HTTPS API
serversTransport: waypoint-insecure
vault-cluster:
loadBalancer:
servers:
- url: "http://ch4.tailnet-68f9.ts.net:8200" # 韩国,活跃节点
- url: "http://ash3c.tailnet-68f9.ts.net:8200" # 美国,备用节点
- url: "http://warden.tailnet-68f9.ts.net:8200" # 北京,备用节点
healthCheck:
path: "/v1/sys/health"
interval: "30s"
timeout: "15s"
routers:
consul-api:
rule: "Host(`consul.git4ta.me`)"
service: consul-cluster
middlewares:
- consul-stripprefix
entryPoints:
- websecure
tls:
certResolver: cloudflare
traefik-dashboard:
rule: "Host(`traefik.git4ta.me`)"
service: dashboard@internal
middlewares:
- dashboard_redirect@internal
- dashboard_stripprefix@internal
entryPoints:
- websecure
tls:
certResolver: cloudflare
nomad-ui:
rule: "Host(`nomad.git4ta.me`)"
service: nomad-cluster
entryPoints:
- websecure
tls:
certResolver: cloudflare
waypoint-ui:
rule: "Host(`waypoint.git4ta.me`)"
service: waypoint-cluster
entryPoints:
- websecure
tls:
certResolver: cloudflare
vault-ui:
rule: "Host(`vault.git4ta.me`)"
service: vault-cluster
entryPoints:
- websecure
tls:
certResolver: cloudflare
EOF
destination = "local/dynamic.yml"
}
template {
data = <<EOF
CLOUDFLARE_EMAIL=houzhongxu.houzhongxu@gmail.com
CLOUDFLARE_DNS_API_TOKEN=HYT-cfZTP_jq6Xd9g3tpFMwxopOyIrf8LZpmGAI3
CLOUDFLARE_ZONE_API_TOKEN=HYT-cfZTP_jq6Xd9g3tpFMwxopOyIrf8LZpmGAI3
EOF
destination = "local/cloudflare.env"
env = true
}
resources {
cpu = 500
memory = 512
}
}
}
}

View File

@@ -0,0 +1,217 @@
job "traefik-consul-kv" {
datacenters = ["dc1"]
type = "service"
group "traefik" {
count = 1
constraint {
attribute = "${node.unique.name}"
value = "hcp1"
}
network {
mode = "host"
port "http" {
static = 80
host_network = "tailscale0"
}
port "traefik" {
static = 8080
host_network = "tailscale0"
}
}
task "traefik" {
driver = "exec"
config {
command = "/usr/local/bin/traefik"
args = [
"--configfile=/local/traefik.yml"
]
}
template {
data = <<EOF
api:
dashboard: true
insecure: true
entryPoints:
web:
address: "0.0.0.0:80"
traefik:
address: "0.0.0.0:8080"
providers:
consulCatalog:
endpoint:
address: "warden.tailnet-68f9.ts.net:8500"
scheme: "http"
watch: true
file:
filename: /local/dynamic.yml
watch: true
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
addRoutersLabels: true
log:
level: INFO
EOF
destination = "local/traefik.yml"
}
template {
data = <<EOF
http:
middlewares:
consul-stripprefix:
stripPrefix:
prefixes:
- "/consul"
traefik-stripprefix:
stripPrefix:
prefixes:
- "/traefik"
nomad-stripprefix:
stripPrefix:
prefixes:
- "/nomad"
consul-redirect:
redirectRegex:
regex: "^/consul/?$"
replacement: "/consul/ui/"
permanent: false
nomad-redirect:
redirectRegex:
regex: "^/nomad/?$"
replacement: "/nomad/ui/"
permanent: false
traefik-redirect:
redirectRegex:
regex: "^/traefik/?$"
replacement: "/traefik/dashboard/"
permanent: false
services:
consul-cluster:
loadBalancer:
servers:
- url: "http://warden.tailnet-68f9.ts.net:8500" # 北京,优先
- url: "http://ch4.tailnet-68f9.ts.net:8500" # 韩国,备用
- url: "http://ash3c.tailnet-68f9.ts.net:8500" # 美国,备用
healthCheck:
path: "/v1/status/leader"
interval: "30s"
timeout: "15s"
nomad-cluster:
loadBalancer:
servers:
- url: "http://ch2.tailnet-68f9.ts.net:4646" # Nomad server leader
healthCheck:
path: "/v1/status/leader"
interval: "30s"
timeout: "15s"
routers:
consul-redirect:
rule: "Path(`/consul`) || Path(`/consul/`)"
service: consul-cluster
middlewares:
- consul-redirect
entryPoints:
- web
priority: 100
consul-ui:
rule: "PathPrefix(`/consul/ui`)"
service: consul-cluster
middlewares:
- consul-stripprefix
entryPoints:
- web
priority: 5
consul-api:
rule: "PathPrefix(`/consul/v1`)"
service: consul-cluster
middlewares:
- consul-stripprefix
entryPoints:
- web
priority: 5
traefik-api:
rule: "PathPrefix(`/traefik/api`)"
service: api@internal
middlewares:
- traefik-stripprefix
entryPoints:
- web
priority: 6
traefik-dashboard:
rule: "PathPrefix(`/traefik/dashboard`)"
service: dashboard@internal
middlewares:
- traefik-stripprefix
entryPoints:
- web
priority: 5
traefik-redirect:
rule: "Path(`/traefik`) || Path(`/traefik/`)"
middlewares:
- "traefik-redirect"
entryPoints:
- web
priority: 100
nomad-redirect:
rule: "Path(`/nomad`) || Path(`/nomad/`)"
service: nomad-cluster
middlewares:
- nomad-redirect
entryPoints:
- web
priority: 100
nomad-ui:
rule: "PathPrefix(`/nomad/ui`)"
service: nomad-cluster
middlewares:
- nomad-stripprefix
entryPoints:
- web
priority: 5
nomad-api:
rule: "PathPrefix(`/nomad/v1`)"
service: nomad-cluster
middlewares:
- nomad-stripprefix
entryPoints:
- web
priority: 5
EOF
destination = "local/dynamic.yml"
}
resources {
cpu = 500
memory = 512
}
}
}
}

View File

@@ -0,0 +1,150 @@
job "traefik-consul-lb" {
datacenters = ["dc1"]
type = "service"
group "traefik" {
count = 1
constraint {
attribute = "${node.unique.name}"
value = "warden"
}
update {
min_healthy_time = "60s"
healthy_deadline = "5m"
progress_deadline = "10m"
auto_revert = false
}
network {
mode = "host"
port "http" {
static = 80
host_network = "tailscale0"
}
port "traefik" {
static = 8080
host_network = "tailscale0"
}
}
task "traefik" {
driver = "exec"
config {
command = "/usr/local/bin/traefik"
args = [
"--configfile=/local/traefik.yml"
]
}
template {
data = <<EOF
api:
dashboard: true
insecure: true
entryPoints:
web:
address: "hcp1.tailnet-68f9.ts.net:80"
traefik:
address: "100.97.62.111:8080"
providers:
file:
filename: /local/dynamic.yml
watch: true
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
addRoutersLabels: true
log:
level: INFO
EOF
destination = "local/traefik.yml"
}
template {
data = <<EOF
http:
middlewares:
consul-stripprefix:
stripPrefix:
prefixes:
- "/consul"
traefik-stripprefix:
stripPrefix:
prefixes:
- "/traefik"
services:
consul-cluster:
loadBalancer:
servers:
- url: "http://warden.tailnet-68f9.ts.net:8500" # 北京,优先
- url: "http://ch4.tailnet-68f9.ts.net:8500" # 韩国,备用
- url: "http://ash3c.tailnet-68f9.ts.net:8500" # 美国,备用
healthCheck:
path: "/v1/status/leader"
interval: "30s"
timeout: "15s"
routers:
consul-api:
rule: "PathPrefix(`/consul`)"
service: consul-cluster
middlewares:
- consul-stripprefix
entryPoints:
- web
traefik-dashboard:
rule: "PathPrefix(`/traefik`)"
service: dashboard@internal
middlewares:
- traefik-stripprefix
entryPoints:
- web
EOF
destination = "local/dynamic.yml"
}
resources {
cpu = 500
memory = 512
}
service {
name = "consul-lb"
port = "http"
check {
name = "consul-lb-health"
type = "http"
path = "/consul/v1/status/leader"
interval = "30s"
timeout = "5s"
}
}
service {
name = "traefik-dashboard"
port = "traefik"
check {
name = "traefik-dashboard-health"
type = "http"
path = "/api/rawdata"
interval = "30s"
timeout = "5s"
}
}
}
}
}

View File

@@ -0,0 +1,40 @@
job "traefik-no-service" {
datacenters = ["dc1"]
type = "service"
group "traefik" {
count = 1
constraint {
attribute = "${node.unique.name}"
value = "hcp1"
}
network {
mode = "host"
port "http" {
static = 80
host_network = "tailscale0"
}
}
task "traefik" {
driver = "exec"
config {
command = "/usr/local/bin/traefik"
args = [
"--api.dashboard=true",
"--api.insecure=true",
"--providers.file.directory=/tmp",
"--entrypoints.web.address=:80"
]
}
resources {
cpu = 200
memory = 128
}
}
}
}

View File

@@ -0,0 +1,68 @@
job "traefik-simple" {
datacenters = ["dc1"]
type = "service"
group "traefik" {
count = 1
constraint {
attribute = "${node.unique.name}"
value = "hcp1"
}
network {
mode = "host"
port "http" {
static = 80
host_network = "tailscale0"
}
port "traefik" {
static = 8080
host_network = "tailscale0"
}
}
task "traefik" {
driver = "exec"
config {
command = "/usr/local/bin/traefik"
args = [
"--configfile=/local/traefik.yml"
]
}
template {
data = <<EOF
api:
dashboard: true
insecure: true
entryPoints:
web:
address: "0.0.0.0:80"
traefik:
address: "0.0.0.0:8080"
providers:
consulCatalog:
endpoint:
address: "warden.tailnet-68f9.ts.net:8500"
scheme: "http"
watch: true
exposedByDefault: false
prefix: "traefik"
log:
level: INFO
EOF
destination = "local/traefik.yml"
}
resources {
cpu = 500
memory = 512
}
}
}
}

View File

@@ -0,0 +1,150 @@
job "traefik-consul-lb" {
datacenters = ["dc1"]
type = "service"
group "traefik" {
count = 1
constraint {
attribute = "${node.unique.name}"
value = "hcp1"
}
update {
min_healthy_time = "60s"
healthy_deadline = "5m"
progress_deadline = "10m"
auto_revert = false
}
network {
mode = "host"
port "http" {
static = 80
host_network = "tailscale0"
}
port "traefik" {
static = 8080
host_network = "tailscale0"
}
}
task "traefik" {
driver = "exec"
config {
command = "/usr/local/bin/traefik"
args = [
"--configfile=/local/traefik.yml"
]
}
template {
data = <<EOF
api:
dashboard: true
insecure: true
entryPoints:
web:
address: "100.97.62.111:80"
traefik:
address: "100.97.62.111:8080"
providers:
file:
filename: /local/dynamic.yml
watch: true
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
addRoutersLabels: true
log:
level: INFO
EOF
destination = "local/traefik.yml"
}
template {
data = <<EOF
http:
middlewares:
consul-stripprefix:
stripPrefix:
prefixes:
- "/consul"
traefik-stripprefix:
stripPrefix:
prefixes:
- "/traefik"
services:
consul-cluster:
loadBalancer:
servers:
- url: "http://warden.tailnet-68f9.ts.net:8500" # 北京,优先
- url: "http://ch4.tailnet-68f9.ts.net:8500" # 韩国,备用
- url: "http://ash3c.tailnet-68f9.ts.net:8500" # 美国,备用
healthCheck:
path: "/v1/status/leader"
interval: "30s"
timeout: "15s"
routers:
consul-api:
rule: "PathPrefix(`/consul`)"
service: consul-cluster
middlewares:
- consul-stripprefix
entryPoints:
- web
traefik-dashboard:
rule: "PathPrefix(`/traefik`)"
service: dashboard@internal
middlewares:
- traefik-stripprefix
entryPoints:
- web
EOF
destination = "local/dynamic.yml"
}
resources {
cpu = 500
memory = 512
}
service {
name = "consul-lb"
port = "http"
check {
name = "consul-lb-health"
type = "http"
path = "/consul/v1/status/leader"
interval = "30s"
timeout = "5s"
}
}
service {
name = "traefik-dashboard"
port = "traefik"
check {
name = "traefik-dashboard-health"
type = "http"
path = "/api/rawdata"
interval = "30s"
timeout = "5s"
}
}
}
}
}