UCB-Linux-系统管理笔记-全-
UCB Linux 系统管理笔记(全)
1:课程介绍与Shell基础

在本节课中,我们将要学习课程的基本安排、Shell命令行界面的基础知识,以及自由开源软件(FOSS)的核心理念。我们将通过动手实践来熟悉常用的Shell命令。
课程概述与安排
课程网站是 decal.ocf.io。所有的课程幻灯片、录像和实验材料都会发布在那里。
Lab 1 和 Vitamin 1 已经发布。如果你无法访问课程网站(Ed)或成绩系统(Gradescope),请通过 decal@ocf.berkeley.edu 联系我们。
你应该已经收到一封关于如何登录你的Decal虚拟机的邮件。如果你还没有收到,同样请通过上述邮箱联系我们。
请尊重所有同学和工作人员。我们都是志愿者,友善的交流能让我们更高效地帮助你。
实验课时间安排在每周讲座之后。在这个时间段,会有工作人员在现场提供帮助,但你可以在任何时间开始做实验。
与Shell进行交互
本节中,我们将开始实际操作。请打开你的终端,并SSH登录到我们的服务器。
以下是登录命令的基本结构:
ssh $OCF_USERNAME@ssh.ocf.berkeley.edu
请将 $OCF_USERNAME 替换为你自己的OCF用户名。例如,如果用户名是 lokesh,则应输入:
ssh lokesh@ssh.ocf.berkeley.edu
登录后,你将进入一个名为 tsunami 的登录服务器。
如果你在线上听课,可以通过聊天框提问。但我们强烈建议你尽可能亲自来实验室,这样获得帮助会更快、更直接。
什么是Shell?
上一节我们介绍了如何连接到Shell环境,本节中我们来看看Shell究竟是什么。
Shell,即命令行界面(CLI),是一种与计算机交互的方式。你日常使用的图形用户界面(GUI)是另一种交互方式。在早期的大型机时代,终端(一种类似带屏幕的打字机的设备)是人们与计算机交互的主要方式。

常见的Shell有以下几种:
- Bash:最常用的Shell,是大多数Linux发行版的默认选择。
- Zsh:macOS系统的默认Shell,功能与Bash类似。
- Fish:“友好交互式Shell”,设计上对新手更友好。
对于本课程,使用Bash或Zsh即可,它们在绝大多数情况下没有区别。
Shell命令的基本结构
每个Shell命令都遵循一个通用的结构。
一个命令通常由命令名、选项(flags)和参数(arguments) 组成。其基本格式如下:
command [flags] [arguments]
例如,ls -l /home 这个命令中:
ls是命令名(列出目录内容)。-l是一个选项(以详细列表格式显示)。/home是一个参数(指定要列出的目录)。
学习新命令时,请善用 man 命令来查阅手册。例如,输入 man ls 可以查看 ls 命令的详细用法。随时查阅手册是完全正常且被鼓励的,这并非记忆测试。
常用Shell命令
现在,让我们来了解一些最常用的Shell命令。
以下是几个基础命令及其功能:
cd:改变当前工作目录。例如,cd Documents进入Documents目录。mkdir:创建新目录。例如,mkdir my_folder。ls:列出当前目录下的文件和文件夹。cat:在终端中显示整个文件的内容。head/tail:显示文件的开头或结尾部分。less:分页查看大文件,可以使用方向键或j/k键滚动,按q退出。mv:移动或重命名文件。例如,mv old_name new_name。cp:复制文件。rm:删除文件。请注意:在终端中使用rm删除文件是永久性的,不会进入回收站,请谨慎使用。
终端文本编辑器

在Linux中,我们经常需要编辑文本文件。以下是几种常见的终端文本编辑器。
你可以根据喜好选择:
- Nano:最简单易用的编辑器,适合初学者。使用箭头键移动,屏幕底部有常用快捷键提示。
- Vim:功能强大但学习曲线陡峭。输入
vimtutor命令可以启动交互式教程。 - Emacs:另一个功能极其丰富的编辑器,其支持者认为它几乎是一个操作系统。
此外,你也可以使用 VS Code 配合SSH扩展来远程编辑服务器上的文件,这对于许多场景来说是一个非常好用的现代选择。
命令演示与实践
让我们通过一些实际操作来巩固所学知识。
首先,使用 ls 列出文件。默认情况下,ls 不会显示以点(.)开头的隐藏文件。要显示所有文件(包括隐藏文件),需要使用 -a 选项:
ls -a
要查看文件内容,对于小文件可以用 cat:
cat not_secret_file
对于大文件,使用 less 来分页查看会更方便:
less large_file.txt
在 less 视图中,可以按 / 键进行搜索,按 q 键退出。
ls -l 命令可以显示文件的详细信息(长格式)。结合 -h 选项可以让文件大小以易读的单位(如K、M)显示:
ls -lh
输出结果的第一列代表文件的权限。

如果你运行了一个长时间的命令或想中止当前操作,可以按 Ctrl+C 来强制终止。
什么是自由开源软件(FOSS)?
自由开源软件(FOSS)是Linux世界的基石。它不仅是免费的(指自由,而非价格),更重要的是其源代码是开放的,允许用户自由使用、研究、修改和分发。
这与专有软件(如Windows)形成对比,后者的源代码是封闭的,用户无法查看或修改。
GNU与自由软件运动
理查德·斯托曼(Richard Stallman)发起了自由软件运动。他创立了GNU项目,并提出了自由软件的“四大自由”:
- 出于任何目的运行软件的自由。
- 研究软件如何工作并对其进行修改的自由(需有源代码)。
- 分发软件副本的自由。
- 分发你修改后的软件版本的自由。
Unix、BSD与Linux简史
在Linux出现之前,Unix是主流操作系统,但多为AT&T等公司的专有版本。加州大学伯克利分校开发了开源的BSD(Berkeley Software Distribution),但曾陷入法律纠纷。
与此同时,林纳斯·托瓦兹(Linus Torvalds)创建了Linux内核。凭借其开源和社区驱动的模式,Linux逐渐流行起来,并最终在服务器领域占据了主导地位。Unix哲学(如“一切皆文件”)为其成功奠定了基础。
为何选择FOSS?
人们选择自由开源软件有多个原因:
- 安全:源代码开放意味着全球开发者可以共同审查代码,发现并修复安全漏洞。
- 成本:通常免费使用,无需支付许可费用。
- 隐私:你可以完全控制软件和数据,避免被商业公司追踪。
- 控制与自由:如果你对软件功能不满意,可以自行修改或寻找他人修改的版本。
- 协作:全球开发者可以共同改进软件。
开源许可证
开源软件使用不同的许可证,主要分为两类:
- Copyleft许可证(如GPL):要求修改后的衍生软件也必须以相同的开源许可证发布。这确保了开源性的延续。Linux内核就采用GPL许可证。
- 宽松许可证(如MIT、BSD、Apache):允许使用者将代码用于闭源商业项目,限制更少。这类许可证非常受欢迎。
附加资源与总结
本节课中我们一起学习了Shell的基础操作、常用命令以及自由开源软件的基本概念。
遇到问题时,请善用以下资源:
- Google:是查找解决方案的绝佳工具。
- Man手册:使用
man命令查询。 - 课程支持:在Discord的
#decal-general频道提问,或最好在实验课时间当面咨询。 - 技术文档:Arch Wiki、Debian手册等提供了极其详细和高质量的文档。

