Amazon EBS (弹性块存储)

第一章:核心定义与本质

Amazon EBS 是一种易于使用、高性能、可扩展的块级存储服务,专为与 Amazon EC2 配合使用而设计。

  • 块存储 vs 文件存储: 它提供的是裸露的、未格式化的块设备。你可以把它想象成一块硬盘,挂载到 EC2 后需要格式化并创建文件系统(如 ext4, NTFS)。
  • 低延迟与持久性: 适用于对时延敏感的工作负载,如数据库、文件系统或任何需要细粒度更新的应用。
  • 可用区级限制: 这是一个关键考点——EBS 卷是可用区 (AZ) 级别的资源。它会自动在所属可用区内复制以防止硬件故障,但它不能直接跨 AZ 挂载。

第二章:EBS 卷类型

考试通常会给你一个性能需求和预算限制,让你选择最合适的卷类型。

1. SSD 系列(适用于事务性工作负载)

  • General Purpose SSD (gp2/gp3):

  • 平衡型: 适合绝大多数工作负载(系统盘、开发环境)。

  • gp3 (推荐): 允许独立配置 IOPS 和吞吐量,比 gp2 成本更低且性能更可预测。

  • Provisioned IOPS SSD (io1/io2):

  • 高性能: 专为关键业务、对 IOPS 极其敏感的数据库(如 SAP HANA, Oracle)设计。

  • 特性: 提供最高级别的 IOPS 和吞吐量,支持 EBS Multi-Attach(允许多个实例同时挂载同一个卷)。

2. HDD 系列(适用于大吞吐量工作负载)

  • Throughput Optimized HDD (st1): 适合频繁访问、大吞吐量的负载,如 MapReduce、Kafka、日志处理。
  • Cold HDD (sc1): 成本最低,适合不常访问的数据,如归档存储。
  • 注意: HDD 系列不能用作 EC2 的启动卷(Boot Volume)。

第三章:数据持久性与快照 (Snapshots)

1. 快照的本质

  • 增量备份: 只有自上次快照以来更改的数据块才会被保存,节省 S3 存储成本。
  • 存储位置: 快照最终存储在 Amazon S3 中(虽然你在 S3 桶里看不到它们),因此具有 11 个 9 的持久性。
  • 跨 AZ 迁移: 虽然 EBS 卷限制在某个 AZ,但你可以通过“创建快照 -> 在另一个 AZ 将快照还原为卷”的方法实现数据搬家。

2. 快照生命周期管理 (Data Lifecycle Manager)

  • 你可以使用 Amazon DLM 自动创建、保留和删除快照,无需手动操作或编写脚本。

第四章:安全性——加密 (Encryption)

  • 一键加密: 使用 AES-256 算法,支持使用 AWS KMS 管理密钥。
  • 加密范围: 静态数据、快照以及从快照创建的所有卷都会被自动加密。
  • 注意: 你无法直接在现有的未加密卷上开启加密。必须通过“创建快照 -> 拷贝快照并选择加密 -> 从加密快照创建新卷”来完成转换。

第五章:高级特性与优化

1. Elastic Volumes (弹性卷)

  • 无需停机: 可以在实例运行的情况下,动态增加卷容量、更改卷类型或调整 IOPS 性能。

2. EBS-Optimized Instances (EBS 优化实例)

  • 专用带宽: 确保 EC2 和 EBS 之间有专属的网络通道,避免与其他网络流量竞争,从而保证稳定的 IOPS 表现。

第六章:架构师思维(场景决策对比)

需求场景 推荐卷类型 / 功能
部署大型 MySQL/Oracle 生产数据库 io2 (Provisioned IOPS)
低成本存储 TB 级别的日志分析数据 st1 (Throughput Optimized)
需要将数据从美东 1 区迁移到美西 2 区 Snapshot + Copy Snapshot
想要多个实例同时读写一个卷(集群文件系统) io1/io2 + Multi-Attach
系统盘的最佳性价比选择 gp3

  1. AZ 属性: 记住 EBS 是 AZ 级别的,跨 AZ 必须用 Snapshot。
  2. 启动卷: 记住只有 SSD (gp/io) 才能当系统启动盘。
  3. 增量性: 理解快照是增量的(Incremental),但还原时它表现得像完整备份。
  4. 实例存储 (Instance Store): 这个是 EBS 的死对头(临时存储,断电丢数据),考试中如果强调“数据不可丢失”,绝对不要选 Instance Store。

AWS EC2 Deep Dive

1. Amazon EC2 基础与架构 (EC2 Basics & Architecture)

Amazon Elastic Compute Cloud (Amazon EC2) 提供可调整大小的计算容量,允许用户在几分钟内启动虚拟服务器。

1.1 核心价值与限制

  • 全球覆盖 (Global Reach):部署在 30 多个地理区域 (Regions) 和本地区域 (Local Zones)。
  • 安全性 (Security):通过 NitroTPM 实现验证启动,通过 VPC 实现网络隔离。
  • 灵活性 (Flexible):支持多种处理器(Intel, AMD, Graviton)和购买模式。
  • 限制 (Limits)
    • On-Demand:基于 vCPU 数量的软限制。
    • Reserved Instances:默认限制购买 20 个。
    • Spot Instances:每个区域有动态的 Spot 限制。

1.2 AWS Nitro System

EC2 的下一代底层平台,将虚拟化功能卸载到专用硬件。

  • 优势:提供接近裸机(Bare Metal)的性能,更高的安全性,以及更低的成本。
  • NitroTPM:利用 Nitro System 提供加密验证,验证实例身份和软件完整性(”Verify me” 模型)。

1.3 实例类型 (Instance Types)

考试中需要根据场景选择正确的类型系列:

类型系列 描述 适用场景
通用型 (General Purpose) t-type, m-type Web 服务器、平衡负载、代码库。
计算优化型 (Compute Optimized) c-type 批处理、高性能 Web 服务器、科学建模、机器学习推理。
内存优化型 (Memory Optimized) r-type, x-type, z-type 高性能数据库、分布式内存缓存 (Redis)。
存储优化型 (Storage Optimized) d-type, h-type, i-type NoSQL 数据库、数据仓库、分布式文件系统。
加速计算型 (Accelerated Computing) p-type, g-type, inf-type 机器学习训练 (Trainium)、图形处理 (GPU)。

2. 购买选项与定价 (Purchase Options & Pricing)

这是 SAA 考试中关于成本优化的绝对核心考点。

2.1 购买选项详解

