如何为Kubernetes构建RESTful Python Flask API

时间:2020-01-09 10:34:20  来源:igfitidea点击:

说明

在本教程中,我们将学习如何通过构建可用于生产环境的Docker容器来为Kubernetes构建RESTful Flask API。

这篇文章提供的解决方案将使用Kubernetes部署,这将允许我们扩展应用程序。部署还提供了其他功能,以控制新映像更新的部署方式以及如何处理故障。

我们还将学习如何为Pod创建服务以暴露它们,以及如何使用机密获取敏感信息。

uWSGI应用服务器

为了运行Flask API,需要一个应用服务器。有一些服务器可用,但是,本教程将介绍uWSGI。另一个受欢迎的选择是gUnicorn。

NGINX Web服务器

Web服务器将处理所有传入的请求,然后将它们反向代理到应用程序服务器。尽管容器可以单独运行应用程序服务器,但是Web服务器可以更好地控制命中Flask API的流量。

NGINX是一种高效的,事件驱动的Web服务器,能够处理大量流量。添加uWSGI后端支持也非常简单。

基本的Flask API

以下是基本的Flask REST API,将用于演示目的。该应用程序将被编写为将与MySQL数据库连接的简单CRUD api。

配置存储在config.py文件中,该文件将存储数据库连接设置。

请注意,没有任何环境信息静态存储在config.py中。作为Docker的最佳实践以及扩展的Kubernetes,特定于环境的信息不应存储在Docker容器中。

更重要的是不要将凭据存储在容器或者代码中。所有敏感信息(称为机密信息)都应由机密文件库处理,例如Hashicorp Vault,或者在本教程中为Kubernetes Secrets。

可以在运行时从Vault或者Kubernetes Secrets中获取机密。

关于Kubernetes秘密的注释

Kubernetes Secrets可轻松存储敏感数据和文件。虽然在本教程中以处理机密为例,但必须记住,其目的只是将机密传输到Pod,以供容器使用。

强烈建议设置为在音乐会中使用Hashicorp Vault和Kubernetes机密。 Hashicorp Vault将是所有机密的授权,并且这些机密将同步到Kubernetes机密。

不幸的是,这超出了本教程的范围。

构建Docker映像

在创建Docker映像之前,我们需要一个Dockerfile。让我们花一点时间来理解支持我们编写的REST API所需的Dockerfile。

Flask具有内置的Web服务器,在开发过程中非常有用,但是,强烈建议我们不要将其用于生产。原因很简单,内置服务器是单处理单线程的。

线程不足是并发问题。 REST API将无法处理大量流量。

按照最佳实践,本教程中的Flask应用程序将使用uWSGI作为服务器。

回到Dockerfile,没有运行Flask应用程序的官方映像。相反,我们将使用官方的Python3映像并在此映像的基础上进行构建。

在项目目录中创建一个名为Dockerfile的新文件

touch Dockerfile

用以下行启动Dockerfile

FROM python:3.6-slim

该映像将提供一个基于Ubuntu的容器,该容器经过精简后可以运行Python。社区提供的图像要小得多。

Dockerfile还应该包含用于安装软件包更新的行,以解决错误修复和漏洞,以及安装所有必备组件。 Flask应用程序的前提条件是:python3-dev和build-essentials。

RUN apt-get clean \
    && apt-get -y update

RUN apt-get -y install \
    nginx \
    python3-dev \
    build-essential

将任何配置添加到以上行下方的容器中安装的服务中。

COPY nginx.conf /etc/nginx/nginx.com

该应用程序将从容器内名为/ app的目录中运行。将此设置为工作目录。

WORKDIR /app

现在,让我们将requirements.txt文件添加到容器中,然后安装Flask应用程序的依赖项。

COPY requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt --src /usr/local/src

该容器仍缺少Flask应用程序本身,将在以下几行中添加它。

COPY app.py /app/app.py
COPY config.py /app/config.py
COPY uwsgi.ini /app/wsgi.ini
COPY startup.sh /app/startup.sh

启动脚本将需要是可执行的,因此需要针对它运行chmod命令。

RUN chmod +x ./startup.sh

最后,让我们通过端口80公开容器,并使该容器作为startup.sh脚本运行。

EXPOSE 80
CMD [ "./startup.sh" ]

将映像发布到注册表

为了在Kubernetes中部署Flask Docker映像,必须将其发布到Kubernetes可以访问的容器注册表中。将新版本推入注册表很重要。

Dockerhub

要将映像部署到Dockerhub,我们需要首先进行身份验证。

码头工人登录

