如何使用 Kubernetes 部署可扩展且安全的 Django 应用程序

介绍

在本教程中,您将一个容器化的 Django 轮询应用程序部署到 Kubernetes 集群中。

Django是一个强大的 Web 框架,可以帮助您快速启动 Python 应用程序。它包括几个方便的功能,例如对象关系映射器、用户身份验证和应用程序的可自定义管理界面。它还包括一个缓存框架,并通过其URL 调度程序模板系统鼓励干净的应用程序设计

How to Build a Django and Gunicorn Application with Docker 中Django Tutorial Polls 应用程序根据用于构建可扩展的云原生 Web 应用程序十二因素方法进行了修改这个容器化设置通过 Nginx 反向代理和 Let’s Encrypt-signed TLS 证书进行了扩展和保护,如何使用 Docker、Nginx 和 Let’s Encrypt扩展和保护Django 应用程序使用 Django 从容器到 Kubernetes系列的最后一个教程中,现代化的 Django 轮询应用程序将部署到 Kubernetes 集群中。

Kubernetes是一个强大的开源容器编排器,可自动部署、扩展和管理容器化应用程序。像 ConfigMaps 和 Secrets 这样的 Kubernetes 对象允许您将配置与容器集中和分离,而像 Deployments 这样的控制器会自动重启失败的容器并实现容器副本的快速扩展。TLS 加密通过 Ingress 对象和ingress-nginx开源 Ingress Controller启用证书经理Kubernetes附加使用免费的续签和颁发证书让我们的加密证书颁发机构。

先决条件

要学习本教程,您需要:

设置好这些组件后,您就可以开始使用本指南了。

步骤 1 — 克隆和配置应用程序

在此步骤中,我们将从 GitHub 克隆应用程序代码并配置数据库凭据和对象存储密钥等设置。

应用程序代码和 Dockerfile 可以polls-docker在 Django Tutorial Polls App GitHub 存储库分支中找到这个 repo 包含 Django 文档的示例 Polls application 的代码,它教你如何从头开始构建一个轮询应用程序。

polls-docker分支包含此 Polls 应用程序的 Dockerized 版本。要了解如何修改 Polls 应用程序以在容器化环境中有效工作,请参阅如何使用 Docker 构建 Django 和 Gunicorn 应用程序

首先使用将 Django Tutorial Polls App GitHub 存储库gitpolls-docker分支克隆到您的本地机器:

  • git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

导航到django-polls目录:

  • cd django-polls

该目录包含 Django 应用程序 Python 代码,DockerfileDocker 将使用该代码构建容器映像,以及一个env包含要传递到容器运行环境的环境变量列表文件。检查Dockerfile

  • cat Dockerfile
Output
FROM python:3.7.4-alpine3.10 ADD django-polls/requirements.txt /app/requirements.txt RUN set -ex \ && apk add --no-cache --virtual .build-deps postgresql-dev build-base \ && python -m venv /env \ && /env/bin/pip install --upgrade pip \ && /env/bin/pip install --no-cache-dir -r /app/requirements.txt \ && runDeps="$(scanelf --needed --nobanner --recursive /env \ | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ | sort -u \ | xargs -r apk info --installed \ | sort -u)" \ && apk add --virtual rundeps $runDeps \ && apk del .build-deps ADD django-polls /app WORKDIR /app ENV VIRTUAL_ENV /env ENV PATH /env/bin:$PATH EXPOSE 8000 CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "mysite.wsgi"]

此 Dockerfile 使用官方 Python 3.7.4 Docker 映像作为基础,并安装django-polls/requirements.txt文件中定义的 Django 和 Gunicorn 的 Python 包要求然后删除一些不必要的构建文件,将应用程序代码复制到映像中,并设置执行PATH最后,它声明 port8000将用于接受传入的容器连接,并gunicorn与 3 个 worker 一起运行,监听 port 8000

要了解有关此 Dockerfile 中每个步骤的更多信息,请参阅如何使用 Docker 构建 Django 和 Gunicorn 应用程序的步骤 6