选项 描述 承诺期 适用场景
On-Demand (按需) 按秒/小时计费。无预付,无承诺。 短期、突发、不可预测的工作负载。开发/测试。
Savings Plans (推荐) 承诺每小时花费 (如 $10/hr),比 RI 更灵活。高达 72% 折扣。 1年/3年 首选推荐。EC2/Fargate/Lambda 混合使用。
Reserved Instances (RI) 承诺使用特定配置。 1年/3年 稳态使用 (Steady-state)。长期数据库。
Spot Instances (竞价) 利用闲置容量,折扣最高 90%。可能被中断 (2分钟警告)。 无状态、容错、批处理、CI/CD、HPC。
Dedicated Hosts 专用物理服务器。完全隔离。支持 BYOL 可选 自带许可 (BYOL) 场景(如 Windows/SQL Server),合规性要求。
Dedicated Instances 专用硬件上的实例,但不指定物理服务器。 仅需硬件隔离,无 BYOL 需求。
Capacity Reservations 在特定 AZ 预留容量。不提供价格折扣(需结合 RI/Savings Plan 使用)。 任意 确保在灾难恢复或特定活动期间有机器可用。

2.2 预留实例 (RI) 类型对比

特性 Standard RI (标准) Convertible RI (可转换)
折扣力度 最高 (最高 72%) 较低 (最高 54%)
灵活性 可修改 AZ、网络类型、实例大小 (Linux)。不可改系列 可修改实例系列 (如 C4 变 C5)、OS、租户。
转售 可以在 RI Marketplace 出售。 不可转售

2.3 Spot 策略

  • Spot Fleet 策略
    • LowestPrice:从价格最低的池中启动实例(成本最低)。
    • Diversified:跨所有池分布实例(可用性最高)。
    • CapacityOptimized:从容量最充裕的池中启动(中断风险最低,推荐)。

3. 存储选项 (Storage Options: Instance Store vs EBS)

理解根卷(Root Volume)的行为差异至关重要。

特性 Instance Store (临时存储) EBS (Elastic Block Store)
定义 直接附加在物理服务器上的磁盘 (Ephemeral)。 网络连接的持久化块存储。
持久性 临时性。停止 (Stop) 或终止 (Terminate) 时数据丢失。 持久性。独立于实例生命周期(默认根卷随实例删除,但可配置保留)。
性能 极高的 I/O 性能(物理连接)。 取决于卷类型和网络带宽。
停止行为 不支持 Stop 操作。只能重启或终止。 支持 Stop 和 Start。停止期间数据保留。
主要用途 缓存、临时缓冲区、无状态应用、复制的数据集群。 数据库、持久文件系统、引导卷。

架构师笔记:Instance Store 提供极高的 I/O 性能,但必须在应用层处理数据冗余(如 RAID 0/1/10 或复制到 S3/EBS),否则硬件故障会导致数据永久丢失。此外,Instance Store 实例启动时间通常比 EBS 实例慢(需从 S3 加载数据)。

3.1 Amazon Machine Images (AMI)

  • 区域性:AMI 是区域(Region)级别的资源。如需在另一区域使用,必须 Copy AMI
  • EC2 Image Builder:自动化创建、维护、验证和修补 AMI 的托管服务。
  • 回收站 (Recycle Bin):支持恢复意外删除的 AMI。
  • UEFI Secure Boot:确保实例只启动经过加密签名的软件,防止恶意软件在引导过程中加载。

4. 网络与放置组 (Networking & Placement Groups)

4.1 IP 地址与 ENI

  • Elastic IP (EIP):静态公有 IPv4 地址。如果 EIP 未关联到运行中的实例,AWS 会收取闲置费。
  • ENI (Elastic Network Interface):虚拟网卡。可以分离并附加到另一台实例(同一 AZ 内),用于故障转移。
  • EC2 Instance Connect:通过 SSH (Linux) 或 RDP (Windows) 安全连接实例,无需管理 SSH 密钥。

4.2 放置组 (Placement Groups)

控制实例在物理硬件上的分布策略。

  • Cluster (集群)
    • 机制:将实例紧密打包在单个 AZ 内。
    • 场景:低延迟、高网络吞吐量(如 HPC 高性能计算)。
  • Spread (分散)
    • 机制:将每个实例放置在不同的物理机架上。
    • 限制:每个 AZ 最多 7 个运行实例。
    • 场景:关键任务,避免单点硬件故障。
  • Partition (分区)
    • 机制:将实例分布在逻辑分区中,分区之间不共享硬件。
    • 场景:大型分布式工作负载(如 Hadoop, Kafka, Cassandra)。

4.3 高性能网络

  • Enhanced Networking (增强联网):使用 SR-IOV 提供更高的 PPS 和更低的延迟。
  • Elastic Fabric Adapter (EFA):用于 HPC 和机器学习的专用网络接口,绕过操作系统内核直接通信。紧密耦合任务首选

5. 生命周期与状态管理 (Lifecycle & State Management)

5.1 实例状态

  • Stop (停止):EBS 卷保留,Instance Store 数据丢失。不收取计算费用,但收取 EBS 存储费。
  • Terminate (终止):实例被删除。默认情况下根 EBS 卷会被删除(除非设置 DeleteOnTermination 为 false)。
  • Hibernate (休眠)
    • 将内存 (RAM) 中的状态写入根 EBS 卷,然后关机。
    • 启动时从硬盘加载内存状态,快速恢复进程。
    • 要求:根卷必须是加密的 EBS 卷。

5.2 实例元数据与用户数据

  • Instance Metadata:实例通过 http://169.254.169.254/latest/meta-data/ 获取自身信息(IP、AMI-ID、IAM 角色等)。
  • User Data:启动时运行的脚本。仅在首次启动时执行一次
  • IMDSv2:元数据服务的第 2 版,要求基于会话的 Token 身份验证,安全性更高。

6. 安全性与监控 (Security & Monitoring)

6.1 Security Groups vs Network ACLs

特性 安全组 (Security Group) 网络 ACL (Network ACL)
作用级别 实例级别 子网级别
状态 有状态 (Stateful):入站允许则出站自动允许。 无状态 (Stateless):需分别配置出入站。
规则 仅支持 ALLOW。 支持 ALLOW 和 DENY。

6.2 监控 (CloudWatch)

  • 默认监控:每 5 分钟推送一次指标(免费)。
  • 详细监控:每 1 分钟推送一次(收费)。
  • 状态检查
    • System Status Checks:AWS 基础设施层面的问题(需 AWS 修复)。
    • Instance Status Checks:你的 OS/配置层面的问题(需用户修复,如重启)。

7. 最佳实践总结 (Exam Tips & Scenarios)

Note - 高性能计算 (HPC):如果题目提到“低延迟、节点间通信紧密”,首选 Cluster Placement Group + Enhanced Networking/EFA

Note - 成本优化

  • 长时间稳定运行 -> Savings Plans / RI
  • 批处理、容错任务 -> Spot Instances
  • 软件许可证绑定物理核心 -> Dedicated Hosts

