# 云原生 · K8s :传统业务迁移的步骤详解与部署案例
2026/9/6 23:57:25 网站建设 项目流程

传统业务系统迁移到 Kubernetes 集群的完整指南


第一部分:迁移的理论步骤(“云原生”化流程)

将传统业务系统迁移到 Kubernetes 集群,本质上是将应用逐步“云原生”化的过程。核心思路是:先将应用“容器化”,再将其“编排”到 K8s 集群中。以下是标准步骤:

1.1 将应用封装进容器(镜像构建)

应用容器化是迁移的第一步,需要设计并规划好 Docker 镜像的构建方案。由于 Docker 镜像具有分层特性,建议按以下层次构建(分层构建有利于复用和加速构建):

  • 操作系统层:制作公司常用的系统版本(如 Rocky Linux、Ubuntu),可在官方基础镜像上添加自己需要的软件包(如网络工具、vim 等)。
  • 运行环境层:在操作系统层之上,打包业务常用的运行环境,例如:
    • JDK 7 / JDK 8 / JDK 11
    • JDK 8 + Tomcat 8 / Tomcat 9
    • Python 3 环境
    • Nginx + PHP-FPM 等
      这些可作为通用基础镜像模板供不同项目使用。
  • 应用层:在通用运行环境的基础上,根据具体应用进行调整(如添加特定依赖、配置文件),最后将编译好的代码(JAR/WAR 或源码)放入镜像中。

1.2 将容器放入 Pod 中

应用容器化后,就需要考虑如何在Pod中运行。Pod 是 Kubernetes 管理的最小单元,Kubernetes 不直接管理容器,而是管理 Pod,一个 Pod 可以包含一个或多个容器。

需要决策:

  • 单容器 Pod还是多容器 Pod(例如主容器 + 辅助容器如日志收集 sidecar)?
  • 为 Pod 设置资源限制(CPU/内存 requests 和 limits)。
  • 配置健康检查(livenessProbe 和 readinessProbe)。
  • 确定是否需要数据持久化(挂载 Volume)。

1.3 使用控制器 (Controllers) 管理 Pod

单一 Pod 如果出现故障,会影响业务连续性,因此需要多副本(类似传统集群)。Kubernetes 提供了多种Controller,需根据应用类型选择合适的控制器,只需在 Pod 模板上封装对应配置即可:

控制器用途
Deployment封装了 Pod 的副本管理、滚动更新、回滚、扩缩容等功能,适用于无状态应用(最常用)。
DaemonSet保证集群中每个 Node 上有且只有一个 Pod 在运行,常用于节点监控、日志收集等。
StatefulSet为有状态应用提供稳定的网络标识(如主机名)和有序部署/扩缩容,适用于数据库、消息队列等。
Job运行一次性任务(如批处理),任务完成后 Pod 自动退出。
CronJob运行定时任务(类似 Linux crontab)。

1.4 使用 Service 管理 Pod 访问

使用 Deployment 通过多副本保证了 Pod 的高可用和横向扩展,此时需要负载均衡将流量分发到多个 Pod。KubernetesService就是实现此功能的资源对象,它为 Pod 提供稳定的访问入口(ClusterIP)。

Service 的负载均衡实现方式支持两种模式:iptablesipvs(后者性能更高)。Service 类型主要有:

  • ClusterIP(默认):仅集群内部访问。
  • NodePort:在每个 Node 上开放一个端口,供外部访问。
  • LoadBalancer:对接云厂商的负载均衡器。

1.5 使用 Ingress 提供外部访问(七层路由)

集群内部可以直接使用 Service 名称(DNS 名)进行通信,但外部访问集群内部服务时,由于网络隔离,通常需要通过 NodePort 或 LoadBalancer 暴露端口。但这些属于四层负载均衡(TCP/UDP),若要实现七层(HTTP/HTTPS)路由(如按域名、路径转发),Kubernetes 提供了Ingress资源。

Ingress 需要配合Ingress Controller(如 Nginx Ingress Controller、Traefik)才能生效。注意:Ingress Controller 是独立组件,不包含在 kube-controller-manager 中,需要单独部署。

1.6 使用 PV / PVC 管理持久化数据

容器中的存储是临时的,Pod 重启后数据会丢失。对于需要持久化数据的应用(如数据库、文件上传),必须使用外部存储方案。Kubernetes 通过PersistentVolume(PV)PersistentVolumeClaim(PVC)抽象存储资源:

  • PV是集群中的存储资源(由管理员预先创建或动态供给)。
  • PVC是用户对存储的请求(声明),Pod 通过 PVC 挂载卷。

