Docker 是什么

把应用 + 依赖打包成"镜像"(image),在隔离的容器里跑——"在我电脑上能跑"问题的终结者

装 Docker

Ubuntu:

# 官方一键脚本
curl -fsSL https://get.docker.com | sudo sh

# 让当前用户能直接跑 docker(不用 sudo)
sudo usermod -aG docker $USER
# 重新登录 SSH 让组生效
exit  # 然后重新 ssh 进来

# 验证
docker run hello-world

核心概念

概念 一句话
镜像 image 不可变的模板(类比类)
容器 container 镜像的运行实例(类比对象)
仓库 registry 存镜像的服务器(Docker Hub / 自建)
Dockerfile 描述怎么建镜像的脚本
卷 volume 容器外持久化数据
网络 network 容器间通信

基础命令

# 拉镜像
docker pull nginx:alpine

# 跑容器
docker run -d --name web -p 80:80 nginx:alpine
#         ↓     ↓        ↓     ↓
#       后台   命名    端口映射 镜像

# 看容器
docker ps              # 跑着的
docker ps -a           # 所有(含已停)

# 看日志
docker logs web
docker logs -f web     # 实时跟踪

# 进容器
docker exec -it web sh
# 在容器里执行命令
docker exec web ls /usr/share/nginx/html

# 停止 / 删除
docker stop web
docker rm web
docker stop web && docker rm web    # 一行搞定

# 看镜像
docker images
docker rmi nginx:alpine

跑一个有数据持久化的容器

# 1. 建命名卷
docker volume create pg-data

# 2. 跑 Postgres
docker run -d \
  --name pg \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=secret \
  -v pg-data:/var/lib/postgresql/data \
  postgres:16

# 3. 进去
docker exec -it pg psql -U postgres

数据存在卷 pg-data 里——容器删了重建数据还在。

写 Dockerfile:把自己的应用打包

例 Node 应用 Dockerfile:

# 1. 基础镜像
FROM node:22-alpine

# 2. 工作目录
WORKDIR /app

# 3. 装依赖(先 copy package*.json 是为了利用缓存)
COPY package*.json ./
RUN npm ci --omit=dev

# 4. 拷代码
COPY . .

# 5. 暴露端口
EXPOSE 3000

# 6. 启动命令
CMD ["node", "server.js"]

构建 + 跑:

docker build -t myapp:1.0 .
docker run -d -p 3000:3000 --name myapp myapp:1.0

docker compose:多容器编排

docker-compose.yml:

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    restart: unless-stopped
    depends_on:
      - api

  api:
    build: ./api
    environment:
      - DATABASE_URL=postgresql://app:secret@db:5432/app
    restart: unless-stopped
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=app
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=app
    volumes:
      - pg-data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  pg-data:
docker compose up -d        # 起整栈
docker compose ps           # 看状态
docker compose logs -f api  # 看某服务日志
docker compose stop         # 停
docker compose down         # 停 + 删容器(卷保留)
docker compose down -v      # 同时删卷(**数据没了**)

几个常用模式

网络互通

compose 自动建网络——服务之间用服务名互访:

api 容器里访问 `db:5432` = 连到 db 服务

不用 IP / 不用 localhost

环境变量

.env 文件:

DB_PASSWORD=secret
API_KEY=abc123

docker-compose.yml 引用 ${DB_PASSWORD}.env.gitignore

资源限制

services:
  api:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

日志限制

services:
  api:
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

防止日志无限增长把磁盘吃光。

镜像优化

多阶段构建(减小镜像)

# 阶段 1:构建
FROM node:22 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 阶段 2:运行(只复制必要文件)
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]
docker build -t myapp .
docker images | grep myapp
# 镜像比"一阶段构建"小一半以上

用小基础镜像

  • node:22 ≈ 1GB
  • node:22-alpine ≈ 150MB
  • gcr.io/distroless/nodejs22 ≈ 100MB(连 shell 都没有,更安全)

.dockerignore

.gitignore 类似——告诉 docker build 别复制哪些文件:

node_modules
.git
.env
*.log

安全提示

  • 不要用 root 跑应用(Dockerfile 加 USER node
  • 不要 :latest tag——锁版本(生产)
  • 扫镜像漏洞trivy image myapp:1.0
  • 不要把 secret 写到镜像里——docker history 能看出来

接下来

学完 Docker 之后的几条路径:

  • 生产部署 → 用 docker compose 起小型服务
  • 多机协调 → 学 Kubernetes(ops-corp/09-13 系列)
  • CI/CD → push 即自动 build + 部署(ops-quick/15-cicd-actions)

下一篇:整个 Linux 教程的总结。