通俗易懂地学习一下docker
本文最后更新于193 天前,其中的信息可能已经过时,如有错误请发送邮件到2067863254@qq.com

Dockerfile和自定义镜像

太好了!我们继续用“物流系统”的比喻,来深入讲解Dockerfile和自定义镜像的知识。这就像是学习如何自己设计模具,而不是总是用别人做好的。


Dockerfile是什么?

通俗解释:Dockerfile就像是制作模具的“配方”或“施工图纸”。

  • 之前我们都是用别人做好的模具(镜像),比如nginxubuntu
  • 现在,我们想做一个专属模具,比如“一个包含我的Python代码、依赖库和配置文件的专属服务器模具”。
  • Dockerfile就是这个模具的详细制作说明书,里面一步一步地写着该怎么制作。

Dockerfile核心语法详解

让我们来看这份“说明书”里最重要的几个指令:

1. FROM– 选择基础模具

比喻:​ 你要做蛋糕,不会从种小麦开始。你会先买一个现成的蛋糕胚作为基础。FROM就是指定这个“基础蛋糕胚”。

  • 语法:FROM <基础镜像>
  • 例子:
    • FROM ubuntu:20.04(基于Ubuntu系统这个模具开始加工)
    • FROM python:3.9(基于一个已经装好Python的模具开始加工,更省事!)
  • 重要:每个Dockerfile必须以FROM指令开头。你必须基于一个已有的镜像开始构建。

2. RUN– 在制作过程中执行命令

比喻:​ 在蛋糕胚上进行操作步骤。比如:“RUN 涂抹奶油”、“RUN 放上草莓”。

  • 语法:RUN <命令>
  • 例子:
    • RUN apt-get update && apt-get install -y python3(在基于Ubuntu的模具里安装Python3)
    • RUN pip install -r requirements.txt(安装Python依赖包)
  • 作用:​ 执行任何需要在容器内部完成的设置和安装命令。

3. COPY/ ADD– 把文件放进模具里

比喻:​ 把你的独家秘方(代码、配置文件)​ 放进蛋糕里。

  • 语法:COPY <源路径> <目标路径>
  • 例子:
    • COPY . /app(将当前目录下的所有文件,复制到模具内的/app目录下)
    • COPY requirements.txt /code/requirements.txt(只复制依赖列表文件)
  • COPYvs ADD​ 对初学者来说,用COPY就够了。ADD有一些额外功能(如自动解压),但原则是:除非你需要解压,否则一律用COPY

4. WORKDIR– 设置工作目录

比喻:​ 指定一个工作台。之后的所有操作(比如RUNCOPY)默认都在这个工作台上进行。

  • 语法:WORKDIR <路径>
  • 例子:WORKDIR /app
  • 好处:​ 避免了在命令中写很长的绝对路径,让“说明书”更清晰。

5. EXPOSE– 声明端口

比喻:​ 在模具的设计图上标注出“这里有个服务窗口”

  • 语法:EXPOSE <端口号>
  • 例子:EXPOSE 80
  • 注意:​ 这只是一个声明,方便别人看文档知道这个镜像用什么端口。它并不会自动完成端口映射!​ 真正的端口映射还是在运行容器时用 -p参数来做。

6. CMD– 容器启动时默认要运行的命令

