入门实践丨如何在K3s上部署Web应用程序

共 12429字,需浏览 25分钟

 ·

2021-06-24 15:38

直播预告

周五下午14:30,K3s快闪直播开播!将介绍如何在K3s上部署K8S Dashboard以及如何卸载K3s。点击【阅读原文】或扫描下方二维码即可传送到快闪直播现场:



在本文中,我们将使用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.camp2016todos = 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.7COPY . /appWORKDIR /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 5000ENTRYPOINT ["python"]


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


您可以这样构建Docker容器:


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


你将看到这样如下输出:


# ...Successfully built c650af8b7942Successfully 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 ... doneCreating flask-app                                 ... doneAttaching to flask-mongodb-k3s-knative-todoapp_mongo_1, flask-app# ... more output truncatedflask-app   |  * Serving Flask app "app" (lazy loading)flask-app   |  * Environment: productionflask-app   |    WARNING: Do not use the development server in a production environment.flask-app   |    Use a production WSGI server instead.flask-app   |  * Debug mode: onflask-app   |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)flask-app   |  * Restarting with statmongo_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 noNAME      STATUS   ROLES                  AGE     VERSIONartemis   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.yamlkubectl apply -f https://github.com/knative/serving/releases/download/v0.22.0/serving-core.yamlkubectl apply -f https://github.com/knative/net-istio/releases/download/v0.22.0/istio.yamlkubectl 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 -wNAME                                READY   STATUS    RESTARTS   AGEcontroller-57956677cf-2rqqd         1/1     Running   0          3m39swebhook-ff79fddb7-mkcrv             1/1     Running   0          3m39sautoscaler-75895c6c95-2vv5b         1/1     Running   0          3m39sactivator-799bbf59dc-t6v8k          1/1     Running   0          3m39sistio-webhook-5f876d5c85-2hnvc      1/1     Running   0          44snetworking-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,并更深入地探讨其核心特征。我希望你能通过这篇教程,将它们应用到你的应用程序中!



推荐阅读

AutoK3s+k3d,K3s部署体验再升级!

k3d入门指南:在Docker中运行K3s

1款工具助力Rancher HA快速部署,极速提升研发测试效率



About k3s


k3s 是首个进入 CNCF 沙箱项目的 K8S 发行版,同时也是当前全球用户量最大的 CNCF 认证轻量级 K8S 发行版。自2019年3月发布以来,备受全球开发者们关注,至今GitHub Star数已超过 16,000,成为了开源社区最受欢迎的边缘计算 K8S 解决方案。截至目前,K3s全球下载量超过100万次,每周平均被安装超过2万次,其中30%的下载量来自中国。


k3s 专为在资源有限的环境中运行 Kubernetes 的研发和运维人员设计,将满足日益增长的在边缘计算环境中运行在 x86、ARM64 和 ARMv7 处理器上的小型、易于管理的 Kubernetes 集群需求。k3s 的发布,为开发者们提供了以“Rancher 2.X + k3s”为核心的从数据中心到云到边到端的 K8S 即服务(Kubernetes-as-a-Service),推动 Kubernetes Everywhere。

扫码添加k3s中文社区助手

加入官方中文技术社区

官网:https://k3s.io

浏览 27
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报