记住,在Linux系统管理中,不断学习和查找资料是常态。不要害怕提问,我们的社区就是为了互助而存在的。
2:Bash脚本编程入门 🐚

在本节课中,我们将要学习Bash脚本编程的基础知识。Bash是一种强大的Shell,它不仅能让我们在终端中手动执行命令,还能通过编写脚本来自动化重复性的系统管理任务。我们将从基础概念开始,逐步学习变量、条件判断、循环、函数以及输入输出重定向。

什么是Bash?🤔
Bash是“Bourne-Again SHell”的缩写,它是早期Unix Shell(如Bourne Shell)的增强版本。Bash不仅是一个交互式的命令行解释器,还是一个功能完整的脚本语言。这意味着你可以将一系列命令写入一个文件,然后让Bash自动执行它们,从而实现任务自动化。
如何运行Bash脚本?🚀
运行Bash脚本主要有两种方法。
第一种方法是直接调用bash解释器,并将脚本文件路径作为参数传递给它。脚本文件通常以.sh作为扩展名。
bash /path/to/your_script.sh
第二种方法是先让脚本文件本身变得可执行,然后直接运行它。这需要在脚本文件的开头添加一行特殊的声明(称为“shebang”)。

chmod +x /path/to/your_script.sh
./your_script.sh

Shebang与注释 📝
Shebang是脚本文件的第一行,它告诉系统应该使用哪个解释器来执行这个文件。对于Bash脚本,这一行通常是:
#!/bin/bash
在Bash中,注释以井号#开头,其后的内容会被解释器忽略。注释对于解释代码逻辑非常重要。
# 这是一行注释
echo "Hello, World!" # 这行命令后面的也是注释

变量与用户输入 💾
变量用于存储信息,以便在脚本中重复使用。在Bash中设置和使用变量时,需要特别注意等号=两边不能有空格。

以下是设置变量和输出变量值的示例:

name="value" # 设置变量
echo $name # 输出变量的值

Bash变量是无类型的。如果你需要进行数学运算,不能直接对变量进行操作,而需要使用expr命令或双括号(( ))来进行表达式求值。


food=1
result=$(expr $food + 1) # 使用expr
echo $result # 输出 2
# 或者使用双括号
result=$((food + 1))
echo $result # 输出 2
你可以使用read命令来获取用户的输入。-p选项用于在等待输入时显示提示信息。
read -p "请输入一个数字: " user_input
echo "你输入的数字是: $user_input"
命令替换允许你将一个命令的输出作为值赋给变量,或者嵌入到另一个命令中。语法是$(command)。
current_date=$(date)
echo "当前日期是: $current_date"
条件判断 🔍
条件判断是编程中的核心,它允许脚本根据不同的情况执行不同的操作。
test命令(或其简写形式[ ])用于评估一个表达式。需要注意的是,在Bash中,条件为真时退出状态码是0,为假时是1,这与许多编程语言的惯例相反。
test 0 -eq 0
echo $? # 输出 0 (真)
test 0 -eq 1
echo $? # 输出 1 (假)


你可以使用-eq(等于)、-ne(不等于)、-lt(小于)、-gt(大于)等参数来比较数值或字符串。
布尔运算符-a表示“与”(AND),-o表示“或”(OR)。
if [ $age -gt 18 -a $age -lt 65 ]; then
echo "你是成年人。"
fi
if语句用于基于条件执行代码块。语句以if开始,以fi结束。
if [ "$input" -eq 79 ]; then
echo "Nice."
else
echo "Not 79."
fi
对于多个条件分支,可以使用elif和else。
if [ "$input" -eq 79 ]; then
echo "Nice."
elif [ "$input" -eq 42 ]; then
echo "The answer."
else
echo "What are numbers?"
fi
case语句提供了一种更清晰的方式来匹配多个模式,类似于其他语言中的switch语句。

read -p "Are you 21 or older? (yes/no): " answer
case $answer in
yes) echo "I give you cookie." ;;
no) echo "That's illegal." ;;
*) echo "Please answer yes or no." ;;
esac
循环 🔁
循环允许你重复执行一段代码。
for循环可以遍历一个列表。
for animal in dog cat bird; do
echo "I have a $animal."
done
它也支持使用大括号{ }表示的数字范围。
for i in {1..5}; do
echo "Number: $i"
done
while循环会在条件为真时持续执行。
count=1
while [ $count -le 5 ]; do
echo "Count is: $count"
count=$((count + 1))
done
要小心无限循环!例如,while true; do echo "nightmare"; done会不停地打印“nightmare”。
函数 📦
函数可以将代码块组织成可重用的单元。在Bash中,你可以像执行命令一样调用函数。
定义函数的语法如下:
function greet {
echo "Hey, there's $1"
}
然后,你可以这样调用它:
greet "sysadmin decal" # 输出: Hey, there's sysadmin decal
在函数内部,$1、$2等代表传递给函数的第一个、第二个参数,这与脚本获取命令行参数的方式一致。
输入/输出流与重定向 📤📥
流重定向是控制命令输入和输出的强大工具。
>操作符将命令的输出重定向到一个文件,如果文件已存在则会覆盖它。
echo "Hello, World!" > output.txt
>>操作符将命令的输出追加到一个文件的末尾。
echo "Another line." >> output.txt
<操作符将一个文件的内容作为命令的输入。
sort < input.txt
管道|将一个命令的输出作为另一个命令的输入。
ls | sort # 列出文件并按字母顺序排序
附加说明与最佳实践 💡
在编写脚本时,选择合适的工具很重要。
- 当你的任务可以方便地通过组合现有的命令行工具(如
grep、sed、awk)来完成时,Bash是绝佳选择。它轻量、直接,非常适合系统自动化。 - 当你需要更复杂的控制结构、数据结构(如列表、字典)、递归或面向对象编程时,应该考虑使用Python等更高级的脚本语言。
除了Bash,还有其他流行的Shell,如Zsh、Fish和Korn Shell。它们的基本概念相似,但语法和特性可能有细微差别。本课程的实验和解决方案均基于Bash。

遇到问题时,请善用man命令查看手册页,或者使用搜索引擎。实践是学习脚本编程的最佳方式。
本节课中我们一起学习了Bash脚本编程的核心概念。我们从如何运行脚本开始,了解了变量、条件判断和循环的使用,探索了如何定义函数来组织代码,最后掌握了强大的流重定向技巧。请利用这些知识来完成本周的实验,在实践中巩固你的理解。如果在编写脚本时遇到问题,请随时向课程助教寻求帮助。
3:软件包管理


概述


