作者:阳明。Kubernetes 布道师,公众号 K8s 技术圈主理人

最近我们新开发了一个项目 fastclass.cn,这个项目是一个独立开发者的学习网站,我们的目标是帮助你使用 Figma、Python、Golang、React、VUE、Flutter、ChatGPT 等设计构建真实的应用程序,助你成为一个全栈开发者,算是在 youdianzhishi.com 的基础上的一个延伸。

由于该项目还处于早期阶段,所以我们需要尽可能地提高效率,减少重复劳动,这样才能更快地推出新的课程。该项目使用的技术栈如下:

  • 前端:React、Next.js、Tailwind CSS
  • 后端:Python、Django、MySQL、Celery、Redis

因为之前的项目是直接用 Docker 方式部署到阿里云的服务器上面的,为了节约成本,自然我们还是使用 Docker 容器的方式部署这个项目,但是由于该项目涉及到更多的服务,比如 Next.js、Celery 这些都比较消耗资源,导致我们的服务器性能不够,所以需要另外一种低成本的方式来部署,最好还能应对不断增长的流量。

Sealos 简介

在这种情况下,我就想到了 Kubernetes,因为 Kubernetes 可以很好地解决这个问题,但是如果我自己搭建 Kubernetes 集群的话,成本又会比较高,使用云服务商的 Kubernetes 服务,比如阿里云的 ACK、腾讯云的 TKE 等,成本也不会太低。这个时候想到了 Sealos 的云服务,其官网介绍:Sealos 是一个无需云计算专业知识,就能在几秒钟内部署、管理和扩展应用的云操作系统。就像使用个人电脑一样!

当然最终选择直接使用 Sealos 云服务主要还是因为其高效、经济:仅需为容器付费,自动伸缩杜绝资源浪费,大幅度节省成本。

这确实是非常符合我们的需求的,我完全不需要一个完整的 Kubernetes 集群,说白了就是我只需要跑几个 Pod 就行,不需要去维护整个集群,这样就能大大减少成本(经济成本、运维成本等),而且 Sealos 云服务还提供了很多功能,比如自动伸缩、监控、日志等,这些都是我需要的,有这样的服务,我就可以专注于开发,而不用去管运维了,何乐而不为呢?

Sealos 是一个基于 Kubernetes 的云服务,所以要使用 Sealos 云服务,建议你最好了解一下 Kubernetes 的基本概念,比如 Pod、Service、Deployment、Ingress 等,这样会更容易上手,当然不了解也不影响你使用,因为 Sealos 云服务提供了很好的界面,你可以很容易地完成部署、管理、扩展等操作。

容器化

当然首先需要将我们的服务容器化,打包成 Docker 镜像,我们的后端服务代码结构如下所示:

容器化说白了就是将我们的服务打包成 Docker 镜像,我们的后端服务是一个 Django 项目,对应的 Dockerfile 内容如下所示:

FROM python:3.11.4-slim-buster

LABEL author=icnych@gmail.com

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV DEBUG False WORKDIR /app RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && \
apt-get update && \
apt-get install -y pkg-config python3-dev default-libmysqlclient-dev build-essential
RUN pip install --upgrade pip --index-url https://mirrors.sustech.edu.cn/pypi/simple && \
pip config set global.index-url https://mirrors.sustech.edu.cn/pypi/simple
COPY . .
RUN pip install -r requirements.txt
RUN apt-get clean autoclean && \
apt-get autoremove --yes && \
rm -rf /var/lib/{apt,dpkg,cache,log}/ \ EXPOSE 8000 CMD ["gunicorn", "--bind", ":8000", "--workers", "4", "--access-logfile", "-", "--error-logfile", "-", "fastclass.wsgi:application"]

这个 Dockerfile 文件很简单,就是基于 python:3.11.4-slim-buster 镜像构建,然后安装一些依赖,最后运行 gunicorn 启动 Django 项目。

