引言
在上一篇文章中,我写了无关Kubernetes健康检查的文章,作为Python的开发人员和粉丝,我开始着手在Django中实现它。 运行健康检查是帮助Kubernetes让你的利用具备高可用性的好办法,例如Django利用。 然而,应用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模型的状况下执行数据库查看,因而我间接生成了查问。
因为memcached客户端不反对ping办法,因而我还能够通过调用get_stats()来对服务器进行ping操作,从而查看高速缓存服务器是否可用。
import loggingfrom django.http import HttpResponse, HttpResponseServerErrorlogger = 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中,如果service没有endpoints(即所有mysql或memcached pod均未通过就绪查看),那么当连贯到该服务时,该服务的cluster IP将无法访问,因为它是虚构IP,所以没有机器能够回绝连贯。
Python的最大问题之一是没有默认的套接字超时。 如果你的数据库没有衰弱的endpoints,那么你的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
弹性Django网站
心愿这能够帮忙你编写更具弹性的Django网站! Django在Docker,Kubernetes和容器化风行之前就曾经写得很好了,而Django应用程序也能够很容易地适应它们。 一些PaaS解决方案(例如Eldarion Cloud))曾经让应用Kubernetes部署Python应用程序变得更容易。
如果有趣味理解无关Kubernetes的更多信息,请查看Kubernetes Slack),最好的Kubernetes开发人员在那里汇集在一起探讨Kubernetes的所有内容,查看#sig-apps频道,以获取无关在Kubernetes上部署应用程序的探讨。