现在,使用docker build以下命令构建图像

  • docker build -t polls .

我们polls使用-t标志命名图像并将当前目录作为构建上下文传递,即构建图像时要引用的文件集。

在 Docker 构建并标记镜像后,使用docker images以下命令列出可用镜像

  • docker images

您应该会看到polls列出图像:

OutputREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
polls               latest              80ec4f33aae1        2 weeks ago         197MB
python              3.7.4-alpine3.10    f309434dea3a        8 months ago        98.7MB

在我们运行 Django 容器之前,我们需要使用env当前目录中存在文件来配置它的运行环境这个文件会传入docker run用于运行容器命令中,Docker会将配置好的环境变量注入到容器的运行环境中。

env使用nano或您喜欢的编辑器打开文件

  • nano env
django-民意调查/环境
DJANGO_SECRET_KEY=
DEBUG=True
DJANGO_ALLOWED_HOSTS=
DATABASE_ENGINE=postgresql_psycopg2
DATABASE_NAME=polls
DATABASE_USERNAME=
DATABASE_PASSWORD=
DATABASE_HOST=
DATABASE_PORT=
STATIC_ACCESS_KEY_ID=
STATIC_SECRET_KEY=
STATIC_BUCKET_NAME=
STATIC_ENDPOINT_URL=
DJANGO_LOGLEVEL=info

填写以下键的缺失值:

  • DJANGO_SECRET_KEY:将其设置为唯一的、不可预测的值,如Django 文档中所述调整可扩展 Django 应用教程的应用设置提供了一种生成此密钥的方法
  • DJANGO_ALLOWED_HOSTS:此变量保护应用程序并防止 HTTP 主机标头攻击。出于测试目的,将此设置为*,将匹配所有主机的通配符。在生产中,您应该将其设置为your_domain.com. 要了解有关此 Django 设置的更多信息,请参阅Django 文档中的核心设置
  • DATABASE_USERNAME:将此设置为在先决条件步骤中创建的 PostgreSQL 数据库用户。
  • DATABASE_NAME:将此设置为polls或在先决条件步骤中创建的 PostgreSQL 数据库的名称。
  • DATABASE_PASSWORD:将此设置为在先决条件步骤中创建的 PostgreSQL 用户密码。
  • DATABASE_HOST:将其设置为数据库的主机名。
  • DATABASE_PORT:将其设置为您的数据库端口。
  • STATIC_ACCESS_KEY_ID:将此设置为您的空间或对象存储的访问密钥。
  • STATIC_SECRET_KEY:将此设置为您的空间或对象存储的访问密钥 Secret。
  • STATIC_BUCKET_NAME:将此设置为您的空间名称或对象存储桶。
  • STATIC_ENDPOINT_URL:将其设置为适当的 Spaces 或对象存储端点 URL,例如,如果您的 Space 位于该区域。https://your_space_name.nyc3.digitaloceanspaces.comnyc3

完成编辑后,保存并关闭文件。

在下一步中,我们将在本地运行配置的容器并创建数据库架构。我们还将将样式表和图像等静态资产上传到对象存储。

第 2 步 – 创建数据库架构并将资产上传到对象存储

构建和配置容器后,使用命令docker run覆盖CMDDockerfile 中的集合并创建数据库模式manage.py makemigrationsmanage.py migrate

  • docker run --env-file env polls sh -c "python manage.py makemigrations && python manage.py migrate"

我们运行polls:latest容器镜像,传入我们刚刚修改的环境变量文件,并用 覆盖 Dockerfile 命令sh -c "python manage.py makemigrations && python manage.py migrate",这将创建由应用程序代码定义的数据库架构。

如果您是第一次运行它,您应该看到:

Output
No changes detected Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying polls.0001_initial... OK Applying sessions.0001_initial... OK

这表明已成功创建数据库模式。

如果您在migrate后续运行,除非数据库架构已更改,否则 Django 将执行空操作。