另外需要注意我们这里使用了 Celery 来处理异步任务,使用的 Redis 做为 Broker,所以需要在 Django 的配置文件中配置 Celery,内容如下所示:

# ==========Celery===========
REDIS_URL = os.getenv("REDIS_URL", "localhost:6379")
REDIS_USER = os.getenv("REDIS_USER", "default")
REDIS_PASSWORD = os.getenv("REDIS_PASSWORD", "default")
REDIS_BROKER_DB = 1
REDIS_RESULT_DB = 2
CELERY_BROKER_URL = (
f"redis://{REDIS_USER}:{REDIS_PASSWORD}@{REDIS_URL}/{REDIS_BROKER_DB}"
)
#: Only add pickle to this list if your broker is secured
#: from unwanted access (see userguide/security.html)
CELERY_ACCEPT_CONTENT = ["json"]
CELERY_RESULT_BACKEND = (
f"redis://{REDIS_USER}:{REDIS_PASSWORD}@{REDIS_URL}/{REDIS_RESULT_DB}"
)
CELERY_TASK_SERIALIZER = "json"
CELERY_TIMEZONE = "Asia/Shanghai"
CELERY_ENABLE_UTC = True

这里我们使用了环境变量来配置 Redis 的连接信息,这样就可以在容器启动的时候通过环境变量来配置。当然还有数据库的连接信息也是通过环境变量配置的,这样就可以很方便地在不同环境中配置不同的连接信息。

DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": os.getenv("DB_NAME", "fastclass"),
"USER": os.getenv("DB_USER", "root"),
"PASSWORD": os.getenv("DB_PASSWORD", "root"),
"HOST": os.getenv("DB_HOST", "localhost"),
"PORT": os.getenv("DB_PORT", 3306),
"OPTIONS": {"charset": "utf8mb4"},
}
}

接下来就是前端的 Next.js 项目,对应的项目结构如下所示:

同样需要将我们的 Next.js 项目容器化,对应的 Dockerfile 内容如下所示:

FROM node:18.19.0-alpine3.18 AS base
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat # 2. Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY . . # 切换镜像源
RUN npm config set registry https://repo.nju.edu.cn/repository/npm/ && npm install sharp && npm install --production && npm run build FROM base AS runner
WORKDIR /app/web ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
ENV NEXT_TELEMETRY_DISABLED 1 # copy need files(this can exclude code files)
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/docker/pm2.json ./pm2.json
COPY --from=builder /app/docker/entrypoint.sh /entrypoint.sh
COPY --from=builder /app/next.config.js ./next.config.js RUN npm install pm2 -g && chmod +x /entrypoint.sh EXPOSE 3000 ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]

这里我们采用的是一个多阶段构建的方式,首先是基于 node:18.19.0-alpine3.18 镜像构建,然后安装依赖,最后使用 pm2 来启动 Next.js 项目。pm2 是一个 Node.js 进程管理工具,可以很方便地管理 Node.js 进程,比如启动、停止、重启等。这里我们通过 ENTRYPOINT 定义了一个脚本 entrypoint.sh,内容如下所示:

#!/bin/bash
set -e
#if [[ -z "$APP_URL" ]]; then
# export NEXT_PUBLIC_PUBLIC_API_PREFIX=${APP_API_URL}/api
#else
# export NEXT_PUBLIC_PUBLIC_API_PREFIX=${APP_URL}/api
#fi
#
#export NEXT_PUBLIC_SENTRY_DSN=${SENTRY_DSN}
/usr/local/bin/pm2 -v
/usr/local/bin/pm2-runtime --raw start /app/web/pm2.json

这个脚本主要是启动 pm2,对应的 pm2.json 文件内容如下所示:

{
"apps": [
{
"name": "FastClass",
"exec_mode": "cluster",
"instances": 2,
"script": "./node_modules/next/dist/bin/next",
"cwd": "/app/web",
"args": "start"
}
]
}

最后分别前后端服务构建成 Docker 镜像,然后推送到镜像仓库,这样我们的服务就容器化完成了。

部署

现在有了应用镜像,接下来只需要将这些镜像部署到 Sealos 云服务上面就行了。

首先当然需要注册一个账号,前往 cloud.sealos.run 注册即可,国内用户需要实名认证,初始会提供 5 元的试用金,可以用来体验一下,整个控制台界面如下所示:

然后我们可以根据自己的业务需求选择不同的可用区域,我们这里选择的是北京 A区域。

由于我们的后端应用依赖 MySQL 和 Redis 数据库,所以我们首先要创建这两个数据库,Sealos 也是提供了单独的数据库服务的(底层使用的是 kubeblocks),选择新建数据库,然后选择要创建的数据库类型,我们先选择 MySQL 数据库。

然后我们可以配置数据库的名称、CPU、内存资源,我们可以选择最低配置,如果后面发现资源不够,可以随时变更资源,这里我们配置的 CPU 和内存实际上就是 Pod 里面的 limit 资源,另外就是实例数建议最低配置为 3 个,这样可以保证数据库的高可用性,在左侧也有对应的资源预估价格显示。我们也可以切换查看对应的 YAML 资源清单文件:

其实这就是 KubeBlocks 的一个 CR 实例。配置完成后点击右上角的"部署"按钮,等待部署完成即可。用同样的方式再部署一个 Redis 数据库即可。

点击查看详情,在左侧可以看到数据库的连接信息,我们的后端服务需要用到这些信息。在右侧可以看到数据库的实时监控信息,我们可以根据这些信息来调整数据库的资源配置,此外还可以备份数据库,在线导入数据等。

数据库准备好过后,接下来就可以部署我们的应用了,点击首页的"应用管理",开始新建应用。首先我们来部署后端服务,在表单中填上后端服务的镜像相关信息。然后部署模式有固定实例和弹性伸缩两种模式,弹性伸缩也就是我们熟悉的 HPA 模式,比如我们这里配置的是内存使用率超过 80% 时,自动扩容到 2 个 Pod,同样还可以配置 CPU、内存等资源。

如果想要对外暴露后端服务,可以在网络配置中开启公网访问,也就是创建一个 Ingress 资源,这样就可以通过公网访问我们的后端服务了,我们这里暂时不需要,所以不勾选。

另外还需要在高级配置里面配置环境变量,比如数据库连接信息、Redis 连接信息等,这样我们的后端服务就可以连接到数据库和 Redis 了。

我们只需要简单的在页面上填写一些配置信息,其实就对应着 Kubernetes 里面的一些资源,比如 Deployment、Service、Ingress、HPA、Secret 等,Sealos 云服务会根据我们的配置信息生成对应的资源清单文件,然后部署到 Kubernetes 集群上面。

配置完成后点击右上角的"部署"按钮,等待部署完成即可,部署完成后我们可以在应用列表中看到我们的后端服务已经部署成功了。

用同样的方式部署前端服务,这里需要注意的是需要开启公网访问,因为我们的前端服务是需要对外暴露的,这样用户才能访问到我们的网站。

而且需要注意开启公网访问后,系统会自动为我们分配一个域名,我们肯定是希望使用自己的域名,所以需要自定义域名,需要在域名服务商处添加自定义域名的 CNAME 解析到这个自动生成的域名地址。

这样我们的前端服务就可以通过自定义域名访问了,但是这里还有一个问题,就是我们的前端 Next.js 服务还需要访问我们的后端服务,当我们访问 https://fastclass.cn 的时候会访问到前端服务,但是当访问 https://fastclass.cn/api/xxx 的时候需要访问到后端服务,这个时候就需要配置 Ingress 路由规则,将 /api 路由转发到后端服务,但是 Sealos 云服务的页面上目前还不支持配置 Ingress 路由规则,所以我们需要手动配置 Ingress 路由规则。