在本节课中,我们将要学习Linux发行版的核心概念,并深入探讨软件包管理器的工作原理。我们将以Debian及其APT包管理系统为例,了解如何安装、管理软件,以及如何创建自己的软件包。
Linux发行版简介
在深入探讨包管理器之前,理解Linux发行版的概念至关重要。Linux内核本身只是一个核心组件,负责管理资源和运行程序。而操作系统中的其他一切,包括内置程序、初始化系统、包管理器以及使计算机可用的所有工具,都属于发行版的范畴。
不同的用户有不同的需求和偏好,因此存在许多不同的Linux发行版。每个发行版都围绕Linux内核,采用不同的软件组合和管理方式,其中就包括包管理器。
什么是包管理器?
为什么我们需要包管理器?包管理器帮助我们安装软件。安装软件听起来简单,但实际上涉及许多复杂步骤:需要哪些文件?从哪里获取?如何更新?安全如何保障?
在Linux世界中,我们采取了一种与macOS和Windows截然不同的方法。包管理器旨在为所有这些问题提供一个统一的解决方案。通常,每个Linux发行版都有自己的包管理系统,几乎所有用户都会使用该系统。
包管理器提供了一个集中式的系统来管理更新。其核心思想是,软件包由发行版社区的志愿者维护,而不是由终端用户自己编译代码,或由开发者针对不同环境打包。这简化了终端用户和开发者的工作。
包管理器与应用商店的区别
你可能会想,这听起来就像应用商店。它们都是获取软件的集中式场所,但Linux包管理器与常见的应用商店在一些关键方面有很大不同。
首先,在更新分发方式上不同。在Linux世界,包维护者(通常与开发者不同)负责将软件更新拉取到包仓库中。虽然这有时会慢一些,但发行版能更好地控制,确保所有软件包能协同工作。而在应用商店,通常由开发者直接向用户推送更新。
其次,在安全与信任方面不同。包仓库由发行版维护,用户信任包维护者不会打包恶意软件。如果存在漏洞,包维护者可以回滚仓库中的版本。而在应用商店,这一切都取决于开发者。
另一个重大区别在于依赖关系处理。在macOS和Windows上,应用程序很少依赖其他应用,因此通常不需要包管理器。而在Linux上,软件更倾向于依赖共享库和系统组件,因此需要更仔细地处理依赖关系,确保不破坏系统。


包管理器的一项关键功能是依赖解析。如果你尝试安装一个依赖某个尚未安装的库的软件包,它会自动安装该库。它还会确保没有版本冲突。



Debian与APT包管理器
Debian是一个非常流行的Linux发行版,以其稳定性著称。它采用周期性发布模式,每两年发布一个新的稳定版本,优先考虑系统稳定性而非软件的最新版本。

Debian的包管理系统称为APT。实际上,它包含两个主要部分:apt(前端工具,负责从仓库读取、解析依赖)和 dpkg(底层工具,知道如何安装一个已下载的软件包文件)。



以下是基本的APT命令:
apt update:更新可用软件包列表(不更新已安装软件的版本)。apt install <package_name>:安装软件包。apt remove <package_name>:移除软件包(但可能保留不再需要的依赖)。apt autoremove:自动移除不再需要的依赖包。

软件包仓库与源列表



包管理器从哪里获取软件?它从一个或多个软件包仓库(repository)中获取。这通常是发行版官方维护的服务器。为了负载均衡和速度,全球有许多镜像站点同步这些仓库的数据。
你的系统通过一个配置文件来知道应该查询哪些仓库。在基于Debian/Ubuntu的系统上,这个文件通常是 /etc/apt/sources.list。该文件中的每一行(非注释行)都指向一个软件包源。


软件包的构成
一个Debian软件包(.deb文件)本质上是一个特殊的归档文件。它主要包含两部分:
- 数据归档:包含要安装到系统上的实际文件(如可执行文件、库、文档等),并按照目标系统的目录结构组织。
- 控制信息:包含包的元数据,如包名、版本、架构、维护者、描述以及最重要的——依赖关系列表。


当你使用 dpkg 或 apt 安装一个.deb文件时,数据文件会被提取并合并到系统的文件系统中,同时控制信息被记录,以便未来管理(如升级、卸载)。
创建自己的软件包

在实验环节,你将学习如何创建一个简单的Debian软件包。这个过程大致分为两步:
- 编译:将源代码(例如C程序)编译成可执行文件。对于简单项目,可能只需
gcc hello.c -o hello。对于复杂项目,通常有更复杂的构建系统。 - 打包:将可执行文件及其相关文件,连同必要的元数据(如包名、版本、依赖),打包成一个.deb文件。
我们将使用一个名为 fpm 的工具来简化打包过程。它可以让你相对轻松地构建一个可工作的软件包。虽然对于提交到官方仓库来说可能不够严谨,但对于本地和个人使用来说已经足够。
总结

本节课我们一起学习了Linux软件包管理的核心概念。我们了解了Linux发行版的作用,探讨了包管理器如何解决软件安装、更新和依赖管理的复杂性问题,并比较了其与应用商店的区别。我们以Debian和APT为例,演示了软件包的安装、移除,剖析了软件包的内部结构,并简要介绍了创建自定义软件包的基本流程。掌握包管理器是有效管理Linux系统的关键技能。
4:进程与服务


在本节课中,我们将要学习Linux操作系统中进程与服务的基本概念。我们将探讨进程是如何被创建和管理的,以及现代Linux系统如何使用Systemd来管理后台服务。理解这些概念对于进行系统管理和故障排查至关重要。
进程:程序的运行实例
上一节我们介绍了操作系统的目标,本节中我们来看看实现这些目标的核心抽象:进程。
进程是程序的一次执行实例。操作系统通过进程来隔离和管理不同的运行任务。每个进程都拥有独立的资源,例如内存空间和文件描述符,这确保了它们不会相互干扰。
以下是进程的一些关键特性:
- 隔离性:每个进程运行在自己的“沙箱”中,无法直接访问其他进程的内存或资源。
- 虚拟内存:每个进程都拥有从0开始的独立虚拟地址空间,这给程序一种它独占了全部内存的错觉。内核负责将虚拟地址映射到物理内存。
- 通信:进程间通过操作系统提供的特定接口(如管道、套接字)进行通信。
内核代码本身并不在进程中运行,它是管理所有进程的“管理者”。


进程的创建:fork与exec模型
既然进程如此重要,那么它们是如何产生的呢?在Linux中,新进程主要通过“fork-exec”模型创建。



这个模型包含三个核心步骤:
- fork(创建):一个现有进程(父进程)调用
fork()系统调用,这会创建一个几乎是其自身完全副本的新进程(子进程)。 - exec(执行):子进程随后调用
exec()系列函数,这将用一个新的程序替换掉当前进程正在运行的代码,开始执行全新的任务。 - wait(等待):父进程可以调用
wait()来等待子进程结束,并获取其退出状态码。
这种机制导致所有进程形成一棵树状结构。例如,当你在Bash shell中输入 cat file.txt 时,Bash会fork自身,然后在子进程中exec cat 程序。
进程树与系统监控

我们可以使用工具来查看系统中运行的进程及其层次关系。

一个常用的命令是 htop。运行 htop 后,按 F5 键可以切换到树状视图,清晰地展示进程间的父子关系。这有助于理解系统是如何组织起来的,例如,你的Shell进程可能是SSH守护进程的子进程。
初始化系统(init)与PID 1
根据fork模型,进程由其他进程创建。这引出一个根本问题:第一个进程从何而来?
答案是内核在启动时创建的init进程,其进程ID(PID)为1。它是所有用户进程的始祖,并承担着特殊职责:
- 孤儿进程收养:如果一个进程的父进程先退出,该进程会成为“孤儿”,并由init进程接管,确保其退出后能被正确清理。
- 服务管理:init系统负责启动和管理系统必需的服务(如登录界面getty、网络服务、SSH守护进程等)。
- 启动目标:它定义了系统启动的不同阶段(如多用户模式、图形界面模式),并确保相关服务按正确顺序启动。


