基础 / 已完成

Docker 入门到进阶

先理解镜像、容器、Compose 和运行环境。

返回学习路线

Docker 可以先理解成一个“标准盒子”。

一个程序要跑起来,通常不只需要代码,还需要 Node.js、Python、数据库、配置文件等环境。Docker 做的事就是:把这些东西尽量装进同一个盒子里。盒子拿到别的电脑或服务器上,只要那里有 Docker,就能用差不多一样的方式跑起来。

一句话:

> Docker = 把程序和运行环境打包进标准盒子。

目录

---

一、用奶茶机理解 Docker

Docker 标准盒子学习配图

假设你会做一杯奶茶。

传统做法是:你告诉朋友买什么茶叶、用多少水、珍珠煮几分钟、糖放多少。朋友照着做,但味道可能还是不一样。

Docker 的做法是:你直接给朋友一台“小奶茶机”。茶叶、杯子、温度、步骤都放好了。朋友只要启动机器,就能做出差不多一样的奶茶。

程序也是这样。

没有 Docker 时,别人电脑上可能缺 Node.js、缺依赖、数据库版本不对。
有 Docker 后,我们把程序需要的环境一起打包,减少“我电脑能跑,你电脑不能跑”的问题。

二、Docker 解决什么问题

Docker 主要解决“环境不一致”。

常见问题:

  • 你电脑是 Node.js 20,服务器是 Node.js 16
  • 你装了某个依赖,别人没装
  • 本地能连数据库,服务器连不上
  • 新同事配置项目要花很久
  • 上线时环境和开发环境不一样

Docker 的价值:

  • 快速启动项目
  • 减少环境配置问题
  • 让开发和部署更接近
  • 方便同时管理前端、后端、数据库、Redis 等服务

三、Docker 和虚拟机的区别

虚拟机像“重新造一整套房子”,里面有完整操作系统,比较重。

Docker 容器像“在大楼里隔出一个房间”,更轻,启动更快。

对比虚拟机Docker 容器
像什么一整套房子一个独立房间
启动
体积
适合模拟完整电脑运行应用

记住:Docker 不是完整电脑,它主要用来运行应用。

四、核心概念

1. 镜像 Image

镜像就是“模板”。

比如:

  • nginx:网页服务器模板
  • mysql:8:MySQL 8 模板
  • redis:7:Redis 7 模板

大白话:

> 镜像 = 菜谱,还没有真正开火做菜。

常用命令:

docker images
docker pull nginx
docker pull mysql:8

2. 容器 Container

容器就是镜像真正跑起来后的东西。

大白话:

> 容器 = 按菜谱做出来的那盘菜。

一个镜像可以启动多个容器。

docker run nginx
docker ps
docker ps -a

3. Dockerfile

Dockerfile 是“制作镜像的说明书”。

它告诉 Docker:

  • 从哪个基础环境开始
  • 把哪些代码复制进去
  • 安装哪些依赖
  • 启动时运行什么命令

4. Docker Hub

Docker Hub 是“镜像超市”。

很多常用镜像别人已经做好了,比如 Nginx、MySQL、Redis。我们可以直接下载使用。

5. 端口 Port

容器里跑了网站,外面默认访问不到。要用端口映射给它开门。

docker run -d -p 8080:80 nginx

意思是:

本机 8080 端口 -> 容器 80 端口

访问:

http://localhost:8080

6. 数据卷 Volume

容器可以删除,但数据库数据不能随便丢。

Volume 就像“容器外面的保险柜”,用来保存重要数据。

docker volume create mysql-data
docker run -d \
  --name mysql-demo \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -v mysql-data:/var/lib/mysql \
  mysql:8

五、基础命令

1. 检查 Docker

docker version
docker info

如果报错连接不到 Docker,通常是 Docker Desktop 没启动。

2. 运行测试容器

docker run hello-world

能看到欢迎信息,说明 Docker 基本可用。

3. 启动 Nginx 网站

docker run -d -p 8080:80 --name my-nginx nginx

然后打开:

http://localhost:8080

参数解释:

-d              后台运行
-p 8080:80      端口映射
--name my-nginx 给容器起名字
nginx           使用 nginx 镜像

4. 管理容器

docker ps
docker ps -a
docker stop my-nginx
docker start my-nginx
docker restart my-nginx
docker rm my-nginx

5. 查看日志和进入容器

docker logs -f my-nginx
docker exec -it my-nginx sh

退出容器:

exit

六、写一个 Dockerfile

假设有一个 Node.js 项目:

my-app/
  package.json
  server.js
  Dockerfile
  .dockerignore

server.js

const http = require("http");

http.createServer((req, res) => {
  res.end("Hello Docker");
}).listen(3000);

package.json

{
  "scripts": {
    "start": "node server.js"
  }
}

Dockerfile

FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

大白话解释:

FROM node:20          从 Node.js 20 环境开始
WORKDIR /app          进入 /app 文件夹
COPY package*.json    先复制依赖说明
RUN npm install       安装依赖
COPY . .              复制项目代码
EXPOSE 3000           说明服务使用 3000 端口
CMD npm start         启动项目

.dockerignore

node_modules
.git
.env
.DS_Store
dist

构建镜像:

docker build -t my-node-app .

运行容器:

docker run -d -p 3000:3000 --name node-demo my-node-app

访问:

http://localhost:3000

Dockerfile 顺序为什么重要

推荐先复制 package.json,再安装依赖,最后复制代码:

COPY package*.json ./
RUN npm install
COPY . .

因为代码经常改,依赖不经常改。这样 Docker 可以复用缓存,构建更快。

七、Docker Compose

真实项目经常不止一个容器。

比如:

  • 后端
  • MySQL
  • Redis
  • Nginx

一个个 docker run 很麻烦。Docker Compose 可以用一个文件统一管理。

docker-compose.yml

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      DB_HOST: mysql
      DB_USER: root
      DB_PASSWORD: 123456
      DB_NAME: demo
    depends_on:
      - mysql

  mysql:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: demo
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"

volumes:
  mysql-data:

启动:

docker compose up -d

查看日志:

docker compose logs -f

停止:

docker compose down

重新构建并启动:

docker compose up -d --build

大白话:

> Compose = 多个容器的总开关。

八、容器之间怎么访问

在 Docker Compose 里,容器之间用“服务名”访问。

例如:

services:
  app:
  mysql:

app 访问数据库时,数据库地址应该写:

mysql

不要写:

localhost

原因很简单:在容器里,localhost 指的是容器自己,不是另一个容器。

正确例子:

mysql://root:123456@mysql:3306/demo

九、进阶重点

1. 环境变量

不要把密码、端口、数据库地址全部写死在代码里。

单容器:

docker run -e NODE_ENV=production -e PORT=3000 my-node-app

Compose:

services:
  app:
    environment:
      NODE_ENV: production
      PORT: 3000

2. 生产镜像要小

开发时镜像大一点没关系,生产环境最好更小、更干净。

可以用轻量镜像:

FROM node:20-alpine

3. 多阶段构建

前端项目常用这种方式:

FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx
COPY --from=builder /app/dist /usr/share/nginx/html

大白话:

第一步:用 Node.js 打包
第二步:只把打包结果放进 Nginx

这样最终镜像更干净。

十、常见问题

1. Docker 命令连接不上

一般是 Docker Desktop 没启动。

docker info

2. 端口被占用

查端口:

lsof -i :8080

也可以换端口:

docker run -d -p 8081:80 nginx

3. 容器启动后马上退出

看日志:

docker logs 容器名

Compose 项目:

docker compose logs -f

4. 数据会不会丢

只放容器里,删除容器可能会丢。

用了 volume,数据会保存在容器外面,更安全。

5. Docker 占磁盘太多

查看:

docker system df

清理:

docker system prune

更彻底:

docker system prune -a

清理前要确认没有重要镜像或容器。

十一、命令速查

镜像:

docker images
docker pull nginx
docker rmi nginx
docker build -t my-app .

容器:

docker ps
docker ps -a
docker run -d -p 8080:80 --name my-nginx nginx
docker stop my-nginx
docker start my-nginx
docker restart my-nginx
docker rm my-nginx
docker logs -f my-nginx
docker exec -it my-nginx sh

数据卷:

docker volume ls
docker volume create my-data
docker volume rm my-data

Compose:

docker compose up -d
docker compose up -d --build
docker compose down
docker compose ps
docker compose logs -f
docker compose restart

清理:

docker system df
docker system prune
docker system prune -a

十二、学习顺序

建议按这个顺序学:

  1. 明白 Docker 是“标准盒子”
  2. 分清镜像和容器
  3. 学会 docker rundocker psdocker logs
  4. 学会端口映射 -p
  5. 学会数据卷 -v
  6. 学会写 Dockerfile
  7. 学会 Docker Compose
  8. 搞懂容器之间用服务名访问
  9. 再看环境变量、镜像瘦身、多阶段构建

最后记住这张表:

名词小学生版理解
镜像模板、菜谱
容器跑起来的程序盒子
Dockerfile做镜像的说明书
Docker Hub镜像超市
端口给容器开门
Volume数据保险柜
Compose多个容器的总开关

Docker 的重点不是背命令,而是理解:

> 它把程序需要的东西装进盒子,让程序换地方也更容易跑起来。