接下来,我们将运行应用程序容器的另一个实例,并在其中使用交互式 shell 为 Django 项目创建管理用户。

  • docker run -i -t --env-file env polls sh

这将在正在运行的容器内为您提供一个 shell 提示,您可以使用它来创建 Django 用户:

  • python manage.py createsuperuser

为您的用户输入用户名、电子邮件地址和密码,创建用户后,点击CTRL+D退出容器并杀死它。

最后,我们将为应用程序生成静态文件并使用collectstatic. 请注意,这可能需要一些时间才能完成。

  • docker run --env-file env polls sh -c "python manage.py collectstatic --noinput"

生成并上传这些文件后,您将收到以下输出。

Output
121 static files copied.

我们现在可以运行应用程序:

  • docker run --env-file env -p 80:8000 polls
Output
[2019-10-17 21:23:36 +0000] [1] [INFO] Starting gunicorn 19.9.0 [2019-10-17 21:23:36 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1) [2019-10-17 21:23:36 +0000] [1] [INFO] Using worker: sync [2019-10-17 21:23:36 +0000] [7] [INFO] Booting worker with pid: 7 [2019-10-17 21:23:36 +0000] [8] [INFO] Booting worker with pid: 8 [2019-10-17 21:23:36 +0000] [9] [INFO] Booting worker with pid: 9

在这里,我们运行在Dockerfile,定义的默认命令gunicorn --bind :8000 --workers 3 mysite.wsgi:application,并揭露集装箱港口8000,使港口80在本地计算机上被映射到端口8000的的polls容器。

您现在应该可以polls通过http://localhost在 URL 栏中键入来使用 Web 浏览器导航到该应用程序由于没有为路径定义路由/,您可能会收到一个404 Page Not Found错误,这是意料之中的。

导航到http://localhost/pollsPolls 应用程序界面:

投票应用界面

要查看管理界面,请访问http://localhost/admin您应该会看到 Polls 应用程序管理员身份验证窗口:

投票管理员身份验证页面

输入您使用该createsuperuser命令创建的管理用户名和密码

身份验证后,您可以访问 Polls 应用的管理界面:

投票管理主界面

请注意,应用程序adminpolls应用程序的静态资产直接从对象存储交付。要确认这一点,请参阅测试空间静态文件交付

完成探索后,CTRL+C在运行 Docker 容器的终端窗口中点击以终止容器。

测试 Django 应用 Docker 映像、将静态资产上传到对象存储、配置数据库架构并准备好与您的应用一起使用后,您就可以将 Django 应用映像上传到 Docker Hub 等映像注册表。

第 3 步 – 将 Django 应用镜像推送到 Docker Hub

要在 Kubernetes 上推出您的应用程序,您的应用程序映像必须上传到诸如Docker Hub 之类的注册表Kubernetes 将从其存储库中提取应用程序映像,然后将其部署到您的集群。

您可以使用私有 Docker 注册表,例如DigitalOcean Container Registry,目前在 Early Access 中免费,或者使用公共 Docker 注册表,例如 Docker Hub。Docker Hub 还允许您创建私有 Docker 存储库。公共存储库允许任何人查看和拉取容器映像,而私有存储库允许您限制对您和您的团队成员的访问。

在本教程中,我们会将 Django 映像推送到先决条件中创建的公共 Docker Hub 存储库。您也可以将图像推送到私有存储库,但从私有存储库中提取图像超出了本文的范围。要了解有关使用 Docker Hub 对 Kubernetes 进行身份验证和提取私有映像的更多信息,请参阅Kubernetes 文档中的从私有注册表中提取映像。

首先登录到本地机器上的 Docker Hub:

  • docker login
Output
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username:

输入您的 Docker Hub 用户名和密码进行登录。

Django 图像当前具有polls:latest标记。要将其推送到您的 Docker Hub 存储库,请使用您的 Docker Hub 用户名和存储库名称重新标记镜像:

  • docker tag polls:latest your_dockerhub_username/your_dockerhub_repo_name:latest