Systemd:现代Linux的初始化系统
如今,绝大多数Linux发行版使用 Systemd 作为其初始化系统。它功能强大,统一了服务管理、日志记录、设备挂载等诸多功能。
Systemd通过单元文件来定义和管理各种系统资源。服务单元文件通常以 .service 为后缀。
以下是一个简单服务单元文件的示例结构:
[Unit]
Description=一个简单的示例服务
[Service]
ExecStart=/usr/bin/python3 /path/to/your_script.py
Restart=always
User=nobody
[Install]
WantedBy=multi-user.target
[Unit]部分提供描述和依赖关系。[Service]部分定义如何启动、停止服务,以及运行用户等。[Install]部分指定在哪个系统启动目标下启用该服务。

使用Systemd管理服务

我们可以使用 systemctl 命令与Systemd交互,管理服务。

以下是一些常用命令:
systemctl start <service>:启动一个服务。systemctl stop <service>:停止一个服务。systemctl restart <service>:重启一个服务。systemctl enable <service>:设置服务在系统启动时自动启动。systemctl disable <service>:取消服务在系统启动时自动启动。systemctl status <service>:查看服务的状态和日志。
要列出系统上所有已加载的单元,可以运行 systemctl list-units。


总结
本节课中我们一起学习了Linux进程与服务的核心知识。我们了解了进程作为程序执行实例的隔离特性,以及它们通过fork-exec模型被创建的机制。我们认识了PID为1的init进程及其在孤儿收养和服务管理中的关键作用。最后,我们重点探讨了现代Linux广泛使用的Systemd初始化系统,学习了如何通过单元文件定义服务,并使用 systemctl 命令对其进行管理。掌握这些概念和工具是进行有效系统运维的基础。
5:网络与操作系统中间季





在本节课中,我们将学习计算机网络的基础知识,包括网络模型、关键协议以及实用的网络诊断工具。我们将从网络通信的基本需求开始,逐步深入到TCP/IP模型的各个层次。
网络模型概述


我们为什么需要网络?核心目标是实现便捷的通信。这需要满足几个关键需求:低延迟、高带宽、易于识别计算机以及容错能力。同时满足所有这些要求非常困难,因此在不同场景下需要优先考虑不同的特性,例如有时需要为低延迟而牺牲可靠性。这导致了不同协议和网络架构的出现。
为了抽象地理解这个复杂的系统,我们使用网络模型。其中占主导地位的是TCP/IP四层模型。这个模型定义较为宽松,意味着某些功能(如防火墙)可能跨越多个层次。高层抽象低层的细节。
以下是TCP/IP模型的四层结构:
- 应用层:用户应用程序所在层,例如你的浏览器。
- 传输层:负责计算机之间的通信,处理可靠性和数据包排序。
- 网络层:在不同网络间传输数据。
- 链路层:最底层,处理物理连接和本地网络通信。
数据发送时,从应用层向下经过各层处理;接收时,则从链路层向上解析。
上一节我们介绍了网络模型,本节中我们来看看每一层的具体细节。
链路层
链路层是最底层,处理所有物理连接和本地网络内的通信,例如通过以太网连接。该层抽象了硬件实现,让我们可以专注于“我能与谁直接通信,而无需经过路由器”。
链路层涉及的核心概念包括:
- MAC地址:每个网络设备的全球唯一硬件标识符。格式为
XX:XX:XX:YY:YY:YY,其中前24位标识制造商。 - ARP(地址解析协议):用于在本地网络上根据IP地址查找对应MAC地址的协议。
网络层
当我们想与另一个网络(例如不同大洲)上的计算机通信时,就需要网络层。它负责在不同网络间路由数据。
网络层的核心是IP地址。你可以将IP地址想象成现实世界的房屋地址,它标识了设备在网络中的当前位置。IP地址可以更改(例如通过DHCP协议分配)。
- IPv4地址:32位长,通常表示为点分十进制格式,如
192.168.1.1。 - 子网掩码:用于划分IP地址的网络部分和主机部分。例如,
192.168.1.0/24表示前24位是网络前缀。 - IPv6地址:由于IPv4地址耗尽,IPv6采用128位地址,格式如
2001:0db8:85a3:0000:0000:8a2e:0370:7334,提供了海量的地址空间。
地址解析协议
ARP是链路层协议,用于将网络层的IP地址解析为链路层的MAC地址。其过程类似于在本地网络中“广播”询问:“谁拥有这个IP地址?”,拥有该IP的设备会回应并告知其MAC地址。系统内核会将解析结果缓存到ARP表中以提高效率。
路由
路由是数据包从源设备穿越多个网络到达目标设备的过程。路由器根据其内部的路由表决定数据包的下一跳路径。例如,从你的家庭网络访问一个网站,数据包会经过你的路由器、ISP的路由器等多个中间节点,最终到达目标服务器。
域名系统
DNS是将人类可读的域名(如 google.com)转换为机器可读的IP地址的服务。当你在浏览器中输入网址时,系统会向DNS服务器查询对应的IP地址。你可以使用公共DNS(如Google的 8.8.8.8 或 Cloudflare的 1.1.1.1),也可以搭建自己的私有DNS服务器。
传输层协议
传输层负责端到端的通信。主要有两个协议:
传输控制协议 提供可靠的、面向连接的通信。它通过“三次握手”建立连接,确保数据按序、完整地传输,适用于文件传输、网页浏览等场景。
建立连接(三次握手):
1. 客户端 -> 服务器:SYN
2. 服务器 -> 客户端:SYN-ACK
3. 客户端 -> 服务器:ACK
开始传输数据...
终止连接:
1. 客户端 -> 服务器:FIN
2. 服务器 -> 客户端:ACK
3. 服务器 -> 客户端:FIN
4. 客户端 -> 服务器:ACK
用户数据报协议 是一种无连接的协议。它不保证可靠性或顺序,但速度更快,适用于能容忍少量数据丢失的实时应用,如视频流、在线游戏。
网络诊断工具
掌握一些命令行工具对诊断网络问题非常有帮助。以下是几个常用工具:
ping
用于测试与目标主机的连通性和延迟。发送ICMP回显请求并等待回复。
ping -c 5 google.com # 向google.com发送5个测试包

traceroute
用于显示数据包到达目标主机所经过的路由路径。
traceroute google.com
arp
用于查看和操作系统的ARP缓存表,显示IP地址与MAC地址的映射关系。
arp -a
dig
用于查询DNS信息,是诊断域名解析问题的强大工具。
dig google.com

ip
一个强大的工具,用于显示或配置网络接口、路由等信息。
ip addr show # 显示所有网络接口的IP地址信息

总结
本节课我们一起学习了计算机网络的基础。我们从TCP/IP四层模型入手,了解了链路层的MAC地址与ARP协议,网络层的IP地址与路由概念,以及传输层的TCP和UDP协议的区别。最后,我们介绍了几种实用的网络诊断工具,如 ping、traceroute、arp、dig 和 ip,这些工具将帮助你在实际管理中排查网络问题。



6:Web服务器与DNS 🖥️🌐