Note - 数据恢复:如果无法连接到实例(如 Key 丢失或配置错误),可以将根 EBS 卷分离,附加到另一台临时实例作为数据盘进行修复,然后再挂载回去。

Note - 启动故障:如果启动时遇到 InsufficientInstanceCapacity,尝试稍后重试或更换 AZ;如果是 Spot 实例,考虑更改价格或策略。

实战场景自测

场景 A:合规性与软件许可

问题:公司需要迁移现有的 Microsoft SQL Server 负载到 AWS,拥有基于 CPU 插槽 (Per-Socket) 的许可证,且必须遵守“运行在专用物理服务器上”的要求。
答案:选择 Dedicated Hosts。只有它提供对物理服务器插槽/核心的可见性,支持 BYOL

场景 B:HPC 高性能计算网络优化

问题:跨多个实例的风洞模拟模型(HPC),节点间通信紧密耦合 (Tightly Coupled),要求低延迟。
答案:在单个 AZ 内配置 Cluster Placement Group。提供最低延迟和最高单流吞吐量。

生产级 Shell 脚本编写规范指南

本文旨在为 Linux 用户及工程师提供一套标准化的 Shell 脚本编写实践。遵循这些规范可以显著降低脚本在生产环境中的不可预见性,并提高代码的可维护性。

1. 解释器声明 (Shebang)

标准做法: #!/usr/bin/env bash

  • 技术原理: 不同 Unix-like 系统的 Bash 二进制文件路径可能不同(如 /bin/bash/usr/local/bin/bash)。env 命令会在当前系统的 PATH 环境变量中动态查找解释器路径。
  • 适用场景: 需要在 macOS、Ubuntu、CentOS 等多种发行版间移植的脚本。

2. 错误处理与防御性编程 (Shell Options)

标准做法: 在脚本开头显式声明执行选项。

1
2
3
4
set -o errexit
set -o nounset
set -o pipefail

或简写为:set -euo pipefail

  • errexit (-e): 脚本中任何命令返回码非零时立即退出,遵循“及早失败”原则。
  • nounset (-u): 尝试引用未定义变量时视为错误并退出,防止因变量名拼写错误导致的意外操作。
  • pipefail: 确保管道命令中任何一个环节失败,整行命令即被视为失败。

3. 变量引用的规范化

标准做法: 始终在引用变量时使用双引号 "$VAR"

  • 原因: 防止单词拆分 (Word Splitting) 和通配符扩展 (Globbing)。未加引号的引用会导致 Shell 将包含空格或特殊字符的变量解析为多个参数。

4. 条件测试表达式