这样应用无需关心底层存储实现(NFS、Ceph、云存储等)。

也结合存储类实现自动划分PV

1.7 使用 ConfigMap 管理应用配置文件

在 DevOps 实践中,强调代码与配置分离。Kubernetes 提供了ConfigMapSecret用于管理配置信息(环境变量、配置文件等):

  • ConfigMap存储非敏感配置(如应用参数)。
  • Secret存储敏感信息(如密码、Token)。

可以从文件、目录或字面值创建 ConfigMap/Secret,然后在 Pod 中通过环境变量或挂载卷的方式使用。

1.8 日志收集

为确保日志能够集中管理,建议应用将日志输出到标准输出(stdout)标准错误(stderr),这样 Kubernetes 默认日志机制(如kubectl logs)能够捕获。然后可集成 EFK(Elasticsearch + Fluentd + Kibana)或 ELK(Elasticsearch + Logstash + Kibana)等日志系统统一收集、存储和展示。

1.9 监控告警

集群和应用的状态监控至关重要。一般集成Prometheus采集指标,配合Grafana进行可视化展示,并设置告警规则(通过 AlertManager)。可以监控 Pod 资源使用、应用性能、集群健康等。

1.10 关于有状态应用(如数据库)的迁移策略

数据库等有状态服务迁移到 K8s 较为复杂(涉及数据一致性、主从同步、备份恢复等)。一个常见的策略是:在迁移初期将数据库保留在 K8s 集群外部(如使用云数据库或自建物理机),让应用先通过 Service 访问外部数据库(使用 ExternalName 或 Endpoints)。待应用稳定运行后,再评估是否使用StatefulSet+PersistentVolume将其也容器化。


第二部分:服务部署与迁移实战案例

以下案例逐步展示如何将不同类型的应用部署到 Kubernetes 集群,包括 WordPress(MySQL + WordPress)、LNMP 环境(Nginx+PHP-FPM + MySQL)、Spring Boot 应用和 Tomcat 应用。

前置条件:已搭建好 Kubernetes 集群,并配置了 NFS 存储类(storageClassName: "nfs",关于存储类的创建可前往:Kubernetes(K8s)笔记Day06查看)或替换为其他 StorageClass。所有 YAML 文件需在 Master 节点(或任意可访问集群的机器)上执行kubectl apply -f <file>


案例 1:LAMP 架构部署 WordPress(使用 MySQL 官方镜像 + WordPress 镜像)

本案例通过 MySQL 与 WordPress 官方镜像部署持久化的博客网站,使用 Deployment + PVC 保存数据,并通过 NodePort 对外访问。

这个案例把应用运行所需的参数(比如数据库地址、账号密码),从代码内部“抽”出来,放到代码外部(比如环境变量里)去设置,是配置外部化的典范,利用公共镜像做到了“即插即用”。

如果业务本身遵循云原生设计(或官方已提供支持),迁移就是改几个变量的事,这也是迁移收益最高、风险最低的方式

1.1 部署 MySQL

创建wp-mysql.yaml文件,包含 Service、PVC 和 Deployment:

需要提前将mysql:5.7镜像上传到hd2,hd3

[root@hd1 wp]# vim wp-mysql.yaml#创建serviceapiVersion:v1kind:Servicemetadata:name:mysql-svcspec:type:ClusterIPports:-port:3306targetPort:3306selector:app:wp-mysql---#创建数据库需要的存储----pvcapiVersion:v1kind:PersistentVolumeClaimmetadata:name:mysql-pvclabels:app:wp-mysqlspec:accessModes:-ReadWriteManystorageClassName:"nfs"resources:requests:storage:2Gi---#创建控制器apiVersion:apps/v1kind:Deploymentmetadata:name:wp-mysqlspec:selector:matchLabels:app:wp-mysqlreplicas:1template:metadata:labels:app:wp-mysqlspec:containers:-name:wp-mysqlimage:docker.io/mysql:5.7imagePullPolicy:IfNotPresentports:-containerPort:3306env:-name:MYSQL_ROOT_PASSWORDvalue:"123456"-name:MYSQL_DATABASEvalue:"wordpress"-name:MYSQL_USERvalue:"wordpress"-name:MYSQL_PASSWORDvalue:"wordpress"volumeMounts:-name:mysqlmountPath:/var/lib/mysqlvolumes:-name:mysqlpersistentVolumeClaim:claimName:mysql-pvc