在本节课中,我们将学习域名系统(DNS)和Web服务器的工作原理。我们将探讨DNS如何将人类可读的域名转换为机器可读的IP地址,以及Web服务器如何响应请求并处理大量流量。最后,我们会介绍负载均衡的概念,以理解大型网站如何扩展其服务。
DNS:域名系统
上一节我们介绍了网络基础,本节中我们来看看域名系统(DNS)。DNS的核心功能是将易于记忆的域名(如 ocf.berkeley.edu)转换为计算机用于通信的IP地址(如 169.229.226.23)。
当你在浏览器中输入一个域名时,你的计算机会向一个称为“递归解析器”的DNS服务器发送请求。这个解析器会从DNS层级结构的根开始,一步步向下查询,直到找到该域名对应的最终IP地址。
以下是DNS查询过程的简化步骤:
- 查询根服务器,获取
.edu域的权威名称服务器信息。 - 查询
.edu服务器,获取berkeley.edu域的权威名称服务器信息。 - 查询
berkeley.edu的服务器,最终获得ocf.berkeley.edu对应的IP地址记录。
这个IP地址随后被返回给你的计算机,用于建立实际的网络连接。
DNS记录类型
DNS系统使用不同类型的记录来存储各种信息。以下是几种关键的DNS记录类型:
- A记录:将域名映射到一个IPv4地址。例如:
ocf.berkeley.edu->169.229.226.23 - AAAA记录:将域名映射到一个IPv6地址。IPv6地址更长,格式如
2001:db8::1,提供了远多于IPv4的地址空间。 - CNAME记录:将一个域名映射到另一个域名(别名)。例如,
uptime.ocf.io可能指向snap.herokuapp.com。解析时,会继续查找别名指向的域名的A记录。 - MX记录:指定接收该域电子邮件的邮件服务器。
- NS记录:指定负责该域的权威名称服务器。
- TXT记录:存储任意文本信息,常用于域名所有权验证(如Google站点验证)或安全策略。
- SRV记录:指定提供特定服务(如即时通讯)的主机和端口号。
- SOA记录:存储关于域的行政管理信息,如管理员邮箱、序列号和刷新间隔。
TTL与DNS缓存
在DNS响应中,有一个重要的字段叫做 TTL,即“生存时间”。它告诉本地DNS解析器应该将该记录在缓存中保存多久。
公式表示:TTL = 缓存有效期(秒)
较高的TTL值(如1小时)可以加快后续的DNS解析速度,因为结果已缓存。但副作用是,当你更新DNS记录时,全球的缓存需要最多TTL所规定的时间才能全部刷新,导致变更生效延迟。
DNS攻击:DNS投毒
DNS系统可能遭受攻击,例如 DNS投毒。在这种攻击中,攻击者位于用户和DNS服务器之间,拦截DNS查询响应,并将其替换为指向恶意网站的虚假IP地址。这样,即使用户输入了正确的域名,也会被引导至错误的网站。
这种攻击可以在网络的不同层级发生,是互联网安全中的一个重要威胁。
Web服务器工作原理
现在我们已经知道如何通过DNS找到服务器,接下来看看Web服务器本身。当你访问一个网站(如 youtube.com)时,你的浏览器会向该域名对应的IP地址发送一个HTTP请求。
Web服务器本质上是一个监听特定网络端口(通常是80或443)的程序。它接收请求,根据请求的路径找到对应的文件(如HTML页面、图片、视频),然后将这些内容打包在HTTP响应中发回给你的浏览器。
扩展Web服务:负载均衡
单个Web服务器的处理能力有限。当用户访问量巨大时,我们需要扩展服务能力。主要有两种方式:
- 垂直扩展:升级单台服务器的硬件(如更多CPU、更大内存)。
- 水平扩展:增加服务器的数量。
水平扩展带来了一个问题:一个域名(如 google.com)通常只对应一个IP地址(A记录),但我们有多台服务器拥有不同的IP地址。解决方案是使用 负载均衡器。
负载均衡器是一台位于多台Web服务器前面的专用机器。所有用户请求首先到达负载均衡器,然后由它按照某种策略将请求分发到后端的某一台实际服务器上。
负载均衡策略
负载均衡器使用不同的算法来决定将请求转发给哪台后端服务器。以下是几种常见策略:
- 轮询:依次将新请求发送给列表中的下一台服务器,确保每台服务器获得大致相等的负载。
- IP哈希:根据客户端的IP地址计算一个哈希值,并将同一IP的请求始终定向到同一台后端服务器。这对于需要保持用户会话(如登录状态)的应用很有用,也称为“粘性会话”。
- 最少连接:动态地将新请求发送给当前连接数最少的服务器。
- 健康检查:负载均衡器会定期向后端服务器发送探测请求,以确保它们处于正常工作状态。如果某台服务器故障,则不再向其转发流量。
负载均衡器本身也可以进行层级化部署,形成树状结构,或者结合 DNS负载均衡(为不同地理位置的用户返回不同的IP地址)等技术,以防止其自身成为性能瓶颈。
总结
本节课中我们一起学习了:
- DNS 如何作为互联网的“电话簿”,将域名解析为IP地址,并了解了各种DNS记录类型及其作用。
- Web服务器 如何响应HTTP请求并提供内容。
- 负载均衡 的概念与策略,这是构建高可用、可扩展Web服务的关键技术,它通过在多台服务器间智能分配流量来应对高并发访问。


理解这些基础组件是如何协同工作的,是进行系统管理和网络运维的重要基石。
7:安全基础与文件权限 🔐