将图像推送到 repo:

  • docker push sammy/sammy-django:latest

在本教程中,Docker Hub 用户名是sammy,repo 名称是sammy-django您应该将这些值替换为您自己的 Docker Hub 用户名和存储库名称。

您将看到一些输出,这些输出随着图像层被推送到 Docker Hub 而更新。

现在,您的映像可用于 Docker Hub 上的 Kubernetes,您可以开始在集群中推出它。

第 4 步 – 设置 ConfigMap

当我们在本地运行 Django 容器时,我们将env文件传入docker run以将配置变量注入运行时环境。在 Kubernetes 上,可以使用ConfigMapsSecrets注入配置变量

ConfigMaps 应该用于存储非机密的配置信息,如应用程序设置,而 Secrets 应该用于存储 API 密钥和数据库凭据等敏感信息。它们都以类似的方式注入到容器中,但 Secrets 具有额外的访问控制和安全功能,例如静态加密Secrets 也以 base64 格式存储数据,而 ConfigMaps 以纯文本格式存储数据。

首先,创建一个名为的目录yaml,我们将在其中存储 Kubernetes 清单。导航到目录。

  • mkdir yaml
  • cd

打开一个名为polls-configmap.yamlnano或者您喜欢的文本编辑器:

  • nano polls-configmap.yaml

粘贴以下 ConfigMap 清单:

polls-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: polls-config
data:
  DJANGO_ALLOWED_HOSTS: "*"
  STATIC_ENDPOINT_URL: "https://your_space_name.space_region.digitaloceanspaces.com"
  STATIC_BUCKET_NAME: "your_space_name"
  DJANGO_LOGLEVEL: "info"
  DEBUG: "True"
  DATABASE_ENGINE: "postgresql_psycopg2"

我们已经从env步骤 1 中修改文件中提取了非敏感配置并将其粘贴到 ConfigMap 清单中。ConfigMap 对象被称为polls-config复制在env上一步中输入到文件中的相同值

出于测试目的,离开DJANGO_ALLOWED_HOSTS作为*对禁用基于主机的报头的过滤。在生产环境中,您应该将其设置为您的应用程序域。

完成文件编辑后,保存并关闭它。

使用kubectl apply以下命令在集群中创建 ConfigMap

  • kubectl apply -f polls-configmap.yaml
Output
configmap/polls-config created

创建 ConfigMap 后,我们将在下一步中创建我们的应用程序使用的 Secret。

第 5 步 – 设置秘密

Secret 值必须是base64 编码的,这意味着在集群中创建 Secret 对象比创建 ConfigMap 稍微复杂一些。您可以重复上一步的过程,手动对 Secret 值进行 base64 编码并将它们粘贴到清单文件中。您还可以使用环境变量文件kubectl create--from-env-file标志创建它们 ,我们将在此步骤中执行此操作。

我们将再次使用步骤 1 中env文件,删除插入到 ConfigMap 中的变量。复制目录中调用文件:envpolls-secretsyaml

  • cp ../env ./polls-secrets

在首选编辑器中编辑文件:

  • nano polls-secrets
民意调查秘密
DJANGO_SECRET_KEY=
DEBUG=True
DJANGO_ALLOWED_HOSTS=
DATABASE_ENGINE=postgresql_psycopg2
DATABASE_NAME=polls
DATABASE_USERNAME=
DATABASE_PASSWORD=
DATABASE_HOST=
DATABASE_PORT=
STATIC_ACCESS_KEY_ID=
STATIC_SECRET_KEY=
STATIC_BUCKET_NAME=
STATIC_ENDPOINT_URL=
DJANGO_LOGLEVEL=info

删除插入到 ConfigMap 清单中的所有变量。完成后,它应该如下所示:

民意调查秘密
DJANGO_SECRET_KEY=your_secret_key
DATABASE_NAME=polls
DATABASE_USERNAME=your_django_db_user
DATABASE_PASSWORD=your_django_db_user_password
DATABASE_HOST=your_db_host
DATABASE_PORT=your_db_port
STATIC_ACCESS_KEY_ID=your_space_access_key
STATIC_SECRET_KEY=your_space_access_key_secret

请务必使用与步骤 1 中使用的值相同的值完成后,保存并关闭文件。

使用kubectl create secret以下命令在您的集群中创建 Secret

  • kubectl create secret generic polls-secret --from-env-file=poll-secrets
Output
secret/polls-secret created

这里我们创建了一个 Secret 对象,polls-secret并传入我们刚刚创建的 secrets 文件。

您可以使用kubectl describe以下方法检查 Secret

  • kubectl describe secret polls-secret
Output
Name: polls-secret Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== DATABASE_PASSWORD: 8 bytes DATABASE_PORT: 5 bytes DATABASE_USERNAME: 5 bytes DJANGO_SECRET_KEY: 14 bytes STATIC_ACCESS_KEY_ID: 20 bytes STATIC_SECRET_KEY: 43 bytes DATABASE_HOST: 47 bytes DATABASE_NAME: 5 bytes

此时,您已使用 Secret 和 ConfigMap 对象类型将应用程序的配置存储在 Kubernetes 集群中。我们现在已准备好将应用程序部署到集群中。

第 6 步 – 使用部署推出 Django 应用程序

在此步骤中,您将为 Django 应用创建部署。Kubernetes 部署是一个控制器,可用于管理集群中的无状态应用程序。控制器是一个控制回路,通过放大或缩小来调节工作负载。控制器还会重新启动并清除失败的容器。

部署控制一个或多个 Pod,这是 Kubernetes 集群中最小的可部署单元。Pod 包含一个或多个容器。要了解有关您可以启动的不同类型工作负载的更多信息,请查看Kubernetes 简介

首先打开一个polls-deployment.yaml在您喜欢的编辑器中调用的文件

  • nano polls-deployment.yaml

粘贴以下部署清单:

polls-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: polls-app
  labels:
    app: polls
spec:
    replicas: 2
  selector:
    matchLabels:
      app: polls
  template:
    metadata:
      labels:
        app: polls
    spec:
      containers:
        - image: your_dockerhub_username/app_repo_name:latest
          name: polls
          envFrom:
          - secretRef:
              name: polls-secret
          - configMapRef:
              name: polls-config
          ports:
            - containerPort: 8000
              name: gunicorn

填写适当的容器镜像名称,引用您在步骤 2 中推送到 Docker Hub 的 Django Polls 镜像

在这里,我们定义了一个名为 Kubernetes Deploymentpolls-app并用键值对标记它app: polls我们指定要运行template字段下方定义的 Pod 的两个副本

使用envFromsecretRefconfigMapRef,我们指定所有从数据polls-secret保密和polls-configConfigMap应注入容器的环境变量。ConfigMap 和 Secret 键成为环境变量名称。

最后,我们公开containerPort 8000并命名它gunicorn

要了解有关配置 Kubernetes 部署的更多信息,请参阅Kubernetes 文档中的部署

完成文件编辑后,保存并关闭它。

使用kubectl apply -f以下命令在集群中创建部署

  • kubectl apply -f polls-deployment.yaml
  • deployment.apps/polls-app created

使用以下命令检查部署是否正确推出kubectl get

  • kubectl get deploy polls-app
Output
NAME READY UP-TO-DATE AVAILABLE AGE polls-app 2/2 2 2 6m38s

如果您遇到错误或某些事情不太正常,您可以使用kubectl describe来检查失败的部署:

  • kubectl describe deploy

您可以使用kubectl get pod以下命令检查两个 Pod

  • kubectl get pod
Output
NAME READY STATUS RESTARTS AGE polls-app-847f8ccbf4-2stf7 1/1 Running 0 6m42s polls-app-847f8ccbf4-tqpwm 1/1 Running 0 6m57s

