Docker 核心概念

Docker 基础概念理解:镜像、容器、仓库


1. 一句话概括主题

Docker 是一个把应用程序和它的运行环境打包在一起的工具,让你可以在任何地方都能用相同的方式运行程序。


2. 它是什么(口语化解释)

想象一下,你开发了一个网站,在你的电脑上运行得很好。但是当你要把它放到服务器上时,可能会遇到各种问题:服务器上的软件版本不一样、缺少某些依赖、配置不同等等。

Docker 就像是一个”打包盒”,它把你的应用程序和它需要的所有东西(比如操作系统、数据库、各种软件包)都打包在一起,形成一个”镜像”。这个镜像可以在任何安装了 Docker 的电脑上运行,而且运行效果完全一样。

简单来说:Docker 就像是一个”应用程序的集装箱”,一次打包,到处运行。


3. 能解决什么问题 + 为什么重要

解决的问题

  1. “在我电脑上能跑”的问题

    • 传统方式:开发环境、测试环境、生产环境可能不一样,导致程序在不同环境表现不同
    • Docker 解决:打包后在任何环境运行都一样
  2. 环境配置复杂的问题

    • 传统方式:每次部署都要手动安装各种软件、配置环境
    • Docker 解决:一次配置,到处使用
  3. 资源浪费的问题

    • 传统方式:每个应用需要独立的虚拟机,占用大量资源
    • Docker 解决:多个容器共享操作系统,资源利用率高
  4. 部署速度慢的问题

    • 传统方式:部署一个新环境可能需要几小时甚至几天
    • Docker 解决:几秒钟就能启动一个容器

为什么重要

  • 提高效率:开发、测试、部署更快
  • 降低成本:更少的服务器资源,更低的运维成本
  • 提高可靠性:环境一致,减少”在我电脑上能跑”的问题
  • 便于扩展:可以轻松地启动多个相同的容器

4. 核心知识点拆解

4.1 镜像(Image)

镜像是什么:镜像就像是一个”模板”或者”快照”,包含了运行程序所需的一切。

类比理解

  • 镜像 = 安装光盘(只读的,不能修改)
  • 一个镜像可以创建多个容器,就像一张光盘可以安装多台电脑

特点

  • 只读的:镜像本身不能被修改
  • 分层的:镜像由多个层组成,可以复用
  • 可复用的:一个镜像可以创建多个容器

示例

# 查看本地有哪些镜像(就像查看你有哪些安装光盘)
docker images
 
# 从网上下载一个镜像(就像下载一个软件安装包)
docker pull nginx:latest

4.2 容器(Container)

容器是什么:容器是镜像运行起来后的实例,就像用安装光盘安装好的系统。

类比理解

  • 镜像 = 安装光盘(模板)
  • 容器 = 安装好的系统(实际运行的程序)

特点

  • 可运行的:容器是实际运行的程序
  • 隔离的:每个容器都有自己独立的环境
  • 轻量级的:多个容器共享操作系统内核

示例

# 用镜像创建一个容器并运行(就像用光盘安装系统)
docker run -d nginx:latest
 
# 查看正在运行的容器(就像查看正在运行的程序)
docker ps

4.3 仓库(Repository)

仓库是什么:仓库是存放镜像的地方,就像应用商店。

类比理解

  • Docker Hub = 官方应用商店(公共的,免费的)
  • 私有仓库 = 公司内部的软件仓库(需要权限)

分类

  1. 公共仓库(Docker Hub)

    • 就像手机的应用商店,任何人都可以下载
    • 例如:nginx:latestubuntu:20.04
  2. 私有仓库

    • 就像公司内部的软件仓库,只有公司员工可以访问
    • 例如:registry.company.com/myapp:latest

4.4 镜像与容器的关系

关系图

镜像(Image)- 模板
  ├── 只读层 1
  ├── 只读层 2
  └── 只读层 3
        ↓
容器(Container)- 运行实例
  ├── 只读层 1(来自镜像,不能修改)
  ├── 只读层 2(来自镜像,不能修改)
  ├── 只读层 3(来自镜像,不能修改)
  └── 可写层(容器独有,可以修改)

关键点

  1. 一个镜像可以创建多个容器

    • 就像一张安装光盘可以安装多台电脑
    • 每个容器都是独立的,互不影响
  2. 容器修改不影响镜像

    • 容器中的修改只存在于可写层
    • 删除容器后,修改会丢失
    • 如果需要保存数据,需要使用数据卷
  3. 容器是镜像的运行实例

    • 镜像 = 类(Class)
    • 容器 = 对象(Object)

5. 示例代码(逐行注释)

示例 1:拉取并运行一个 Nginx 容器

# 第1步:从 Docker Hub 拉取 nginx 镜像
# 这就像从应用商店下载一个软件
docker pull nginx:latest
 
# 第2步:查看本地有哪些镜像
# 确认镜像已经下载成功
docker images
 