在本节课中,我们将要学习计算机安全的基础概念,包括为什么安全至关重要、核心安全原则(保密性、完整性、可用性),以及如何在Linux系统中通过文件所有权和权限来实施安全控制。我们还将探讨加密、哈希函数和数字签名等基本技术。
概述:为什么我们需要关注安全? 🛡️
我们关心安全,是因为我们的数据(如医疗、财务信息)存在于现实世界中,并由各种公共实体管理。如果这些实体的安全系统失效,我们的数据将变得脆弱,可能被他人获取,这是非常严重的问题。近年来发生了许多安全漏洞事件,例如UC Berkeley和密码管理器LastPass都曾遭遇过。因此,思考如何管理自身安全至关重要,尤其是当你需要管理自己的Linux服务器时。你不仅需要保护自己的信息,还可能保护他人的信息。每次设计系统或维护服务器时,都应牢记安全原则。
核心安全原则
以下是构建安全系统时需要遵循的几个基本原则。
安全即经济学 💰
安全系统的实施通常成本高昂。例如,一辆价值100美元的自行车,不值得购买一个200美元的昂贵锁具。因此,在设计安全时,必须考虑安全系统的价值应与所保护资产的价值相匹配。为不重要的东西使用过于昂贵的安全措施是没有意义的。
最小权限原则
这个原则的核心是,只授予完成任务所必需的最小访问权限。例如,如果一个应用只需要访问两个文件夹,那么就只授予它访问这两个文件夹的权限,而不是更多。这样可以限制潜在的安全风险。
纵深防御
纵深防御意味着设置多层安全措施。例如,使用双因素认证。这样,即使其中一层防御被攻破,其他层仍然可以提供保护,避免整个系统被完全攻陷。
完全调解
完全调解要求对整个数据流程拥有控制权,而不是在中间环节存在不受信任或不安全的元素。你需要确保从起点到终点的整个链条都是安全的。
考虑人为因素
设计安全模型时必须考虑人为因素。例如,在要求用户创建密码的系统中,用户可能会创建弱密码或重复使用密码。设计时需要考虑到这些情况,并采取措施(如密码强度要求)来降低风险。
最重要的是,你需要了解自己的威胁模型。威胁模型是指思考谁可能攻击你的服务、哪些地方容易暴露,以及你需要防范什么。例如,一个普通人的威胁模型可能只是防范随机的、非针对性的自动化攻击。而一个亿万富翁或政府机构的威胁模型则可能包括有针对性、资源丰富的攻击者。根据不同的威胁模型,你的安全策略和措施(如最小权限原则)都需要相应调整。
安全目标
实施安全系统时,我们主要追求以下几个目标。
保密性
保密性意味着只有被授权访问特定数据的人才能读取该数据。未经授权的人不应访问这些信息。
完整性
完整性确保数据在传输或存储过程中未被篡改。这与保密性不同,保密性关注的是读取权限,而完整性关注的是数据本身是否保持原始状态。例如,当你从服务器读取数据时,需要确保数据在传输过程中没有被中间人修改。
身份验证
身份验证是确认数据创建者或访问者身份的过程。它是确保保密性和完整性得以实现的基础。例如,通过验证用户身份,系统可以决定是否允许其访问特定数据。
可用性
可用性是指服务应始终保持可访问状态。提高安全性不应以牺牲服务的正常可用性为代价。例如,如果一个安全机制导致服务器频繁宕机,那么即使它很安全,也会影响整体服务。
实现保密性:加密
当我们谈论保密性时,有多种方式可以存储信息。
明文存储
令人惊讶的是,在不久以前,人们甚至以明文形式在服务器上存储密码。这种方式极其不安全,因为一旦发生数据泄露,所有密码都会直接暴露,攻击者无需任何额外工作即可获取它们。
密文存储
密文是指使用密钥对明文进行加密后得到的文本。加密后的信息看起来就像一堆随机数据。密钥的作用是允许你将明文加密为密文,并在需要读取数据时,用同一把密钥将密文解密回明文。
这个过程可以用以下伪代码描述:
ciphertext = encrypt(plaintext, key)
plaintext = decrypt(ciphertext, key)
这种使用相同密钥进行加密和解密的方式称为对称加密。
非对称加密
还存在另一种加密方式,称为非对称加密。它使用一对密钥:一个公钥和一个私钥。
- 用公钥加密的数据,只能用对应的私钥解密。
- 用私钥加密(通常称为“签名”)的数据,可以用对应的公钥解密(验证)。
非对称加密的一个常见应用是SSH密钥认证。你将公钥放在服务器上,当尝试连接时,服务器会发送一个挑战,你用私钥签名后发回,服务器用你的公钥验证签名,从而确认你的身份。
实现完整性:哈希函数
完整性用于验证文件在传输过程中是否被篡改。为此,我们使用哈希函数。
哈希函数可以将任意长度的数据转换为一个固定长度的、唯一的字符串(称为哈希值或摘要)。即使输入数据发生微小变化,输出的哈希值也会截然不同。加密哈希函数还需要避免哈希碰撞(即两个不同的输入产生相同的输出)。

哈希函数是单向函数:从输入计算哈希值很容易,但从哈希值反推原始输入在计算上极其困难。
哈希函数的一个常见用途是验证文件下载的完整性。例如,下载Linux系统镜像时,官方网站通常会提供该文件的SHA-256哈希值。下载完成后,你可以在终端运行命令计算本地文件的哈希值并进行比对。
计算文件哈希值的命令示例:
sha256sum /path/to/your/file.iso

实现身份验证:数字签名

身份验证用于证明数据的来源。我们可以使用非对称加密技术来签名文件。
虽然过程与加密类似(使用私钥处理数据),但其目的不是保密,而是验证。发送方用私钥对文件生成签名,接收方用发送方的公钥验证签名。如果验证成功,就证明该文件确实来自声称的发送方,因为只有拥有私钥的人才能生成有效的签名。
这个过程结合哈希函数可以更强大:先对消息计算哈希值,再用私钥对哈希值签名。接收方可以同时验证消息的完整性和来源。
确保可用性

在安全背景下讨论可用性,通常涉及防止服务因攻击(如DDoS)而不可用。
以下是几种提高可用性的策略:
- 过滤:根据IP地址或地理位置阻止恶意请求。例如,如果服务只面向加州用户,可以屏蔽其他地区的IP。
- 负载均衡:将流量分发到多个后端服务器,避免单点过载。
- 冗余:部署多个相同的系统,当一个出现故障时,另一个可以接管。
- 备份:定期备份数据,确保在发生最坏情况时能够恢复。
Linux文件安全:权限与所有权
Linux是一个多用户环境,因此文件权限和所有权管理至关重要。
查看文件权限
使用 ls -l 命令可以查看文件的详细信息。输出结果中包含了权限信息。
每个文件都有三种所有权级别:
- 文件所有者:创建该文件的用户。
- 所属组:文件所属的用户组。
- 其他用户:既不是文件所有者,也不在所属组中的其他所有用户。
权限由一串字符表示,例如 -rwxr-xr--。第一个字符表示文件类型(- 表示普通文件,d 表示目录)。随后是三组字符,每组三个,分别对应所有者、所属组和其他用户的权限。
r代表读权限。w代表写权限。x代表执行权限。
例如,-rwxr-xr-- 表示:
- 所有者:可读、可写、可执行。
- 所属组:可读、可执行。
- 其他用户:仅可读。
修改文件所有权和权限
以下是修改文件所有权和权限的两个主要命令。
1. chown:改变文件所有者
chown 命令用于更改文件的所有者和所属组。通常需要 sudo 权限来执行。使用 -R 参数可以递归地更改目录及其内部所有文件的所有权。
命令语法示例:
sudo chown newuser:newgroup filename
sudo chown -R newuser:newgroup directoryname/
2. chmod:改变文件权限
chmod 命令用于直接修改文件的权限。同样可以使用 -R 参数进行递归操作。
权限可以通过字母或数字模式来修改:
- 字母模式:
u代表所有者,g代表组,o代表其他,a代表所有。用+添加权限,用-移除权限。chmod o+r filename # 给其他用户添加读权限 chmod g-w filename # 移除所属组的写权限 - 数字模式:用三位八进制数表示权限,如
755(对应rwxr-xr-x)。
正确设置文件权限(例如,将SSH私钥权限设置为仅所有者可读)是防止信息泄露的关键。
证书与信任链
在非对称加密中,如何确认一个公钥确实属于其声称的所有者?这需要通过证书和信任链来解决。
证书由受信任的证书颁发机构签发,它将一个公钥与一个身份(如网站域名)绑定在一起。你的操作系统或浏览器预装了一组受信任的根CA证书。当访问一个HTTPS网站时,浏览器会检查网站提供的证书,并沿着信任链向上验证,直到一个受信任的根CA。这确保了公钥的真实性。
总结

本节课中我们一起学习了计算机安全的基础知识。我们探讨了为什么安全至关重要,并介绍了核心安全原则:安全即经济学、最小权限、纵深防御等。我们明确了安全的四大目标:保密性、完整性、身份验证和可用性,并了解了通过加密、哈希函数和数字签名来实现这些目标的技术。最后,我们深入学习了在Linux系统中管理文件权限和所有权的实践命令(chown 和 chmod),这是保护系统数据安全的第一道防线。理解这些概念对于管理和维护安全的Linux系统至关重要。
8:版本控制(Git)与备份