标准做法: 优先使用 [[ ... ]] 而非 [ ... ]test

  • 技术优势: [[ 是 Bash 内建关键字,支持 &&|| 以及正则表达式匹配 (=~),且在进行字符串比较时无需对变量加额外引号也可避免语法错误。

5. 路径处理与执行环境无关化

标准做法: 通过脚本自身定位其所在目录,避免使用相对路径。

1
2
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

  • 应用场景: 当脚本需要加载配置文件或调用同目录下的其他组件时,使用 "$SCRIPT_DIR/config.conf" 可确保脚本从系统任意路径被调用时都能正常定位资源。

6. 函数内部的作用域控制

标准做法: 在函数内声明变量时必须使用 local 关键字。

  • 原因: Shell 默认变量作用域为全局。不使用 local 会导致函数内部变量意外覆盖全局同名变量,造成难以追踪的状态污染。

7. 资源清理与信号捕获 (Resource Management)

标准做法: 使用 trap 确保资源(如临时文件、锁文件)在脚本退出时被正确释放。

1
2
3
tmp_file=$(mktemp)
trap 'rm -f "$tmp_file"' EXIT

  • 技术要点: EXIT 信号涵盖了正常退出、出错退出以及接收到终止信号(如 Ctrl+C)的情况。

8. 静态代码分析工具 (ShellCheck)

标准做法: 在发布前使用 shellcheck 扫描脚本。

注意: shellcheck 并非 Linux 内置命令,需根据发行版自行安装(如 apt install shellcheck)。它已成为 Shell 脚本工程化的事实标准。

  • 基本用法: shellcheck your_script.sh
  • 核心价值:
  1. 自动识别逻辑缺陷: 如未加引号的变量、无效的条件判断、潜在的资源泄露。
  2. 强制符合最佳实践: 提供具体的规则代码(如 SC2086),并给出详细的修改建议。
  3. CI/CD 集成: 在自动化流水线中,可以使用 -f json-f checkstyle 格式输出结果,作为代码合并的前置检查条件。

总结:专业脚本模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env bash

# 1. 开启安全模式
set -euo pipefail

# 2. 获取脚本绝对路径
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

# 3. 资源清理钩子
cleanup() {
# 执行清理逻辑
:
}
trap cleanup EXIT

# 4. 函数定义 (使用 local 变量)
main() {
local task_name="Production_Deploy"
echo "Starting $task_name in $SCRIPT_DIR..."
}

main "$@"

Agent 学习笔记 (二):智能体的进化之路与分类图谱

1. 智能体的发展历程 (The Evolution of Agents)

1.1 从控制论到大模型:三个关键阶段

智能体并不是横空出世的概念,它的演进经历了从“硬编码”到“自我学习”,再到如今“常识推理”的跨越。

  1. 早期控制论 (Cybernetics & Symbolic AI)
  • 特点:基于固定的逻辑门和专家系统。
  • 痛点:只能处理高度结构化的环境,稍微改变规则就会失效(脆性)。
  1. 强化学习时代 (Reinforcement Learning)
  • 特点:Agent 通过“试错”和奖励机制(Reward)来学习策略。
  • 代表:AlphaGo。
  • 痛点:泛化能力极弱。下围棋的智能体没法帮你订机票,每个任务都需要从零训练。
  1. 大模型驱动时代 (LLM-based Agents)
  • 特点:以大模型为“大脑”,利用海量的通用知识进行零样本(Zero-shot)推理。
  • 救赎:赋予了 Agent 真正的“通用性”,使其能够像人类一样通过自然语言理解复杂意图。

2. 智能体的核心分类 (Taxonomy of Agents)

在经典的 AI 理论(如《AIMA》)中,根据 Agent 的“聪明程度”和处理逻辑,通常将其分为以下五类。理解这些分类有助于我们在工程实践中选择最合适的架构。

类型 核心逻辑 适用场景
简单反射智能体 (Simple Reflex) 根据当前感知直接做出反应 (Condition-Action)。 简单的自动化脚本(如:检测到 CPU 占用 > 90% 就告警)。
基于模型的反射 (Model-based) 能够维护一个“内部状态”,记录当前看不到的环境信息。 复杂的系统监控(需要结合历史状态判断当前异常)。
基于目标的智能体 (Goal-based) 拥有明确的目标,会主动寻找达成路径。 我们目前学习的主流 Agent(如:帮我部署一套 K8s 集群)。
基于效用的智能体 (Utility-based) 不仅要完成目标,还要寻找“最优解”(如最省钱、最快速)。 资源调度优化、路径规划。
学习智能体 (Learning Agents) 能够从执行结果中学习,不断改进性能。 自我进化的代码修复 Agent。

3. 现代 LLM Agent 的架构范式 (Modern Paradigms)

在当前的工程实践中,我们更多地从“运作模式”来区分 Agent。这类似于 Docker Compose 中对不同 Service 的定义方式。

3.1 自主智能体 (Autonomous Agents)

  • 定义:给定一个高层目标(Goal),Agent 自行拆解步骤、调用工具并完成任务。
  • 例子:AutoGPT。你告诉它“帮我调研某项技术并写一份报告”,剩下的它全包。

3.2 协作智能体 (Multi-Agent Systems, MAS)

  • 定义:多个 Agent 扮演不同角色(如:程序员、测试员、架构师),通过对话协作完成复杂工程。
  • 类比:这非常像我们 IT 开发中的团队协作模式。每个 Agent 只需要精通自己的领域。

4. 深入理解:智能体的“心智模型” (Mindset of an Agent)

正如 Docker 容器需要镜像(Image)作为模板,Agent 的运行依赖于以下三个核心支柱的解耦:

  1. Planning (规划能力):将大目标拆解为子任务(Task Decomposition)。
  2. Memory (记忆能力)
  • 短期记忆:Context(上下文)。
  • 长期记忆:Vector DB(向量数据库 / RAG)。
  1. Tool Use (工具调用):通过 API 扩展能力边界。

5. 总结 (Summary)

Agent 的进化史本质上是**“自动化程度”不断提升**的过程。

  • 从早期的 If-Else 到现在的 LLM Reasoning
  • 从单一任务的脚本到具备“心智”的自主实体。

Agent 学习笔记 (一):从大语言模型到自主智能体

1. 为什么要从 LLM 转向 Agent?(From LLM to Agent)

1.1 纯语言模型的局限性

虽然像 Gemini-3 这样的大语言模型(LLM)已经非常强大,但作为开发者,我们常会遇到以下“痛点”:

  • 无法主动执行:它只能“说”,不能“做”。你让它改代码,它只能给你代码片段,却没法直接提交到你的 GitHub 仓库。
  • 时效性短板:它的知识停留在训练截止日期,无法感知现实世界的实时变化。
  • 幻觉风险:在面对复杂任务时,LLM 往往会“一本正经地胡说八道”,缺乏实地验证。

1.2 Agent 带来的范式转移

Agent (智能体) 的出现解决了这些问题。如果说 LLM 是一个博学但“瘫痪”的大脑,那么 Agent 就是给大脑接上了感官(感知环境)和四肢(执行任务)

核心理念:Agent = LLM + 规划 (Planning) + 记忆 (Memory) + 工具使用 (Tool Use)。


2. 什么是智能体?(Understanding Agents)

2.1 智能体的定义

在计算机科学中,智能体是一个能够感知环境、进行推理、并采取行动以实现特定目标的系统。

2.2 核心设计框架:PEAS 模型

要设计一个 Agent,我们首先需要从四个维度进行定义,这类似于我们在 Docker 中定义网络和卷:

维度 说明 例子 (以“DevOps 助手”为例)
P (Performance) 性能标准:衡量任务是否成功的指标。 代码修复成功率、构建通过率。
E (Environment) 环境:Agent 运行的场所。 GitHub 仓库、Linux 服务器、CI/CD 流水线。
A (Actuators) 执行器:Agent 用来改变环境的工具。 Git 命令、Shell 脚本执行器、API 请求。
S (Sensors) 传感器:Agent 获取信息的来源。 编译报错日志、用户反馈、监控指标。

3. 智能体 vs. 传统自动化 (Agent vs. Workflow)

为了更深入地理解,我们将 Agent 与我们常用的传统自动化脚本进行对比:

特性 传统自动化 (Deterministic) LLM 驱动智能体 (Probabilistic)
执行逻辑 硬编码的 If-Else 逻辑,路径固定。 基于 LLM 推理,动态生成执行路径。
错误处理 遇到预设外的错误直接 Crash。 能够感知错误,并尝试通过新行动修复。
交互能力 只能处理结构化数据。 能理解模糊的自然语言指令。
适用场景 确定性的重复任务(如:定时备份)。 开放性的复杂任务(如:根据需求写代码并测试)。

4. 深入理解 Agent 工作流 (Agent Lifecycle)

让我们通过一个典型的任务执行过程,看看 Agent 内部发生了什么。

核心循环:ReAct 模式 (Reason + Act)

当你向 Agent 发出一个指令(如:“帮我修复服务器上的 404 报错”)时,它会进入以下闭环:

  1. 感知 (Perception)
  • 从传感器获取初始 Observation(观察),比如读取 Nginx 的 access.log
  1. 思考 (Thought)
  • 分析:LLM 分析日志发现是静态资源路径配置错误。
  • 规划:决定先备份配置文件,再修改 root 路径。
  1. 行动 (Action)
  • 执行:调用执行器(Actuators)运行 sed 命令修改配置。
  1. 观察 (Observation)
  • 反馈:重启服务并检测状态码,获取新的执行结果。

如果目标未达成,则跳转回第 2 步循环执行。


5. 动手实践:构建最简单的推理循环

以下是一个高度简化的 Agent 伪代码,体现了核心的“思考-行动”逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 模拟 Agent 的核心循环
def run_agent(user_goal):
history = [f"User Goal: {user_goal}"]

for step in range(max_steps):
# 1. 思考 (Thought): 调用 LLM 决定下一步做什么
thought = llm.generate(f"{history}\nWhat is your next thought and action?")

# 2. 行动 (Action): 解析 LLM 提取出的工具调用
tool_call = parse_tool_call(thought)

# 3. 观察 (Observation): 执行工具并获取反馈
result = execute_tool(tool_call)

# 将结果反馈给 LLM,形成闭环
history.append(f"Action: {tool_call}, Observation: {result}")

if "Task Complete" in result:
break


6. 总结 (Summary)

本章我们明确了 Agent 的基本定义:它不再是简单的问答机器,而是一个闭环系统

  • 它具备自主性:能自己决定下一步。
  • 它具备适应性:能根据环境反馈调整策略。

在下一章中,我们将深入探讨 Agent 的发展史,从早期的控制论到今天的 Agentic-RL,看看这项技术是如何一步步演进至今的。

解析 Linux chmod 的数字模式与符号模式

在学习 AWS 认证(如 SAA)或进行 DevOps 实操时,我们经常会遇到这样一个报错:
WARNING: UNPROTECTED PRIVATE KEY FILE!
这是因为 SSH 客户端要求私钥文件(.pem)必须具备严格的权限控制。解决它的核心命令就是 chmod

本文将带你彻底搞懂 chmod 的两种操作方式:数字模式 (Numeric Mode)符号模式 (Symbolic Mode)


一、 数字模式:逻辑严密的八进制法

数字模式是 Linux 系统中最常用的方式,它通过三个(或四个)八进制数字来定义权限。

1. 核心权重计算

每一个数字代表一个特定角色的权限总和。你只需要记住 4 (读)、2 (写)、1 (执行)

权限 缩写 数字权重
读取 (Read) r 4
写入 (Write) w 2
执行 (Execute) x 1
无权限 - 0

计算公式: 最终权限 = $Read + Write + Execute$。

  • 例如:rwx = 4 + 2 + 1 = 7
  • 例如:rw- = 4 + 2 + 0 = 6
  • 例如:r-- = 4 + 0 + 0 = 4

2. 三位数的含义

一个典型的数字命令如 chmod 755,其数字位置对应不同的对象:

  1. 第一位:文件所有者 (User/Owner)
  2. 第二位:所属组 (Group)
  3. 第三位:其他人 (Others)

典型案例: chmod 400 my-key.pem
意味着:所有者仅读 (4),组和其他人无任何权限 (00)。这是 AWS 私钥的安全标准。


二、 符号模式:直观的语义表达

如果你不想做算术题,符号模式提供了更具可读性的方式。它的语法结构是:谁 (Who) 操作 (Operator) 权限 (Permission)

1. 组成部分

  • Who(对象)u (用户), g (组), o (其他人), a (所有人)
  • Operator(操作)+ (增加), - (移除), = (精确设定/覆盖)
  • Permission(权限)r (读), w (写), x (执行)

2. 常用操作对比

需求 符号命令 说明
增加执行权 chmod +x script.sh 给所有人增加执行权限
移除写权限 chmod go-w file.txt 移除组和其他人的写权限
精确设置权限 chmod u=rwx,go=rx file 所有者全开,其他人只读/执行
保护私钥 chmod u=r,go= key.pem 精确设置所有者只读,其余留空

三、 实战:为什么 AWS 私钥非要 400?

当你从 AWS 下载 .pem 文件后,默认权限通常是 0644 (针对 Linux) 或更高。

  • 0644 的危险之处: 这意味着系统里的其他用户可以读取你的私钥,从而可能盗取你的服务器访问权。
  • SSH 的强制校验: SSH 协议设计者为了安全性,会在连接前检查私钥权限。如果权限超过 0400(即除了所有者,其他人有任何权限),连接就会被强制中断。

解决方案对比:

  • 数字法: chmod 400 my-key.pem(最推荐,简单快捷)
  • 符号法: chmod u=r,go= my-key.pem(最清晰,明确清空他人权限)

四、 总结:我该选哪种?

  • 选择数字模式:当你需要快速、一次性设置完整的权限位时(如 755, 644, 400)。这在编写自动化脚本、Ansible 配置时是行业标准。
  • 选择符号模式:当你只想微调现有权限时(如“我想给这个文件加个执行权”,即 chmod +x),或者你觉得计算数字太麻烦时。

💡 小贴士: 你可以使用 ls -l 命令来查看修改后的结果。如果看到权限位显示为 -r--------,那么恭喜你,你的私钥现在非常安全!

WindowsTerminal_cKSZwHPfFB.png

Docker 学习笔记 (四):数据持久化、网络与多容器编排

1. 数据持久化 (Docker Volumes)

在之前的章节中,我们学会了如何运行容器。但你可能会发现一个问题:当容器被删除 (docker rm) 后,你在容器内产生的数据(比如数据库里的记录、日志文件)也随之消失了。

1.1 为什么要使用 Volume?

默认情况下,容器的文件系统是临时的。Docker Volumes 的出现是为了解决数据持久化的问题,它允许我们将数据存储在容器的生命周期之外。

核心优势

  • 数据持久化 (Data Persistence):即使容器停止或被删除,数据依然存在。
  • 数据共享 (Data Sharing):多个容器可以同时挂载同一个 Volume 来共享数据。
  • 解耦 (Decoupling):将数据与应用运行环境分离,便于管理和备份。

1.2 Volume 的三种类型

根据使用场景不同,Docker 提供了三种挂载方式:

类型 描述 适用场景
Bind Mounts 直接将宿主机的特定目录或文件映射到容器中。 开发环境。例如将本地源代码目录挂载进容器,代码修改后容器内实时生效。
Named Volumes 由 Docker 在宿主机的一个特定区域(通常是 /var/lib/docker/volumes)管理。用户给它起个名字,方便复用。 生产环境持久化数据。例如数据库文件,这是最推荐的方式。
Anonymous Volumes 类似于 Named Volumes,但没有名字(只有一串随机 ID)。 通常用于不需要持久化太久或不关心具体位置的临时数据。

1.3 常用 Volume 操作命令 (Volume CLI)

仅仅理解概念是不够的,这里是如何在命令行中实际操作 Volume:

  • 创建 Volume:
    1
    docker volume create my-vol
  • 挂载 Volume 启动容器:
    使用 -v 参数将 my-vol 挂载到容器内的 /app/data 目录。
    1
    docker run -d -v my-vol:/app/data mongo
  • 查看所有 Volume:
    1
    docker volume ls
  • 查看 Volume 详情 (如在宿主机上的具体路径):
    1
    docker volume inspect my-vol
  • 删除 Volume (注意:必须先删除使用该 Volume 的容器):
    1
    docker volume rm my-vol

2. 进阶配置 (Advanced Topics)

除了基础运行,我们在生产环境中还需要关注容器的稳定性和资源控制。

2.1 资源限制 (Resource Limits)

如果不加限制,一个容器可能会吃掉宿主机所有的 CPU 和内存,导致机器卡死。我们可以通过参数进行限制:

  • CPU 限制:控制容器能使用的计算能力。
  • 内存限制:防止内存泄漏导致 OOM (Out Of Memory)。
1
2
# 示例:限制容器最多使用 0.5 个 CPU 核和 512MB 内存
docker run -d --cpus="0.5" --memory="512m" nginx

2.2 重启策略 (Restart Policies)

定义容器退出(Exit)后的行为,这对保证服务高可用非常重要。

  • no: 默认值。不管什么情况,挂了就不重启。
  • on-failure: 只有在非正常退出(退出码非 0)时才重启。
  • always: 只要容器停止了就重启(手动 stop 除外)。
  • unless-stopped: 类似于 always,但在 Docker 守护进程重启时(比如服务器重启),如果容器之前是人为停止的,就不会自动启动。

3. Docker 网络 (Networking)

Docker 网络提供了容器间通信的基础设施,同时保持了隔离性。

3.1 网络驱动模式 (Network Drivers)

驱动 描述 适用场景
Bridge (默认) 在宿主机创建一个私有网络。容器通过端口映射与外部通信,容器间通过 IP 通信。 单机环境下的绝大多数应用。
Host 移除网络隔离,容器直接使用宿主机的 IP 和端口。 需要极致网络性能,或不需要隔离的场景。
None 禁用网络,容器只有本地回环地址。 极高安全要求的隔离环境。
Overlay 允许跨多台宿主机的容器通信。 Docker Swarm 或集群环境。

3.2 最佳实践:用户自定义网络

不要依赖默认的 bridge 网络。创建一个自定义网络可以让容器通过容器名 (Container Name) 互相访问(内置 DNS 解析),而不需要记随时变动的 IP 地址。

1
2
3
4
5
6
7
# 1. 创建网络
docker network create my-app-net

# 2. 启动容器加入网络
docker run -d --name db --network my-app-net mongo
docker run -d --name web --network my-app-net -p 80:80 my-web-app
# 此时,web 容器里代码连接数据库只需要填主机名为 "db" 即可。

4. Docker Compose:多容器编排

4.1 痛点:手动管理的噩梦

在微服务架构中,一个应用可能包含前端、后端 API、数据库、Redis 缓存等多个服务。
如果只用 docker run

  1. 你需要分别启动 4 个容器。
  2. 你需要记住复杂的启动命令(端口、环境变量、网络、挂载卷)。
  3. 你需要手动控制启动顺序(先启数据库,再启后端)。

4.2 解决方案:Docker Compose

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。我们使用 YAML 文件来配置应用的服务。

💡 关于“服务名” (Service Name) 的命名:
docker-compose.yml 中,services: 下方的第一层缩进(如 web:, db:)就是服务名
当你运行 docker-compose up -d 时,Compose 会基于这些服务名自动创建容器名(通常格式为 项目名_服务名_1)。
在后续操作中(如 pause, logs, restart),你只需要使用 YAML 文件中定义的服务名即可,Compose 会自动帮你找到对应的容器。

核心优势

  • 声明式配置:在一个文件中定义所有服务、网络和卷。
  • 一键启动/停止:一条命令管理整个生命周期。
  • 环境一致性:开发、测试、生产使用同一套配置。

4.3 docker-compose.yml 实战解析

下面是一个典型的全栈应用配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
version: '3.8'  # 指定 Compose 文件版本

services:
# 1. 前端/Web 服务
web:
image: nginx:latest
ports:
- "80:80" # 映射端口
networks:
- my_network # 加入网络
depends_on:
- api # 确保 api 服务先启动

# 2. 后端 API 服务
api:
build: ./backend # 支持直接从 Dockerfile 构建
environment:
- DB_HOST=db # 环境变量配置
networks:
- my_network
depends_on:
- db

# 3. 数据库服务
db:
image: mongo:latest
volumes:
- db-data:/data/db # 使用 Named Volume 持久化数据
networks:
- my_network

# 定义全局 Volume
volumes:
db-data:

# 定义全局网络
networks:
my_network:

4.4 常用命令

  • 启动所有服务 (后台运行):

    1
    docker-compose up -d
  • 停止所有服务 (仅停止容器,不移除):

    1
    docker-compose stop
  • 停止并移除所有资源 (容器、网络、镜像等):

    1
    docker-compose down

    ⚠️ 注意 stop vs down
    stop 只是把容器关掉,容器还在;down 会把容器彻底删掉,网络也会被清理。

  • 查看服务日志

    1
    docker-compose logs -f
  • 暂停/恢复特定服务 (这里的 db 就是我们在 YAML 里定义的那个名字):

    1
    2
    docker-compose pause db
    docker-compose unpause db
  • 停止特定服务:
    如果你只想停止 db 而不影响其他服务:

    1
    docker-compose stop db
  • 不在当前目录时指定文件:
    如果你不在 docker-compose.yml 所在的目录,可以使用 -f 参数指定文件路径:

    1
    2
    # 比如你的配置文件在 /opt/myapp/docker-compose.yml
    docker-compose -f /opt/myapp/docker-compose.yml pause db

总结 (Summary)

通过这四章的学习,你已经掌握了 Docker 的核心技能:

  1. 概念:理解了容器 vs 虚拟机,以及镜像、容器、仓库的关系。
  2. 操作:学会了 run, build, push 等生命周期管理命令。
  3. 构建:能够编写 Dockerfile 制作自己的镜像。
  4. 进阶:掌握了 Volume 数据持久化、Network 网络通信以及 Compose 多容器编排。

接下来的旅程,我们会进一步探索 Kubernetes (K8s),它是容器编排的终极形态,用于管理成百上千个跨主机的容器。

Docker 学习笔记 (三):理解镜像与仓库


1. 什么是 Docker 镜像?(Docker Images Deep Dive)

在前两章中,我们使用了 hello-world 镜像。但镜像本质上是什么?

1.1 镜像的本质

镜像是一个只读的模板 (Read-only Template),它包含了运行应用程序所需的一切:

  • 代码 (Application Code)
  • 运行时环境 (Runtime Environment):如 Node.js, Python。
  • 依赖库 (Libraries & Dependencies)
  • 配置文件 (Configuration)
  • 基础操作系统 (Base Layer):如 Alpine, Ubuntu (通常是裁剪版)。

你可以把它想象成应用程序的“DNA”或者“快照 (Snapshot)”,一旦创建,其中的内容就是不可变的。

1.2 分层架构 (Layered Architecture)

Docker 镜像不是一个单一的大文件,而是由多层 (Layers) 组成的。

  • 结构:每一层通常对应 Dockerfile 中的一条指令。
  • 优势:这种分层机制使得存储和传输非常高效。例如,如果多个镜像都使用 Ubuntu 作为基础镜像,那么宿主机只需要存储一份 Ubuntu 的层,所有容器都可以共享它。

2. 镜像仓库 (Container Registries)

镜像构建好后,需要一个地方存储和分发,这就是镜像仓库。

2.1 核心作用

  • 协作 (Collaboration):团队成员之间共享镜像。
  • 版本控制 (Versioning):通过 Tag (标签) 追踪不同版本的镜像,方便回滚和更新。
  • 安全性 (Security):企业级仓库通常提供漏洞扫描和访问控制。
  • 自动化 (Automation):与 CI/CD 流水线集成,自动构建和推送。

2.2 仓库类型

  1. 公共仓库 (Public Registries):如 Docker Hub,对所有人开放,拥有海量开源软件镜像。
  2. 私有仓库 (Private Registries):用于存储专有软件或敏感数据。
    • SaaS 服务:如 Docker Hub Private Repos, Quay.io。
    • 自托管 (Self-Hosted):如 Harbor, JFrog Artifactory。
    • 云厂商服务:AWS ECR, Google GCR, Azure ACR。

3. 编写 Dockerfile (Building Images)

手动安装环境太麻烦且不可复现。Dockerfile 是构建镜像的脚本文件,体现了 “Infrastructure as Code” 的理念。

3.1 核心指令解析

一个典型的 Dockerfile 结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 指定基础镜像 (Base Image)
FROM node:18-alpine

# 2. 设置工作目录 (Working Directory)
WORKDIR /app

# 3. 复制依赖定义并安装 (Dependencies)
COPY package.json package-lock.json ./
RUN npm install --production

# 4. 复制源代码 (Application Code)
COPY . .

# 5. 定义容器启动命令 (Command)
CMD ["node", "server.js"]
  • FROM: 每一份 Dockerfile 的起点。尽量选择轻量级的镜像(如 alpine 版本)。
  • WORKDIR: 相当于 cd,后续命令都会在这个目录下执行。
  • COPY: 将宿主机的文件复制到容器内部。
  • RUN: 在构建镜像时执行的命令(如安装软件、解压文件)。每执行一次 RUN 就会建立一个新的层。
  • CMD: 在启动容器时默认执行的命令。

3.2 构建与上下文

构建命令通常为:

1
docker build -t my-app:v1 .

注意最后的 .,它代表构建上下文 (Build Context)。Docker 客户端会将该目录下的所有文件发送给 Docker Daemon 进行构建。


4. 镜像优化与最佳实践 (Advanced Topics)

4.1 使用 .dockerignore

类似于 .gitignore。构建时,我们不应该把本地的 node_modules、日志文件、临时文件发送给 Docker Daemon。使用 .dockerignore 可以显著减小构建上下文的大小,加快构建速度并提高安全性。

4.2 多阶段构建 (Multistage Builds)

这是一个高级技巧,用于优化镜像体积。

  • 问题:编译 Go 或 Java 应用需要安装大量的编译器和工具 (SDK),但运行只需要一个二进制文件。如果把 SDK 都打包进最终镜像,体积会非常大。
  • 解决:使用多阶段构建。
    • Stage 1 (Build): 包含编译器,负责编译代码。
    • Stage 2 (Run): 仅包含基础 OS。
    • 操作:从 Stage 1 复制编译好的产物到 Stage 2。最终镜像只包含 Stage 2 的内容,体积极小。

4.3 Distroless 镜像

这是一种为了安全性极致优化的镜像。

  • 特点:不包含 Shell (bash/sh)、包管理器 (apt/apk) 等任何多余工具。
  • 优势:体积微小,攻击面极小(黑客即使利用漏洞进入容器,也没有 Shell 可以执行命令)。
  • 挑战:由于没有 Shell,调试 (Debug) 会变得非常困难。

Docker 学习笔记 (二):运行容器与生命周期

1. 运行你的第一个容器 (Run your first container)

让我们通过运行一个最基础的容器来开始我们的 Docker 之旅:hello-world。这是一个官方提供的极简镜像,专门用于测试 Docker 环境是否安装配置正确。

1.1 执行命令

在终端中输入以下命令:

1
docker run hello-world

1.2 输出解析

执行后,你将看到类似的输出,让我们逐行解析 Docker 到底做了什么:

hello-world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Unable to find image 'hello-world:latest' locally
# 1. Docker 客户端先在本地查找镜像,发现没有找到。

latest: Pulling from library/hello-world
# 2. Docker 客户端联系 Docker Hub (默认仓库),开始拉取 'hello-world' 镜像。

Pull complete
# 3. 镜像下载完成(这个镜像非常小)。

Digest: sha256:xxxx
Status: Downloaded newer image for hello-world:latest
# 4. 镜像已准备就绪。

Hello from Docker!
This message shows that your installation appears to be working correctly.
# 5. 容器启动!运行了镜像中的程序,打印出了这段欢迎信息。

1.3 幕后流程

正如我们在第一章中所学,这完美演示了 Docker 的工作流:

  1. Client 发送 run 指令。
  2. Daemon 检查本地无镜像,从 Registry 拉取。
  3. Daemon 创建新容器,运行可执行文件产生输出。
  4. Daemon 将输出流回 Client 显示给你。

2. 容器生命周期详解 (Container Lifecycle)

理解容器在其生命周期内发生的变化至关重要。下图展示了容器从创建、运行、暂停、停止到最终移除的完整流程及对应的命令。

2.1 核心状态流转

容器运行中 (Container running)

这是容器的主要工作状态。

  • 进入方式
    • docker run <image>:直接从镜像创建并启动容器。
    • docker create + docker start:先创建容器实例,再手动启动。
  • 可用操作
    • 日志查看:docker logs —— 查看应用日志。
    • 检查详情:docker inspect —— 查看容器元数据(IP、端口映射等)。
    • 执行命令:docker exec —— 在运行的容器内执行额外命令(如进入 Shell)。

暂停状态 (Paused)

  • 操作
    • docker pause <cId>:暂停容器。此时容器并未真正停止,而是保留内存内容,进程被挂起。
    • docker unpause <cId>:解除暂停,恢复到运行状态。

停止状态 (Container stopped)

容器不再运行,但其实例仍然保留在系统中。

  • 进入方式
    1. 优雅停止docker stop <cId> —— 容器优雅退出,内存内容被清除。
    2. 强制停止docker kill <cId> —— 强制发送 SIGKILL 信号终止进程(默认)。
    3. 自然退出
      • exit 0:进程无错误正常退出。
      • exit <non-zero>:进程因错误退出。
  • 状态特征
    • 假设没有设置重启策略 (Assuming no restart policy in place)。
    • 容器实例依然存在,可以通过 docker ps -a 查看到。
    • 仍然可以执行 docker logsdocker inspect
    • 可以通过 docker start <cId> 将其重新拉起。

容器移除 (Container removed)

  • 操作
    • docker rm <cId>:移除一个已停止的容器。
  • 结果
    • 容器及其包含的所有内容(文件修改等)被永久移除,不再可用。

2.2 生命周期命令速查表

起始状态 命令 目标状态 说明
(None) docker run Running 创建并启动
Running docker pause Paused 挂起进程,保留内存
Paused docker unpause Running 恢复进程
Running docker stop Stopped 优雅停止,清除内存
Running docker kill Stopped 强制停止
Running exit Stopped 进程自行退出
Stopped docker start Running 重新启动已有容器
Stopped docker rm Removed 彻底删除容器实例

Docker 学习笔记 (一):容器化革命与架构原理


1. 为什么要使用容器?(Why Containers?)

1.1 传统应用部署的痛点

在容器技术普及之前,部署一个应用程序(比如 Node.js 应用)往往是一场“噩梦”。我们需要在服务器上:

  • 安装 Node.js 及其特定的依赖版本。
  • 安装应用程序本身的依赖库。
  • 配置运行环境,最后启动应用。

但这带来了巨大的复杂性:

  • 环境地狱:如果服务器上还要运行 Python、Java、Go 等其他语言的应用怎么办?
  • 版本冲突:如果应用 A 需要 Node.js v14,而应用 B 需要 Node.js v18,如何让它们在同一台机器上和谐共存?
  • “Devs vs Ops” 的经典推诿
    • 开发人员 (Devs) 写好了代码和部署脚本。
    • 运维人员 (Ops) 在服务器上运行脚本 —— 报错了!
    • Devs:“但在我的机器上是好的啊!”
    • Ops:“那是你的机器,服务器环境不一样。”
    • …经历无数次调整脚本、安装依赖、调试后,应用终于上线了。

1.2 容器带来的救赎

Docker 容器的出现改变了这一切。

核心理念:容器将应用程序及其所有的依赖项配置打包在一起。从外部看,所有的容器看起来都一样,运行方式也几乎相同。

由此带来的好处:

  • 简化设置:不再需要繁琐的手动环境配置。
  • 可移植性 (Portability):在开发笔记本上能跑,就能在测试服、生产环境云服务器上跑,“一次构建,到处运行”。
  • 环境一致性:消除了“在我的机器上没问题”这类借口。
  • 隔离性:不同应用之间互不干扰。
  • 更高效的资源利用:相比虚拟机更轻量。

新的协作模式

  1. Devs 编写 Dockerfile,定义环境和依赖。
  2. Devs 构建并推送镜像 (Image)。
  3. Ops 只需要拿到镜像并部署,无需关心内部细节。

2. 容器与虚拟机 (Containers vs Virtual Machines)

这是面试和理解容器技术时最常见的问题:Docker 容器和 VMware/VirtualBox 这种虚拟机有什么区别?

2.1 架构对比

虚拟化 (Virtualization) - “独栋别墅”

  • 结构:硬件基础设施 -> 宿主机系统 (Host OS) -> Hypervisor -> 客户机系统 (Guest OS) -> 依赖/代码。
  • 特点:每个虚拟机 (VM) 都有自己完整的操作系统(Guest OS)。
  • 比喻:就像一排独栋别墅,每一栋都有自己的地基、墙壁、水电设施,相互完全独立,但占地面积大,建设成本高。

容器化 (Containerization) - “现代化公寓”

  • 结构:硬件基础设施 -> 宿主机系统 (Host OS) -> 容器引擎 (Container Engine) -> 容器 (代码/依赖)。
  • 特点:所有容器共享宿主机的操作系统内核 (Kernel),没有 Guest OS 这一层。
  • 比喻:就像一栋公寓大楼,大家共享地基和基础设施(内核),但每个房间(容器)内部是独立的。这使得它非常轻量和高效。

Acrobat_RHf8HLLsBg.png

2.2 核心特性 PK

特性 虚拟机 (VMs) Docker 容器
隔离性 强隔离:每个 VM 有独立的 OS,隔离彻底,安全性极高。 进程级隔离:共享宿主机内核,通过 Namespace/Cgroup 实现隔离。
大小/开销 庞大:包含完整 OS,镜像通常是 GB 级别。启动慢。 轻量:仅包含应用和必要库,镜像通常是 MB 级别。秒级启动。
可移植性 较弱:往往绑定特定的 Hypervisor 或 OS 配置。 极佳:平台无关,只要有 Docker 引擎就能跑。

2.3 该怎么选?

  • 选择虚拟机 (VM) 当:
    • 你需要极强的环境隔离(例如运行不同租户的敏感工作负载)。
    • 你需要运行完全不同的操作系统(如在 Linux 上跑 Windows)。
    • 你需要处理难以容器化的传统遗留应用。
  • 选择容器 (Docker) 当:
    • 你正在构建现代的、云原生的微服务架构。
    • 你需要快速扩缩容,追求极致的启动速度。
    • 你需要跨环境(开发、测试、生产)的高度一致性。

3. Docker 架构组件 (Docker Components)

Docker 采用的是客户端-服务器 (C/S) 架构。理解这部分有助于排查连接问题。

3.1 三大核心组件

  1. Docker Client (客户端)

    • 这是用户与 Docker 交互的入口,也就是我们常用的 CLI (命令行界面),例如执行 docker build, docker run
    • 客户端通过 API 与 Docker Host 通信。
  2. Docker Host (主机)

    • 这是 Docker 实际干活的地方。
    • Docker Daemon:后台守护进程,负责监听 API 请求,管理 Docker 对象(镜像、容器、网络、卷)。
    • REST API:客户端和守护进程之间的通信桥梁。
    • Images Cache:本地的镜像仓库。
    • Containers:正在运行的容器实例。
  3. Image Registry (镜像仓库)

    • 存储镜像的地方。
    • Docker Hub 是默认的公共仓库,也有企业私有的 Registry。

Acrobat_hBtsZMVwZL.png


4. 深入理解 Docker 工作流 (Lifecycle)

让我们通过两个最常用的命令,看看 Docker 内部发生了什么。

场景一:运行一个容器 (docker run)

当你输入 docker run <image> 时:

  1. 指令发出:你在 CLI 输入命令。
  2. 发送请求:CLI 将指令转换为 API 请求,发送给 Docker Host 的 REST API。
  3. 检查本地缓存:Docker Host 首先检查本地 (Local Cache) 是否已经有这个镜像?
  4. 拉取镜像 (Pull)
    • 如果有:直接使用。
    • 如果没有:Host 会连接 Image Registry,下载(Pull)该镜像到本地。
  5. 实例化:Docker Host 根据镜像创建一个新的容器实例并启动它。

场景二:构建并发布镜像 (docker build & docker push)

当你开发完代码,需要打包发布时:

  1. 构建指令:你输入 docker build 命令。
  2. 发送上下文:CLI 将请求发送给 Host,同时会把当前的“构建上下文” (Context,通常是当前目录下的文件) 和 Dockerfile 发送给 Docker Daemon。
  3. 执行构建:Docker Host 按照 Dockerfile 的指令,一步步构建出镜像。
  4. 保存镜像:构建好的镜像会被打上标签 (Tag) 并存储在本地缓存中。
  5. 推送指令:你输入 docker push
  6. 上传:Docker Host 将本地的镜像上传到远端的 Image Registry,供其他人下载使用。
0%