# 第3步:运行容器
# -d 表示在后台运行(detached mode)
# --name my-nginx 给容器起个名字,方便管理
# -p 8080:80 端口映射,把容器的80端口映射到主机的8080端口
# nginx:latest 使用的镜像名称
docker run -d --name my-nginx -p 8080:80 nginx:latest
 
# 第4步:查看运行中的容器
# 应该能看到 my-nginx 容器正在运行
docker ps
 
# 第5步:测试容器是否正常工作
# 在浏览器访问 http://localhost:8080
# 或者用 curl 命令测试
curl http://localhost:8080
 
# 第6步:查看容器日志
# 如果容器有问题,可以查看日志来排查
docker logs my-nginx
 
# 第7步:停止容器
# 停止运行中的容器
docker stop my-nginx
 
# 第8步:删除容器
# 删除已停止的容器
docker rm my-nginx

示例 2:创建一个简单的 Web 应用容器

# 创建一个简单的 HTML 文件
echo "<h1>Hello Docker!</h1>" > index.html
 
# 运行一个 nginx 容器,并把当前目录挂载到容器中
# -v $(pwd):/usr/share/nginx/html 把当前目录挂载到容器的网页目录
# 这样修改 index.html 文件,容器中的网页也会更新
docker run -d \
  --name my-web \
  -p 8080:80 \
  -v $(pwd):/usr/share/nginx/html \
  nginx:latest
 
# 访问 http://localhost:8080 就能看到 "Hello Docker!"

6. 常见错误与踩坑

错误 1:端口被占用

问题:运行容器时提示端口已被占用

Error: bind: address already in use

原因:主机的端口(如 8080)已经被其他程序占用

解决方法

# 方法1:查看哪个程序占用了端口
lsof -i :8080
# 或者
netstat -tulpn | grep 8080
 
# 方法2:使用其他端口
docker run -d -p 8081:80 nginx:latest
 
# 方法3:停止占用端口的程序
# 根据 lsof 或 netstat 的结果,停止对应的程序

错误 2:镜像不存在

问题:运行容器时提示找不到镜像

Error: Unable to find image 'myapp:latest' locally

原因:本地没有这个镜像,也没有自动拉取

解决方法

# 方法1:先拉取镜像,再运行
docker pull myapp:latest
docker run myapp:latest
 
# 方法2:直接运行,Docker 会自动拉取(如果镜像存在)
docker run myapp:latest

错误 3:容器名称冲突

问题:创建容器时提示名称已存在

Error: Conflict. The container name "/my-nginx" is already in use

原因:已经有一个同名的容器存在(可能是停止的)

解决方法

# 方法1:删除旧的容器
docker rm my-nginx
# 然后再创建新容器
 
# 方法2:使用不同的名称
docker run -d --name my-nginx-2 nginx:latest
 
# 方法3:强制删除并重新创建
docker rm -f my-nginx
docker run -d --name my-nginx nginx:latest

错误 4:忘记使用 -d 参数导致终端被占用

问题:运行容器后,终端被占用,无法输入其他命令

原因:没有使用 -d 参数,容器在前台运行

解决方法

# 按 Ctrl+C 停止容器
# 或者新开一个终端窗口
# 下次运行时记得加 -d 参数
docker run -d nginx:latest

错误 5:容器停止后数据丢失

问题:在容器中创建的文件,容器停止后就不见了

原因:容器中的数据存储在可写层,容器删除后数据就丢失了

解决方法

# 使用数据卷来持久化数据
# 这样即使容器删除,数据也不会丢失
docker run -d \
  -v my-data:/data \
  nginx:latest
 
# 或者使用绑定挂载
docker run -d \
  -v /host/path:/container/path \
  nginx:latest

7. 实际应用场景

场景 1:Web 应用部署

场景描述:部署一个 Node.js 开发的网站

传统方式

  1. 在服务器上安装 Node.js
  2. 安装各种依赖包
  3. 配置环境变量
  4. 启动应用
  5. 配置 Nginx 反向代理
  6. 配置 SSL 证书

使用 Docker

# 1. 编写 Dockerfile(定义如何构建镜像)
# 2. 构建镜像
docker build -t my-webapp:latest .
 
# 3. 运行容器
docker run -d -p 80:3000 my-webapp:latest
 
# 完成!就这么简单

场景 2:数据库服务

场景描述:快速启动一个 MySQL 数据库用于开发测试

传统方式

  1. 下载 MySQL 安装包
  2. 安装 MySQL
  3. 配置 MySQL
  4. 创建数据库和用户
  5. 配置防火墙

使用 Docker

# 一条命令搞定
docker run -d \
  --name mysql-dev \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -e MYSQL_DATABASE=testdb \
  -p 3306:3306 \
  mysql:8.0
 
# 数据库就启动好了,可以直接连接使用

场景 3:微服务架构

