orztv
commited on
Commit
·
7695663
1
Parent(s):
273bb23
update
Browse files- Dockerfile +41 -0
- README.md +90 -0
- services.json +24 -0
- start.sh +114 -0
- traefik/dynamic.yml +29 -0
- traefik/traefik.yml +19 -0
Dockerfile
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM nikolaik/python-nodejs:python3.10-nodejs20
|
2 |
+
|
3 |
+
USER root
|
4 |
+
|
5 |
+
# 安装 Traefik
|
6 |
+
ARG TRAEFIK_VERSION=2.9.6
|
7 |
+
ENV TRAEFIK_CONFIG_FILE=/home/pn/app/traefik/traefik.yml
|
8 |
+
|
9 |
+
RUN wget -q https://github.com/traefik/traefik/releases/download/v${TRAEFIK_VERSION}/traefik_v${TRAEFIK_VERSION}_linux_amd64.tar.gz \
|
10 |
+
&& tar -xzf traefik_v${TRAEFIK_VERSION}_linux_amd64.tar.gz \
|
11 |
+
&& mv traefik /usr/local/bin/ \
|
12 |
+
&& rm traefik_v${TRAEFIK_VERSION}_linux_amd64.tar.gz
|
13 |
+
|
14 |
+
# 安装 jq 用于解析 JSON
|
15 |
+
RUN apt-get update && apt-get install -y jq
|
16 |
+
|
17 |
+
# 切换到 pn 用户
|
18 |
+
USER pn
|
19 |
+
|
20 |
+
# 设置工作目录
|
21 |
+
WORKDIR /home/pn/app
|
22 |
+
|
23 |
+
# 创建 Traefik 配置目录
|
24 |
+
RUN mkdir -p /home/pn/app/traefik
|
25 |
+
|
26 |
+
# 复制配置文件和启动脚本
|
27 |
+
COPY --chown=pn:pn traefik/ /home/pn/app/traefik/
|
28 |
+
COPY --chown=pn:pn start.sh /home/pn/app/start.sh
|
29 |
+
COPY --chown=pn:pn services.json /home/pn/app/services.json
|
30 |
+
RUN chmod +x /home/pn/app/start.sh
|
31 |
+
|
32 |
+
# 设置环境变量
|
33 |
+
ENV TRAEFIK_PORT=7860 \
|
34 |
+
PYTHON_PORT=8000 \
|
35 |
+
NODE_PORT=8001
|
36 |
+
|
37 |
+
# 暴露 Traefik 和后端服务端口
|
38 |
+
EXPOSE $TRAEFIK_PORT $PYTHON_PORT $NODE_PORT
|
39 |
+
|
40 |
+
# 启动容器时运行启动脚本
|
41 |
+
CMD ["/home/pn/app/start.sh"]
|
README.md
CHANGED
@@ -8,3 +8,93 @@ pinned: false
|
|
8 |
---
|
9 |
|
10 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
---
|
9 |
|
10 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
11 |
+
|
12 |
+
Traefik 作为反向代理,使用 YAML 或 TOML 文件。Traefik 将监听 7860 端口,并根据路径前缀将请求转发到相应的服务。
|
13 |
+
反代两个服务:
|
14 |
+
1. `python -m http.server 8000`
|
15 |
+
2. `sudo npm install -g http-server` 后 `http-server -p 8001`
|
16 |
+
|
17 |
+
帮我写一个完整的 Dockerfile 程序。使用 `nikolaik/python-nodejs:python3.10-nodejs20` 镜像。
|
18 |
+
本镜像已经安装好 Node 及 Python 的了,容器启动默认使用 `pn` 用户,UID 为 1000。容器中需要使用这个用户。
|
19 |
+
|
20 |
+
## 程序特点及用法
|
21 |
+
|
22 |
+
本程序采用了动态配置和服务管理的方式,具有以下特点和用法:
|
23 |
+
|
24 |
+
1. **易用性**:
|
25 |
+
- 通过修改 `services.json` 文件,可以轻松添加、删除或修改服务,无需更改其他配置文件。
|
26 |
+
- 使用环境变量来配置端口号和其他可变参数,增加了灵活性。
|
27 |
+
|
28 |
+
2. **扩展性**:
|
29 |
+
- 新服务可以通过在 `services.json` 中添加一个新条目来增加,包括其命令、端口和路径前缀。
|
30 |
+
- Dockerfile 中预装了常用工具,如 `jq`,方便进行 JSON 解析和处理。
|
31 |
+
|
32 |
+
3. **复用性**:
|
33 |
+
- `start.sh` 脚本可以处理任意数量的服务,无需为每个新服务修改脚本。
|
34 |
+
- 使用通用的健康检查函数,适用于所有服务。
|
35 |
+
|
36 |
+
4. **逻辑性**:
|
37 |
+
- 配置生成和服务启动的逻辑集中在 `start.sh` 脚本中,使得整个流程更加清晰。
|
38 |
+
- 使用 Traefik 作为反向代理,通过动态配置文件实现路由规则的灵活管理。
|
39 |
+
|
40 |
+
## 如何使用
|
41 |
+
|
42 |
+
1. **添加新服务**:
|
43 |
+
在 `services.json` 文件中添加新的服务配置,例如:
|
44 |
+
```json
|
45 |
+
{
|
46 |
+
"name": "new-service",
|
47 |
+
"command": "new-service-command",
|
48 |
+
"port": 8002,
|
49 |
+
"path_prefix": "/new-service",
|
50 |
+
"health_check_path": "/health"
|
51 |
+
}
|
52 |
+
```
|
53 |
+
|
54 |
+
2. **修改现有服务**:
|
55 |
+
直接在 `services.json` 文件中修改相应服务的配置。
|
56 |
+
|
57 |
+
3. **自定义端口**:
|
58 |
+
通过环境变量设置 `TRAEFIK_PORT`、`PYTHON_PORT` 和 `NODE_PORT` 来自定义端口。
|
59 |
+
|
60 |
+
4. **配置 HTTPS**:
|
61 |
+
- 修改 `traefik.yml` 中的 `certificatesResolvers` 部分,配置有效的电子邮件地址以使用 Let’s Encrypt。
|
62 |
+
- 确保端口 80 和 443 对外开放,以便 Let’s Encrypt 能够验证和获取证书。
|
63 |
+
|
64 |
+
5. **构建和运行**:
|
65 |
+
```bash
|
66 |
+
docker build -t my-traefik-app .
|
67 |
+
docker run -p 7860:7860 -p 80:80 -p 443:443 my-traefik-app
|
68 |
+
```
|
69 |
+
|
70 |
+
6. **访问服务**:
|
71 |
+
- Python 服务:`http://localhost:7860/python` 或 `https://localhost/python`
|
72 |
+
- Node 服务:`http://localhost:7860/node` 或 `https://localhost/node`
|
73 |
+
- Traefik 仪表板:`https://localhost/dashboard/`
|
74 |
+
|
75 |
+
7. **查看日志和监控**:
|
76 |
+
使用 Docker 日志命令查看容器日志,包括服务启动状态和健康检查结果。
|
77 |
+
```bash
|
78 |
+
docker logs -f <container_id>
|
79 |
+
```
|
80 |
+
|
81 |
+
8. **健康检查和失败处理**:
|
82 |
+
- `start.sh` 脚本中已集成健康检查功能,确保所有服务正常运行。
|
83 |
+
- 若某个服务未能通过健康检查,容器将输出相应的错误信息,便于及时修复。
|
84 |
+
|
85 |
+
## 进一步优化建议
|
86 |
+
|
87 |
+
1. **配置管理**:
|
88 |
+
- 使用配置管理工具(如 `consul` 或 `etcd`)进行集中式配置管理,提升配置的可维护性和一致性。
|
89 |
+
|
90 |
+
2. **日志管理**:
|
91 |
+
- 集成集中式日志管理系统(如 ELK Stack),便于日志的收集、分析和监控。
|
92 |
+
|
93 |
+
3. **容器编排**:
|
94 |
+
- 考虑使用 Kubernetes 进行容器编排,提升系统的扩展性和可靠性。
|
95 |
+
|
96 |
+
4. **安全增强**:
|
97 |
+
- 配置 Traefik 的访问控制,如基本认证或 OAuth,保护敏感服务和仪表板的访问。
|
98 |
+
- 定期更新基础镜像和依赖,以减少安全漏洞。
|
99 |
+
|
100 |
+
通过以上优化,您的程序在易用性、扩展性、复用性和逻辑性等方面将得到显著提升,能够更好地满足实际业务需求。如果您有任何进一步的问题或需要更多的帮助,请随时与我联系。
|
services.json
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"name": "python-service",
|
4 |
+
"command": "python -m http.server",
|
5 |
+
"port": 8000,
|
6 |
+
"path_prefix": "/python",
|
7 |
+
"health_check_path": "/",
|
8 |
+
"env": {
|
9 |
+
"PYTHONUNBUFFERED": "1"
|
10 |
+
},
|
11 |
+
"working_dir": "/home/pn/app/python"
|
12 |
+
},
|
13 |
+
{
|
14 |
+
"name": "node-service",
|
15 |
+
"command": "http-server",
|
16 |
+
"port": 8001,
|
17 |
+
"path_prefix": "/node",
|
18 |
+
"health_check_path": "/",
|
19 |
+
"env": {
|
20 |
+
"NODE_ENV": "production"
|
21 |
+
},
|
22 |
+
"working_dir": "/home/pn/app/node"
|
23 |
+
}
|
24 |
+
]
|
start.sh
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
set -e
|
3 |
+
|
4 |
+
# 添加日志函数
|
5 |
+
log() {
|
6 |
+
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
|
7 |
+
}
|
8 |
+
|
9 |
+
# 捕获 SIGTERM 信号,优雅关闭所有后台进程
|
10 |
+
trap "log '收到终止信号,关闭进程...'; kill $(jobs -p); exit 0" SIGTERM
|
11 |
+
|
12 |
+
# 读取服务配置
|
13 |
+
services=$(jq -c '.[]' services.json)
|
14 |
+
|
15 |
+
# 动态生成 Traefik 配置
|
16 |
+
generate_traefik_config() {
|
17 |
+
local dynamic_config="/home/pn/app/traefik/dynamic.yml"
|
18 |
+
echo "http:" > $dynamic_config
|
19 |
+
echo " routers:" >> $dynamic_config
|
20 |
+
echo " services:" >> $dynamic_config
|
21 |
+
echo " middlewares:" >> $dynamic_config
|
22 |
+
echo " strip-prefix:" >> $dynamic_config
|
23 |
+
echo " stripPrefix:" >> $dynamic_config
|
24 |
+
echo " prefixes:" >> $dynamic_config
|
25 |
+
|
26 |
+
echo "$services" | while read -r service; do
|
27 |
+
name=$(echo $service | jq -r '.name')
|
28 |
+
port=$(echo $service | jq -r '.port')
|
29 |
+
path_prefix=$(echo $service | jq -r '.path_prefix')
|
30 |
+
|
31 |
+
echo " - \"$path_prefix\"" >> $dynamic_config
|
32 |
+
done
|
33 |
+
|
34 |
+
echo "" >> $dynamic_config
|
35 |
+
echo " routers:" >> $dynamic_config
|
36 |
+
|
37 |
+
echo "$services" | while read -r service; do
|
38 |
+
name=$(echo $service | jq -r '.name')
|
39 |
+
port=$(echo $service | jq -r '.port')
|
40 |
+
path_prefix=$(echo $service | jq -r '.path_prefix')
|
41 |
+
|
42 |
+
echo " $name:" >> $dynamic_config
|
43 |
+
echo " rule: \"PathPrefix('$path_prefix')\"" >> $dynamic_config
|
44 |
+
echo " service: $name" >> $dynamic_config
|
45 |
+
echo " middlewares:" >> $dynamic_config
|
46 |
+
echo " - strip-prefix" >> $dynamic_config
|
47 |
+
done
|
48 |
+
|
49 |
+
echo "" >> $dynamic_config
|
50 |
+
echo " services:" >> $dynamic_config
|
51 |
+
|
52 |
+
echo "$services" | while read -r service; do
|
53 |
+
name=$(echo $service | jq -r '.name')
|
54 |
+
port=$(echo $service | jq -r '.port')
|
55 |
+
|
56 |
+
echo " $name:" >> $dynamic_config
|
57 |
+
echo " loadBalancer:" >> $dynamic_config
|
58 |
+
echo " servers:" >> $dynamic_config
|
59 |
+
echo " - url: \"http://localhost:$port\"" >> $dynamic_config
|
60 |
+
done
|
61 |
+
}
|
62 |
+
|
63 |
+
# 生成 Traefik 配置
|
64 |
+
generate_traefik_config
|
65 |
+
|
66 |
+
# 启动服务
|
67 |
+
echo "$services" | while read -r service; do
|
68 |
+
name=$(echo $service | jq -r '.name')
|
69 |
+
command=$(echo $service | jq -r '.command')
|
70 |
+
port=$(echo $service | jq -r '.port')
|
71 |
+
working_dir=$(echo $service | jq -r '.working_dir // "/home/pn/app"')
|
72 |
+
|
73 |
+
log "Starting $name on port $port"
|
74 |
+
|
75 |
+
# 设置环境变量
|
76 |
+
eval $(echo $service | jq -r '.env // {} | to_entries | .[] | "export " + .key + "=\"" + .value + "\""')
|
77 |
+
|
78 |
+
# 切换到工作目录并启动服务
|
79 |
+
(cd $working_dir && $command -p $port) &
|
80 |
+
done
|
81 |
+
|
82 |
+
# 等待服务启动
|
83 |
+
sleep 2
|
84 |
+
|
85 |
+
# 健康检查函数
|
86 |
+
check_health() {
|
87 |
+
local port=$1
|
88 |
+
local service=$2
|
89 |
+
local health_check_path=$3
|
90 |
+
for i in {1..5}; do
|
91 |
+
if curl -s "http://localhost:$port$health_check_path" > /dev/null; then
|
92 |
+
log "$service is up"
|
93 |
+
return 0
|
94 |
+
fi
|
95 |
+
sleep 1
|
96 |
+
done
|
97 |
+
log "ERROR: $service failed to start"
|
98 |
+
return 1
|
99 |
+
}
|
100 |
+
|
101 |
+
# 执行健康检查
|
102 |
+
echo "$services" | while read -r service; do
|
103 |
+
name=$(echo $service | jq -r '.name')
|
104 |
+
port=$(echo $service | jq -r '.port')
|
105 |
+
health_check_path=$(echo $service | jq -r '.health_check_path')
|
106 |
+
|
107 |
+
if ! check_health $port "$name" "$health_check_path"; then
|
108 |
+
log "ERROR: 健康检查失败,退出程序"
|
109 |
+
exit 1
|
110 |
+
fi
|
111 |
+
done
|
112 |
+
|
113 |
+
# 启动 Traefik
|
114 |
+
exec traefik --configFile=$TRAEFIK_CONFIG_FILE
|
traefik/dynamic.yml
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
http:
|
2 |
+
routers:
|
3 |
+
python-service:
|
4 |
+
rule: "PathPrefix(`/python`)"
|
5 |
+
service: python-service
|
6 |
+
middlewares:
|
7 |
+
- strip-prefix
|
8 |
+
node-service:
|
9 |
+
rule: "PathPrefix(`/node`)"
|
10 |
+
service: node-service
|
11 |
+
middlewares:
|
12 |
+
- strip-prefix
|
13 |
+
|
14 |
+
services:
|
15 |
+
python-service:
|
16 |
+
loadBalancer:
|
17 |
+
servers:
|
18 |
+
- url: "http://localhost:${PYTHON_PORT}"
|
19 |
+
node-service:
|
20 |
+
loadBalancer:
|
21 |
+
servers:
|
22 |
+
- url: "http://localhost:${NODE_PORT}"
|
23 |
+
|
24 |
+
middlewares:
|
25 |
+
strip-prefix:
|
26 |
+
stripPrefix:
|
27 |
+
prefixes:
|
28 |
+
- "/python"
|
29 |
+
- "/node"
|
traefik/traefik.yml
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
global:
|
2 |
+
checkNewVersion: true
|
3 |
+
sendAnonymousUsage: false
|
4 |
+
|
5 |
+
log:
|
6 |
+
level: INFO
|
7 |
+
|
8 |
+
entryPoints:
|
9 |
+
web:
|
10 |
+
address: ":${TRAEFIK_PORT}"
|
11 |
+
|
12 |
+
providers:
|
13 |
+
file:
|
14 |
+
filename: /home/pn/app/traefik/dynamic.yml
|
15 |
+
watch: true
|
16 |
+
|
17 |
+
api:
|
18 |
+
insecure: true
|
19 |
+
dashboard: true
|