Docker 学习笔记(K8s前置必备)

本文档是学习 Kubernetes(K8s)前的 Docker 核心知识梳理,涵盖基础命令、进阶操作、镜像打包部署、Docker Compose 多容器管理等核心内容,适合后端/运维初学者快速上手,为后续 K8s 学习打下坚实基础。

一、Docker 核心认知

1.1 什么是 Docker?

Docker 是一款开源的容器化平台,核心作用是将应用程序及其依赖(如环境变量、库文件、配置文件等)打包成一个标准化的「容器镜像」,使得应用可以在任何支持 Docker 的环境中无缝运行,彻底解决「开发环境能跑,生产环境报错」的环境一致性问题。

1.2 核心概念

  • 镜像(Image):应用程序的「安装包」,包含运行应用所需的所有依赖,是只读的模板(如 Node.js 镜像、Nginx 镜像)。

  • 容器(Container):镜像的「运行实例」,是可读写的运行环境,镜像与容器的关系类似「类与对象」。

  • 仓库(Repository):存放镜像的远程仓库,类似 GitHub,官方仓库为 Docker Hub,国内有阿里云、腾讯云等镜像加速器。

  • Dockerfile:构建镜像的「脚本文件」,包含一系列构建镜像的指令(如基础镜像、复制文件、安装依赖、启动命令等)。

  • Docker Compose:多容器管理工具,通过 YAML 文件定义多个容器的运行配置,实现一键启动/停止多个关联服务(如前端+后端+数据库)。

1.3 与虚拟机的区别

Docker 容器与传统虚拟机(VM)的核心差异在于「虚拟化层级」:

  • 虚拟机:虚拟化整个操作系统(内核+系统环境),体积大(GB级)、启动慢(分钟级)、资源占用高。

  • Docker 容器:共享宿主机内核,仅虚拟化应用所需的运行环境,体积小(MB级)、启动快(秒级)、资源占用低。

二、Docker 基础命令(必背)

以下命令是日常开发最常用的基础操作,建议多敲多练形成肌肉记忆。

2.1 镜像相关命令


# 1. 拉取镜像(从Docker Hub)
# 格式:docker pull 镜像名:标签(标签不写默认latest,即最新版)
docker pull node:18-alpine  # 拉取Node.js 18的轻量版镜像
docker pull nginx:latest    # 拉取最新版Nginx镜像

# 2. 查看本地镜像列表
docker images  # 简写:docker images
docker images -a  # 查看所有镜像(包括中间层镜像)
docker images -q  # 只显示镜像ID(批量操作时常用)

# 3. 删除本地镜像
# 格式:docker rmi 镜像ID/镜像名:标签
docker rmi nginx:latest  # 通过镜像名删除
docker rmi 87a94228f133  # 通过镜像ID删除
docker rmi $(docker images -q)  # 批量删除所有本地镜像(慎用)

# 4. 搜索镜像(从Docker Hub)
docker search redis  # 搜索Redis相关镜像

2.2 容器相关命令


# 1. 启动容器(从镜像创建并启动)
# 格式:docker run [参数] 镜像名:标签 [容器内启动命令]
# 核心参数:
# -d:后台运行(守护进程模式)
# -p:端口映射(宿主机端口:容器内端口)
# -v:数据卷挂载(宿主机目录:容器内目录,实现数据持久化)
# --name:给容器起别名(方便后续操作)
# -it:交互式运行(进入容器内部终端)

# 示例1:启动Nginx容器(后台运行,端口80映射到宿主机8080)
docker run -d -p 8080:80 --name my-nginx nginx:latest

# 示例2:启动Node.js容器(交互式运行,进入终端)
docker run -it --name my-node node:18-alpine /bin/sh

# 示例3:启动MySQL容器(挂载数据卷,设置root密码)
docker run -d -p 3306:3306 --name my-mysql -v /host/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0

# 2. 查看容器状态
docker ps  # 查看正在运行的容器
docker ps -a  # 查看所有容器(包括停止的)
docker ps -q  # 只显示运行中容器的ID

# 3. 进入正在运行的容器(交互式操作)
# 格式:docker exec [参数] 容器名/容器ID [命令]
docker exec -it my-nginx /bin/bash  # 进入Nginx容器终端
docker exec -it my-node node  # 直接在Node容器中执行node命令

# 4. 启动/停止/重启容器
docker start my-nginx  # 启动已停止的容器
docker stop my-nginx   # 停止运行中的容器
docker restart my-nginx  # 重启容器
docker kill my-nginx   # 强制停止容器(类似断电,慎用)

# 5. 删除容器
# 格式:docker rm 容器名/容器ID
docker rm my-nginx  # 删除已停止的容器
docker rm -f my-nginx  # 强制删除运行中的容器
docker rm $(docker ps -a -q)  # 批量删除所有容器(慎用)

# 6. 查看容器日志
# 格式:docker logs [参数] 容器名/容器ID
docker logs my-nginx  # 查看容器日志
docker logs -f my-nginx  # 实时跟踪日志(类似tail -f)
docker logs --tail 100 my-nginx  # 查看最后100行日志

# 7. 查看容器详细信息
docker inspect my-nginx  # 查看容器的IP、挂载、网络等所有信息

2.3 其他基础命令


# 1. 查看Docker服务状态
systemctl status docker  # Linux
docker info  # 查看Docker详细信息(版本、镜像数、容器数等)

# 2. 启动/停止Docker服务
systemctl start docker   # Linux
systemctl stop docker    # Linux
systemctl restart docker # Linux

# 3. 清理无用资源(镜像、容器、数据卷等)
docker system prune  # 清理停止的容器、无用的镜像和网络(安全)
docker system prune -a  # 清理所有未使用的资源(包括未被引用的镜像,慎用)

三、Docker 进阶命令(实战必备)

3.1 数据卷(Volume)操作

数据卷是 Docker 中实现数据持久化的核心机制,用于将容器内的目录与宿主机目录映射,避免容器删除后数据丢失。


# 1. 创建自定义数据卷
docker volume create my-volume  # 创建名为my-volume的数据卷

# 2. 查看数据卷列表
docker volume ls

# 3. 查看数据卷详细信息(包括挂载路径)
docker volume inspect my-volume

# 4. 挂载自定义数据卷到容器
docker run -d -p 8080:80 -v my-volume:/usr/share/nginx/html --name my-nginx nginx:latest

# 5. 删除数据卷
docker volume rm my-volume  # 删除未被使用的数据卷
docker volume prune  # 批量删除所有未被使用的数据卷

3.2 镜像构建与推送

通过 Dockerfile 构建自定义镜像,并推送到远程仓库(如 Docker Hub、阿里云镜像仓库),实现镜像的复用和分发。


# 1. 构建镜像(需先编写Dockerfile)
# 格式:docker build -t 镜像名:标签 构建上下文目录(. 表示当前目录)
docker build -t my-node-app:v1.0 .

# 2. 给镜像打标签(推送远程仓库时需要,格式:仓库地址/镜像名:标签)
# 示例:推送到Docker Hub(需先登录Docker Hub)
docker tag my-node-app:v1.0 username/my-node-app:v1.0

# 示例:推送到阿里云镜像仓库
docker tag my-node-app:v1.0 registry.cn-hangzhou.aliyuncs.com/username/my-node-app:v1.0

# 3. 登录远程仓库
docker login  # 登录Docker Hub
docker login registry.cn-hangzhou.aliyuncs.com  # 登录阿里云镜像仓库

# 4. 推送镜像到远程仓库
docker push username/my-node-app:v1.0  # 推送到Docker Hub
docker push registry.cn-hangzhou.aliyuncs.com/username/my-node-app:v1.0  # 推送到阿里云

# 5. 从远程仓库拉取自定义镜像
docker pull username/my-node-app:v1.0

3.3 网络操作

Docker 内置网络管理功能,支持多容器之间的网络互通,常用网络模式有 bridge(默认)、host、overlay 等。


# 1. 查看Docker网络列表
docker network ls

# 2. 创建自定义网络(推荐,实现容器间隔离和互通)
docker network create my-network  # 创建bridge模式的自定义网络

# 3. 启动容器时加入自定义网络
docker run -d --name app1 --network my-network my-node-app:v1.0
docker run -d --name app2 --network my-network my-node-app:v1.0

# 4. 容器间通过容器名互通(自定义网络支持DNS解析)
# 在app1容器中可直接通过 app2 访问app2容器(无需IP)
docker exec -it app1 ping app2

# 5. 查看网络详细信息
docker network inspect my-network

# 6. 删除网络
docker network rm my-network

四、镜像打包部署(Dockerfile 实战)

Dockerfile 是构建自定义镜像的核心,通过编写一系列指令,定义镜像的构建流程。以下是针对 Node.js 项目的实战案例。

4.1 Dockerfile 核心指令

  • FROM:指定基础镜像(必须是Dockerfile的第一行指令)。

  • WORKDIR:设置容器内的工作目录(后续命令都在此目录执行)。

  • COPY/ADD:复制宿主机文件到容器内(COPY仅复制文件,ADD支持解压压缩包)。

  • RUN:构建镜像时执行的命令(如安装依赖、创建目录)。

  • ENV:设置环境变量。

  • EXPOSE:声明容器对外暴露的端口(仅声明,不实际映射)。

  • CMD:容器启动时执行的命令(一个Dockerfile只能有一个CMD,多写则最后一个生效)。

  • ENTRYPOINT:容器启动时的入口命令(与CMD的区别:ENTRYPOINT不可被docker run的命令覆盖,CMD可覆盖)。

4.2 Node.js 项目 Dockerfile 实战

假设项目结构如下:


my-node-app/
├── package.json
├── app.js
└── Dockerfile

编写 Dockerfile:


# 1. 指定基础镜像(选择轻量的alpine版本,减少镜像体积)
FROM node:18-alpine

# 2. 设置工作目录(容器内的目录,不存在则自动创建)
WORKDIR /app

# 3. 复制package.json和package-lock.json到容器内(先复制依赖文件,利用Docker缓存)
COPY package*.json ./

# 4. 安装项目依赖(--production仅安装生产环境依赖,减少镜像体积)
RUN npm install --production

# 5. 复制项目源代码到容器内
COPY . .

# 6. 声明容器暴露的端口(仅声明,实际映射需在docker run时用-p参数)
EXPOSE 3000

# 7. 容器启动时执行的命令(启动Node.js应用)
CMD ["node", "app.js"]

4.3 构建并运行自定义镜像


# 1. 构建镜像(在Dockerfile所在目录执行)
docker build -t my-node-app:v1.0 .

# 2. 查看构建后的镜像
docker images | grep my-node-app

# 3. 启动自定义镜像的容器
docker run -d -p 3000:3000 --name my-app my-node-app:v1.0

# 4. 验证服务是否正常(访问宿主机3000端口)
curl http://localhost:3000

4.4 镜像优化技巧

  • 选择轻量基础镜像(如 alpine 版本),减少镜像体积。

  • 合理排序指令,利用 Docker 缓存(不变的指令放前面,如 FROM、COPY package*.json)。

  • 安装依赖时使用 --production 排除开发环境依赖。

  • 使用 .dockerignore 文件排除不需要复制到容器的文件(如 node_modules、.git、日志文件等)。

  • 采用多阶段构建(适用于编译型项目,如Go、Java),仅保留运行时所需文件,进一步减小镜像体积。

五、Docker Compose 多容器管理

在实际项目中,应用通常需要多个服务协同工作(如前端服务、后端服务、数据库服务),Docker Compose 可以通过一个 YAML 文件定义所有服务的配置,实现一键启动/停止所有服务。

5.1 Docker Compose 安装

Docker Desktop(Windows/Mac)默认集成 Docker Compose,Linux 系统需单独安装:


# Linux 安装示例(CentOS/Ubuntu)
sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 赋予执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 验证安装
docker-compose --version

5.2 docker-compose.yml 核心指令

  • version:指定 docker-compose.yml 的语法版本(推荐 3.x)。

  • services:定义所有需要运行的服务(每个服务对应一个容器)。

  • image:指定服务使用的镜像。

  • build:指定构建自定义镜像的 Dockerfile 路径(替代 image 指令)。

  • ports:端口映射(同 docker run -p)。

  • volumes:数据卷挂载(同 docker run -v)。

  • environment:设置环境变量(同 docker run -e)。

  • depends_on:定义服务启动顺序(如先启动数据库,再启动后端服务)。

  • networks:指定服务加入的网络(同 docker run --network)。

5.3 多服务实战(Node.js + MySQL)

项目结构:


my-project/
├── backend/
│   ├── package.json
│   ├── app.js
│   └── Dockerfile
└── docker-compose.yml

编写 docker-compose.yml:


version: '3.8'  # 语法版本

services:
  # 后端服务(Node.js)
  backend:
    build: ./backend  # 从./backend目录的Dockerfile构建镜像
    ports:
      - "3000:3000"  # 宿主机3000端口映射到容器3000端口
    volumes:
      - ./backend:/app  # 开发环境挂载代码目录(实时更新,无需重新构建镜像)
      - /app/node_modules  # 排除node_modules目录(避免宿主机覆盖容器内的依赖)
    environment:
      - NODE_ENV=production
      - DB_HOST=mysql  # 数据库服务名(自定义网络支持DNS解析)
      - DB_PORT=3306
      - DB_USER=root
      - DB_PASSWORD=123456
      - DB_NAME=test_db
    depends_on:
      - mysql  # 先启动mysql服务,再启动backend服务
    networks:
      - my-network

  # 数据库服务(MySQL)
  mysql:
    image: mysql:8.0  # 使用官方MySQL 8.0镜像
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql  # 数据卷挂载,持久化MySQL数据
      - ./backend/init.sql:/docker-entrypoint-initdb.d/init.sql  # 初始化数据库脚本
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_DATABASE=test_db
    networks:
      - my-network

# 定义数据卷(持久化MySQL数据)
volumes:
  mysql-data:

# 定义自定义网络(服务间互通)
networks:
  my-network:
    driver: bridge

5.4 Docker Compose 核心命令


# 1. 启动所有服务(后台运行)
# 格式:docker-compose up [参数]
docker-compose up -d  # -d:后台运行

# 2. 查看服务状态
docker-compose ps

# 3. 查看服务日志
docker-compose logs  # 查看所有服务日志
docker-compose logs -f backend  # 实时跟踪backend服务日志

# 4. 进入某个服务的容器
docker-compose exec backend /bin/sh  # 进入backend容器终端

# 5. 停止所有服务(保留容器和数据)
docker-compose down

# 6. 停止所有服务并删除容器、数据卷、网络(彻底清理)
docker-compose down -v

# 7. 构建/重新构建服务镜像
docker-compose build  # 构建所有服务的镜像
docker-compose build backend  # 仅构建backend服务的镜像
docker-compose up -d --build  # 启动服务时重新构建镜像

# 8. 扩展服务实例数(仅适用于支持扩缩容的服务)
docker-compose up -d --scale backend=3  # 将backend服务扩展到3个实例

六、常见问题与排错技巧

6.1 容器启动失败

  • 查看容器日志:docker logs 容器名,日志中通常会显示失败原因(如端口被占用、依赖缺失、配置错误)。

  • 检查端口是否被占用:netstat -tuln | grep 端口号(Linux),更换未被占用的端口重新启动。

  • 检查镜像是否正确:确保拉取的镜像标签正确,自定义镜像构建无错误。

6.2 容器间无法互通

  • 确保所有服务加入同一个网络(推荐使用自定义网络,而非默认的 bridge 网络)。

  • 使用服务名而非 IP 访问(自定义网络支持 DNS 解析,默认 bridge 网络不支持)。

  • 检查容器是否正常运行:docker ps,确保目标服务容器处于运行状态。

6.3 数据卷挂载失败

  • 检查宿主机目录权限:确保宿主机目录有足够的权限(如 755),容器内用户可以读写。

  • 检查挂载路径格式:确保路径写法正确(宿主机目录:容器内目录),Windows 系统路径需使用反斜杠 \\ 或正斜杠 /

  • 查看容器挂载信息:docker inspect 容器名 | grep Mounts -A 20,确认挂载是否生效。

6.4 镜像体积过大

  • 使用轻量基础镜像(如 alpine 版本)。

  • 优化 Dockerfile,利用缓存,排除不必要的文件(通过 .dockerignore)。

  • 采用多阶段构建,仅保留运行时所需文件。

七、学习总结与后续规划

Docker 是 K8s 的基础,掌握 Docker 的核心知识点(镜像、容器、数据卷、Dockerfile、Compose)后,学习 K8s 会更加轻松,因为 K8s 的核心思想(容器编排、服务发现、负载均衡)与 Docker 一脉相承。

后续学习建议:

  1. 熟练掌握本文档中的命令和实战案例,多动手实操(如打包不同类型的应用:前端、后端、数据库)。

  2. 深入理解 Docker 的网络模型和数据持久化机制(为 K8s 的网络和存储学习打下基础)。

  3. 学习 Docker 镜像的优化技巧,理解镜像分层原理。

  4. 尝试使用 Docker Compose 部署复杂的多服务应用(如前端+后端+数据库+缓存)。

  5. 完成 Docker 学习后,进入 K8s 学习,重点理解 K8s 对容器的编排和管理能力(Pod、Deployment、Service 等核心组件)。

最后,记住:技术学习的核心是「实践」,多敲命令、多踩坑、多排错,才能真正掌握 Docker!

(注:文档部分内容可能由 AI 生成)