您的 Django 应用程序的两个副本现已启动并在集群中运行。要访问该应用程序,您需要创建一个 Kubernetes 服务,我们将在接下来进行。

步骤 7 — 允许使用服务进行外部访问

在此步骤中,您将为 Django 应用程序创建一个服务。Kubernetes Service 是一种抽象,它允许您将一组正在运行的 Pod 公开为网络服务。使用 Service,您可以为您的应用程序创建一个稳定的端点,该端点不会随着 Pod 死亡和重新创建而改变。

有多种服务类型,包括 ClusterIP 服务,它在集群内部 IP 上公开服务,NodePort 服务,在每个节点上的称为 NodePort 的静态端口上公开服务,以及 LoadBalancer 服务,它提供一个云负载均衡器。将外部流量定向到集群中的 Pod(通过它自动创建的 NodePorts)。要了解有关这些的更多信息,请参阅Kubernetes 文档中的服务

在我们的最终设置中,我们将使用一个使用 Ingress 公开的 ClusterIP 服务,以及在本指南的先决条件中设置的 Ingress Controller。现在,为了测试一切是否正常运行,我们将创建一个临时的 NodePort 服务来访问 Django 应用程序。

首先polls-svc.yaml使用您喜欢的编辑器创建一个名为的文件

  • nano polls-svc.yaml

粘贴以下服务清单:

polls-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: polls
  labels:
    app: polls
spec:
  type: NodePort
  selector:
    app: polls
  ports:
    - port: 8000
      targetPort: 8000

在这里,我们创建了一个名为 NodePort 的服务polls并为其指定app: polls标签。然后我们选择带有app: polls标签的后端 Pod并定位它们的8000端口。

完成文件编辑后,保存并关闭它。

使用kubectl apply以下方法推出服务

  • kubectl apply -f polls-svc.yaml
Output
service/polls created

确认您的服务是使用kubectl get svc以下方法创建的

  • kubectl get svc polls
Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE polls NodePort 10.245.197.189 <none> 8000:32654/TCP 59s

此输出显示服务的集群内部 IP 和 NodePort ( 32654)。要连接到服务,我们需要集群节点的外部 IP 地址:

  • kubectl get node -o wide
Output
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME pool-7no0qd9e0-364fd Ready <none> 27h v1.18.8 10.118.0.5 203.0.113.1 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9 pool-7no0qd9e0-364fi Ready <none> 27h v1.18.8 10.118.0.4 203.0.113.2 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9 pool-7no0qd9e0-364fv Ready <none> 27h v1.18.8 10.118.0.3 203.0.113.3 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9

在您的 Web 浏览器中,使用任何 Node 的外部 IP 地址和 NodePort 访问您的 Polls 应用程序。鉴于上面的输出,应用程序的 URL 将是:http://203.0.113.1:32654/polls

您应该会看到与您在步骤 1 中本地访问的相同的 Polls 应用程序界面:

投票应用界面

您可以使用/adminroute:重复相同的测试您应该会看到与以前相同的管理界面:http://203.0.113.1:32654/admin

投票管理员身份验证页面

在此阶段,您已使用 Deployment 推出了 Django Polls 应用程序容器的两个副本。您还为这两个副本创建了一个稳定的网络端点,并使用 NodePort 服务使其可从外部访问。

本教程的最后一步是使用 HTTPS 保护到您的应用程序的外部流量。为此,我们将使用ingress-nginx先决条件中安装入口控制器,并创建一个入口对象来将外部流量路由到pollsKubernetes 服务。

第 8 步 – 使用 Nginx Ingress 和 cert-manager 配置 HTTPS

Kubernetes Ingresses允许您灵活地将流量从 Kubernetes 集群外部路由到集群内部的服务。这是使用 Ingress 对象完成的,这些对象定义了将 HTTP 和 HTTPS 流量路由到 Kubernetes 服务的规则,以及 Ingress Controllers,它们通过负载平衡流量并将其路由到适当的后端服务来实现规则。