说明

  • Servicemysql-svc仅供集群内部访问(ClusterIP)。
  • PVCmysql-pvc申请 2Gi 存储,访问模式为ReadWriteMany(NFS 支持)。
  • Deployment 仅 1 个副本,环境变量注入数据库初始配置。
1.2 部署 WordPress

创建wp-wordpress.yaml文件:

[root@hd1 wp]# vim wp-wordpress.yaml#创建wordpress的serviceapiVersion:v1kind:Servicemetadata:name:wordpressspec:type:NodePortports:-port:80nodePort:30001selector:app:wordpress---#创建wordpress的存储pvcapiVersion:v1kind:PersistentVolumeClaimmetadata:name:wordpress-pvclabels:app:wordpressspec:accessModes:-ReadWriteManystorageClassName:"nfs"resources:requests:storage:2Gi---#创建wordpress业务系统以及控制器apiVersion:apps/v1kind:Deploymentmetadata:name:wp-wordpressspec:selector:matchLabels:app:wordpressreplicas:1template:metadata:labels:app:wordpressspec:containers:-name:wp-wordpressimage:wordpress:6.2.1-apacheimagePullPolicy:IfNotPresentports:-containerPort:80env:-name:WORDPRESS_DB_HOSTvalue:"mysql-svc"# 通过 Service 名称访问 MySQL-name:WORDPRESS_DB_USERvalue:"wordpress"-name:WORDPRESS_DB_PASSWORDvalue:"wordpress"volumeMounts:-name:wordpressmountPath:/var/www/html# 挂载 WordPress 程序文件(可持久化)volumes:-name:wordpresspersistentVolumeClaim:claimName:wordpress-pvc

说明

  • Service 类型为NodePort,对外暴露端口30001
  • WordPress 通过环境变量WORDPRESS_DB_HOST指向 MySQL 的 Service 名称(集群内 DNS 解析)。
  • PVC 挂载/var/www/html以保存上传的插件、主题等。
1.3 初始化和测试
  1. 依次执行:
    kubectl apply-fwp-mysql.yaml kubectl apply-fwp-wordpress.yaml
  2. 等待 Pod 就绪后,打开浏览器访问http://<任意NodeIP>:30001,进入 WordPress 安装界面(如图 1)。
  3. 填写站点信息、管理员账户,点击“安装”。
  4. 登录后即可看到博客后台(如图 2、图 3)。

注意:若使用 NFS 作为 PV 供给,需确保 NFS 服务正常运行且 PVC 绑定成功。


案例 2:LNMP 架构(Nginx + PHP-FPM + MySQL)运行 WordPress

本案例更贴近传统 PHP 项目部署方式:业务组件(Nginx+PHP)和 MySQL 跑在容器里,但 PHP 业务源码(WordPress 代码) 放在容器外,通过 PVC 挂载进容器。

这个案例是最保守的“平移”策略,适合应急过渡

2.1 部署 Nginx + PHP-FPM

创建lnmp-nginx-php.yaml

[root@hd1 lnmp]# vim lnmp-nginx-php.yamlapiVersion:v1kind:Servicemetadata:name:nginx-php-svclabels:app:lnmp-nginx-phpspec:type:NodePortports:-port:80nodePort:30001selector:app:lnmp-nginx-php---apiVersion:v1kind:PersistentVolumeClaimmetadata:name:lnmp-web-pvclabels:app:wordpressspec:accessModes:-ReadWriteManystorageClassName:"nfs"resources:requests:storage:2Gi---apiVersion:apps/v1kind:Deploymentmetadata:name:lnmp-nginx-phpspec:selector:matchLabels:app:lnmp-nginx-phpreplicas:1template:metadata:labels:app:lnmp-nginx-phpspec:containers:-name:lnmp-nginximage:richarvey/nginx-php-fpm# 集成了 Nginx + PHP-FPM 的镜像imagePullPolicy:IfNotPresentports:-containerPort:80-containerPort:9000volumeMounts:-name:nginx-datamountPath:/var/www/html/# 网站根目录volumes:-name:nginx-datapersistentVolumeClaim:claimName:lnmp-web-pvc

镜像:richarvey/nginx-php-fpm是一个由第三方开发者 richarvey 在 Docker Hub 上构建并维护的公开镜像,可以直接使用docker pull 拉取。GitHub 源码仓库地址:https://github.com/richarvey/nginx-php-fpm

