初识Docker

一、没有 Docker 的日子有多痛?

1.1 "在我机器上能跑啊"

这是程序员最经典的甩锅语录,但很多时候真不是甩锅。丸子做课程设计时,三个人的小组项目,光是统一开发环境就折腾了一周:

  • 小A的 Windows 上 node-sass 死活装不上
  • 小B的 Mac 需要装一堆 Python 依赖
  • 丸子的 Ubuntu 倒是能跑,但跟生产环境不一致

最后想了个"天才"的办法:用 U 盘拷代码,只在一台电脑上开发,效率自然也是非常的低。

1.2 "入职大礼包"

丸子去实习,第一天上班的日程:

  • 9:00 报到
  • 9:30 开始装环境
  • 10:00 Node.js 装好了
  • 10:30 npm install 卡在 node-sass
  • 11:00 求助同事,发现要装 Python 2.7
  • 11:30 Windows 编译工具报错
  • 12:00 吃饭,下午继续...

到下午 4 点,还在配环境。mentor 苦笑着说:"正常,我当年花了 8 小时。"

1.3 多版本噩梦

实验室同时维护三个项目:

bash 复制代码
项目A: Node 12 + Webpack 4
项目B: Node 16 + Vite
项目C: Node 18 尝鲜版

每次切换项目前,丸子都要:

bash 复制代码
nvm use 12
# 跑项目A
# 改需求

nvm use 16
# 等等,我刚刚在项目A改了啥?
# 切回去...啊又报错了!

1.4 部署是玄学。。。

最恐怖的是部署上线。本地开发、测试环境、预发环境、生产环境,四套环境能跑出四种不同的效果。有一次因为"生产环境的 Node 版本高了一点,有个 API 行为不一致",全组人加班到天亮。

这些问题最终都指向同一个核心矛盾:代码是同一份,但运行环境千差万别。Docker 就是为了解决这个矛盾而生的。

二、Docker 是什么?容器技术的原理

2.1 一句话理解 Docker

Docker 就是把你的应用和它需要的一切(运行环境、系统工具、依赖库)打包成一个"集装箱",这个集装箱可以在任何支持 Docker 的地方运行,而且运行结果完全一致。

想象一下:

  • 传统方式:我写了份菜谱(代码)给你,你得自己买锅碗瓢盆、调料、灶具(环境),然后做出来的菜可能跟我的不太一样
  • Docker 方式:我把整道菜做好,真空包装(镜像)寄给你,你只需要加热一下(运行容器),味道跟我做的一模一样

2.2 底层原理

Docker 的核心来自 Linux 的三种技术:

1. Namespace(命名空间)------ "分房间"

bash 复制代码
# 在容器里
$ ps aux
PID   USER     COMMAND
1     app      npm start
2     app      node server.js

# 在宿主机上
$ ps aux | grep npm
1001  root     npm start

容器以为自己独占系统,其实只是被"隔离"在一个小房间里。每个容器有自己的进程树、网络、用户等。

2. Cgroups(控制组)------ "限流"

dockerfile 复制代码
# 限制容器最多用 512M 内存
docker run -m 512m my-app

给每个容器分配资源配额,防止一个容器吃光所有内存。

3. Union File System(联合文件系统)------ "分层存储"

这是 Docker 最聪明的地方。镜像像千层蛋糕:

复制代码
最上层:你的代码(可写)
中间层:项目依赖(node_modules)
基础层:Node.js 运行环境
最底层:Alpine Linux

每一层都是只读的,只有最上层可写。这带来两个好处:

  • 多个容器可以共享基础层,节省磁盘
  • 构建镜像时,如果某一层没变,直接用缓存,加速构建

2.3 虚拟机 vs Docker

很多人分不清 Docker 和虚拟机,其实很简单:

虚拟机:每个应用自带操作系统

复制代码
[你的App] + [Node.js] + [CentOS]
[别人的App] + [Python] + [Ubuntu]
├── 硬件

Docker:所有应用共享操作系统内核

复制代码
[你的App] + [Node.js]   [别人的App] + [Python]
├── Docker Engine
├── 宿主机操作系统
├── 硬件

Docker 更轻、更快、更省资源。启动一个虚拟机要几分钟,启动一个容器只要几秒钟。

三、前端什么时候该用 Docker?

场景1:新人快速上岗(最快5分钟)