在先决条件中,您安装了ingress-nginx入口控制器和cert-manager TLS 证书自动化插件。您还使用 Let’s Encrypt 证书颁发机构为您的域设置了临时和生产 ClusterIssuers,并创建了一个 Ingress 来测试证书颁发和 TLS 加密到两个虚拟后端服务。在继续此步骤之前,您应该删除echo-ingress先决条件教程中创建Ingress

  • kubectl delete ingress echo-ingress

如果您愿意,也可以使用kubectl delete svc删除虚拟服务和部署kubectl delete deploy,但这对于完成本教程不是必需的。

您还应该创建一个指向 Ingress 负载均衡器公共 IP 地址的 DNSA记录your_domain.com如果您使用的是 DigitalOcean 负载均衡器,您可以在控制面板负载均衡器部分找到此 IP 地址如果您还使用 DigitalOcean 来管理域的 DNS 记录,请参阅如何管理 DNS 记录以了解如何创建A记录。

如果您使用的是 DigitalOcean Kubernetes,还要确保您已经实施了如何在 DigitalOcean Kubernetes 上使用 Cert-Manager 设置 Nginx Ingress 的步骤 5 中描述的解决方法

一旦你有一个A记录指向入口控制器负载均衡器,你可以创建一个入口并your_domain.compolls服务。

polls-ingress.yaml使用您喜欢的编辑器打开一个名为的文件

  • nano polls-ingress.yaml

粘贴以下 Ingress 清单:

[polls-ingress.yaml]
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: polls-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-staging"
spec:
  tls:
  - hosts:
    - your_domain.com
    secretName: polls-tls
  rules:
  - host: your_domain.com
    http:
      paths:
      - backend:
          serviceName: polls
          servicePort: 8000

我们创建一个名为的 Ingress 对象polls-ingress并对其进行注释,以指示控制平面使用 ingress-nginx Ingress Controller 和暂存 ClusterIssuer。我们还为your_domain.com证书和私钥启用 TLS并将其存储在名为polls-tls. 最后,我们定义了一个规则来将your_domain.com主机的流量路由polls端口上的服务8000

完成文件编辑后,保存并关闭它。

使用kubectl apply以下命令在集群中创建 Ingress

  • kubectl apply -f polls-ingress.yaml
Output
ingress.networking.k8s.io/polls-ingress created

您可以使用kubectl describe来跟踪您刚刚创建的 Ingress 的状态:

  • kubectl describe ingress polls-ingress
Output
Name: polls-ingress Namespace: default Address: workaround.your_domain.com Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) TLS: polls-tls terminates your_domain.com Rules: Host Path Backends ---- ---- -------- your_domain.com polls:8000 (10.244.0.207:8000,10.244.0.53:8000) Annotations: cert-manager.io/cluster-issuer: letsencrypt-staging kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 51s nginx-ingress-controller Ingress default/polls-ingress Normal CreateCertificate 51s cert-manager Successfully created Certificate "polls-tls" Normal UPDATE 25s nginx-ingress-controller Ingress default/polls-ingress

您还可以describepolls-tls证书运行 a以进一步确认其成功创建:

  • kubectl describe certificate polls-tls
Output
. . . Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Issuing 3m33s cert-manager Issuing certificate as Secret does not exist Normal Generated 3m32s cert-manager Stored new private key in temporary Secret resource "polls-tls-v9lv9" Normal Requested 3m32s cert-manager Created new CertificateRequest resource "polls-tls-drx9c" Normal Issuing 2m58s cert-manager The certificate has been successfully issued

这确认 TLS 证书已成功颁发并且 HTTPS 加密现在对your_domain.com.

鉴于我们使用了暂存 ClusterIssuer,大多数 Web 浏览器不会信任它颁发的假 Let’s Encrypt 证书,因此导航到your_domain.com会带您到错误页面。

要发送测试请求,我们将wget从命令行使用

  • wget -O - http://your_domain.com/polls