2.2 部署 MySQL

创建lnmp-mysql.yaml

[root@hd1 lnmp]# vim lnmp-mysql.yamlapiVersion:v1kind:Servicemetadata:name:lnmp-mysql-svcspec:type:ClusterIPports:-port:3306targetPort:3306selector:app:lnmp-mysql---apiVersion:v1kind:PersistentVolumeClaimmetadata:name:lnmp-mysql-pvclabels:app:lnmp-mysqlspec:accessModes:-ReadWriteManystorageClassName:"nfs"resources:requests:storage:2Gi---apiVersion:apps/v1kind:Deploymentmetadata:name:lnmp-mysqlspec:selector:matchLabels:app:lnmp-mysqlreplicas:1template:metadata:labels:app:lnmp-mysqlspec:containers:-name:lnmp-mysqlimage:docker.io/mysql:5.7imagePullPolicy:IfNotPresentports:-containerPort:3306env:-name:MYSQL_ROOT_PASSWORDvalue:"123456"-name:MYSQL_DATABASEvalue:"wordpress"-name:MYSQL_USERvalue:"wordpress"-name:MYSQL_PASSWORDvalue:"wordpress"volumeMounts:-name:mysqlmountPath:/var/lib/mysqlvolumes:-name:mysqlpersistentVolumeClaim:claimName:lnmp-mysql-pvc
2.3 部署 WordPress 源码

WordPress 源码需要提前放入 PVC 挂载的目录中(NFS 共享目录)。

  1. 下载 WordPress 安装包(官网:https://cn.wordpress.org):

    [root@hd1 ~]# tar xf wordpress-6.7.1-zh_CN.tar.gz[root@hd1 ~]# cd wordpress/# 将解压后的所有内容移动到 PVC 对应的 NFS 目录(路径根据实际 PVC 挂载点调整)[root@hd1 wordpress]# mv ./* /data/nfs_pro/default-lnmp-web-pvc-pvc-33ebc2d2-9e4f-42d9-9110-7519f9d5b890/

    说明:该路径是 NFS 服务器上为lnmp-web-pvc分配的实际存储路径,可通过kubectl get pv查看。

  2. 依次部署:

    kubectl apply-flnmp-nginx-php.yaml kubectl apply-flnmp-mysql.yaml
  3. 访问http://<NodeIP>:30001,即可看到 WordPress 安装界面(如下图)。

  4. 点击“现在就开始”,填写数据库连接信息(数据库主机为lnmp-mysql-svc,用户名wordpress,密码wordpress,数据库名wordpress),如下图所示:

  5. 提交后继续安装,设置站点标题、管理员账号等,最终登录后台:


案例 3:部署 Spring Boot Web 应用

Spring Boot 是目前 Java 后端开发的主流框架。本案例演示如何将 Spring Boot 应用打包为 Docker 镜像并部署到 K8s 中。

本案例实现了完全无状态、声明式管理、随时弹性伸缩的云原生最佳实践。

3.1 准备 Spring Boot 项目

已有 Spring Boot 项目(springboot-web-demo),编译生成 JAR 包springboot-web-demo-1.0-SNAPSHOT.jar

3.2 编写 Dockerfile

在当前目录创建dockerfile(注意文件名,通常为Dockerfile):

FROM openjdk:8-jdk COPY target/springboot-web-demo-1.0-SNAPSHOT.jar /springboot-web.jar ENTRYPOINT ["java", "-jar", "/springboot-web.jar"]

对于spring boot的web项目,它把整个项目(包括内置的 Tomcat 代码)打包成了一个可执行文件,你只需要把它放在容器的工作目录(如 /app)下,用 java -jar 启动即可

构建镜像并推送到私有仓库(示例仓库地址为www.zutuanxue.com/library/spring-web:v1):

dockerbuild-tspring-web:v1.dockertag spring-web:v1 www.zutuanxue.com/library/spring-web:v1dockerpush www.zutuanxue.com/library/spring-web:v1# 若需推送
3.3 编写 Kubernetes 部署文件spring-web.yaml
cat spring-web.yamlapiVersion:v1kind:Servicemetadata:name:spring-web-svcspec:type:NodePortports:-port:8181targetPort:8080nodePort:30600selector:app:spring-web---apiVersion:apps/v1kind:Deploymentmetadata:name:spring-webspec:selector:matchLabels:app:spring-webreplicas:3template:metadata:labels:app:spring-webspec:containers:-name:spring-webimage:www.zutuanxue.com/library/spring-web:v1imagePullPolicy:IfNotPresentports:-containerPort:8080

说明

  • Service 将外部端口30600映射到 Pod 的8080端口(应用默认端口)。
  • Deployment 副本数为 3,实现高可用。
  • 未配置持久化存储(无状态应用)。
3.4 部署并测试
kubectl apply-fspring-web.yaml kubectl get pod kubectl get svc

打开浏览器访问http://<NodeIP>:30600/hello?name=zutuanxue(假设应用有/hello接口)。即可看到响应。


案例 4:构建 Tomcat 应用(部署 WAR 包)

对于传统的 Java Web 应用(WAR 包),需要部署到 Tomcat 容器中。

本案例是中间状态,容器化程度加深(代码进镜像),但启动命令仍依赖容器脚本

4.1 准备 WAR 包,并编写 Dockerfile 构建镜像

假设已有 WAR 文件jspdemo_war.war,编写 Dockerfile:

FROM tomcat COPY jspdemo_war.war /usr/local/tomcat/webapps/jspdemo_war.war ENTRYPOINT ["catalina.sh","run"]

将当前目录下的 jspdemo_war.war 文件,永久性地写入到镜像文件系统中的 /usr/local/tomcat/webapps/ 目录下

Java Web 项目(打 WAR 包)要放在 Tomcat 的专用部署目录(/usr/local/tomcat/webapps/)

构建并推送镜像(示例仓库www.zutuanxue.com/library/tomcat-java:v1):

dockerbuild-ttomcat-java:v1.dockertag tomcat-java:v1 www.zutuanxue.com/library/tomcat-java:v1dockerpush www.zutuanxue.com/library/tomcat-java:v1

将构建的镜像上传至私人仓库,然后在yaml文件中引用,这是生产环境最主流的方式,将我们的私人仓库变成唯一的可信源

4.2 编写 Kubernetes 部署文件tomcat-java.yaml
cat tomcat-java.yamlapiVersion:v1kind:Servicemetadata:name:tomcat-java-svcspec:type:NodePortports:-port:8282targetPort:8080nodePort:30700selector:app:tomcat-java---apiVersion:apps/v1kind:Deploymentmetadata:name:tomcat-javaspec:selector:matchLabels:app:tomcat-javareplicas:3template:metadata:labels:app:tomcat-javaspec:containers:-name:tomcat-javaimage:www.zutuanxue.com/library/tomcat-java:v1imagePullPolicy:IfNotPresentports:-containerPort:8080
4.3 部署并测试
kubectl apply-ftomcat-java.yaml

访问http://<NodeIP>:30700/jspdemo_war(项目名),输入用户名lisi和对应密码(示例中说明“用户名与密码为:lisi”,具体密码需根据实际应用设定,可能为默认或配置,此处按文档描述)。


第三部分:内容补充

3.1 命名空间(Namespace)

生产环境中通常按环境(开发、测试、生产)或团队划分命名空间,以隔离资源。在所有 YAML 文件中可指定metadata.namespace,或通过kubectl apply -f <file> -n <namespace>

3.2 滚动更新与回滚

Deployment 支持滚动更新(默认策略),更新镜像时只需修改 YAML 中的image标签,重新apply即可。若更新失败,可使用kubectl rollout undo deployment/<name>回滚到上一版本。

3.3 配置管理进阶

除了环境变量,还可将 ConfigMap 挂载为配置文件(如application.properties)。例如:

volumes:-name:configconfigMap:name:app-configvolumeMounts:-name:configmountPath:/config

3.4 健康检查配置示例

在 Pod 的containers中添加:

livenessProbe:httpGet:path:/healthport:8080initialDelaySeconds:30periodSeconds:10readinessProbe:httpGet:path:/readyport:8080initialDelaySeconds:5periodSeconds:5

3.5 资源限制示例

resources:requests:memory:"256Mi"cpu:"250m"limits:memory:"512Mi"cpu:"500m"

总结

将传统业务系统迁移到 Kubernetes 是一个系统化工程,需要依次完成容器化Pod 设计控制器选择服务暴露存储与配置管理可观测性等环节。对于不同类型应用(无状态 Web、有状态数据库、PHP、Java),Kubernetes 均提供了灵活的编排能力。实际落地时,应结合业务特点,选择合适的控制器和存储方案,并逐步推进,尤其对于数据库等关键组件,可采取“先外后内”的保守策略。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询