问题 :新同事小李来了,你要花半天时间帮他配环境
Docker 方案

bash 复制代码
# 小李只需要
git clone <项目地址>
docker-compose up -d
# 然后就可以开始写代码了

你的项目里需要这些文件:

Dockerfile

dockerfile 复制代码
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

.dockerignore(重要!)

复制代码
node_modules
npm-debug.log
.DS_Store
.git

docker-compose.yml

yaml 复制代码
version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app           # 代码实时同步
      - /app/node_modules  # 重要!避免覆盖容器内的node_modules
    environment:
      - CHOKIDAR_USEPOLLING=true  # 解决热更新问题

场景2:多项目、多 Node 版本

问题 :同时维护三个不同 Node 版本的项目
传统方案 :nvm 切来切去,精神分裂
Docker 方案:每个项目独立环境

项目A的 Dockerfile:

dockerfile 复制代码
FROM node:12.22-alpine
# Node 12 项目

项目B的 Dockerfile:

dockerfile 复制代码
FROM node:16.15-alpine
# Node 16 项目

项目C的 Dockerfile:

dockerfile 复制代码
FROM node:18.7-alpine
# Node 18 项目

要运行项目A:

bash 复制代码
cd project-a
docker-compose up

完全不用操心版本冲突。

场景3:前后端分离开发

问题 :后端 API 还没写好,前端没法联调
Docker 方案:用容器启动 Mock 服务

yaml 复制代码
# docker-compose.yml
version: '3.8'
services:
  frontend:
    build: ./frontend
    ports: ["3000:3000"]
    volumes:
      - ./frontend:/app
    depends_on:
      - mock-api
  
  mock-api:
    image: mockserver/mockserver
    ports: ["8080:8080"]
    command: [
      "-serverPort", "8080",
      "-proxyRemotePort", "80",
      "-proxyRemoteHost", "jsonplaceholder.typicode.com"
    ]

后端接口没写好?没事,我自己 Mock 一个。

场景4:团队统一开发环境

问题 :有人用 VS Code,有人用 WebStorm,有人用 vim,环境各不相同
Docker 方案:容器内开发

dockerfile 复制代码
# Dockerfile.dev
FROM node:18-alpine
RUN apk add --no-cache git curl
WORKDIR /app
# 安装全局依赖
RUN npm install -g nodemon typescript
bash 复制代码
# 进入容器开发
docker run -it -v $(pwd):/app -p 3000:3000 my-dev-image sh
# 现在所有人都在完全相同的环境里写代码

场景5:CI/CD 自动化

问题 :每次部署都要手动构建,容易出错
Docker 方案:GitHub Actions 自动构建

yaml 复制代码
# .github/workflows/deploy.yml
name: Build and Deploy
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      
      - name: Build Docker Image
        run: |
          docker build -t my-app .
          docker tag my-app username/my-app:latest
      
      - name: Push to Registry
        run: docker push username/my-app:latest
      
      - name: Deploy to Server
        run: |
          ssh user@server "docker pull username/my-app:latest"
          ssh user@server "docker stop my-app || true"
          ssh user@server "docker run -d -p 80:3000 --name my-app username/my-app:latest"

场景6:演示项目、课程作业

问题 :教授/面试官要运行你的项目,但你没法帮他配环境
Docker 方案:一键运行

在你的项目 README 里写上:

bash 复制代码
# 运行这个项目
git clone https://github.com/yourname/your-project
cd your-project
docker-compose up
# 打开 http://localhost:3000
相关推荐
老华带你飞2 小时前
学生请假管理|基于springboot 学生请假管理系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·spring
wanhengidc3 小时前
巨椰 云手机 云游戏稳定运行
运维·服务器·arm开发·游戏·云计算
林义满3 小时前
大促零宕机背后的运维升级:长三角中小跨境电商的架构优化实践
大数据·运维·架构
前端不太难3 小时前
如何给 RN 项目设计「不会失控」的导航分层模型
前端·javascript·架构
用户4099322502123 小时前
Vue3中v-show如何通过CSS修改display属性控制条件显示?与v-if的应用场景该如何区分?
前端·javascript·vue.js
不会聊天真君6473 小时前
CSS3(Web前端开发笔记第二期)
前端·笔记·css3
discode3 小时前
【开源项目技术分享】@host-navs 站导,一个简洁高效的网站链接导航工具站
前端