初识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
相关推荐
武子康3 分钟前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
Pedantic1 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆1 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆2 小时前
VSCode自动格式化三要素
前端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen4 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518136 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端