Docker部署与Linux传统部署的区别

Docker与Linux部署对比分析

为了让你彻底理解 “Linux 传统环境痛点” 与 “Docker 解决方案” 的对应关系,我会举 3 个最常见的 Linux 运维场景案例 —— 每个案例先讲传统环境下的问题表现、解决过程(有多麻烦),再讲 Docker 如何轻松规避这些问题,通过 “对比” 让差异更直观。

案例 1:依赖冲突 ——JDK 版本不兼容,老项目和新项目 “打架”

传统 Linux 环境的问题与解决

场景

你在一台 CentOS 7 服务器 上:

  1. 先部署了一个老 Java 项目(如基于 Spring Boot 1.x),必须用 JDK 8(因为 Spring Boot 1.x 不支持 JDK 9+);

  2. 3 个月后要部署新项目(基于 Spring Boot 3.x),必须用 JDK 17(Spring Boot 3.x 最低要求 JDK 17)。

传统环境的问题

Linux 系统的JAVA_HOME全局配置,只能指向一个 JDK 版本:

  • JAVA_HOME指向 JDK 8:新项目启动报错 “Unsupported major.minor version 61.0”(JDK 17 编译的类文件版本是 61,JDK 8 无法识别);

  • JAVA_HOME指向 JDK 17:老项目启动报错 “NoClassDefFoundError: javax/xml/bind/DatatypeConverter”(JDK 9 + 移除了javax.xml.bind包,老项目依赖这个包)。

传统环境的解决过程(很繁琐)

为了让两个项目共存,你需要做 3 件事:

  1. 装两个 JDK 版本
  • 先装 JDK 8:yum install java-1.8.0-openjdk-devel,路径是/usr/lib/jvm/java-1.8.0-openjdk

  • 再手动下载 JDK 17 压缩包,解压到/usr/lib/jvm/java-17-openjdk(CentOS 7 的 yum 源没有 JDK 17,得自己找官网包)。

  1. 为每个项目写 “启动脚本”
  • 老项目启动脚本(指定 JDK 8):
#!/bin/bash​
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk​
export PATH=$JAVA_HOME/bin:$PATH​
java -jar /opt/old-project/old-demo.jar  # 老项目JAR路径
  • 新项目启动脚本(指定 JDK 17):
#!/bin/bash
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export PATH=$JAVA_HOME/bin:$PATH
java -jar /opt/new-project/new-demo.jar  # 新项目JAR路径
  1. 配置服务自启动(避免每次手动执行脚本)
  • 为每个脚本创建systemd服务文件(如/etc/systemd/system/old-project.service),指定脚本路径;

  • 执行systemctl daemon-reloadsystemctl enable old-project等命令,确保开机启动。

解决后的隐患

  • 若后续有第三个项目需要 JDK 11,你得重复上述步骤(装 JDK 11、写新脚本、配 systemd);

  • 若误删某个 JDK 目录,或修改了脚本中的JAVA_HOME路径,对应的项目会直接崩溃,排查时还得先看脚本配置。

Docker 如何解决这个问题

Docker 的思路

每个项目打包成一个独立镜像,镜像内自带需要的 JDK 版本,不依赖 Linux 系统的全局 JDK。

具体操作

  1. 老项目(JDK 8)的 Dockerfile
# 基础镜像:自带JDK 8(无需在Linux系统装JDK 8)
FROM openjdk:8-jdk-alpine
# 复制老项目JAR到容器
COPY old-demo.jar /app/old-demo.jar
# 启动命令(直接用镜像内的JDK 8)
CMD ["java", "-jar", "/app/old-demo.jar"]
  1. 新项目(JDK 17)的 Dockerfile
# 基础镜像:自带JDK 17(无需在Linux系统装JDK 17)
FROM openjdk:17-jdk-alpine
# 复制新项目JAR到容器
COPY new-demo.jar /app/new-demo.jar
# 启动命令(直接用镜像内的JDK 17)
CMD ["java", "-jar", "/app/new-demo.jar"]
  1. 启动两个容器
# 启动老项目容器
docker run -d --name old-project -p 8081:8080 old-project:v1
# 启动新项目容器
docker run -d --name new-project -p 8082:8080 new-project:v1

Docker 的优势

  • 无需在 Linux 系统装任何 JDK,镜像自带,避免全局配置冲突;

  • 两个项目的 JDK 版本完全隔离,改一个项目的 JDK 版本(如把新项目换成 JDK 21),只需重新构建镜像,不影响老项目;

  • 启动 / 停止项目只需docker start/stop 容器名,无需管理复杂的脚本和 systemd 配置。

