乐趣区

关于kubernetes:在django使用kubernetes健康检查

引言

在上一篇文章中,我写了无关 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 logging

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 中,如果 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 上部署应用程序的探讨。

退出移动版