出现提示时,输入Dockerhub登录凭据。成功通过身份验证后,身份验证令牌将存储在本地,这将使我们可以在不包含凭证的情况下针对Dockerhub运行命令。

任何推送到存储库的映像都必须在其名称中包含存储库信息。对于Dockerhub,该映像必须以Dockerhub ID开头。

使用以下命令为存储库添加标签。

docker -t flask-api:1.0.0 theitroad/flask-api:1.0.0

可以使用我们应用于它的新标签将我们的映像推送到Dockerhub。

docker push theitroad/flask-api:1.0.0

在Kubernetes机密中存储数据库凭证

绝不能将秘密存储为纯文本,代码或者任何Kubernetes清单中的内容。密码,证书和任何其他敏感数据应远离应用程序存储。

在本教程中,我们将使用Kubernetes Secrets作为我们的秘密存储区。 Flask应用程序的数据库凭据可以存储在此处,并在将其Docker映像部署为Pod时检索。

机密存储为Base64编码的字符串。让我们在base64中编码数据库的用户名和密码。

echo -n 'db-username' | base64
echo -n 'my-super-secret-password' | base64

这两个命令都将输出一串看似随机的字符,例如下面的示例。记下它们。

c3VwZXItc2VjcmV0LXBhc3N3b3JkCg==

现在创建一个名为flaskapi-secrets.yml的新文件,并向其中添加以下内容。

---
apiVersion: v1
kind: Secret
metadata:
  name: flaskapi-secrets
type: Opaque
data:
  db_username: ZGItdXNlcm5hbWU=
  db_password: c3VwZXItc2VjcmV0LXBhc3N3b3JkCg==

在数据下添加了两个键。一个键将存储数据库用户名的值,另一个键将存储数据库密码。

键的值是先前创建的base64编码的字符串。

使用kubectl apply命令将密钥添加到Kubernetes。

kubectl apply -f flaskapi-secrets.yml

创建完成后,将此文件存储在远离应用程序和任何其他清单的地方。它应该始终受到严格的保护。或者,我们可以在完成后删除此文件。

创建Kubernetes部署

本教程中使用的Flask应用程序是无状态的,这意味着会话不绑定到特定实例,也不存储任何用户会话信息。这是一个简单的API,这意味着我们可以放大或者缩小它而不必担心状态。

Kubernetes部署是在Kubernetes中部署应用程序的理想方式。部署使我们可以根据需要轻松地放大或者缩小应用程序。

部署允许我们设置部署策略,该策略用于处理Pod故障和Docker映像更新。

当Flask应用程序的Deployment清单更新为使用新的映像版本并随后应用时,Deployment控制器允许我们设置部署策略。默认情况下,必须先成功部署应用程序的新版本,然后才能删除旧版本。

以下是Kubernetes部署的示例。它将用于部署具有3个副本的Flask应用程序。

创建一个名为flaskapp-deployment.yml的新文件,并将以下内容添加到其中。确保将图像名称(当前为theitroad / flask-api:1.0.0)替换为我们自己的图像名称。

请注意清单中CONTAINER键下的ENV键。 Flask API会获取环境设置的环境变量。这使我们能够在从DEV到UAT到Production的任何环境中使用完全相同的映像。

部署部署

使用kubectl apply命令在Kubernetes集群上创建部署。还有一个create命令,但是apply命令使我们能够更轻松地应用更新的清单。

kubectl apply -f flaskapi-deployment.yml

要验证是否成功创建了部署,请使用kubectl get svc命令。

kubectl get svc

最后,要验证创建的部署是否正常,请使用kubectl get pods命令。

kubectl get pods

如果任何Pod处于失败状态,则kubectl get pods命令将仅显示基本信息。有关Pod的更多详细信息,请使用describe命令。

kubectl describe pod <pod-name>

Pod日志

日志对于识别和排除任何错误至关重要。要查看容器中的日志,请使用kubectl log <pod name>命令。

kubectl log flaskapi-abcd1234

重要的是要记住,Docker和Kubernetes只会输出发送到STDOUT的日志。始终确保应用程序运行应用程序导出的任何服务将日志记录为STDOUT。

创建一个Kubernetes服务

服务使我们可以将Pod内部公开给其他Pod,外部公开给公众。每个服务都分配有一个静态分配的内部IP地址,这使我们可以连接到该服务。

另一方面,Pod是临时的,替换旧的或者失效的Pod的新Pod将不会重新使用IP地址。因此,始终建议我们连接到服务而不是Pods。

要为Flask应用程序创建服务,请创建一个名为flaskapi-service.yml的新文件。

向其添加以下行: