当前位置: 首页 > news >正文

第 44篇 k8s之实战:将 Web 应用迁移到 Kubernetes(上)

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。


在第 10 篇中,我们通过docker run命令和自定义网络,手动启动了 Flask + Redis 计数器应用。在第 16 篇中,我们用 Docker Compose 将整个过程声明化,一条docker compose up -d就能启动整个应用栈。

现在,经过了 33 篇 Kubernetes 核心知识的学习——从 Pod、Deployment、Service、Ingress,到 ConfigMap、Secret、PVC、探针、资源管理、调度策略、RBAC、Helm——是时候把这一切串起来了。

这篇和下篇,我们将完成一次完整的应用迁移:把运行在 Docker Compose 中的 Flask + Redis 计数器应用,迁移到 Kubernetes 集群上,并达到生产级标准。今天先完成基础架构部署和配置管理。

一、回顾与规划:从 Compose 到 K8s 的架构映射

1.1 Docker Compose 时代的旧架构

回顾第 10 篇和第 16 篇,我们的 Compose 文件定义了以下组件:

services: redis: image: redis:alpine volumes: - redis-data:/data networks: - app-net flask-app: image: flask-redis-counter:3.0 ports: -"5000:5000"environment: -REDIS_HOST=redis networks: - app-net volumes: redis-data: networks: app-net:

这个架构在单机上运行良好,但迁移到 K8s 需要把每个 Compose 概念映射到对应的 K8s 对象。我们在第 18 篇做过概念映射,现在是把它落地的时候了。

1.2 Kubernetes 目标架构

迁移后的 K8s 架构如下:

┌─────────────────────────────────────────────────────────────┐ │ Kubernetes 集群 │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ Flask Deployment │ │ Redis Deployment │ │ │ │ replicas:3│ │ replicas:1│ │ │ │ ┌──────┐┌──────┐ │ │ ┌──────┐ │ │ │ │ │ Pod1 ││ Pod2 │ │ │ │ Pod │ │ │ │ │ └──────┘└──────┘ │ │ └──────┘ │ │ │ └────────┬─────────┘ └────────┬─────────┘ │ │ │ │ │ │ ┌────────▼─────────┐ ┌────────▼─────────┐ │ │ │ Flask Service │ │ Redis Service │ │ │ │ ClusterIP │ │ ClusterIP │ │ │ └────────┬─────────┘ └──────────────────┘ │ │ │ │ │ ┌────────▼─────────┐ │ │ │ Ingress │ │ │ │ counter.local │ │ │ └──────────────────┘ │ │ │ │ 存储: Redis PVC(1Gi)配置: ConfigMap + Secret │ │ 监控: Prometheus 日志: Loki │ │ 安全: RBAC + NetworkPolicy │ └─────────────────────────────────────────────────────────────┘

迁移对照表

二、准备镜像

2.1 构建并加载镜像

# 构建 Flask 应用镜像(基于第 5 篇的多阶段 Dockerfile)dockerbuild-tflask-redis-counter:3.0.# 输出关键行:# [+] Building 35.2s (17/17) FINISHED# => [runtime 8/9] COPY --chown=appuser:appuser . .# => => naming to docker.io/library/flask-redis-counter:3.0# 加载到 Minikube 环境minikube image load flask-redis-counter:3.0# 验证镜像已加载minikubesshdockerimages|grepflask-redis-counter# flask-redis-counter 3.0 a1b2c3d4e5f6 138MB

2.2 Docker Compose 启动(回顾用)

如果你还想看看 Compose 版本的运行效果作为对照:

[+]Running3/3 ✔ Network flask-redis-counter_app-net Created0.1s ✔ Container redis Healthy5.2s ✔ Container flask-app Started5.5s

测试:

curlhttp://localhost:5000# Hello World! I have been seen 1 times.

关键:从这里开始,我们不再使用 Compose,一切由 K8s 接管。

三、部署 Redis(StatefulSet + Service + PVC)

首先部署应用的基石——Redis 存储层。我们使用 Deployment(单副本,配合 PVC 实现持久化)。

3.1 创建 Redis PVC

# redis-pvc.yamlapiVersion: v1 kind: PersistentVolumeClaim metadata: name: redis-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: standard
kubectl apply-fredis-pvc.yaml# persistentvolumeclaim/redis-pvc createdkubectl get pvc# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS# redis-pvc Bound pvc-a1b2c3d4-e5f6-7890-abcd-ef1234567890 1Gi RWO standard

3.2 部署 Redis

# redis-deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: name: redis spec: replicas:1selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:alpine ports: - containerPort:6379volumeMounts: - name: redis-data mountPath: /data volumes: - name: redis-data persistentVolumeClaim: claimName: redis-pvc --- apiVersion: v1 kind: Service metadata: name: redis-service spec: type: ClusterIP selector: app: redis ports: - port:6379targetPort:6379
kubectl apply-fredis-deployment.yaml# deployment.apps/redis created# service/redis-service createdkubectl get pods-lapp=redis# NAME READY STATUS RESTARTS AGE# redis-xxxxxxxxx-xxxxx 1/1 Running 0 30skubectl get svc redis-service# NAME TYPE CLUSTER-IP PORT(S) AGE# redis-service ClusterIP 10.96.100.50 6379/TCP 30s

四、创建配置(ConfigMap + Secret)

4.1 创建 ConfigMap(非敏感应用配置)

# configmap.yamlapiVersion: v1 kind: ConfigMap metadata: name: flask-config data: FLASK_ENV:"production"LOG_LEVEL:"info"REDIS_HOST:"redis-service"REDIS_PORT:"6379"
kubectl apply-fconfigmap.yaml# configmap/flask-config createdkubectl describe configmap flask-config# Name: flask-config# Namespace: default# Data# ====# FLASK_ENV:# ----# production# LOG_LEVEL:# ----# info

4.2 创建 Secret(敏感信息)

# secret.yamlapiVersion: v1 kind: Secret metadata: name: flask-secret type: Opaque stringData: SECRET_KEY:"my-production-secret-key-2025"
kubectl apply-fsecret.yaml# secret/flask-secret created

五、部署 Flask 应用(Deployment + Service)

5.1 创建 Flask Deployment

# flask-deployment.yamlapiVersion: apps/v1 kind: Deployment metadata: name: flask-deployment labels: app: flask-counter spec: replicas:3selector: matchLabels: app: flask-counter template: metadata: labels: app: flask-counter spec: containers: - name: flask image: flask-redis-counter:3.0 imagePullPolicy: IfNotPresent ports: - containerPort:5000envFrom: - configMapRef: name: flask-config - secretRef: name: flask-secret resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 256Mi startupProbe: httpGet: path: /health port:5000periodSeconds:5failureThreshold:12livenessProbe: httpGet: path: /health port:5000periodSeconds:15failureThreshold:3readinessProbe: httpGet: path: /health port:5000periodSeconds:5failureThreshold:2
kubectl apply-fflask-deployment.yaml# deployment.apps/flask-deployment created

验证部署状态:

kubectl get pods-lapp=flask-counter-w# NAME READY STATUS RESTARTS AGE# flask-deployment-xxxxxxxxx-xxxxx 0/1 ContainerCreating 0 2s# flask-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 15s# flask-deployment-xxxxxxxxx-yyyyy 0/1 ContainerCreating 0 2s# flask-deployment-xxxxxxxxx-yyyyy 1/1 Running 0 15s# flask-deployment-xxxxxxxxx-zzzzz 0/1 ContainerCreating 0 2s# flask-deployment-xxxxxxxxx-zzzzz 1/1 Running 0 15s

查看 Deployment 整体状态:

kubectl get deployments# NAME READY UP-TO-DATE AVAILABLE AGE# flask-deployment 3/3 3 3 30s# redis 1/1 1 1 2m

5.2 创建 Flask Service

# flask-service.yamlapiVersion: v1 kind: Service metadata: name: flask-service spec: type: ClusterIP selector: app: flask-counter ports: - port:5000targetPort:5000
kubectl apply-fflask-service.yaml# service/flask-service createdkubectl get svc# NAME TYPE CLUSTER-IP PORT(S) AGE# flask-service ClusterIP 10.96.200.80 5000/TCP 10s# redis-service ClusterIP 10.96.100.50 6379/TCP 2m

六、验证内部通信与外部访问

6.1 验证内部通信

# 从 Flask Pod 访问 Rediskubectlexecdeploy/flask-deployment -- redis-cli-hredis-service PING# PONG

Flask 应用通过redis-service这个 Service 名称成功连接到了 Redis Pod。DNS 解析和 Service 负载均衡均工作正常。

6.2 端口转发验证

在没有 Ingress 的情况下,用端口转发快速验证:

kubectl port-forward svc/flask-service5000:5000

打开另一个终端:

curlhttp://localhost:5000# Hello World! I have been seen 1 times.curlhttp://localhost:5000# Hello World! I have been seen 2 times.

计数器正常工作,说明 Flask ↔ Redis 通信链路已打通。

6.3 检查各个对象状态