案例 2:移植麻烦 —— 从本地 Linux 虚拟机迁移到云服务器,环境配半天

传统 Linux 环境的问题与解决

场景

你在本地 Ubuntu 22.04 虚拟机 上开发了一个 “JavaWeb+MySQL” 项目,现在要迁移到云服务器的 CentOS 8 系统 上。

传统环境的问题

本地虚拟机和云服务器的 Linux 发行版不同,软件安装命令、依赖路径全不一样,迁移时处处 “卡壳”:

  1. MySQL 安装方式不同
  • 本地 Ubuntu:sudo apt install mysql-server,配置文件路径是/etc/mysql/mysql.conf.d/mysqld.cnf

  • 云服务器 CentOS 8:apt命令不存在,得用dnf install mysql-server,配置文件路径是/etc/my.cnf.d/mysqld.cnf—— 命令和路径全要改。

  1. 项目依赖的系统库缺失
  • 本地 Ubuntu 上,项目用到了libpng库(处理图片),你之前手动装过sudo apt install libpng-dev

  • 云服务器 CentOS 8 上没有这个库,项目启动报错 “libpng16.so.16: cannot open shared object file: No such file or directory”,得重新装dnf install libpng-devel(注意包名还不一样,Ubuntu 是libpng-dev,CentOS 是libpng-devel)。

  1. 文件权限问题
  • 本地 Ubuntu 上,项目日志目录/var/log/my-project的权限是chmod 775,用户是ubuntu

  • 云服务器 CentOS 8 上,默认用户是ec2-user,启动项目时提示 “Permission denied”,得重新执行chown -R ec2-user:ec2-user /var/log/my-projectchmod 775 /var/log/my-project

传统环境的解决过程(耗时且易出错)

  1. 先在云服务器上 “复刻” 本地的软件列表:把本地apt list --installed的输出导出,对应到 CentOS 的dnf包名,一个一个装(有些包甚至没有直接对应,得找替代方案);

  2. 把本地项目的配置文件(如数据库连接地址、日志路径)全部改成云服务器的路径;

  3. 启动项目后,根据报错信息逐个排查缺失的依赖(比如缺libpng就装libpng-devel,缺libjpeg就装libjpeg-turbo-devel);

  4. 解决权限问题:每次遇到 “Permission denied”,就用chownchmod调整,直到项目能正常启动。

解决后的隐患

  • 若后续本地项目升级(如新增了libcurl依赖),迁移到云服务器时又得重新装libcurl-devel,重复走一遍排查流程;

  • 不同人维护时,可能忘了 “当时装过哪些依赖”,导致新环境部署时又要从头踩坑。

Docker 如何解决这个问题

Docker 的思路

把 “项目 + MySQL + 所有依赖” 打包成镜像或用 Docker Compose 管理,本地和云服务器用完全相同的配置启动,无需适配发行版。

具体操作

  1. 写 docker-compose.yml(管理项目和 MySQL 容器)
version: '3'
services:
  # MySQL容器(自带MySQL,无需在Linux装)
  mysql:
    image: mysql:8.0  # 用官方MySQL 8.0镜像
    environment:
      MYSQL_ROOT_PASSWORD: 123456  # 数据库密码
      MYSQL_DATABASE: my_project  # 项目用的数据库
    volumes:
      - mysql-data:/var/lib/mysql  # 数据持久化(避免容器删了数据丢了)
    ports:
      - "3306:3306"

  # JavaWeb项目容器(自带JDK和所有依赖)
  web:
    build: .  # 用当前目录的Dockerfile构建项目镜像
    depends_on:
      - mysql  # 确保MySQL先启动
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/my_project  # 连接MySQL容器(用容器名访问)
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: 123456

volumes:
  mysql-data:  # 定义数据卷,持久化MySQL数据
  1. 项目的 Dockerfile(打包依赖)
FROM openjdk:11-jdk-alpine
# 安装项目需要的libpng库(镜像内装,和Linux发行版无关)
RUN apk add --no-cache libpng
# 复制项目JAR
COPY demo.jar /app/demo.jar
# 启动命令
CMD ["java", "-jar", "/app/demo.jar"]
  1. 迁移步骤(本地→云服务器)
  • 本地:把docker-compose.ymlDockerfiledemo.jar打包成压缩包;

  • 云服务器:解压压缩包,执行docker-compose up -d——Docker 会自动拉取 MySQL 镜像、构建项目镜像、启动两个容器,无需手动装任何软件。

Docker 的优势

  • 本地和云服务器的部署命令完全一样(都是docker-compose up -d),无需适配发行版(Ubuntu/CentOS 都能跑);

  • 项目依赖的libpng等库打包在镜像内,云服务器无需手动装,避免 “缺依赖” 报错;

  • 数据库连接地址用mysql(容器名),无需改 IP,迁移时配置文件不用动。

案例 3:资源浪费 —— 多服务闲置时占内存,服务器资源不够用

传统 Linux 环境的问题与解决

场景

你在一台 4GB 内存的 Linux 服务器 上部署了 3 个服务:

  1. Redis(缓存):默认启动占用 100MB 内存;

  2. MySQL(数据库):默认启动占用 300MB 内存;

  3. Tomcat(Java 项目):默认启动占用 200MB 内存。

传统环境的问题

这 3 个服务即使闲置(如半夜没人访问),也会一直占用内存:

  • 实际需求:Redis 只缓存少量数据(需 50MB)、MySQL 数据量小(需 100MB)、Tomcat 项目访问量低(需 100MB),总实际需求仅 250MB;

  • 实际占用:Redis 100MB + MySQL 300MB + Tomcat 200MB = 600MB,浪费了 3.4GB 内存(但这些内存又不能给其他服务用,因为传统环境无法动态调整)。

如果后续要加一个 Elasticsearch 服务(默认需要 2GB 内存),服务器总内存只有 4GB,加完后内存会不够用(600MB+2GB=2.6GB,看似够,但 Elasticsearch 运行中可能扩容,容易触发 OOM)。

传统环境的解决过程(治标不治本)

  1. 手动调整服务配置
  • Redis:改redis.conf,把maxmemory设为 50MB(限制最大内存);

  • MySQL:改my.cnf,把innodb_buffer_pool_size设为 100MB(减少缓存池大小);

  • Tomcat:改catalina.sh,加-Xms100m -Xmx100m(限制 JVM 内存)。

  1. 定时启停服务
  • 写一个 Shell 脚本,半夜 2 点停止 Redis 和 Tomcat(没人访问),早上 6 点再启动;

  • 把脚本加入crontab(定时任务),实现自动启停。

解决后的隐患

  • 调整配置需要懂每个服务的参数(如 Redis 的maxmemory、MySQL 的innodb_buffer_pool_size),新手容易改错导致服务崩溃;

  • 定时启停有风险:如果半夜有突发访问(如定时任务执行),Redis 和 Tomcat 停了会导致业务报错;

  • 若后续服务增加(如加 MongoDB),还是会面临内存不够用的问题,只能升级服务器(花钱)。

Docker 如何解决这个问题

Docker 的思路

--memory参数限制每个容器的最大内存,闲置时容器不会占用额外内存,且内存可动态分配(比如把 Redis 的内存让给 Elasticsearch)。

具体操作

  1. 启动容器时限制内存
# 启动Redis:限制最大内存50MB
docker run -d --name redis --memory=50m -p 6379:6379 redis:6
# 启动MySQL:限制最大内存100MB
docker run -d --name mysql --memory=100m -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:8.0
# 启动Tomcat:限制最大内存100MB(同时限制JVM内存)
docker run -d --name tomcat --memory=100m -e JAVA_OPTS="-Xms50m -Xmx100m" -p 8080:8080 tomcat:9
  1. 后续加 Elasticsearch
# 启动Elasticsearch:限制最大内存2GB
docker run -d --name es --memory=2g -p 9200:9200 elasticsearch:7.17.0

Docker 的优势

  • 总内存占用:50MB(Redis)+100MB(MySQL)+100MB(Tomcat)+2GB(ES)=2.25GB,4GB 服务器还剩 1.75GB 内存,不会不够用;

  • 无需改服务配置文件(如 Redis 的redis.conf),只需加--memory参数,新手也能操作;

  • 若某个服务需要更多内存(如 ES 高峰期需要 2.5GB),可先停止 Redis(docker stop redis),释放 50MB 内存,临时满足 ES 需求,高峰期过后再启动 Redis。

总结:传统 Linux 解决问题的 “痛点” vs Docker 的 “爽点”

问题类型传统 Linux 解决方式的痛点Docker 解决方式的爽点
依赖冲突装多个版本、写启动脚本、配 systemd,步骤多易出错镜像自带依赖,隔离性强,改版本只需重构镜像
移植麻烦适配发行版、装缺失依赖、改配置路径,耗时且易漏一行docker-compose up -d,本地云服务器通用
资源浪费手动调配置、定时启停,治标不治本且有风险--memory限制内存,动态分配,不浪费资源

简单说:传统 Linux 环境下,“解决问题的过程本身就是新问题”,而 Docker 通过 “容器隔离 + 镜像打包”,从根源上规避了这些问题 —— 这也是为什么现在企业都在用 Docker 替代传统部署方式的核心原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值