You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Django Eureka Client在Kubernetes集群中无法从Eureka Server注销

Django Eureka Client在Kubernetes中无法注销实例

本地环境下,启动Django项目能正常注册到Spring Eureka Server,按CTRL+C停止时也能正常注销;但在Kubernetes集群中,通过kubectl apply -f kub8s-media.yaml启动Pod可成功注册,执行kubectl delete -f kub8s-media.yaml删除Pod或kubectl rollout restart deployment kub8s-deploy重启Deployment时,Django实例无法从Eureka Server注销。

相关配置文件

Dockerfile

FROM python

RUN mkdir /backend-media

COPY . /backend-media

WORKDIR /backend-media

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

EXPOSE 8001

RUN pip install -r requirements.txt

CMD ["python", "manage.py", "runserver", "0.0.0.0:8001"]

kub8s-media.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-media-deploy
spec:
  selector:
    matchLabels:
      app: backend-media
  replicas: 1
  template:
    metadata:
      labels:
        app: backend-media
    spec:
      containers:
      - name: backend-media-app
        ports:
          - containerPort: 8001
        image: aalfaa00/media:latest

---
apiVersion: v1
kind: Service
metadata:
  name: backend-media-svc
  labels:
    app: backend-media
spec:
  type: NodePort
  ports:
    - port: 8001
      protocol: TCP
  selector:
    app: backend-media

eureka.py

import random
import string
import os
import py_eureka_client.eureka_client as eureka_client

N = 32
res = ''.join(random.choices(string.ascii_lowercase + string.digits, k=N))

server_port = 8001

def eureka_init():
    if os.environ.get("RUN_MAIN"):
        eureka_client.init(eureka_server="http://192.168.49.2:32451",
                        app_name="service",
                        instance_port=server_port,
                        instance_id=("media:" + str(res)))
        print("Eureka client is running")

def stop_eureka():
    if os.environ.get("RUN_MAIN"):
        eureka_client.stop()
        print("Stopping Eureka client")

manage.py

import os
import sys
from media_service.eureka import eureka_init, stop_eureka

def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'media_service.settings')
    if os.environ.get('RUN_MAIN'):
        print('run')
        eureka_init()
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)
    stop_eureka()

if __name__ == '__main__':
    main()

问题原因及解决方案

1. Kubernetes信号处理缺失

本地按CTRL+C发送SIGINT信号,Django runserver会优雅退出并执行stop_eureka();但Kubernetes删除Pod时默认发送SIGTERM信号,runserver未处理该信号,进程直接被杀死,导致注销逻辑无法执行。

解决方法:
在manage.py中添加信号监听,捕获SIGTERM和SIGINT触发注销:

import os
import sys
import signal
from media_service.eureka import eureka_init, stop_eureka

def handle_shutdown(signum, frame):
    print(f"收到信号{signum},开始注销Eureka实例...")
    stop_eureka()
    sys.exit(0)

# 注册信号处理器
signal.signal(signal.SIGTERM, handle_shutdown)
signal.signal(signal.SIGINT, handle_shutdown)

def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'media_service.settings')
    if os.environ.get('RUN_MAIN'):
        print('run')
        eureka_init()
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)
    stop_eureka()

if __name__ == '__main__':
    main()

2. Django runserver的阻塞特性

execute_from_command_line(sys.argv)执行runserver时是阻塞状态,后续的stop_eureka()仅在进程正常退出时执行,而Kubernetes的强制终止会跳过这步。上述信号处理可解决此问题。

3. 优化Eureka Server的实例剔除逻辑

即使注销失败,可通过调整Eureka Server配置缩短心跳间隔和过期时间,自动清理无响应实例:
在Eureka Server配置文件中添加:

eureka.instance.lease-renewal-interval-in-seconds=10
eureka.instance.lease-expiration-duration-in-seconds=30

超过30秒未收到心跳的实例会被自动剔除。

4. 替换为生产级WSGI服务器

Django runserver是开发环境工具,生产环境建议用Gunicorn/UWSGI,这类服务器支持优雅退出:

  • 修改Dockerfile的CMD:
CMD ["gunicorn", "--bind", "0.0.0.0:8001", "--workers", "2", "media_service.wsgi:application"]
  • 创建启动脚本start.sh:
#!/bin/bash
python -c "from media_service.eureka import eureka_init; eureka_init()"
gunicorn --bind 0.0.0.0:8001 --workers 2 media_service.wsgi:application
python -c "from media_service.eureka import stop_eureka; stop_eureka()"
  • 在Dockerfile中添加脚本权限:
RUN chmod +x start.sh
CMD ["./start.sh"]

内容的提问来源于stack exchange,提问作者Ismoil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 06:54:23