feat: 重构服务注册与发现机制,使用Consul进行集中管理
- 移除各服务的独立注册脚本,改为通过Consul配置文件集中管理 - 为所有服务添加健康检查端点 - 更新docker-compose配置,添加网络和健康检查依赖 - 修改data-service的启动命令和端口配置 - 禁用Consul的ACL以简化开发环境配置
This commit is contained in:
parent
806e444297
commit
f19ce5992f
@ -3,6 +3,6 @@ ui_config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
acl {
|
acl {
|
||||||
enabled = true
|
enabled = false
|
||||||
default_policy = "deny"
|
default_policy = "deny"
|
||||||
}
|
}
|
||||||
17
consul/config/data-service.hcl
Normal file
17
consul/config/data-service.hcl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
service {
|
||||||
|
name = "data-service"
|
||||||
|
id = "data-service-1"
|
||||||
|
address = "data-service"
|
||||||
|
port = 8000
|
||||||
|
|
||||||
|
check {
|
||||||
|
http = "http://aktools:8080/quote_zh_a_hist?symbol=sh600000&period=daily&start_date=20220101&end_date=20220102"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
"traefik.enable" = "true"
|
||||||
|
"traefik.http.routers.data-service.rule" = "PathPrefix(`/api/data`)"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
consul/config/emotion-service.hcl
Normal file
17
consul/config/emotion-service.hcl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
service {
|
||||||
|
name = "emotion-service"
|
||||||
|
id = "emotion-service-1"
|
||||||
|
address = "emotion-service"
|
||||||
|
port = 8002
|
||||||
|
|
||||||
|
check {
|
||||||
|
http = "http://emotion-service:8002/health"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
"traefik.enable" = "true"
|
||||||
|
"traefik.http.routers.emotion-service.rule" = "PathPrefix(`/api/emotion`)"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
consul/config/frontend.hcl
Normal file
17
consul/config/frontend.hcl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
service {
|
||||||
|
name = "frontend"
|
||||||
|
id = "frontend-1"
|
||||||
|
address = "frontend"
|
||||||
|
port = 80
|
||||||
|
|
||||||
|
check {
|
||||||
|
http = "http://frontend:80/"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
"traefik.enable" = "true"
|
||||||
|
"traefik.http.routers.frontend.rule" = "PathPrefix(`/`)"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
consul/config/quant-service.hcl
Normal file
17
consul/config/quant-service.hcl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
service {
|
||||||
|
name = "quant-service"
|
||||||
|
id = "quant-service-1"
|
||||||
|
address = "quant-service"
|
||||||
|
port = 8001
|
||||||
|
|
||||||
|
check {
|
||||||
|
http = "http://quant-service:8001/health"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
"traefik.enable" = "true"
|
||||||
|
"traefik.http.routers.quant-service.rule" = "PathPrefix(`/api/quant`)"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
consul/config/recommend-service.hcl
Normal file
17
consul/config/recommend-service.hcl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
service {
|
||||||
|
name = "recommend-service"
|
||||||
|
id = "recommend-service-1"
|
||||||
|
address = "recommend-service"
|
||||||
|
port = 8003
|
||||||
|
|
||||||
|
check {
|
||||||
|
http = "http://recommend-service:8003/health"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
"traefik.enable" = "true"
|
||||||
|
"traefik.http.routers.recommend-service.rule" = "PathPrefix(`/api/recommend`)"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
consul/config/user-service.hcl
Normal file
17
consul/config/user-service.hcl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
service {
|
||||||
|
name = "user-service"
|
||||||
|
id = "user-service-1"
|
||||||
|
address = "user-service"
|
||||||
|
port = 8004
|
||||||
|
|
||||||
|
check {
|
||||||
|
http = "http://user-service:8004/health"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
"traefik.enable" = "true"
|
||||||
|
"traefik.http.routers.user-service.rule" = "PathPrefix(`/api/user`)"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,78 +1,138 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
|
networks:
|
||||||
|
microservice-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
consul:
|
||||||
|
image: consul:1.15
|
||||||
|
container_name: ari-consul
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "8500:8500" # Consul Web UI
|
||||||
|
- "8600:8600/udp" # DNS服务
|
||||||
|
volumes:
|
||||||
|
- ./consul/config:/consul/config
|
||||||
|
command: "consul agent -dev -config-dir=/consul/config -client=0.0.0.0"
|
||||||
|
networks:
|
||||||
|
- microservice-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8500/v1/status/leader"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:v2.9
|
image: traefik:v2.9
|
||||||
command:
|
container_name: ari-traefik
|
||||||
- --entrypoints.web.address=:80
|
restart: always
|
||||||
- --providers.consulcatalog=true
|
depends_on:
|
||||||
- --providers.consulcatalog.endpoint.address=consul:8500
|
consul:
|
||||||
- --api.dashboard=true
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80" # 主入口
|
||||||
|
- "8080:8080" # Dashboard
|
||||||
volumes:
|
volumes:
|
||||||
- ./traefik/traefik.yml:/etc/traefik/traefik.yml
|
- ./traefik/traefik.yml:/etc/traefik/traefik.yml
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
command:
|
||||||
|
- --providers.consulcatalog=true
|
||||||
|
- --providers.consulcatalog.endpoint.address=consul:8500
|
||||||
|
- --providers.consulcatalog.exposedbydefault=false
|
||||||
|
- --api.dashboard=true
|
||||||
|
- --log.level=INFO
|
||||||
|
networks:
|
||||||
|
- microservice-network
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.traefik-dashboard.rule=PathPrefix(`/dashboard`) || PathPrefix(`/api`)"
|
||||||
|
- "traefik.http.routers.traefik-dashboard.service=api@internal"
|
||||||
|
- "traefik.http.routers.traefik-dashboard.entrypoints=web"
|
||||||
|
|
||||||
data-service:
|
data-service:
|
||||||
build: ./services/data-service
|
build: ./services/data-service
|
||||||
labels:
|
container_name: ari-data-service
|
||||||
- "traefik.enable=true"
|
restart: always
|
||||||
- "traefik.http.routers.data.rule=PathPrefix(`/api/data`)"
|
depends_on:
|
||||||
|
consul:
|
||||||
|
condition: service_healthy
|
||||||
expose:
|
expose:
|
||||||
- "8000"
|
- "8000"
|
||||||
|
networks:
|
||||||
|
- microservice-network
|
||||||
|
environment:
|
||||||
|
- SERVICE_NAME=data-service
|
||||||
|
|
||||||
quant-service:
|
quant-service:
|
||||||
build: ./services/quant-service
|
build: ./services/quant-service
|
||||||
labels:
|
container_name: ari-quant-service
|
||||||
- "traefik.enable=true"
|
restart: always
|
||||||
- "traefik.http.routers.quant.rule=PathPrefix(`/api/quant`)"
|
depends_on:
|
||||||
|
consul:
|
||||||
|
condition: service_healthy
|
||||||
expose:
|
expose:
|
||||||
- "8001"
|
- "8001"
|
||||||
|
networks:
|
||||||
|
- microservice-network
|
||||||
|
environment:
|
||||||
|
- SERVICE_NAME=quant-service
|
||||||
|
|
||||||
emotion-service:
|
emotion-service:
|
||||||
build: ./services/emotion-service
|
build: ./services/emotion-service
|
||||||
labels:
|
container_name: ari-emotion-service
|
||||||
- "traefik.enable=true"
|
restart: always
|
||||||
- "traefik.http.routers.emotion.rule=PathPrefix(`/api/emotion`)"
|
depends_on:
|
||||||
|
consul:
|
||||||
|
condition: service_healthy
|
||||||
expose:
|
expose:
|
||||||
- "8002"
|
- "8002"
|
||||||
|
networks:
|
||||||
|
- microservice-network
|
||||||
|
environment:
|
||||||
|
- SERVICE_NAME=emotion-service
|
||||||
|
|
||||||
recommend-service:
|
recommend-service:
|
||||||
build: ./services/recommend-service
|
build: ./services/recommend-service
|
||||||
labels:
|
container_name: ari-recommend-service
|
||||||
- "traefik.enable=true"
|
restart: always
|
||||||
- "traefik.http.routers.recommend.rule=PathPrefix(`/api/recommend`)"
|
depends_on:
|
||||||
|
consul:
|
||||||
|
condition: service_healthy
|
||||||
expose:
|
expose:
|
||||||
- "8003"
|
- "8003"
|
||||||
|
networks:
|
||||||
|
- microservice-network
|
||||||
|
environment:
|
||||||
|
- SERVICE_NAME=recommend-service
|
||||||
|
|
||||||
user-service:
|
user-service:
|
||||||
build: ./services/user-service
|
build: ./services/user-service
|
||||||
labels:
|
container_name: ari-user-service
|
||||||
- "traefik.enable=true"
|
restart: always
|
||||||
- "traefik.http.routers.user.rule=PathPrefix(`/api/user`)"
|
depends_on:
|
||||||
|
consul:
|
||||||
|
condition: service_healthy
|
||||||
expose:
|
expose:
|
||||||
- "8004"
|
- "8004"
|
||||||
|
networks:
|
||||||
|
- microservice-network
|
||||||
|
environment:
|
||||||
|
- SERVICE_NAME=user-service
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
build: ./services/frontend
|
build: ./services/frontend
|
||||||
labels:
|
container_name: ari-frontend
|
||||||
- "traefik.enable=true"
|
restart: always
|
||||||
- "traefik.http.routers.frontend.rule=PathPrefix(`/`)"
|
depends_on:
|
||||||
|
- data-service
|
||||||
|
- quant-service
|
||||||
|
- emotion-service
|
||||||
|
- recommend-service
|
||||||
|
- user-service
|
||||||
expose:
|
expose:
|
||||||
- "80"
|
- "80"
|
||||||
|
networks:
|
||||||
gitea-webhook:
|
- microservice-network
|
||||||
build: ./gitea-webhook
|
environment:
|
||||||
ports:
|
- SERVICE_NAME=frontend
|
||||||
- "5005:5005"
|
|
||||||
|
|
||||||
consul:
|
|
||||||
image: consul:1.15
|
|
||||||
ports:
|
|
||||||
- "8500:8500" # Consul Web UI
|
|
||||||
- "8600:8600/udp"
|
|
||||||
volumes:
|
|
||||||
- ./consul/config:/consul/config
|
|
||||||
command: "consul agent -dev -config-dir=/consul/config"
|
|
||||||
@ -4,4 +4,4 @@ WORKDIR /app
|
|||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
RUN pip install -r requirements.txt
|
RUN pip install -r requirements.txt
|
||||||
COPY . .
|
COPY . .
|
||||||
CMD ["sh", "-c", "aktools run --port 8001 & python register.py && wait"]
|
CMD ["python", "-m", "aktools", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
from flask import Flask, jsonify
|
|
||||||
import threading
|
|
||||||
import subprocess
|
|
||||||
from register import register_to_consul
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
@app.route("/health")
|
|
||||||
def health():
|
|
||||||
return jsonify({"status": "ok"}), 200
|
|
||||||
|
|
||||||
@app.route("/hello")
|
|
||||||
def hello():
|
|
||||||
return jsonify({"message": "Hello from service!"})
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
threading.Thread(target=register_to_consul).start()
|
|
||||||
subprocess.Popen(["aktools", "run", "--port", "8001"])
|
|
||||||
app.run(host="0.0.0.0", port=8000)
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
import time
|
|
||||||
import requests
|
|
||||||
|
|
||||||
def register_to_consul():
|
|
||||||
time.sleep(3) # 等待服务稳定再注册
|
|
||||||
service_name = "aktools-service" # AKTools 主服务
|
|
||||||
port = 8001 # AKTools 端口
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"Name": service_name,
|
|
||||||
"ID": f"{service_name}-1",
|
|
||||||
"Address": service_name, # 容器名作为地址
|
|
||||||
"Port": port,
|
|
||||||
"Check": {
|
|
||||||
"TCP": f"{service_name}:{port}",
|
|
||||||
"Interval": "10s"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
requests.put("http://consul:8500/v1/agent/service/register", json=payload)
|
|
||||||
print(f"[{service_name}] Registered to Consul")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Consul register failed: {e}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
register_to_consul()
|
|
||||||
@ -1,2 +1 @@
|
|||||||
flask
|
|
||||||
aktools
|
aktools
|
||||||
@ -1,6 +1,5 @@
|
|||||||
from flask import Flask, jsonify
|
from flask import Flask, jsonify
|
||||||
import threading
|
import threading
|
||||||
from register import register_to_consul
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@ -13,5 +12,4 @@ def hello():
|
|||||||
return jsonify({"message": "Hello from service!"})
|
return jsonify({"message": "Hello from service!"})
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
threading.Thread(target=register_to_consul).start()
|
|
||||||
app.run(host="0.0.0.0", port=8002)
|
app.run(host="0.0.0.0", port=8002)
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import time
|
|
||||||
import requests
|
|
||||||
|
|
||||||
def register_to_consul():
|
|
||||||
time.sleep(3) # 等待服务稳定再注册
|
|
||||||
service_name = "emotion-service" # 替换为 quant-service/emotion-service 等
|
|
||||||
port = 8002 # 替换为 8001, 8002 等
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"Name": service_name,
|
|
||||||
"ID": f"{service_name}-1",
|
|
||||||
"Address": service_name, # 容器名作为地址
|
|
||||||
"Port": port,
|
|
||||||
"Check": {
|
|
||||||
"HTTP": f"http://{service_name}:{port}/health",
|
|
||||||
"Interval": "10s"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
requests.put("http://consul:8500/v1/agent/service/register", json=payload)
|
|
||||||
print(f"[{service_name}] Registered to Consul")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Consul register failed: {e}")
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
from flask import Flask, jsonify
|
from flask import Flask, jsonify
|
||||||
import threading
|
import threading
|
||||||
from register import register_to_consul
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@ -13,5 +12,4 @@ def hello():
|
|||||||
return jsonify({"message": "Hello from service!"})
|
return jsonify({"message": "Hello from service!"})
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
threading.Thread(target=register_to_consul).start()
|
|
||||||
app.run(host="0.0.0.0", port=8001)
|
app.run(host="0.0.0.0", port=8001)
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import time
|
|
||||||
import requests
|
|
||||||
|
|
||||||
def register_to_consul():
|
|
||||||
time.sleep(3) # 等待服务稳定再注册
|
|
||||||
service_name = "quant-service" # 替换为 quant-service/emotion-service 等
|
|
||||||
port = 8001 # 替换为 8001, 8002 等
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"Name": service_name,
|
|
||||||
"ID": f"{service_name}-1",
|
|
||||||
"Address": service_name, # 容器名作为地址
|
|
||||||
"Port": port,
|
|
||||||
"Check": {
|
|
||||||
"HTTP": f"http://{service_name}:{port}/health",
|
|
||||||
"Interval": "10s"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
requests.put("http://consul:8500/v1/agent/service/register", json=payload)
|
|
||||||
print(f"[{service_name}] Registered to Consul")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Consul register failed: {e}")
|
|
||||||
@ -4,4 +4,5 @@ using Microsoft.Extensions.Hosting;
|
|||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
app.MapGet("/", () => new { service = "recommend-service", status = "ok" });
|
app.MapGet("/", () => new { service = "recommend-service", status = "ok" });
|
||||||
|
app.MapGet("/health", () => new { status = "ok" });
|
||||||
app.Run("http://0.0.0.0:8003");
|
app.Run("http://0.0.0.0:8003");
|
||||||
@ -4,4 +4,5 @@ using Microsoft.Extensions.Hosting;
|
|||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
app.MapGet("/", () => new { service = "user-service", status = "ok" });
|
app.MapGet("/", () => new { service = "user-service", status = "ok" });
|
||||||
|
app.MapGet("/health", () => new { status = "ok" });
|
||||||
app.Run("http://0.0.0.0:8004");
|
app.Run("http://0.0.0.0:8004");
|
||||||
Loading…
Reference in New Issue
Block a user