在本文中,我们将使用Flask和JavaScript编写的、带有MongoDB数据库的TODO应用程序,并学习如何将其部署到Kubernetes上。这篇文章是针对初学者的,如果你之前没有深度接触过Kubernetes集群,也不要担心!

我们将使用K3s,这是一个轻量级的Kubernetes发行版,非常适合快速入门。但首先让我们谈谈我们想要实现的目标。

首先,我将介绍示例应用程序。这其实已经简化了许多细节,但它说明了常见的用例。然后我们将熟悉了解容器化应用程序的过程。在我们继续之前,我会讨论我们如何使用容器来让我们的开发更加轻松,特别是如果我们在一个团队中工作,或者是当我们在一个新的环境中工作时,希望减轻开发人员的负担。

一旦我们将应用程序容器化,下一步就是将它们部署到Kubernetes上。虽然我们可以手动创建服务、Ingress和网关,但我们可以使用Knative以在任何时候都支持我们的应用程序。

设置应用程序

我们将使用一个简单的TODO应用程序来演示前端、REST API后端和MongoDB协同工作。这要归功于Prashant Shahi提出的这个例子。我做了一些小改动,纯粹是为了教学的目的:

https://github.com/prashant-shahi

首先,git clone代码库:

git clone https://github.com/benjamintanweihao/Flask-MongoDB-K3s-KNative-TodoApp

接下来,我们将检查目录,了解情况:


cd Flask-MongoDB-K3s-KNative-TodoApp
tree

该文件夹结构是一个典型的Flask应用程序。Entry point是app.py,它还包含REST APIs。Templates文件夹包含了将被渲染成HTML的文件:

打开 app.py,我们可以看到所有的主要部分:

├── app.py
├── requirements.txt
├── static
│ ├── assets
│ │ ├── style.css
│ │ ├── twemoji.js
│ │ └── twemoji.min.js
└── templates
├── index.html
└── update.html

从上面的代码段,您可以看到应用程序需要MongoDB作为数据库。使用lists()方法,您可以看到如何定义路由(即@ app.route(“/ list”))、如何从MongoDB获取数据,以及模板是如何呈现的示例。

mongodb_host = os.environ.get('MONGO_HOST', 'localhost')
mongodb_port = int(os.environ.get('MONGO_PORT', '27017'))
client = MongoClient(mongodb_host, mongodb_port)
db = client.camp2016
todos = db.todo app = Flask(__name__)
title = "TODO with Flask" @app.route("/list")
def lists ():
#Display the all Tasks
todos_l = todos.find()
a1="active"
return render_template('index.html',a1=a1,todos=todos_l,t=title,h=heading) if __name__ == "__main__":
env = os.environ.get('APP_ENV', 'development')
port = int(os.environ.get('PORT', 5000))
debug = False if env == 'production' else True
app.run(host='0.0.0.0', port=port, debug=debug)

这里需要注意的另一件事是使用了MONGO_HOST和MONGO_PORT的环境变量和Flask相关的环境变量。其中,最重要的是debug。当变量设置为True时,Flask服务器会在检测到和发生更改时自动重新加载。这在开发过程中特别方便,也是我们要充分利用的特性。

用Docker容器开发

在处理应用程序时,我曾经花费大量时间设置环境并安装所有依赖项。在那之后,我可以通过添加新功能来启动和运行。然而,这仅仅描述了一个理想的场景,对吗?

你有多少次回到你已经开发的应用程序(比如六个月前),却发现自己正在慢慢陷入依赖项地狱?依赖项通常是一个灵活的目标,除非您采取措施锁定对象,否则您的应用程序可能无法正常工作。解决这个问题的方法之一是将所有依赖项打包到Docker容器中。

Docker带来的另一件特性是自动化。这意味着不再需要复制和粘贴命令,也不再需要设置数据库之类的东西。

Docker化 Flask程序

以下是Dockerfile:

FROM alpine:3.7
COPY . /app
WORKDIR /app RUN apk add --no-cache bash git nginx uwsgi uwsgi-python py2-pip \
&& pip2 install --upgrade pip \
&& pip2 install -r requirements.txt \
&& rm -rf /var/cache/apk/* EXPOSE 5000
ENTRYPOINT ["python"]

我们从一个最小的(在大小和功能方面)基础镜像开始。然后,应用程序的内容进入容器中的/app目录。接下来,我们执行一系列命令来安装Python、Nginx web server和Flask应用程序的所有需求。这些正是在新系统上设置应用程序所需的步骤。

您可以这样构建Docker容器:

% docker build -t <yourusername>/todo-app .

你将看到这样如下输出:

# ...
Successfully built c650af8b7942
Successfully tagged benjamintanweihao/todo-app:latest

那 MongoDB 呢?

您是否应该经历为MongoDB创建Dockerfile的相同过程?在此之前,已经有人做过这样的尝试,具体演示请查看案例链接:https://hub.docker.com/_/mongo.不过现在您有两个容器,其中Flask容器依赖于MongoDB容器。

一种方法是先启动MongoDB容器,然后启动Flask容器。但是,假设您想添加缓存并决定引入Redis容器。那么启动每个容器的过程会很快变枯燥繁琐。解决方案是Docker Compose,这是一个允许您定义和运行多个Docker容器的工具,正符合我们当前面临的情况。

Docker Compose

以下是Docker compose文件,docker-compose.yaml:

services:
flaskapp:
build: .
image: benjamintanweihao/todo-app:latest
ports:
- 5000:5000
container_name: flask-app
environment:
- MONGO_HOST=mongo
- MONGO_PORT=27017
networks:
- todo-net
depends_on:
- mongo
volumes:
- .:/app # <---
mongo:
image: mvertes/alpine-mongo
ports:
- 27017:27017
networks:
- todo-net networks:
todo-net:
driver: bridge

即使您不熟悉Docker Compose,这里的YAML文件也并不复杂。让我们看一下重要的部分。

在最开头,这个文件定义了由flaskapp和mongo组成的服务,以及指定桥接连接的网络。这将创建一个网络连接,以便服务中定义的容器可以相互通信。

每个服务都定义镜像、端口映射和前面定义的网络。在flaskapp中也定义了环境变量(请查看app.py,看看它们是否确实是相同的)。

我想提醒您注意flask应用程序中指定的volume。我们在这里所做的是将主机的当前目录(应该是包含app.py的项目目录)映射到容器的/app目录 我们为什么要这样做?回想一下,在Dockerfile中,我们将app复制到/app目录中,如下所示:

COPY . /app

假设你想对应用程序做一个更改。你不可能轻易改变容器中的app.py。通过对本地目录的映射,你基本上是在用你目录中的本地副本覆盖容器中的app.py。因此,假设Flask应用程序处于调试模式(如果你在这一点上没有改变任何东西的话,它就是调试模式),当你启动容器并做出改变时,渲染的输出会反映出这个改变。

但是,重要的是要意识到容器中的app.py仍然是旧版本,您仍然需要记住构建新镜像(希望您已将CI/CD设置为自动执行此操作)

让我们看看这是怎么回事。运行以下命令:

docker-compose up

接下来你将看到:

Creating network "flask-mongodb-k3s-knative-todoapp_my-net" with driver "bridge"
Creating flask-mongodb-k3s-knative-todoapp_mongo_1 ... done
Creating flask-app ... done
Attaching to flask-mongodb-k3s-knative-todoapp_mongo_1, flask-app
# ... more output truncated
flask-app | * Serving Flask app "app" (lazy loading)
flask-app | * Environment: production
flask-app | WARNING: Do not use the development server in a production environment.
flask-app | Use a production WSGI server instead.
flask-app | * Debug mode: on
flask-app | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
flask-app | * Restarting with stat
mongo_1 | 2021-05-15T15:41:37.993+0000 I NETWORK [listener] connection accepted from 172.23.0.1:48844 #2 (2 connections now open)
mongo_1 | 2021-05-15T15:41:37.993+0000 I NETWORK [conn2] received client metadata from 172.23.0.1:48844 conn2: { driver: { name: "PyMongo", version: "3.11.4" }, os: { type: "Linux", name: "", architecture: "x86_64", version: "5.8.0-53-generic" }, platform: "CPython 2.7.15.final.0" }
flask-app | * Debugger is active!
flask-app | * Debugger PIN: 183-021-098

现在开始在浏览器中访问:http://localhost:5000

如果你看到这个,恭喜你!Flask和Mongo在一起正常工作了。您可以随意使用应用程序来感受它。

现在让我们对应用程序标题中的app.py做一个小小的改动:

index d322672..1c447ba 100644
--- a/app.py
+++ b/app.py
-heading = "tOdO Reminder"
+heading = "TODO Reminder!!!!!"

保存文件并重新加载应用程序:

完成后,您可以输入以下命令:

docker-compose down

将应用程序部署到Kubernetes上

截至目前,我们已将我们的应用程序及其支持服务(现在只是MongoDB)容器化。我们如何开始将我们的应用程序部署到Kubernetes?

在此之前,让我们安装Kubernetes。为此,我选择了K3s,因为它是安装Kubernetes和启动和运行的最简单方法。

% curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server --no-deploy=traefik"  sh -s -

过一会儿,你就可以安装 Kubernetes了:

[INFO]  Finding release for channel stable
[INFO] Using v1.20.6+k3s1 as release
[INFO] Downloading hash https://github.com/k3s-io/k3s/releases/download/v1.20.6+k3s1/sha256sum-amd64.txt
# truncated ...
[INFO] systemd: Starting k3s

验证是否已正确设置K3s:

% kubectl get no
NAME STATUS ROLES AGE VERSION
artemis Ready control-plane,master 2m53s v1.20.6+k3s1

MongoDB

有多种方法可以完成这一操作。您可以使用我们创建的镜像,MongoDB operator或Helm:

helm install mongodb-release bitnami/mongodb --set architecture=standalone --set auth.enabled=false
 Please be patient while the chart is being deployed 

MongoDB(R) can be accessed on the following DNS name(s) and ports from within your cluster:

    mongodb-release.default.svc.cluster.local

To connect to your database, create a MongoDB(R) client container:

    kubectl run --namespace default mongodb-release-client --rm --tty -i --restart='Never' --env="MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD" --image docker.io/bitnami/mongodb:4.4.6-debian-10-r0 --command -- bash

Then, run the following command:
mongo admin --host "mongodb-release" To connect to your database from outside the cluster execute the following commands: kubectl port-forward --namespace default svc/mongodb-release 27017:27017 &
mongo --host 127.0.0.1

安装Knative和Istio

在本文中,我们将使用Knative。Knative构建在Kubernetes之上,使得开发人员可以很容易地部署和运行应用程序,而不必知道Kubernetes的很多细节。

Knative由两部分组成:Serving和Eventing。在本节中,我们将讨论Serving部分。使用Knative Serving,您可以在几秒钟内创建可弹性伸缩的、安全的和无状态的服务,这就是我们需要对TODO应用程序做的!在此之前,我们先安装Knative:

以下说明基于:

https://knative.dev/docs/install/install-serving-with-yaml/

kubectl apply -f https://github.com/knative/serving/releases/download/v0.22.0/serving-crds.yaml
kubectl apply -f https://github.com/knative/serving/releases/download/v0.22.0/serving-core.yaml
kubectl apply -f https://github.com/knative/net-istio/releases/download/v0.22.0/istio.yaml
kubectl apply -f https://github.com/knative/net-istio/releases/download/v0.22.0/net-istio.yaml

这设置了Knative和istio。你可能想知道为什么我们需要Istio。原因是Knative需要一个Ingress Controller,使其可以执行流量分发(例如, Todo应用程序的版本1和版本2需要同时运行)和自动HTTP请求重试。

Istio有替代方案吗?或许可以考虑Gloo(https://docs.solo.io/gloo-edge/master/installation/knative/)。但当前不支持Traefik,这就是为什么我们在安装K3s时必须禁用它。由于Istio是默认且最受支持的,我们将使用它。

现在等待所有的knative-serving 的pod运行:

kubectl get pods --namespace knative-serving -w
NAME READY STATUS RESTARTS AGE
controller-57956677cf-2rqqd 1/1 Running 0 3m39s
webhook-ff79fddb7-mkcrv 1/1 Running 0 3m39s
autoscaler-75895c6c95-2vv5b 1/1 Running 0 3m39s
activator-799bbf59dc-t6v8k 1/1 Running 0 3m39s
istio-webhook-5f876d5c85-2hnvc 1/1 Running 0 44s
networking-istio-6bbc6b9664-shtd2 1/1 Running 0 44s

设置自定义域

默认情况下,Knative Serving使用example.com作为默认域。如果您按照说明设置了K3s,则应该安装负载均衡器。这意味着通过一些设置,您可以使用sslip.io之类的DNS服务创建自定义域。

sslip.io是一种服务,当使用带有嵌入式IP地址的主机名进行查询时,它会返回该IP地址。例如,192.168.0.1.sslip.io等URL将指向192.168.0.1。这是极好的服务,你不必去买你自己的域名。

继续并应用以下manifest:

kubectl apply -f https://storage.googleapis.com/knative-nightly/serving/latest/serving-default-domain.yaml

如果您打开 serving-default-domain. yaml,您需要在 spec 中注意到以下内容:

# other parts truncated
spec:
serviceAccountName: controller
containers:
- name: default-doma
image: ko://knative.dev/serving/cmd/default-domain
args: ["-magic-dns=sslip.io"]

这将启用您将在下一步中需要使用的DNS。

测试是否一切正常

下载kn二进制文件。您可以查阅链接:https://knative.dev/development/client/install-kn/。一定要重命名二进制文件 kn然后把它放在$PATH的某个地方。一旦解决了这个问题,就继续创建示例Hello World服务。我已经将benjamintanweihao/helloworld python镜像推送到Docker Hub:

% kn service create helloworld-python --image=docker.io/benjamintanweihao/helloworld-python --env TARGET="Python Sample v1"

这将产生以下输出:

Creating service 'helloworld-python' in namespace 'default':

  0.037s The Route is still working to reflect the latest desired specification.
0.099s Configuration "helloworld-python" is waiting for a Revision to become ready.
29.277s ...
29.314s Ingress has not yet been reconciled.
29.446s Waiting for load balancer to be ready
29.605s Ready to serve. Service 'helloworld-python' created to latest revision 'helloworld-python-00001' is available at URL:
http://helloworld-python.default.192.168.86.26.sslip.io

输入以下代码即可列出所有命名空间中所有已部署的Knative服务:

% kn service  list -A

如果有kubectl,这就变成:

% kubectl get ksvc -A

要删除服务,只需执行以下操作:

kn service delete helloworld-python # or kubectl delete ksvc helloworld-python

如果您还没有这样做,请确保TODO应用程序镜像已推送到DockerHub。记住用DockerHub ID替换{username}:

% docker push {username}/todo-app:latest

推送镜像后,可以使用kn命令创建TODO服务。记住用DockerHub ID替换{username}:

kn service create todo-app --image=docker.io/{username}/todo-app --env MONGO_HOST="mongodb-release.default.svc.cluster.local"

如果一切运行顺利,你将看到:

Creating service 'todo-app' in namespace 'default':

  0.022s The Route is still working to reflect the latest desired specification.
0.085s Configuration "todo-app" is waiting for a Revision to become ready.
4.586s ...
4.608s Ingress has not yet been reconciled.
4.675s Waiting for load balancer to be ready
4.974s Ready to serve. Service 'todo-app' created to latest revision 'todo-app-00001' is available at URL:
http://todo-app.default.192.168.86.26.sslip.io

现在访问http://todo-app.default.192.168.86.26.sslip.io (或者在上一个输出的最后一行的内容)您应该可以看到应用程序!现在我们来看看Knative为你做了什么。KNative仅需一行命令就可以为您启动一个服务,并且为您提供了一个可以从集群访问的URL。

我对Knative的了解仅仅停留于表面,但我希望这个教程可以激励你更多地了解它!当我开始看Knative的时候,我不太明白它做了什么。希望这个例子能让我们看到Knative的惊人之处和它的便利性。

结 论

在本文中,我们简要介绍了使用Python构建的web应用程序并需要MongoDB,并学习了如何:

  • 使用Docker容器化TODO应用程序
  • 使用Docker减轻依赖项
  • 使用Docker进行开发
  • 使用Docker Compose打包多个容器
  • 安装K3s
  • 安装Knative(Serving)和Istio
  • 使用Helm署MongoDB
  • 使用Knative部署TODO应用程序

虽然将应用程序迁移到 Kubernetes 当然不是一项简单的任务,但是将应用程序容器化通常会让你成功一半。当然,本文还有很多东西没有涉及,比如安全性和可扩展性。

K3s 是轻量级的Kubernetes发行版,可以极其轻松地使用笔记本/台式机测试和运行 Kubernetes 工作负载,对个人开发者来说十分友好。同时,也十分适合企业在边缘端大规模部署集群。

当我开始研究 Knative 的时候,我并不十分理解它的作用。希望这个例子能够帮助我们理解 Knative 的魅力及其带来的便利。实际上,Knative 的亮点之一就是“在几秒钟之内就能启动一个可扩展的、安全的、无状态的服务”。

我将在以后的文章中更多地介绍 Knative,并更深入地探讨其核心特征。我希望你能通过这篇教程,将它们应用到你的应用程序中!

入门实践丨如何在K3s上部署Web应用程序的更多相关文章

  1. Asp.Net Core 2.0 之旅---在Ubuntu上部署WEB应用程序

    1.Ubuntu 上 安装NET Core 2.0 SDK 第一步的安装,微软大佬已经写的非常详细了=>直达链接,按照教程来即可. 2.将我们的WEB 发布到一个文件夹,将这个文件夹打包成 压缩 ...

  2. Linux上部署web服务器并发布web项目-转

    Linux上部署web服务器并发布web项目   近在学习如何在linux上搭建web服务器来发布web项目,由于本人是linux新手,所以中间入了不少坑,搞了好久才搞出点成果.以下是具体的详细步骤以 ...

  3. 在Linux上部署Web项目

    You believe it or not there is a feeling, lifetime all not lost to time. 在Linux上部署Web项目 这个是普通的web项目, ...

  4. 用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面

    用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面 1.什么是跨域以及产生原因 跨域是指a页面想获取b页面资源,如果a.b页面的协议.域名.端口.子域名不同,或是a页面为ip地 ...

  5. Linux上部署web服务器并发布web项目

    近在学习如何在linux上搭建web服务器来发布web项目,由于本人是linux新手,所以中间入了不少坑,搞了好久才搞出点成果.以下是具体的详细步骤以及我对此做的一些总结和个人的一些见解,希望对跟我一 ...

  6. 在jboss上部署web应用

    1.JBoss介绍 JBoss完全实现了J2EE的服务栈: EJB (Enterprise JavaBeans) JMS (Java Message Service) JTS/JTA (Java Tr ...

  7. Azure Terraform(三)部署 Web 应用程序

    一,引言 上一节关于 Terraform 的文章讲到 Terraform 使用到的一些语法,以及通过演示使用 Terraform 在Azure 上部署资源组,极大的方便了基础设施实施人员,也提高了基础 ...

  8. 部署WEB应用程序

    部署WEB应用程序: 1.在模板机上新建IIS站点 2.安装WebDeploy后在IIS控制台中导出站点为应用程序包 其站点在新虚机上必须存在,否则会报错,如下: 应用程序(C:\ProgramDat ...

  9. 如何:使用 Visual Studio 中的一键式发布来部署 Web 应用程序项目

    原文: 如何:使用 Visual Studio 中的一键式发布来部署 Web 应用程序项目 本主题介绍如何在以下产品中使用 一键式发布 发布(部署)Web 应用程序项目: Visual Studio ...

随机推荐

  1. 深度解析对象的hashcode和equals的差异,以及String的内存分配方式

    Q:Java对象的hashcode是怎么得到的 A:Java对象的hashcode是native方法,不是通过Java实现的.hashcode的值是根据对象的内存地址得到的一串数字. Q:如果两个对象 ...

  2. 02 CTF WEB 知识梳理

    1. 工具集 基础工具 Burpsuit, Python, FireFox(Hackbar, FoxyProxy, User-Agent Swither .etc) Burpsuit 代理工具,攻击w ...

  3. 7. IDEA概述和安装

    1.1IDEA概述 IDEA全称InteliJ IDEA,是用于Java语言开发的继承环境,它是业界公认的目前用于Java程序开发的最好工具 集成环境:把代码编写,编译,执行,调试等多种功能综合到一起 ...

  4. 啥?SynchronousQueue和钟点房一个道理

    今天这篇文章,我们继续讲架构师大刘的故事. 大刘有段时间经常会给一些程序员讲课.这一方面是由于团队培训的需要,一方面也是大刘自身想搞搞凡尔赛,嘚瑟一下自身的实力. 大刘讲课是允许公司任何一个人进去听的 ...

  5. [BD] Flume

    什么是Flume 采集日志,存在HDFS上 分布式.高可用.高可靠的海量日志采集.聚合和传输系统 支持在日志系统中定制各类数据发送方,用于收集数据 支持对数据进行简单处理,写到数据接收方 组件 sou ...

  6. Ansible_包含和导入playbook文件

    一.管理大型的playbook 1️⃣:如果playbook很长或很复杂,我们可以将其分成较小的文件以便于管理 2️⃣:可采用模块化方式将多个playbook组合为一个主要playbook,或者将文件 ...

  7. 025.Python面向对象以及对对象的操作

    一 面向对象基本概念 1.1 OOP面向对象的程序开发 用几大特征表达一类事物称为一个类,类更像是一张图纸,表达只是一个抽象概念 对象是类的具体实现,更像是由这图纸产出的具体物品,类只有一个,但是对象 ...

  8. 012.Python的字典和集合的相关函数

    一 字典的相关函数 1.1 增函数 dictvar = {"a":1,"b":2} dictvar["c"] = 3 print(dictv ...

  9. easyui datagrid 自定义单元格单击与双击事件(Day_38)

    $(function(){ $('#tableId').datagrid({//单击事件   onClickRow:function(rowIndex,rowData){  alert("单 ...

  10. 阿里云RDs 网络白名单 专用网络 经典网络

    云服务为了安全性总是有不同的安全规则,第一就是需要明白里面的网络类型   专有网络是您自己独有的云上私有网络.您可以完全掌控自己的专有网络,例如选择IP地址范围.配置路由表和网关等,您可以在自己定义的 ...