场景描述:运行多个相互关联的服务(前端、后端、数据库、Redis)

传统方式

  • 需要手动配置每个服务
  • 需要手动配置服务之间的网络
  • 部署复杂,容易出错

使用 Docker Compose

# docker-compose.yml
version: '3.8'
services:
  frontend:
    image: nginx:latest
    ports:
      - "80:80"
  
  backend:
    build: ./backend
    depends_on:
      - db
      - redis
  
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
  
  redis:
    image: redis:latest
# 一条命令启动所有服务
docker-compose up -d

场景 4:CI/CD 流水线

场景描述:自动化构建、测试、部署

使用 Docker

  1. 代码提交到 Git
  2. CI 系统自动构建 Docker 镜像
  3. 运行测试容器进行测试
  4. 测试通过后推送到镜像仓库
  5. 生产环境自动拉取新镜像并部署

8. 给新手的练习题(可立即实践)

练习 1:运行你的第一个容器

目标:运行一个 Nginx 容器,在浏览器中访问

步骤

  1. 拉取 nginx 镜像:docker pull nginx:latest
  2. 运行容器:docker run -d --name my-first-container -p 8080:80 nginx:latest
  3. 在浏览器访问:http://localhost:8080
  4. 查看容器状态:docker ps
  5. 查看容器日志:docker logs my-first-container
  6. 停止容器:docker stop my-first-container
  7. 删除容器:docker rm my-first-container

预期结果:能看到 Nginx 的欢迎页面

练习 2:创建一个简单的网站

目标:创建一个 HTML 文件,用 Nginx 容器来展示

步骤

  1. 创建一个 index.html 文件,内容为 <h1>我的第一个 Docker 网站</h1>
  2. 运行容器并挂载当前目录:docker run -d --name my-site -p 8080:80 -v $(pwd):/usr/share/nginx/html nginx:latest
  3. 访问 http://localhost:8080 查看你的网站
  4. 修改 index.html 文件,刷新浏览器,看看变化

预期结果:能看到你创建的 HTML 内容,并且修改后能立即看到变化

练习 3:运行一个交互式容器

目标:进入一个 Ubuntu 容器,体验容器环境

步骤

  1. 运行交互式容器:docker run -it --name my-ubuntu ubuntu:20.04 /bin/bash 20260130-运行交互式容器
  2. 在容器内执行命令:
    • ls - 查看文件列表
    • pwd - 查看当前目录
    • whoami - 查看当前用户
    • apt update && apt install -y curl - 安装软件
  3. 退出容器:输入 exit
  4. 查看容器:docker ps -a(应该能看到已停止的容器)

预期结果:能够进入容器并执行命令,体验容器的隔离环境

练习 4:管理多个容器

目标:运行多个容器,练习容器的管理

步骤

  1. 运行 3 个 nginx 容器,使用不同的端口:
    docker run -d --name web1 -p 8081:80 nginx:latest
    docker run -d --name web2 -p 8082:80 nginx:latest
    docker run -d --name web3 -p 8083:80 nginx:latest
  2. 查看所有运行中的容器:docker ps
  3. 分别访问 http://localhost:808180828083
  4. 停止所有容器:docker stop web1 web2 web3
  5. 删除所有容器:docker rm web1 web2 web3

预期结果:能够同时运行多个容器,并管理它们


9. 用更简单的语言再总结一遍(方便复习)

核心概念回顾

Docker 是什么

  • 就像是一个”应用程序的打包盒”
  • 把你的程序和它需要的一切都打包在一起
  • 打包后可以在任何地方运行,效果完全一样

三个核心概念

  1. 镜像(Image)

    • 就像”安装光盘”或”软件安装包”
    • 是只读的模板,包含了运行程序所需的一切
    • 一个镜像可以创建多个容器
  2. 容器(Container)

    • 就像”安装好的系统”或”运行中的程序”
    • 是镜像运行起来的实例
    • 每个容器都是独立的,互不影响
  3. 仓库(Repository)

    • 就像”应用商店”
    • 是存放镜像的地方
    • Docker Hub 是最大的公共仓库

关系

  • 镜像 → 容器:就像用光盘安装系统
  • 一个镜像可以创建多个容器
  • 容器删除后,数据会丢失(除非使用数据卷)

为什么重要

  • 解决了”在我电脑上能跑”的问题
  • 部署更快、更简单
  • 资源利用率更高
  • 环境一致性更好

常用命令

  • docker pull - 下载镜像(就像下载软件)
  • docker run - 运行容器(就像启动程序)
  • docker ps - 查看运行中的容器(就像查看运行的程序)
  • docker stop - 停止容器(就像关闭程序)
  • docker rm - 删除容器(就像卸载程序)

记住

  • 镜像 = 模板(不能修改)
  • 容器 = 实例(可以运行和修改)
  • 仓库 = 商店(存放镜像的地方)

📚 相关链接


📚 参考资源


相关笔记