Kubernetes Health Checks in Django
健康检查是Kubernetes询问您的应用程序是否健康的一种方式。他们认为您的应用程序可以在未准备就绪的情况下启动,因此不要假设对应用程序的启动有任何顺序。因此,我们需要能够检查数据库或memcached是否已消失并且无法再由该应用访问。
健康检查视图
编写健康检查的幼稚方法是为其编写视图。像这样:
def liveliness(request): return HttpResponse("OK") def readiness(request): try: # Connect to database return HttpResponse("OK") except Exception, e: return HttpResponseServerError("db: cannot connect to database.")
但是Django在运行视图之前会运行很多用户代码,例如中间件和装饰器。因此,这些故障会产生我们不希望通过准备就绪探针做出的响应。
使用中间件解决健康检查
由于许多Django中间件(例如Django的AuthenticationMiddleware)都使用该数据库,因此无法将活动性和就绪性检查作为简单的视图来实现。当您的应用无法访问数据库时,Django会生成一个异常,并在Django执行视图很久之前返回500错误页面。这不能为Kubernetes提供最佳的开发人员体验。
为了部分解决Django应用程序的运行状况检查,我编写了一些中间件来实现运行状况检查。我想执行数据库检查而不假定使用任何特定的Django模型,因此直接生成了查询。
get_stats()
由于memcached客户端不支持ping
方法,我还能够通过调用ping服务器来检查缓存服务器是否可用。
from django.http import HttpResponse, HttpResponseServerError logger = logging.getLogger("healthz") class HealthCheckMiddleware(object): def __init__(self, get_response): self.get_response = get_response # One-time configuration and initialization. def __call__(self, request): if request.method == "GET": if request.path == "/readiness": return self.readiness(request) elif request.path == "/healthz": return self.healthz(request) return self.get_response(request) def healthz(self, request): """ Returns that the server is alive. """ return HttpResponse("OK") def readiness(self, request): # Connect to each database and do a generic standard SQL query # that doesn't write any data and doesn't depend on any tables # being present. try: from django.db import connections for name in connections: cursor = connections[name].cursor() cursor.execute("SELECT 1;") row = cursor.fetchone() if row is None: return HttpResponseServerError("db: invalid response") except Exception, e: logger.exception(e) return HttpResponseServerError("db: cannot connect to database.") # Call get_stats() to connect to each memcached instance and get it's stats. # This can effectively check if each is online. try: from django.core.cache import caches from django.core.cache.backends.memcached import BaseMemcachedCache for cache in caches.all(): if isinstance(cache, BaseMemcachedCache): stats = cache._cache.get_stats() if len(stats) != len(cache._servers): return HttpResponseServerError("cache: cannot connect to cache.") except Exception, e: logger.exception(e) return HttpResponseServerError("cache: cannot connect to cache.") return HttpResponse("OK")
您可以将此MIDDLEWARE_CLASSES
添加到您的开头,以将运行状况检查添加到您的应用中。将其放在MIDDLEWARE_CLASSES
确保它可以在其他可能访问数据库的其他中间件类之前运行的开头。
支持健康检查
我们需要做更多的工作来支持健康检查。默认情况下,Django在每次连接时都连接到数据库。即使使用连接池,它也会在请求到来时延迟连接到数据库。在Kubernetes中,如果您的服务没有终结点(即所有mysql或memcached pod均未通过就绪检查),则当您连接到该服务时,该服务的群集IP将根本无法访问。因为它是虚拟IP,所以没有机器可以拒绝连接。
Python的最大问题之一是没有默认的套接字超时。如果您的数据库没有健康的终结点,则Django应用可能会永远挂起,等待连接到它。我们需要做的是确保在settings.py中正确设置了连接超时(提示:无论如何,您都应该这样做)。根据您使用的数据库后端,这可能会有所不同,因此请阅读文档。
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'myapp', 'USER': 'myapp', 'PASSWORD': os.environ.get('DB_PASS'), 'HOST': 'mysql', 'PORT': '3306', 'OPTIONS': { 'connect_timeout': 3, } } }
然后,您需要确保自己timeoutSeconds
的健康检查时间更长。
readinessProbe: # an http probe httpGet: path: /readiness port: 8080 initialDelaySeconds: 20 timeoutSeconds: 5