点击"终端"就可以进入到 Kubernetes 集群的终端界面,然后我们可以通过 kubectl 来管理 Kubernetes 集群,首先需要将 fastclass.cn 的 https 证书导入到 Kubernetes 集群中,用一个 Secret 对象来存储证书信息,然后我们修改下系统自动生成的 Ingress 对象,将 https 证书换成我们自己的证书。

然后再创建一个新的 Ingress 对象,用来配置后端服务的路由规则,这样我们的前端服务就可以访问到后端服务了,如下所示:

这样我们就可以正常访问我们的网站了。除此之外我们还需要部署下 Celery 服务,用来处理后端的异步任务的。和部署后端服务类似,也是使用相同的镜像和环境变量,不过需要注意的是这里我们不是启动 Web 服务,而是启动 Celery Worker 服务,所以需要修改启动命令。

同样还有一个定时任务服务,用来定时执行一些任务,这里我们使用的是 Celery Beat 服务,同样需要使用相同的镜像和环境变量,不过需要修改启动命令,命令如下所示:

celery -A fastclass beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler

最终我们部署了 4 个服务,分别是前端服务、后端服务、Celery Worker 服务、Celery Beat 服务,这样我们的应用就部署完成了。

后续其他的功能服务,我们也可以采用微服务的方式来部署,非常方便。

KubePanel 里面也可以看到我们整个集群的资源使用情况,相当于一个 Kubernetes 集群 Dashboard。

如果控制台页面不支持的一些 Kubernetes 功能特性,我们还可以通过终端来自行操作,就相当于我们平时使用的 Kubernetes 集群一样。

此外我们还可以将集群的 kubeconfig 文件导入到本地,这样我们就可以使用 kubectl 命令在本地来管理集群了。

在费用中心也可以看到我们的消费详细账单信息。

我们这里只是使用了 Sealos 的一部分功能,还有很多其他功能,比如对象存储、云开发等等能力,大家可以自行探索。

这不比买 ECS 服务器折腾来得简单方便吗?成本也降低不少,如果你是一个创业团队,需要小步快跑,快速验证产品,那么 Sealos 绝对是你应用托管的一个最佳选择。