kubectl get all# NAME READY STATUS RESTARTS AGE# pod/flask-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 2m# pod/flask-deployment-xxxxxxxxx-yyyyy 1/1 Running 0 2m# pod/flask-deployment-xxxxxxxxx-zzzzz 1/1 Running 0 2m# pod/redis-xxxxxxxxx-xxxxx 1/1 Running 0 5m## NAME TYPE CLUSTER-IP PORT(S) AGE# service/flask-service ClusterIP 10.96.200.80 5000/TCP 2m# service/redis-service ClusterIP 10.96.100.50 6379/TCP 5m## NAME READY UP-TO-DATE AVAILABLE AGE# deployment.apps/flask-deployment 3/3 3 3 2m# deployment.apps/redis 1/1 1 1 5m

七、本篇总结

  • 架构转换:将 Compose 的 services、ports、environment、volumes 分别映射为 K8s 的 Deployment、Service、ConfigMap、PVC。

  • 存储持久化:Redis 使用 PVC 实现数据持久化,存储类为standard(Minikube 默认)。

  • 配置管理:ConfigMap 管理非敏感配置(Redis 连接信息、日志级别),Secret 管理敏感信息(SECRET_KEY)。Flask Pod 通过envFrom一次性注入。

  • 生产化配置:包含三种探针(startup/liveness/readiness)、资源限制(Requests/Limits),确保应用稳定运行。

下一篇——第 45 篇:实战:将 Web 应用迁移到 Kubernetes(下),我们将继续为应用配置 Ingress 外部入口、HPA 自动伸缩、滚动更新验证,并接入 Prometheus 监控和 Loki 日志系统,完成从开发环境到生产级 K8s 集群的完整迁移。

想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !

http://www.jsqmd.com/news/958156/

相关文章:

  • GEO主流概念解析!2026年 GEO 优化服务商价格一般多少?有哪些公司比较靠谱 ——5 家geo公司供参考 - 互联网科技品牌测评
  • 上海在职MBA院校排名及学费:安泰领衔第一梯队,20万档仍有优质选择
  • 南宁家政钟点工怎么找靠谱的?别只图便宜忽略这三点 - 教育信息速递
  • 从‘玄学’到可控:拆解CUT论文中对比学习如何让AI理解‘风格’与‘内容’
  • 【金融AI工具配置黄金法则】:20年风控专家亲授7大避坑指南与实时合规校验清单
  • 终极Windows实时屏幕翻译工具:Translumo完全指南
  • 用74HC00与非门做个会叫的电子门铃:从电路图到焊板子的保姆级教程
  • MOSFET双向电平转换电路:原理、设计与实战调试指南
  • AI工具产品路线预测实战指南(2024决策者必读版):基于172家SaaS厂商真实演进路径建模
  • 4步解锁旧Mac潜能:让2012款设备流畅运行最新macOS
  • QQ号群组探测工具:验证账号有效性并导出全部加入群信息
  • 计算机小程序毕设实战-基于springboot+微信小程序的在线预约挂号系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 南宁购宠避坑攻略|江南区明轩猫犬舍全国连锁老店,靠谱买猫狗首选 - 萌宠俱乐部
  • MySQL 8.0连接JDBC老报错?可能是驱动和URL没配对!保姆级排查教程(含Educoder环境适配)
  • 实战应用:基于快马生成的Node.js后端框架打造jvid核心API服务
  • 我用AI“团队”3天干完了外包2个月的活:零代码开发,真的杀疯了
  • Python 元对象模型深度解析:`type` 和 `object` 之间到底是什么关系?
  • GEO服务商怎么选?哪家效果和服务和口碑好?2026年6月TOP10靠谱GEO公司对比盘点 - 互联网科技品牌测评
  • 如何轻松上手Ragas:LLM应用评估的终极指南
  • HarmonyOS 6.1 全场景实战|《灵犀厨房》实战(二十八):【数据持久化】收藏与浏览历史——让数据在 App 重启后依然“活着”
  • 委托、多态、继承接口
  • 计算机毕业设计之C5.0决策树算法在学生成绩预测中应用
  • 实战应用:基于快马平台构建可部署的页面每日更新监控系统
  • 极域电子教室破解技术深度解析:从内核驱动到用户态对抗的完整方案
  • 终极免费FF14钓鱼计时器:渔人的直感完整使用教程
  • 航空搜救指挥痛点:三维电子沙盘如何破解复杂地形调度难题
  • Shiply 2026 自研升级API方案对比
  • 从零安装 Claude Code
  • 2026南宁家政公司十大排名,口碑第一名花落谁家?看完这篇不纠结 - 教育信息速递
  • 解锁上班新姿势[特殊字符]