比喻:​ 给这个货箱(容器)贴上使用说明书的第一条:“启动后,请自动运行这个程序”。

  • 语法:CMD [“可执行文件”, “参数1”, “参数2”](推荐这种格式,称为exec格式
  • 例子:CMD [“python”, “app.py”]
  • 重要:​ Dockerfile中只能有一条CMD指令,如果有多条,则只有最后一条生效。
  • RUNvs CMD的区别(核心概念!):
    • RUN构建镜像(制造模具)时执行的命令,比如安装软件。
    • CMD启动容器(激活货箱)时执行的命令,比如启动服务器。你可以通过在docker run时指定新命令来覆盖CMD

7. ENV– 设置环境变量

比喻:​ 在模具里预设一些全局配置参数,比如“甜度=高”。

  • 语法:ENV <key> <value>ENV <key1>=<value1> <key2>=<value2>
  • 例子:ENV MODE=production

一个完整的Dockerfile例子

假设我们有一个简单的Python Flask应用,项目结构如下:

my-app/
├── app.py          # 你的Python代码
├── requirements.txt # 依赖列表
└── Dockerfile      # 我们正在写的“模具说明书”

Dockerfile 内容:

# 第一行:选择一个已经装好Python的基础模具,省去自己安装Python的麻烦
FROM python:3.9-slim

# 设置工作目录为 /app,后续操作都在这里进行
WORKDIR /app

# 先把依赖列表文件复制到工作目录
# (这是一个优化技巧,利用Docker的缓存层,如果requirements.txt没变,则不需要重新pip install)
COPY requirements.txt .

# 在构建镜像时执行命令:安装依赖包
RUN pip install --no-cache-dir -r requirements.txt

# 再把当前目录的所有文件(你的代码)都复制到工作目录
COPY . .

# 声明容器运行时提供服务的端口是5000(只是声明,不是映射)
EXPOSE 5000

# 设置一个环境变量
ENV FLASK_APP=app.py

# 指定容器启动时默认运行的命令:启动Flask应用
CMD ["flask", "run", "--host", "0.0.0.0"]

如何“施工”:使用Dockerfile构建自定义镜像

现在,我们有了“施工图纸”(Dockerfile),可以开始制造我们自己的模具了! 命令:docker build -t <你的镜像名> <上下文路径>

  • -t​ 给构建成功的镜像打一个标签(起个名字),格式通常是用户名/镜像名:标签,如果不上传可以随便起,比如my-python-app:v1
  • .​ 这个点代表构建上下文的路径。Docker引擎会把当前目录(包括子目录)的所有文件打包发送给Docker守护进程。所以不要把无关的大文件放在Dockerfile所在目录。可以用 .dockerignore文件来忽略不需要的文件(类似 .gitignore)。

实际操作:

  1. 在终端中,进入包含Dockerfile的目录(my-app/)。
  2. 执行命令: docker build -t my-python-app:latest .
  3. 你会看到Docker一步步执行Dockerfile中的指令,每一行都会生成一个临时的“镜像层”。
  4. 构建成功后,用 docker images查看,你就能看到崭新的 my-python-app镜像了!

运行你的自定义镜像:

docker run -d -p 5000:5000 my-python-app:latest

现在,你的自定义应用就在容器中运行起来了!

核心思想总结

  1. 分层构建:​ Dockerfile的每条指令都会创建一个新的镜像层。如果Dockerfile没变,重建时会直接使用缓存,极大加快构建速度。这就是为什么我们把变化频率低的操作(如COPY requirements.txtRUN pip install)放在前面,变化频率高的操作(如COPY . .复制代码)放在后面。
  2. 一个容器一个进程:​ 理想情况下,一个容器只运行一个主进程(由CMD指定)。这符合Docker的“单一职责”原则。
  3. 镜像要尽可能小:​ 选择更小的基础镜像(如-slim版本),及时清理不必要的缓存文件,让你的“模具”更轻便。

现在,你已经掌握了从“使用者”到“创造者”的关键一步!试着为你自己的项目写一个Dockerfile吧,这是学习Docker最有成就感的部分!



好的!我们继续用“物流系统”的比喻,来讲解Docker容器网络这个既重要又有趣的话题。

为什么需要容器网络?

想象一下我们的物流中心:

  • 每个容器都是一个独立的“货箱”
  • 这些货箱里运行着不同的服务:有的装数据库,有的装网站前端,有的装后端API

问题来了:​ 如果这些货箱都完全隔离,互相不知道对方的存在,那网站前端怎么访问后端API?后端又怎么连接数据库? 答案就是:我们需要在货箱之间修建“道路”,让它们能够相互通信!​ 这就是Docker网络的作用。


Docker网络的三种基本“道路系统”

Docker提供了几种不同的网络模式,就像不同级别的道路:

1. 桥接网络 – “物流中心内部道路”(默认模式)

比喻:​ 这是Docker自己创建的一个虚拟的内部道路系统。所有连接到这个网络的容器,就像在同一个物流园区里,可以通过内部道路相互访问。

  • 特点:
    • 容器之间可以互相通信
    • 每个容器有自己独立的IP地址(比如172.17.0.2, 172.17.0.3)
    • 与外界隔离,安全性较好
    • 这是默认模式,如果你不指定网络,容器就会连接到默认的桥接网络
  • 实际体验: # 运行两个容器,它们会自动连接到默认的桥接网络 docker run -d --name web nginx docker run -d --name database mysql # 进入web容器,尝试ping数据库容器 docker exec -it web /bin/bash # 在容器内执行: ping database # 这会失败!因为默认桥接网络不支持容器名解析 ping 172.17.0.3 # 你需要知道数据库容器的实际IP地址

默认桥接网络的问题:​ 容器之间只能用IP地址通信,不能用容器名,很不方便!

2. 自定义桥接网络 – “带路牌的智能内部道路”(推荐!)

比喻:​ 我们自己修建一个更智能的内部道路系统,每个路口都有清晰的路牌(容器名)

  • 特点:
    • 容器之间不仅可以通过IP通信,还可以直接用容器名相互访问
    • 提供了自动的DNS解析服务(容器名自动解析为IP)
    • 更好的隔离性(只有加入这个网络的容器才能互相访问)
  • 创建和使用: # 1. 创建一个自定义的桥接网络,命名为"my-app-network" docker network create my-app-network # 2. 运行容器时,明确指定加入这个网络 docker run -d --name web --network my-app-network nginx docker run -d --name database --network my-app-network mysql # 3. 现在进入web容器,可以直接用容器名访问数据库! docker exec -it web /bin/bash ping database # 成功了!因为自定义网络支持DNS解析

这是最常用的方式!​ 让你的多容器应用可以像在同一个”内部网络”中一样方便地通信。

3. 主机网络 – “直接把货箱放在马路边”

比喻:​ 跳过所有内部道路,直接把货箱放在公共马路(主机网络)​ 旁边。容器直接使用主机的网络堆栈。

  • 特点:
    • 容器没有自己的独立网络空间,直接使用主机的IP和端口
    • 性能最好(因为没有网络转换的开销)
    • 最不安全(端口冲突风险大)
  • 使用方式: docker run -d --name web --network host nginx这时候,Nginx就直接在主机的80端口上运行,你不需要-p 80:80端口映射了。

4. 无网络 – “完全隔离的封闭货箱”

比喻:​ 这个货箱没有任何对外的道路,完全封闭。

  • 使用场景:​ 运行一些不需要网络连接的任务,比如数据批处理。 docker run --network none my-batch-job-image

实际场景:搭建一个完整的Web应用

假设我们要搭建一个典型的Web应用:Nginx(前端) + Python应用(后端) + MySQL(数据库)

步骤1:创建专属的“内部道路系统”

docker network create my-app-network

步骤2:启动数据库容器,并加入网络

docker run -d --name mysql-db \
  --network my-app-network \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -v mysql-data:/var/lib/mysql \
  mysql:8.0

步骤3:启动后端应用容器,并加入网络

docker run -d --name backend-api \
  --network my-app-network \
  -v /path/to/your/code:/app \
  your-python-app-image

步骤4:启动前端Web服务器,并加入网络

docker run -d --name nginx-frontend \
  --network my-app-network \
  -p 80:80 \
  -v /path/to/nginx.conf:/etc/nginx/nginx.conf \
  nginx

通信流程:

  1. 用户访问 http://你的服务器IP→ 到达 nginx-frontend​ 容器
  2. Nginx需要调用API → 它直接访问 http://backend-api:8000(用容器名!)
  3. Python后端需要读写数据 → 它直接连接 mysql-db:3306(用容器名!)

这一切都能正常工作,就是因为所有容器都在同一个自定义网络 my-app-network中!


常用的网络管理命令

# 查看所有网络
docker network ls

# 查看某个网络的详细信息(包括哪些容器连接在上面)
docker network inspect my-app-network

# 将正在运行的容器连接到某个网络
docker network connect my-app-network existing-container

# 将容器从某个网络断开
docker network disconnect my-app-network container-name

# 删除网络(必须没有容器连接在上面)
docker network rm my-app-network

核心思想总结

  1. 默认桥接网络不好用:容器之间只能用IP地址通信,不能用名字。
  2. 自定义桥接网络是王道:提供了DNS解析(容器名→IP),让多容器应用开发变得简单。
  3. 网络就是容器间的”道路”:没有网络,容器就是孤岛;有了网络,它们才能协同工作。
  4. 安全隔离:不同的自定义网络是相互隔离的,你可以为不同的项目创建不同的网络。

一句话记住Docker网络:它就是为各个”货箱”(容器)修建内部道路,让它们能够用名字相互喊话、协同工作! 现在,你可以尝试创建一个自定义网络,运行几个容器来体验这种便捷的通信方式了!这是构建复杂多容器应用的基础。接下来我们可以聊聊docker-compose,它能让你用一份配置文件轻松管理整个”物流系统”(包括网络、容器、数据卷等)。



太棒了!Docker Compose 是我们 Docker 学习的最后一个重要拼图,它会让一切变得非常简单和优雅。


为什么需要 Docker Compose?

回忆一下我们之前部署多容器应用有多麻烦:

# 1. 创建网络
docker network create my-app-network

# 2. 启动数据库
docker run -d --name mysql-db --network my-app-network -e MYSQL_ROOT_PASSWORD=123456 -v mysql-data:/var/lib/mysql mysql:8.0

# 3. 启动后端
docker run -d --name backend-api --network my-app-network -v /path/to/code:/app your-python-app-image

# 4. 启动前端
docker run -d --name nginx-frontend --network my-app-network -p 80:80 nginx

问题:

  • 命令又长又复杂,容易打错
  • 要记住很多参数和环境变量
  • 重启整个应用很麻烦
  • 难以在不同环境(开发、测试、生产)之间保持一致性

Docker Compose 的比喻:​ 它就像是物流中心的”一键部署控制台”! 有了这个控制台,你不需要手动一个个安排货箱、修道路、接水管。只需要按下一个按钮(docker-compose up),整个物流系统就自动按设计图纸运转起来了。


Docker Compose 的核心:docker-compose.yml 文件

这个 YAML 文件就是我们的“物流中心设计蓝图”,它用人类可读的方式描述了整个多容器应用。

一个完整的 docker-compose.yml 例子

让我们用之前的三件套应用(Nginx + Python + MySQL)来举例:

# 设计蓝图的版本号
version: '3.8'

# 定义所有服务(就是我们的各个"货箱")
services:
  # 第一个服务:前端Web服务器
  nginx:
    image: nginx:latest  # 使用哪个模具(镜像)
    ports:
      - "80:80"          # 端口映射:主机80端口 -> 容器80端口
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf  # 配置文件挂载
    depends_on:
      - backend          # 声明依赖:先启动backend再启动我
    networks:
      - app-network      # 连接到哪个道路系统

  # 第二个服务:后端API
  backend:
    build: ./backend      # 不是用现成镜像,而是根据Dockerfile构建
    environment:
      - DATABASE_URL=mysql://db:3306/mydb  # 环境变量
      - DEBUG=true
    volumes:
      - ./backend:/app    # 代码热重载:开发时修改代码自动生效
    depends_on:
      - db               # 依赖数据库
    networks:
      - app-network

  # 第三个服务:数据库
  db:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=123456
      - MYSQL_DATABASE=mydb
    volumes:
      - db_data:/var/lib/mysql  # 数据持久化
    networks:
      - app-network

# 定义数据卷(我们的"外接硬盘")
volumes:
  db_data:

# 定义网络(我们的"内部道路系统")
networks:
  app-network:
    driver: bridge

看到了吗?这个 YAML 文件清晰地描述了我们之前用一堆命令才能完成的事情!


Docker Compose 核心语法详解

1. 服务定义(Services)

每个服务相当于一个容器,可以配置:

  • image: 使用现成的镜像,如 nginx:latest
  • build: 根据 Dockerfile 构建镜像,如 build: ./backend
  • ports: 端口映射,格式 "主机端口:容器端口"
  • volumes: 数据卷挂载,支持三种格式:
    • 命名卷:db_data:/var/lib/mysql(推荐用于数据)
    • 绑定挂载:./nginx.conf:/etc/nginx/nginx.conf(推荐用于配置文件)
    • 匿名卷:/var/lib/mysql(不推荐)
  • environment: 环境变量,可以用字典或数组格式
  • depends_on: 依赖关系,控制启动顺序
  • networks: 连接的网络

2. 网络定义(Networks)

  • 可以创建自定义网络,让服务之间用服务名互相访问
  • 如果不指定,Compose 会自动创建一个默认网络

3. 数据卷定义(Volumes)

  • 声明需要使用的命名卷,Compose 会自动创建和管理

Docker Compose 常用命令

有了”设计蓝图”,现在来学习”控制台按钮”:

1. 一键部署​ – docker-compose up

# 启动所有服务(前台运行,可以看到日志)
docker-compose up

# 后台启动所有服务
docker-compose up -d

# 重新构建镜像并启动(Dockerfile有修改时使用)
docker-compose up --build

就像:​ 按下”开始运营”按钮,整个物流中心按蓝图自动运转起来。

2. 查看状态​ – docker-compose ps

# 查看当前项目的服务状态
docker-compose ps

输出示例:

Name                  Command               State           Ports         
----------------------------------------------------------------------------
myapp_backend_1   python app.py               Up                            
myapp_db_1        docker-entrypoint.sh mysqld Up      3306/tcp, 33060/tcp    
myapp_nginx_1     nginx -g daemon off;        Up      0.0.0.0:80->80/tcp

3. 查看日志​ – docker-compose logs

# 查看所有服务的日志
docker-compose logs

# 查看特定服务的日志
docker-compose logs backend

# 实时跟踪日志
docker-compose logs -f backend

4. 执行命令​ – docker-compose exec

# 在backend服务中执行命令
docker-compose exec backend /bin/bash
docker-compose exec backend python manage.py migrate

5. 停止服务​ – docker-compose down

# 停止并删除所有容器、网络(但保留数据卷)
docker-compose down

# 停止并删除所有容器、网络、数据卷
docker-compose down -v

6. 其他实用命令

# 查看服务依赖图
docker-compose config

# 重启服务
docker-compose restart

# 缩放服务实例数(比如启动3个backend实例)
docker-compose up --scale backend=3

实际项目结构示例

一个典型的 Docker Compose 项目目录结构:

my-app/
├── docker-compose.yml          # Compose配置文件
├── .env                        # 环境变量文件(密码等敏感信息)
├── nginx/
│   ├── nginx.conf             # Nginx配置
│   └── Dockerfile             # 自定义Nginx镜像
├── backend/
│   ├── Dockerfile             # 后端Dockerfile
│   ├── requirements.txt
│   └── app.py
└── frontend/
    ├── Dockerfile             # 前端Dockerfile
    └── src/

.env 文件示例(用于配置敏感信息):

MYSQL_ROOT_PASSWORD=mysecretpassword
DEBUG=true
DATABASE_URL=mysql://db:3306/mydb

然后在 docker-compose.yml 中使用:

environment:
  - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}