Output
. . . ERROR: cannot verify your_domain.com's certificate, issued by ‘CN=Fake LE Intermediate X1’: Unable to locally verify the issuer's authority. To connect to your_domain.com insecurely, use `--no-check-certificate'.

我们将使用建议的--no-check-certificate标志来绕过证书验证:

  • wget --no-check-certificate -q -O - http://your_domain.com/polls
Output
<link rel="stylesheet" type="text/css" href="https://your_space.nyc3.digitaloceanspaces.com/django-polls/static/polls/style.css"> <p>No polls are available.</p>

此输出显示/polls界面页面的 HTML ,同时确认样式表是从对象存储提供的。

现在您已经使用暂存 ClusterIssuer 成功测试了证书颁发,您可以修改 Ingress 以使用生产 ClusterIssuer。

polls-ingress.yaml再次打开编辑:

  • nano polls-ingress.yaml

修改cluster-issuer注解:

[polls-ingress.yaml]
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: polls-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - your_domain.com
    secretName: polls-tls
  rules:
  - host: your_domain.com
    http:
      paths:
      - backend:
          serviceName: polls
          servicePort: 8000

完成后,保存并关闭文件。使用kubectl apply以下命令更新 Ingress

  • kubectl apply -f polls-ingress.yaml
Output
ingress.networking.k8s.io/polls-ingress configured

您可以使用kubectl describe certificate polls-tlskubectl describe ingress polls-ingress跟踪证书颁发状态:

  • kubectl describe ingress polls-ingress
Output
. . . Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 23m nginx-ingress-controller Ingress default/polls-ingress Normal CreateCertificate 23m cert-manager Successfully created Certificate "polls-tls" Normal UPDATE 76s (x2 over 22m) nginx-ingress-controller Ingress default/polls-ingress Normal UpdateCertificate 76s cert-manager Successfully updated Certificate "polls-tls"

以上输出确认新的生产证书已成功颁发并存储在polls-tlsSecret 中。

your_domain.com/polls在 Web 浏览器中导航到以确认 HTTPS 加密已启用且一切正常。您应该会看到 Polls 应用程序界面:

投票应用界面

验证 HTTPS 加密在您的 Web 浏览器中处于活动状态。如果您使用的是谷歌浏览器,在没有任何错误的情况下到达上述页面即确认一切正常。此外,您应该会在 URL 栏中看到一个挂锁。单击挂锁将允许您检查 Let’s Encrypt 证书详细信息。

作为最后的清理任务,您可以选择将polls服务类型从 NodePort 切换到仅限内部使用的 ClusterIP 类型。

polls-svc.yaml使用您的编辑器进行修改

  • nano polls-svc.yaml

type将从更改NodePortClusterIP

polls-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: polls
  labels:
    app: polls
spec:
  type: ClusterIP
  selector:
    app: polls
  ports:
    - port: 8000
      targetPort: 8000

完成文件编辑后,保存并关闭它。

使用kubectl apply以下方法展开更改

  • kubectl apply -f polls-svc.yaml --force
Output
service/polls configured

使用以下命令确认您的服务已修改kubectl get svc

  • kubectl get svc polls
Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE polls ClusterIP 10.245.203.186 <none> 8000/TCP 22s

This output shows that the Service type is now ClusterIP. The only way to access it is via your domain and the Ingress created in this step.

Conclusion

In this tutorial you deployed a scalable, HTTPS-secured Django app into a Kubernetes cluster. Static content is served directly from object storage, and the number of running Pods can be quickly scaled up or down using the replicas field in the polls-app Deployment manifest.

If you’re using a DigitalOcean Space, you can also enable delivery of static assets via a content delivery network and create a custom subdomain for your Space. Please consult Enabling CDN from How to Set Up a Scalable Django App with DigitalOcean Managed Databases and Spaces to learn more.

要查看本系列的其余部分,请访问我们的从容器到 Kubernetes with Django 系列页面

觉得文章有用?

点个广告表达一下你的爱意吧 !😁