在本节课中,我们将要学习版本控制系统Git的核心概念、基本操作以及数据备份的重要性与方法。我们将从Git的工作原理讲起,逐步介绍其常用命令,并探讨如何通过备份策略保护你的数据。
Git简介与工作原理
上一节我们介绍了课程概述,本节中我们来看看什么是Git以及它为何如此重要。
Git是一个免费、开源的分布式版本控制系统,由Linus Torvalds于2005年为Linux内核开发而创建。它的主要目的是跟踪项目或代码随时间推移所产生的不同版本或更改。
使用Git的核心原因包括:
- 版本追踪:管理项目开发过程中的多个迭代版本,例如
script_v1.py、script_final.py、script_final_final.py。 - 团队协作:允许多人并行工作于同一项目的不同部分,最后合并更改,而无需过度担心冲突。
- 功能开发:可以创建独立的分支(如
production生产分支和testing测试分支),在不影响稳定版本的情况下进行新功能尝试。
Git有两个关键特性使其与众不同:
- 数据完整性:Git使用SHA-1哈希算法为所有内容生成校验和。这意味着任何文件的更改都无法瞒过Git,因为哈希值会发生变化。
- 公式:
SHA-1(文件内容) -> 唯一哈希值
- 公式:
- 高性能:几乎所有操作都在本地执行,浏览历史无需网络连接,速度极快。
Git内部原理:有向无环图
Git将项目历史表示为一个有向无环图。
- 有向:图中的每个节点(提交)都通过箭头指向其父提交,表明历史流向。
- 无环:历史不能形成循环,因为你无法穿越时间回到更早的、基于当前状态的提交。
每个提交对应项目在某个时间点的快照(即所有文件和目录的状态)。提交由树(代表目录)和Blob(代表文件)组成。
分支是指向某条开发线末端(最新提交)的指针。默认分支名通常是master或main。HEAD是一个特殊指针,指向你当前所在的提交(即工作目录的状态)。
分布式特性
Git是分布式的,这意味着同一个仓库可以有多个副本,每个副本都支持独立的开发。这通过git push和git pull等命令,提供了在不同副本间传输和协调版本的机制。
Git基础命令与工作流
上一节我们了解了Git的核心概念,本节中我们来看看如何使用Git命令行进行实际操作。
文件状态
在Git中,文件主要处于以下几种状态:
- 未跟踪:文件存在于工作目录,但Git尚未开始管理它。
- 已跟踪:Git已知晓的文件。已跟踪文件又可细分为:
- 未修改:自上次提交后未更改。
- 已修改:自上次提交后已被更改。
- 已暂存:已修改的文件被标记,准备包含在下次提交中。
使用 git status 命令可以查看当前所有文件的状态。
忽略文件

你可以在项目根目录创建一个名为 .gitignore 的文件,来指定哪些文件或目录应被Git忽略(例如日志文件、编译缓存__pycache__/、系统文件.DS_Store等)。
创建仓库与基本操作
以下是创建一个新Git仓库并进行首次提交的基本步骤:


# 1. 初始化新仓库
git init my_project
cd my_project
# 2. 创建或修改文件(例如,使用文本编辑器)
echo "Hello, Git!" > README.txt
# 3. 将文件添加到暂存区
git add README.txt
# 4. 提交更改,创建历史快照
git commit -m "Initial commit: add README file"
如果你想基于现有远程仓库(如GitHub上的项目)开始工作,可以使用克隆命令:
# 克隆远程仓库到本地
git clone <远程仓库URL> <本地目录名>
每次提交后,暂存区会被清空。你需要再次使用 git add 将新的更改放入暂存区,为下一次提交做准备。可以使用 git add . 来添加所有更改过的文件。

分支、合并与远程协作

上一节我们介绍了基础的提交操作,本节中我们来看看Git更强大的功能:分支管理和团队协作。
分支与合并
分支允许你在主开发线之外创建独立的开发上下文,常用于尝试新功能或修复bug,而不影响稳定代码。
以下是分支操作的基本命令:
# 1. 创建并切换到一个新分支
git checkout -b feature_branch
# 2. 在新分支上进行开发、提交...
# ... 编辑文件 ...
git add .
git commit -m "Add new feature"
# 3. 切换回主分支(如master)
git checkout master
# 4. 将特性分支合并到主分支
git merge feature_branch
# 5. (可选)删除已合并的特性分支
git branch -d feature_branch
合并是将一个分支的更改集成到另一个分支的操作。变基是另一种整合更改的方法,它会将当前分支的提交“重新播放”在目标分支的最新提交之后,从而产生一条更线性的历史。选择合并还是变基取决于团队偏好和项目需求。
处理冲突
当Git无法自动合并两个分支的更改时(例如,两人修改了同一文件的相同行),就会发生冲突。Git会在冲突文件中标记出冲突内容,你需要手动编辑文件来解决冲突,然后执行 git add 和 git commit 来完成合并。
远程协作
为了与其他人协作,通常需要一个中央远程仓库(如GitHub, GitLab)。
# 查看已配置的远程仓库
git remote -v
# 从远程仓库获取更新(不自动合并)
git fetch origin
# 获取并合并远程更新到当前分支
git pull origin master
# 将本地提交推送到远程仓库
git push origin feature_branch
在典型的协作工作流中,你会:
- 从主分支创建特性分支。
- 在特性分支上开发并提交。
- 将特性分支推送到远程仓库。
- 创建拉取请求,邀请他人审查代码。
- 审查通过后,将特性分支合并到主分支。
数据备份策略与实践
上一节我们探讨了如何使用Git进行版本控制和协作,本节中我们来看看另一个至关重要的主题:数据备份。
为何需要备份
根据墨菲定律,任何可能出错的事情最终都会出错。系统崩溃、硬件故障、误操作(如 rm -rf / 错误)、设备丢失或被盗都可能导致数据永久丢失。自动化备份至关重要,因为人们很容易忘记手动备份。
备份3-2-1原则
一个健壮的备份策略应遵循 3-2-1原则:
- 至少保留3份数据副本。
- 将数据存储在至少两种不同的介质上(例如,电脑硬盘 + 外部硬盘 + 云存储)。
- 其中至少一份副本存放在异地(如云存储服务),以防本地灾害。
历史教训(如GitLab 2017年的数据删除事故)表明,没有有效备份将导致灾难性后果。


备份工具
以下是一些常用的备份工具:
rsync:一个强大的文件同步工具,可以高效地在本地和远程之间同步目录,仅传输更改过的文件。# 基本语法:将本地目录同步到远程服务器 rsync -avz /path/to/local/dir/ user@remote_host:/path/to/backup/dir/rclone:类似于rsync,但专为云存储服务(如Google Drive, Dropbox, Amazon S3)设计。- 云存储服务:直接使用Google Drive、Dropbox、iCloud等的同步客户端。
- 版本控制系统:像Git这样的工具本身也是代码和文本项目的优秀备份机制,尤其是配合远程仓库使用。



