Docker 安装与核心概念
一、Docker 是什么
Docker 是一个容器化工具,让你把应用和它的所有依赖打包到一个"容器"里,在任何地方都能运行。
类比:你把一道菜的所有食材、调料、锅具打包成一个箱子,搬到任何厨房都能直接做出来,不用担心"这个厨房没有酱油"的问题。
二、核心概念
镜像(Image)
只读的模板,用来创建容器。
类比:
- 镜像 = 一张光盘(ISO 安装盘)
- 容器 = 用这张光盘装好的、正在运行的操作系统
你可以从网上下载别人做好的镜像(比如 python:3.11、nginx:latest),也可以自己用 Dockerfile 制作镜像。
镜像的特点:
- 只读——你不能改镜像里面的东西,只能在容器里改
- 可以叠加——比如基于 python:3.11 镜像,再加上你的代码,变成一个新的镜像
- 可以分发——你做好的镜像可以给别人用
容器(Container)
镜像的运行实例,一个独立的小环境。
类比:
- 容器 = 用光盘装好的、正在运行的操作系统
- 你可以同时运行多个容器,每个容器互相隔离
容器的特点:
- 可读写——你可以在容器里创建文件、修改配置
- 临时的——容器删了,里面的数据就没了(除非用了卷)
- 隔离的——容器 A 里的操作不影响容器 B
Dockerfile
制作镜像的配方。
你写一个文本文件,告诉 Docker:
- 基于什么镜像(FROM)
- 复制哪些文件进去(COPY)
- 执行什么命令(RUN)
- 启动时运行什么(CMD)
Docker 读这个文件,自动帮你构建出一个镜像。
卷(Volume)
让容器里的数据持久化。
容器删了数据就没了,但如果你把一个目录"挂载"到容器外面,数据就存在宿主机上,容器删了数据还在。
宿主机目录 /data ←→ 容器目录 /app/data
类比:容器是临时租的房子,卷是你自己买的 U 盘——搬走房子(删容器),U 盘(数据)还在。
它们的关系
Dockerfile(配方)
↓ docker build
镜像(光盘)
↓ docker run
容器(正在运行的系统)
↑
用卷挂载数据(持久化)
三、Docker 安装(Ubuntu)
方式一:使用国内镜像源(推荐)
# 1. 安装依赖工具
sudo apt install -y ca-certificates curl gnupg
# ca-certificates:系统 SSL 安全证书,用于安全下载 Docker 官方文件
# curl:网络下载工具,用来拉取 Docker 官方密钥、源文件
# gnupg:加密签名工具,校验 Docker 软件包真伪,防止篡改
# 2. 添加 Docker 的 GPG 密钥(让 apt 信任 Docker 的软件包)
sudo mkdir -p /etc/apt/keyrings
# -p核心参数:
# 如果 /etc/apt/keyrings 文件夹不存在 → 自动逐层创建;
# /etc/apt/keyrings
# 路径含义:Ubuntu 系统存放第三方软件源加密密钥的标准目录。
curl -fsSL https://mirrors.tencentyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# -f:下载失败直接抛出错误,不会静默卡住;
# -s:静默模式,不打印下载进度、多余日志;
# -L:自动跟随网址重定向;
# gpg:加密校验工具;
# --dearmor:转换格式,把网页下载的文本密钥,转为 apt 软件源能识别的二进制密钥文件;
# -o = output 输出,把转换完成的密钥保存到第一步创建的目录里,文件名叫 docker.gpg。
# 3. 添加 Docker 的 apt 源(用国内镜像)
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.tencentyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# deb:声明这是 Debian/Ubuntu 二进制软件源(安装程序包用);
# [arch=$(dpkg --print-architecture)]:自动识别服务器架构(amd64/arm64),适配 x86、ARM 机器;
# signed-by=/etc/apt/keyrings/docker.gpg:指定用刚才导入的密钥校验本软件源所有安装包;
# 中间网址:国内 Docker 镜像源,比官方海外源下载速度快很多;
# $(lsb_release -cs):自动读取系统 Ubuntu 版本代号(jammy/focal 等),不用手动改版本;
# stable:稳定版 Docker 分支,不装测试、开发版。
# 4. 更新索引并安装 Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# docker-ce:Docker 核心引擎,容器运行底层服务;
# docker-ce-cli:Docker 命令行工具,你敲docker xxx全靠它;
# containerd.io:容器运行时,管理容器生命周期;
# docker-compose-plugin:多容器编排插件,开发必备;
# 5. 把当前用户加入 docker 组(以后不用每次 sudo)
sudo usermod -aG docker $USER
newgrp docker
# -G:附加附加用户组(不是登录主组)
# -a:append 追加;不能省略
# 不加 -a 只写 -G 会清空你用户原本所有附加组,造成权限丢失
# newgrp:
# new group,临时切换当前终端会话的用户组环境。
# docker:
# 切换到 docker 用户组。
# 6. 验证安装
docker run hello-world
方式二:使用官方一键脚本
# 阿里云镜像
curl -fsSL https://get.docker.com | sudo sh -s -- --mirror Aliyun
# 或 Azure 中国镜像
curl -fsSL https://get.docker.com | sudo sh -s -- --mirror AzureChinaCloud
安装过程踩坑记录
apt install docker.io报错containerd.io : Conflicts: containerd- 原因:Ubuntu 自带的 docker.io 包跟已安装的 containerd.io 冲突
- 解决:不要用 docker.io,用 Docker 官方源安装 docker-ce
curl get.docker.com连接被重置- 原因:服务器无法直接访问 Docker 官网
- 解决:使用国内镜像源
docker 命令需要 sudo
- 原因:普通用户不在 docker 组
- 解决:
sudo usermod -aG docker $USER然后newgrp docker
四、Docker 常用命令
镜像相关
# 查看本地所有镜像
docker images
# 搜索远程镜像
docker search nginx
# 拉取镜像(从 Docker Hub 下载)
docker pull nginx:latest
docker pull python:3.11-slim
# 删除镜像
docker rmi 镜像名:标签
容器相关
# 创建并启动容器
docker run -d -p 80:80 nginx
# -d 后台运行
# -p 宿主机端口:容器端口
# 查看运行中的容器
docker ps
# 查看所有容器(含停止的)
docker ps -a
# 停止容器
docker stop 容器名/容器ID
# 启动已停止的容器
docker start 容器名/容器ID
# 删除容器(必须先停止)
docker rm 容器名/容器ID
# 强制删除运行中的容器
docker rm -f 容器名/容器ID
# 查看容器日志
docker logs 容器名
docker logs -f 容器名 # 实时跟踪
# 进入容器内部
docker exec -it 容器名 bash
# 查看容器资源使用
docker stats
构建相关
# 从 Dockerfile 构建镜像
docker build -t 镜像名:标签 .
# -t 指定镜像名称和标签
# . 表示当前目录(Dockerfile 所在目录)
卷相关
# 运行容器时挂载卷
docker run -d -v 宿主机路径:容器路径 镜像名
# 例:docker run -d -v /data/blog:/app/data blog-api
# 命名卷(Docker 管理的卷)
docker volume create mydata
docker run -d -v mydata:/app/data 镜像名
清理相关
# 删除所有已停止的容器
docker container prune
# 删除所有未使用的镜像
docker image prune
# 删除所有未使用的数据(容器+镜像+卷)
docker system prune -a
五、Docker 网络
Docker 会自动创建一个虚拟网络,容器之间可以通过容器名互相访问。
# 查看 Docker 网络
docker network ls
# 运行两个容器在同一个网络
docker network create mynet
docker run -d --name api --network mynet 镜像名
docker run -d --name web --network mynet 镜像名
# 在 web 容器里可以通过 http://api 访问 api 容器
六、Docker vs 虚拟机
| 对比 | Docker 容器 | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级 | 分钟级 |
| 镜像大小 | MB 级 | GB 级 |
| 性能 | 接近原生 | 有损耗 |
| 隔离级别 | 进程级 | OS 级 |
| 内核 | 共享宿主机内核 | 独立内核 |
面试常问:Docker 和虚拟机的区别?
答:Docker 容器共享宿主机内核,启动快、占用资源少;虚拟机有独立内核,隔离性更强但更重。Docker 适合微服务和快速部署,虚拟机适合需要强隔离的场景。
七、Dockerfile 基础语法
# 基础镜像
FROM python:3.11-slim
# 设置工作目录
WORKDIR /app
# 复制文件到容器
COPY requirements.txt .
COPY . .
# 执行命令(构建时执行)
RUN pip install -r requirements.txt
# 暴露端口(声明,不是实际映射)
EXPOSE 8001
# 启动命令(容器运行时执行)
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001"]
常用指令
| 指令 | 作用 | 示例 |
|---|---|---|
| FROM | 指定基础镜像 | FROM python:3.11-slim |
| WORKDIR | 设置工作目录 | WORKDIR /app |
| COPY | 复制文件到容器 | COPY . . |
| RUN | 构建时执行命令 | RUN pip install -r requirements.txt |
| EXPOSE | 声明端口 | EXPOSE 8001 |
| CMD | 容器启动命令 | CMD ["uvicorn", "main:app"] |
| ENV | 设置环境变量 | ENV PYTHONUNBUFFERED=1 |
| ARG | 构建时的变量 | ARG VERSION=1.0 |
指令类比
| 指令 | 类比 | 说明 |
|---|---|---|
| FROM | 买一台新电脑 | 选择一个操作系统和预装环境 |
| WORKDIR | 设定工作区 | cd到某个目录 |
| COPY | 拷文件进去 | 把代码和数据复制到镜像 |
| RUN | 装软件、配环境 | 执行一次性的安装和配置 |
| CMD | 设置开机启动 | 容器启动时自动运行的命令 |
| EXPOSE | 告诉别人端口号 | 声明应用监听哪个端口 |
分层缓存机制
Dockerfile 的每条指令都会创建一层。Docker 会缓存每一层,如果某一层没有变化,就用缓存而不是重新构建。
# 这样写更好——先复制依赖文件,再复制代码
COPY requirements.txt . # 只要 requirements.txt 没变,这一层就用缓存
RUN pip install -r requirements.txt
COPY . . # 代码变了只重建这一层
如果写反了(先 COPY . . 再 RUN pip install),每次代码改动都会重新安装依赖,很慢。
八、docker-compose 基础
什么是 docker-compose
用一个 YAML 文件定义多个容器,一条命令全部启动。
类比:Docker 是一个厨师做一道菜,docker-compose 是一份菜谱,告诉多个厨师分别做什么,一起端上来。
基本格式
version: '3'
services:
后端服务名:
build: ./backend
ports:
- "8001:8001"
volumes:
- ./data:/app/data
restart: always
前端服务名:
build: ./frontend
ports:
- "3000:3000"
depends_on:
- 后端服务名
restart: always
常用命令
# 启动所有服务(后台运行)
docker-compose up -d
# 停止所有服务
docker-compose down
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f
# 重新构建并启动
docker-compose up -d --build
常用配置项
| 配置 | 作用 |
|---|---|
| build | 指定 Dockerfile 所在目录 |
| ports | 端口映射(宿主机:容器) |
| volumes | 卷挂载(宿主机:容器) |
| environment | 环境变量 |
| depends_on | 启动顺序依赖 |
| restart | 重启策略(always/on-failure/no) |
| networks | 指定网络 |
九、问答
Q:Docker 和虚拟机的区别?
Docker 容器共享宿主机内核,启动快(秒级)、占用资源少(MB级);虚拟机有独立内核,启动慢(分钟级)、占用资源多(GB级)。Docker 适合微服务和快速部署,虚拟机适合需要强隔离的场景。
Q:镜像和容器的区别?
镜像是只读模板,容器是镜像的运行实例。一个镜像可以创建多个容器,容器之间互相隔离。类比:镜像=光盘,容器=用光盘装好的操作系统。
Q:Dockerfile 中 COPY 和 ADD 的区别?
COPY 只做简单复制。ADD 除了复制还能自动解压 tar 包、支持 URL 下载。一般用 COPY 就够了,需要解压时才用 ADD。
Q:数据持久化怎么做?
用 -v 参数挂载卷:docker run -v 宿主机路径:容器路径。容器删了数据还在宿主机上。也可以用命名卷(docker volume create)让 Docker 管理。
Q:docker-compose 是什么?
用一个 YAML 文件定义多个容器的启动配置,一条 docker-compose up 命令全部启动。适合需要多个服务协作的场景(比如前端+后端+数据库)。
Q:Dockerfile 的分层缓存是什么?
Dockerfile 每条指令创建一层,Docker 会缓存每一层。如果某层没变化就用缓存,不重新构建。所以要把不常变的指令(如安装依赖)放前面,常变的(如复制代码)放后面。