Sealos 就是小团队的神器的更多相关文章

  1. 记一次小团队Git实践(下)

    在上篇中,我们已经能基本使用git了,接下来继续更深入的挖掘一下git. 更多的配置自定义信息 除了前面讲的用户名和邮箱的配置,还可以自定义其他配置: # 自定义你喜欢的编辑器,可选 git conf ...

  2. 记一次小团队Git实践(中)

    对于初学者,从使用上先入手,往往学的最快,并从中汲取教训,再回头更深入的学习,效果尤佳. 安装git 安装git自不必说,mac已经内置了git,linux下一个命令就能搞定,windows下需要下载 ...

  3. 记一次小团队Git实践(上)

    公司规模不大,成立之初,选择了svn作为版本控制系统.这对于用惯了git的我来说,将就了一段时间后,极为不爽,切换到git-svn勉强能用.随后,因为产品需要发布不同的版本,而git-svn对远程分支 ...

  4. Git 在小团队中的管理流程(转)

    目标读者:了解 Git 的基本概念,能够使用 Git 进行基本的本地和远程操作. 有关 Git 的基础知识可以参见 知乎回答-怎样使用 GitHub?,天猪(刘勇)给出了一些很好的学习资料. 本文介绍 ...

  5. 小代码编写神器:LINQPad 使用入门

    原文:小代码编写神器:LINQPad 使用入门 一:概述 1:想查看程序运行结果,又不想启动 VS 怎么办? 2:想测试下自己的 C# 能力,不使用 VS 的智能感知,怎么办? 那么,我们有一个选择, ...

  6. 小团队git开发模式

    实验室要使用Git进行代码管理,但是git非常复杂,各种开发模式也是层出不穷.作为新手的偶们很是发囧啊!!网上搜了一下,发现很多并不适合我们小团队运作(它本身就是为Linux内核管理而开发的分布式代码 ...

  7. IT小团队的管理者的突围之道

    笔者前几天被问到一个问题,你在团队管理方面有什么值得分享的吗?咋一听,实用千言万语,但是事后回忆说出来的东西感觉空无一物,缺少干货.故想通过写一篇随笔思考整理一下,刷新一下自己对小团队管理的认知.这里 ...

  8. 小团队Git协作流程

    git和svn 最大的差异在于git是分布式的管理方式而svn是集中式的管理方式. 集中式 集中式代码管理的核心是服务器,所有开发者在开始coding之前必须从服务器获取代码,然后开发,最后解决冲突, ...

  9. Git 在小团队中的管理流程

    目标读者:了解 Git 的基本概念,能够使用 Git 进行基本的本地和远程操作. 有关 Git 的基础知识可以参见 知乎回答-怎样使用 GitHub?,天猪(刘勇)给出了一些很好的学习资料. 本文介绍 ...

  10. gogs 小团队使用

    最近小团队开始使用 gogs 来保存手头的项目.具体的使用流程如下: 由 root 用户新建 organization, 比如说建立 hardware,然后把团队的 技术负责人拉到 owners 这个 ...

随机推荐

  1. Freertos学习:08-信号量

    --- title: rtos-freertos-08-ipc-semaphore date: 2020-06-23 11:01:12 categories: tags: - freertos - i ...

  2. [HDCTF 2023]BabyMisc

    BabyMisc ...脑洞坑题(如果7z密码不是那一串超长字符串真不至于0解) 先打开Script.zip,随便打开一个文件夹,得到的是pxx的文件,内容为16进制字节.猜测pxx为对应字节的位置 ...

  3. yb课堂实战之轮播图接口引入本地缓存 《二十一》

    轮播图接口引入缓存 CacheKeyManager.java package net.ybclass.online_ybclass.config; /** * 缓存key管理类 */ public c ...

  4. ScreenToGif:一款开源免费且好用的录屏转Gif软件

    ScreenToGif介绍 GitHub上的介绍:此工具允许您记录屏幕的选定区域.来自网络摄像头的实时提要或来自草图板的实时绘图.之后,您可以编辑动画并将其保存为 gif.apng.视频.psd 或 ...

  5. 深入解析 Vue Router:构建单页面应用的利器

    Vue.js 是一个渐进式 JavaScript 框架,常用于构建用户界面.随着应用的复杂度增加,路由(Routing)变得越来越重要,这就是 Vue Router 的用武之地.Vue Router ...

  6. influxdb得导出与导入

    转载请注明出处: 1.备份元数据 基本语法: influxd backup <path-to-backup> 备份元数据,没有任何其他参数,备份将只转移当前状态的系统元数据到path-to ...

  7. 最简GIF解析代码gif_jumper,用于stb_image的小改进

    gif jumper gif支持多帧动画,但是没有存储总帧数,解析gif直到结束才能知道总帧数. 所以gif解析代码,要么采用链表,要么不停realloc()分配内存,stb_image的代码就是如此 ...

  8. [oeasy]python0085_ASCII之父_Bemer_COBOL_数据交换网络

    编码进化 回忆上次内容 上次 回顾了 字符编码的 进化过程 IBM 在数字化过程中 作用 非常大 IBM 的 BCDIC 有 黑历史 6-bit的 BCDIC 直接进化成 8-bit的 EBCDIC ...

  9. [oeasy]python0072_修改字体前景颜色_foreground_color_font

    修改颜色 回忆上次内容 m 可以改变字体样式 0-9 之间设置的都是字体效果 0 重置为默认 1 变亮 2 变暗 3 斜体 4 下划线 5 慢闪 6 快闪 7 前景背景互换 8 隐藏 9 中划线 叠加 ...

  10. ASP.NET Core 程序集注入(三)

    前言: 在Autofac的使用中,提供了个种注入的API其中GetAssemblies()用着特别的舒坦. 1.core2.0也可以使用Autofac的包,但框架自身也提供了默认的注入Api,ISer ...