建议使用cron等工具设置定时任务,实现备份自动化。
总结与资源
本节课中我们一起学习了版本控制工具Git的核心概念、基本命令和工作流程,包括初始化仓库、提交更改、分支管理、合并冲突以及与远程仓库协作。我们还深入探讨了数据备份的重要性,并介绍了3-2-1备份原则及实用工具。
更多资源

- Pro Git 书籍:官方指南,内容全面。
- Git Cheat Sheet:速查表有助于快速回忆命令。
- GitHub Guides:提供实用的入门教程。
- Stack Overflow & Google:遇到问题时不可或缺的帮手。

记住,实践是掌握Git和建立有效备份习惯的关键。现在就开始为你重要的项目初始化一个Git仓库,并设置一个简单的备份方案吧!
9:容器技术入门

在本节课中,我们将要学习容器技术的基本概念、工作原理以及如何使用Docker和Docker Compose等工具来创建和管理容器。容器是一种轻量级的软件打包和运行方式,它允许你将应用程序及其所有依赖项打包在一起,并在任何支持容器的系统上运行。
容器是什么?🤔

容器是一种打包软件的方式。你可以将一组库和二进制文件打包在一起,使其看起来像一个Linux发行版,但你可以在一个不一定运行该发行版的机器上运行它。例如,如果一个软件被打包在Ubuntu上运行,你可以在Fedora或Arch机器上运行一个Ubuntu容器来运行该软件。
它的工作原理基于内核的几项技术:cgroups(控制组)用于分配资源,namespaces(命名空间)用于隔离进程、文件系统、网络等。例如,你可以将进程绑定到一个文件夹,使其认为那是根目录;你也可以使用网络命名空间来创建一个隔离的网络环境,让容器只能彼此通信,或者只能通过特定端口与外界通信。
上一节我们介绍了容器的基本定义,本节中我们来看看容器与虚拟机的区别。
容器 vs. 虚拟机 🆚
在容器技术出现之前,如果你想运行多个具有不同依赖的应用程序,通常需要使用虚拟机。虚拟机的架构如下:硬件之上是管理程序(Hypervisor),它允许多个客户操作系统在一台机器上运行。每个客户操作系统都有自己的内核、引导加载程序和完整的操作系统副本,这带来了巨大的开销。
容器则移除了所有这些冗余层。它没有管理程序,没有模拟的CPU,只是在一组二进制文件和库周围画了一条虚线,说“这就是我们应用程序运行的环境”。因此,容器比虚拟机更轻量、启动更快。
然而,两者有重要区别。虚拟机提供更好的隔离性。如果你出于安全原因需要运行某个程序,虚拟机是更好的选择。如果一个容器在根级别被攻破,通常意味着整个主机系统都可能被攻破,而虚拟机则能提供更强的安全边界。
此外,虚拟机可以运行不同的操作系统(如Windows、macOS),而容器主要运行Linux环境。在macOS或Windows上运行Docker时,实际上是在后台启动了一个运行Linux内核的虚拟机,因此会损失一些效率。
Docker的核心概念 🐳
Docker是容器技术的一个流行实现。理解Docker,首先要区分两个核心概念:镜像和容器。
- 镜像:是一个只读的模板,包含了运行应用程序所需的一切:代码、运行时、库、环境变量和配置文件。你可以把它类比为面向对象编程中的“类”。
- 容器:是镜像的一个运行实例。当你运行一个镜像时,你就创建了一个容器。容器是进程、文件系统和网络等资源的隔离集合。你可以把它类比为“类”的实例化“对象”。
以下是Docker的一些基本命令:
docker images:列出本地已拉取的镜像。docker ps:列出当前正在运行的容器。docker run <image>:运行一个镜像。如果本地没有该镜像,会先从Docker Hub拉取。docker start/stop/restart <container>:启动、停止或重启一个容器。docker logs <container>:查看容器的日志输出。docker exec -it <container> /bin/bash:在正在运行的容器中启动一个交互式shell。
编写Dockerfile 📝
Docker镜像是通过一个名为Dockerfile的文本文件构建的。Dockerfile中的每一行都是一条指令,用于构建镜像的层。
以下是一个简单的Dockerfile示例:
# 指定基础镜像
FROM node:19
# 设置工作目录
WORKDIR /app
# 将当前目录的文件复制到容器的/app目录
COPY . /app
# 安装依赖
RUN npm install
# 定义容器启动时运行的命令
CMD ["node", "server.js"]
# 声明容器运行时监听的端口
EXPOSE 3000
FROM:指定构建的基础镜像。WORKDIR:设置容器内的工作目录。COPY:将文件从构建上下文复制到容器内。RUN:在构建镜像时执行命令(如安装软件包)。CMD:指定容器启动时默认执行的命令。EXPOSE:声明容器打算使用的端口(这只是一个声明,实际映射需要在运行时通过-p参数或Docker Compose配置)。
你还可以进行多阶段构建,这允许你在一个Dockerfile中使用多个FROM指令,从一个镜像复制文件到另一个镜像,有助于创建更小、更安全的最终镜像。
使用Docker Compose编排多个容器 🚂
通常,一个应用需要多个容器协同工作,例如一个Web应用容器和一个数据库容器。Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。
你使用一个docker-compose.yml文件来配置应用程序的服务。以下是一个示例:
version: '3.8'
services:
db:
image: postgres:14
volumes:
- ./data:/var/lib/postgresql/data
- ./postgres.conf:/etc/postgresql/postgresql.conf
environment:
POSTGRES_PASSWORD: secretpassword
web:
build: .
command: npm start
ports:
- "3000:3000"
depends_on:
- db
volumes:
- .:/app
在这个配置中:
- 定义了两个服务:
db(使用PostgreSQL 14镜像)和web(基于当前目录的Dockerfile构建)。 volumes:将主机目录挂载到容器内,实现数据持久化和文件同步。environment:设置容器内的环境变量。ports:将主机端口映射到容器端口。depends_on:指定服务启动顺序,确保数据库先启动。
以下是常用的Docker Compose命令:
docker-compose up -d:在后台启动所有服务。docker-compose down:停止并移除所有容器、网络等(谨慎使用,会删除未使用卷挂载的数据)。docker-compose ps:列出项目中的所有容器。docker-compose logs:查看所有容器的日志。docker-compose logs <service>:查看特定服务的日志。
容器编排与Kubernetes ☸️
Docker Compose适用于单机环境。当需要跨多台机器管理和扩展容器时,就需要更强大的编排工具,其中最主流的就是Kubernetes。
Kubernetes可以管理一个由多台机器(节点)组成的集群,自动调度容器、管理服务发现、负载均衡、滚动更新和自愈。它解决了如何将计算任务分布到大量硬件上的问题,是实现水平扩展的关键。
总结 📚

本节课中我们一起学习了容器技术。我们从容器与虚拟机的核心区别讲起,理解了容器轻量、快速的优势及其在隔离性上的权衡。我们深入探讨了Docker的核心概念——镜像和容器,并学习了如何通过Dockerfile构建镜像以及使用Docker命令管理容器生命周期。接着,我们介绍了使用Docker Compose编排多个关联容器的方法,这是开发复杂应用的利器。最后,我们展望了更高级的容器编排世界,提到了Kubernetes,它为跨多台机器的容器部署和管理提供了强大的解决方案。掌握这些基础知识,是迈向现代云原生应用开发和部署的重要一步。

浙公网安备 33010602011771号