Docker 学习笔记(K8s前置必备)
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 一脉相承。
后续学习建议:
-
熟练掌握本文档中的命令和实战案例,多动手实操(如打包不同类型的应用:前端、后端、数据库)。
-
深入理解 Docker 的网络模型和数据持久化机制(为 K8s 的网络和存储学习打下基础)。
-
学习 Docker 镜像的优化技巧,理解镜像分层原理。
-
尝试使用 Docker Compose 部署复杂的多服务应用(如前端+后端+数据库+缓存)。
-
完成 Docker 学习后,进入 K8s 学习,重点理解 K8s 对容器的编排和管理能力(Pod、Deployment、Service 等核心组件)。
最后,记住:技术学习的核心是「实践」,多敲命令、多踩坑、多排错,才能真正掌握 Docker!
(注:文档部分内容可能由 AI 生成)