开发环境 vs 生产环境

Docker Compose 的一个强大功能是支持多配置文件:

开发环境(使用热重载)

# 使用默认的 docker-compose.yml 和开发环境配置
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

docker-compose.dev.yml:

version: '3.8'
services:
  backend:
    volumes:
      - ./backend:/app  # 代码热重载
    environment:
      - DEBUG=true

生产环境

# 使用生产环境配置
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

docker-compose.prod.yml:

version: '3.8'
services:
  backend:
    environment:
      - DEBUG=false
      - PRODUCTION=true

核心思想总结

  1. 声明式配置:用 YAML 文件描述”你想要什么”,而不是用命令指定”怎么做到”。
  2. 一键操作:复杂的多容器应用,现在只需要 docker-compose updocker-compose down
  3. 环境一致性:开发、测试、生产环境使用相同的配置,避免”在我电脑上是好的”问题。
  4. 服务编排:自动处理网络、数据卷、依赖关系等复杂问题。

一句话记住 Docker Compose:它就是一个”应用级别”的管理工具,让你用一份配置文件就能管理整个多容器应用的生命周期! 现在,你可以尝试为你之前学习的多容器应用创建一个 docker-compose.yml文件,体验一下一键部署的爽快感了!这是从 Docker 初学者到实践者的重要一步。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