MidTerm Review
Lecture 1 : Intro
Types of Cloud Computing
-
SaaS (Software as a Service)
based on delivery of complete software applications that run on infrastructure the SaaS vendor manages.
eg. Gmail, Google Docs -
PaaS (Platform as a Service)
based on delivery of platforms and infrastructure services that enable developers to build and deploy applications. but they should provide their own code to be deployed.
eg. AWS S3, Heroku -
IaaS (Infrastructure as a Service)
based on delivery of only infrastructure services. users should handle all the software and hardware resources, including operating system, managing software and deployment. eg. AWS, Google Cloud Compute Engine

Benefits of Using Cloud Computing versus Building Your Own?
- Cloud?

More Definitions
- Hybrid Cloud: Public 和 Private 的混合使用. - 兼顾成本和安全(Confidentiality / Security)
- Multi-Cloud:
使用多个云服务提供商. - 避免
Ventor Lock-in - Severless Computing:
不是没有服务器,是不用管理服务器. 按
执行次数计费。 - 节省成本和时间 eg. AWS Lambda, Azure Functions
还有个概念叫边缘计算(Edge Computing),它是介于云计算和物联网之间的计算模式。它将计算资源部署在离数据源更近的地方,以减少延迟和提高效率 (Reduce latency, improve bandwidth efficiency, and enables real-time processing)。
Containers (Docker) & Orchestration (Kubernetes, K8s)
-
容器:
- 以
Docker为代表,是一种standard way to package and deployapplication. - 将整个
application及其依赖打包进一个single unit, 可以轻松地保证在不同的环境中运行的reliability。
- 以
-
编排:
- 就专讲
Kubernetes. 是一种open-source container orchestration platform,最早由Google开发 - 用于管理
containers的部署、伸缩和调度 (manage containerized applications at scale in cloud environments). - 自动化部署、扩展和管理这些容器 (Automates the deployment, scaling, and management of containerized workloads).
- 就专讲
Lab 1
-
API: Application Programming Interface
- 一套让不同系统相互通信的规则和端点 (
endpoints). - API可以用来执行
CRUD操作 (Create, Read, Update, Delete).
- 一套让不同系统相互通信的规则和端点 (
-
FastAPI: Python的web框架,用于构建API.
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
import json
# FastAPI 实例创建
app = FastAPI()
# Jinja2Templates: 用于渲染HTML的模板
templates = Jinja2Templates(directory="templates")
# FastAPI的endpoint / 路由
@app.get("/")
# 需要渲染到HTML的时候就需要有request参数
def read_root(request: Request):
# templates.TemplateResponse: 模板响应
return templates.TemplateResponse(
"index.html",
{
"request": request,
"message": " Hello World from FastAPI!",
"users": get_users_data(),
},
)
# 辅助函数 - 读取users.json文件
def get_users_data():
with open("users.json", "r", encoding="utf-8") as file:
file_contents = "".join(file.readlines())
data = json.loads(file_contents)
return data
# 第二个路由,依旧request
@app.get("/users")
def get_users(request: Request):
with open("users.json", "r", encoding="utf-8") as file:
file_contents = "".join(file.readlines())
data = json.loads(file_contents)
return templates.TemplateResponse(
"users.html",
{
"request": request,
"users": data["users"],
},
)
# 第三个路由,依旧request
@app.get("/movies")
def read_movies(request: Request):
with open("movie_data.json", "r", encoding="utf-8") as file:
file_contents = "".join(file.readlines())
data = json.loads(file_contents)
return templates.TemplateResponse(
"movies.html",
{
"request": request,
"movies": data["results"],
},
)
Lecture 2 : Cloud Storage, APIs, and Access Controls
Cloud Storage
- hardware storage 的短板:
- expensive
- inflexible
- difficult to scale
所以我们 Big 3 云服务商都各自有solution:
- AWS S3
- Azure Blob Storage
- Google Cloud Storage
Cloud Storage的优点:

S3 Bucket
这学期就只学 Amazon S3.
S3 stands for Simple Storage Service - 三个S. (p.s. EC2 stands for Elastic Cloud Compute - 2个E.)
S3 stores files as objects. 它有很多用途:
- Data Storage
- Backup & Recovery
- Hosting Static Websites
- Data Archiving
S3 跟传统的文件系统(如C盘)有最重要的区别:
- 文件系统是树状层级结构 (tree hierarchy)
- S3 是基于键的存储. 有三个核心概念:
- 存储桶 (Bucket): 最外层文件夹
- 对象 (Object): file. 每一个file就是一个object, 每一个object都有
- 键 (Key): 这个object的唯一标识符-路径. 形如
bucket_name/object_name.
由于S3 Bucket的名字是Global NameSpace的,所以一个bucket的名字要全AWS、全世界唯一..
RBAC: Role-Based Access Control
如果我们对S3 Bucket不加任何访问控制,那么任何人都可以访问这个bucket里的所有object,有安全隐患。
RBAC的解决方案是,我们不给individual user直接访问S3 Bucket的权限.
而是group users by roles, 给不同的role分配不同的权限。
优点是:
- Enhanced Security: 只有被授权的user才能访问S3 Bucket.
- Simplified Management: 只需要管理role的权限,不需要管理每个user的权限。
- Increased Efficiency
- Improved Compliance: 符合合规性要求。
PLP: Principle Of Least Privilege
- RBAC 的
Principle Of Least Privilege (PLP): 只授予用户完成其工作所需的最低权限,而不是授予更多权限。- Enhanced Security: Minimizes the blast radius of potential attacks or accidental data breaches. 最小化 潜在攻击 / 意外数据泄露 的影响半径
- Reduced Errors: 减少误操作(别的用户没法再误改误删)
- Improved Compliance
我们通过IAM (Identity and Access Management)来实现PLP.
PLP?- Start with least privilege
- Begin by granting minimal permissions
- Regularly review permissions
- Use temporary credentials
- Provide short-lived access for specific tasks using IAM roles and STS (Security Token Service)
- Monitor activity
- Use
AWS CloudTrailto track user actions and resources access.
- Use
比如给你的EC2 instance分配一个IAM role去访问S3 Bucket, 这个role只有读取S3 Bucket的权限,没有完全访问权限。
IAM: Identity and Access Management
IAM服务的几个核心Components:
- Policy: 这是一个JSON文件,定义了哪些用户/角色/组的权限可以操作哪些资源。
- Permission: 这是具体操作,比如
s3:CreateBucket,s3:StopInstance等。 - Role: 这是一个身份,附加了一堆
Policies。Role可以被用户使用,也可以被如EC2 instance使用。 - User: 人,有用户名密码(登录),或API Key (代码访问AWS)。
- Instance Profile: 这就是
3中提到的,把Role附加到EC2 instance上的机制。(最安全给我们的云应用,如EC2上的FastAPI,授权的方式)

IAM Authentication?
- 从AWS外部:
- 从IAM Dashboard生成Root User的API Credentials (Access Key ID & Secret Access Key)
- 下载个AWS CLI,配置好credentials
- Boto3 和 CLI 就会自动获取credentials,然后就可以操作AWS了。
- !! 最不安全
- 从AWS内部:
- Attach 一个 IAM Role to an EC2 instance
- Boto3 和 CLI 就会自动获取Role的credentials,然后就可以操作AWS了。
- 搞个EC2
- 在EC2上“修改IAM Role”,Create a new IAM Role
- 用例选EC2, 权限选
S3 -> AmazonS3FullAccess(一般实际会选AmazonS3ReadOnlyAccess) - 给role起个名
这样EC2 instance 和 S3 Bucket的权限,就通过IAM Role关联起来了。
然后就可以:
- 本机SSH EC2 instance
aws s3 cp s3://my-bucket/my-file.txt .这样就把S3 Bucket里的文件下载到EC2 instance的当前目录了。
Boto3: Python SDK for AWS
Boto3 是 AWS 官方的 Python SDK (Software Development Kit).
- Provides a consistent API for all AWS services.
- Supports both
low-levelandhigh-levelabstractions.
最主要的目的就是Automation, for no human in the loop.
他还有其他优势,诸如:

有一些key concepts需要做解释:
- Resources(资源): 高阶的(high-level) abstraction,比如
s3.Bucket.. - Clients(客户端): 低级的(low-level) access to AWS services APIs, 比如
s3_client.list_buckets() - Sessions(会话): 用于管理AWS credentials和configuration settings.
- Waiters(等待者): 很重要的概念!! 有些操作(如创建一个数据库)并不是立即完成的。Waiter会自动等待这个操作完成,再去执行脚本的下一步,而不是让我们写一个for loop去死等。
- Paginators(分页器): 有些操作(如获取一个S3 Bucket里的所有object)可能返回很多结果。Paginator会
自动分页(如一次加载十条),而不是让它们一次性全部加载到内存里。
Boto3 Code
import boto3
s3 = boto3.resource('s3')
for bucket in s3.buckets.all():
print(bucket.name)
'''
EC2也可以
'''
ec2 = boto3.resource('ec2')
instance = ec2.create_instance(
ImageId='ami-0c55b159cbfafe1f0',
InstanceType='t2.micro',
MinCount=1,
MaxCount=1,
)
'''
或者用Boto3 Client来创建一个S3 Bucket
'''
s3 = boto3.client('s3')
s3.create_bucket(Bucket='my-bucket')
s3.upload_file('my-file.json', 'my-bucket', 'my-file.json')
提前解释:
下面代码中的s3.Object('my-bucket', 'my-file.json'),是获取一个S3 Object。
第一个参数是bucket, 第二个参数则是object的key(即路径). 第一节课中提到的基于键的存储就是这个意思。
import boto3
import json
s3 = boto3.resource('s3')
def load_data():
obj = s3.Object('my-bucket', 'my-file.json')
body = obj.get()['Body'].read()
data = json.loads(body)
return data
print(load_data())
Lab 2 : Integration with AWS
lab2比起lab1的区别就在于,是通过boto3从s3 bucket加载数据,而不是从本地文件加载数据。
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
import json
import boto3
# FastAPI 实例创建
app = FastAPI()
# Jinja2Templates: 用于渲染HTML的模板
templates = Jinja2Templates(directory="templates")
# boto3 访问 s3 bucket
s3 = boto3.resource('s3')
# FastAPI的endpoint / 路由
@app.get("/")
# 需要渲染到HTML的时候就需要有request参数
def read_root(request: Request):
# templates.TemplateResponse: 模板响应
return templates.TemplateResponse(
"index.html",
{
"request": request,
"message": " Hello World from FastAPI!",
"users": load_data('lab2/users.json'),
},
)
# # 辅助函数 - 读取users.json文件
# def get_users_data():
# with open("users.json", "r", encoding="utf-8") as file:
# file_contents = "".join(file.readlines())
# data = json.loads(file_contents)
# return data
# 换成:辅助函数 - 从s3 bucket读取users.json / movie_data.json文件
def load_data(key: str):
obj = s3.Object('cse427-yf', key)
body = obj.get()['Body'].read()
data = json.loads(body)
return data
# 第二个路由,依旧request
@app.get("/users")
def get_users(request: Request):
return templates.TemplateResponse(
"users.html",
{
"request": request,
"users": load_data('lab2/users.json')["users"],
},
)
# 第三个路由,依旧request
@app.get("/movies")
def read_movies(request: Request):
return templates.TemplateResponse(
"movies.html",
{
"request": request,
"movies": load_data('lab2/movie_data.json')["results"],
},
)
Lecture 3 : VM & Docker Containers
Why VM & Containers?
- 云的基石:Foundation of cloud and big data architecture.
- 行业标准:Containers are the current standard for deploying the web apps and cloud computing
- 抽象层的需求:随着apps 和 data 越来越多,我们需要一个
abstraction layerto manage them.- Application Compatibility: 我们需要
Software Isolationto focus on just my app, not the underlying infrastructure. - Distributed Computing: 当我们需要
scale up的时候,我们需要一种简单、标准化的方式来快速部署、复制和启动我们的app
- Application Compatibility: 我们需要
What is a Virtual Machine?
Virtual Machine (VM) is a software emulation of a physical computer.
它解决的问题就是Application Compatibility,让我们可以在一个Host硬件上运行多个Guest OS.
P.S. 这是一种Hardware-level abstraction.
VM通过一个叫Hypervisor(虚拟机监视器)的软件,提供操作系统隔离(OS isolation)的假象
Hypervisor 会 manage the allocation of shared and replicated resources between host & guest OS,也就是分配真实的硬件资源,比如 CPU 和 RAM,一个服务器分割成多个虚拟机,每个有自己的CPU和RAM.
- 当我们在lab2启动了一个EC2 instance的时候,实际上就是启动了一个VM.
Hypervisor 的类型:
- Type 1 : Bare Metal Hypervisor (直接在硬件上模拟硬件)
- 取代 host OS,
直接运行在物理硬件上 - 性能非常好,接近裸金属(Bare Metal)
- 目前所有的云服务商用的都是Type 1 Hypervisor!!
- 取代 host OS,
- Type 2 : Hosted Hypervisor (用软件模拟硬件)
- 应用软件类型,运行在 host OS 上,如 VirtualBox, VMware
- 性能不如Type 1,但更易于管理,适用于个人用户
VM 的问题
- Resource Overhead: Hypervisors provisions excess resource. Hypervisor分配的资源是固定的,所以总会多分,分配完就被占用了导致浪费。
- LARGE: 由于 includeing the OS kernel, 一个 VM image 就得有好几个 GB
- Slow to Boot :启动一个 VM 就跟启动一个新电脑一样慢。
这些毛病引出来一个烧烤:
我只是想运行两个独立的 web app, 真的有必要给他们各自启动一个完整的 linux 系统吗?
于是引出解决方案:
不在“硬件层”做 Virtualization, 而是在“操作系统层”进行 Isolation, 这就是Containerization。
Container
- Container 提供了与 VM 类似的
isolated environment, independent from the host OS. - Key Difference: Container 在操作系统层面上进行隔离,而不是硬件层面上。
- Containers share the underlying kernel of the host OS, but have their own isolated user space.
可以想象 Container 就像是一个轻量级的 VM (但它共享了 Host OS 的 kernel, 又有自己的空间).
- VMs implement
hardware level virtualization, while Containers implementOS level virtualization. - VMs 的 resource allocation 是
fixedby the Hypervisor, 而 Containershave no limits by default.- 这使得 Containers are
more efficientthan VMs for most apps.
- 这使得 Containers are
Container 的实现原理 - Namespace
Container 是如何实现上述的 “sharing the underlying kernel of the host OS, while owning their own isolated user space” 的?
答案是,利用了 Linux kernel feature: namespace.
Namespace 是 Container main building block 之一.
Namespace abstracts global resources (PID, network, IPC, etc.), to make them appear to the processes within the namespace as isolated instances of those resources.
Namespace将全局资源(如PID, network, IPC等)抽象为隔离的实例,使得在namespace内的进程看起来就像自己独占了这些资源一样。
Linux 提供了多种 Namespace:
- PID: 在 Container 中,你的app看到的pid可能是1,但他在host OS中可能是3456
- net: container可以有自己的
独立IP和port - mount: 挂载点(文件系统)
- IPC: 进程间通信
- uts: hostname
- user: users & UIDs (可以
sudoinside the container but not outside)
总的来说,Namespaces 让 Container 里面的 process 产生了 “i am running in an isolated os” 的假象,实际上他们都仍在“share the underlying kernel of the host OS”
P.S. 我们使用 unshare 命令来创建一个 Namespace, 例如:
unshare -n bash
当我sudo unshare --pid --fork --mount-proc bash, 这里面是没有 加上--uts这个参数的时候, 这个时候我用hostname command 会输出什么结果?
答案是:依旧会输出 host OS 的 hostname.
所以说,所以每一个global resource都是独立的。
给某一个 resource, 比如 PID, 用 unshare 创建一个 namespace, 这个namespace里面的 process 看到的这个resource (PID) 就是隔离的;但这个 process 看到的其他 resource (如 network, IPC, etc.) 依旧是共享的, host os 上的。
VM vs Container 再总结
- Container more
efficient and lightweightthan VM. - Container's resource allocation is
dynamicby the Container Runtime, while VM's resource allocation isfixedby the Hypervisor. - Container is visualized in the
OS level, while VM is visualized in thehardware level.
但:
- VM provides
full isolationfrom the host OS, while Container providespartial isolation, meaning VM ismore securethan Container. - Container
cannot run all OSas it shares kernel, while VMcanrun any OS. - GUI dev is
difficultin Container, while it'seasyin software such as VirtualBox.
所以我们说,most modern companies combine both, for security and efficiency.
Docker
Docker is a software that utilizes these kernel features to package software into lightweight containers.
它提供了一个 easy API that abstracts low-level OS visualization (底层虚拟化技术,指的就是前面讲的container的os层虚拟化,被他封装成了一个 easy API).
那么要理解Docker,我们首先需要理解Image Layer和Container Layer的区别.
首先,什么是image?
- 镜像image 是一个
read-only的 template,或者说是一个immutable的 package. - 包含了一个应用所需要的所有
一切:code, libraries, dependencies, executable files, etc.
Docker Image Layers
Docker Image 是如何构建的?答案是 分层(layers)
- 一个 image 是由多个 read-only layers 组成的
- 每个 layer 都 depends on the one before it
- images build by executing each layer
sequentially, 然后最后combing them into a single image- 比如,底层是bootfs, 然后是Debian,再上Emacs,最后是Apache..
这是 Image Layers,那在这里面什么是 Container Layer?
当我们 run a container based on an image, 我们实际上是在创建一个 writable layer on top of the image.
这个 app 就运行在这个 writable layer 上,他的所有改动都只会在最上面这个 writable layer 上.

Docker Image Layers vs Docker Container Layer (KEY!!)
一般从 Docker Hub 拉取一个 Parent Image,比如 python:3 或者 alpine(一种lightweight linux distribution) 作为构建镜像的开始。

Dockerfile
创建镜像我们主要使用 Dockerfile.
- Dockerfile 是一个纯文本 text file, which contains a series of instructions for building a Docker image.
- 每个 instruction is a command that will
create a new layerin the image.
FROM <image>:<tag>: 设置父镜像。这个是 Dockerfile 的第一条指令,必须有,比如FROM python:3或者FROM alpine.- 当然如果不想依赖任何父镜像,想从零构建,可以
FROM scratch.
- 当然如果不想依赖任何父镜像,想从零构建,可以
COPY <local path> <container path>: 将本地文件复制到镜像中。RUN <command>: 执行命令。通常用来在构建时安装依赖,比如RUN pip install -r requirements.txt.CMD ["cmd"]: 设置容器启动时默认执行的命令。比如CMD ["uvicorn", "main:app", "--reload"].
Docker API (CLI)
要使用 Docker, 首先需要启动 “Docker守护进程 (Docker Daemon)”. 在 Mac / Windows 上,就是启动个 Docker Desktop 就完事了。
这个Daemon会在后台运行,监听命令。我们在CLI中敲的docker command 实际上就是和这个Daemon交互,发给他去执行。
docker build -t <image name> .: 构建镜像。-t是 tag, 用来给镜像命名。.是 Dockerfile 在当前目录下的意思。docker run <image name>: 运行容器。docker ps: 查看正在运行的容器。docker exec -it <container id> /bin/bash: 进入容器。BEST FRIEND FOR DEBUGGING!! 他允许我在一个正在运行的container里面打开一个bash shell执行命令.
docker run -p 8000:8000 my-app:demo1 做了端口转发,把container的8000端口映射到host的8000端口。
docker run -p 8001:8000 my-app:demo1 的 container log 显示的还是 8000 端口,因为在 container 内部自己的 Namespace 里面,它总以为自己运行在 8000 端口.
Store & Share Images - Docker Hub
我们 docker build 出来一个 image 了,但它现在只在我本机,如何分享? - Docker Hub
几个相关命令:
docker pull <image name>: 从 Docker Hub 拉取 image.docker tag <local-image> <dockerhub username>/<image name>:<tag>: 给 image 打 tag. (必须得有一个local image 才能打 tag)docker login: 登录 Docker Hub.docker push <dockerhub username>/<image name>:<tag>: 推送到 Docker Hub.
Multi-Platform - Docker Buildx
本机 Mac 是 ARM 架构的,但 EC2 实例是 AMD x86 架构的。那我 docker build 出来的 image 显然不能在 EC2 实例上运行。为了不给每个平台都构建推送一个不同 tag 的 image,我们使用 Docker Buildx 来解决这个问题。
Docker Buildx 是一个 CLI plugin, 它支持多平台构建 (Multi-Platform Build):
docker buildx build --platform linux/amd64,linux/arm64 -t [dockerhub username]/[image name]:[tag] . --push: 构建并推送 amd64 和 arm64 两个平台的 image 到 Docker Hub.
Buildx 引入了 Context 和 Builder 的概念。
- Context 是构建的上下文.
docker context use <context name>可以切换我们的 docker 命令应该发送给哪个 daemon ! - Builder 是 buildx 创建的一个
build instance, 它控制 docker image 如何被创建。- 所以当我们docker buildx build的时候,实际上是在使用一个 Builder 来构建 image. - 这就导致,如果我们使用--platform参数改变了平台之后;如果再需要使用默认的docker build命令 (也就是原本的单平台构建),就需要docker buildx build -t myapp --load .
Lab 3 : Docker
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
import json
import boto3
app = FastAPI()
templates = Jinja2Templates(directory="templates")
# s3 = boto3.resource("s3")
'''
switch to user "Environment Variables" to access S3
'''
import os
access_key = os.getenv("AWS_ACCESS_KEY_ID")
secret_key = os.getenv("AWS_SECRET_ACCESS_KEY")
s3 = boto3.resource(
"s3",
aws_access_key_id=access_key,
aws_secret_access_key=secret_key,
)
# 剩下都不变...
lab3 的重点在于 docker 的 build 和 push,代码的改变部分只有 s3 bucket 访问。
由于 lab2 是从 一个 带着 [有 s3 bucket 访问权限的 IAM User] 的 EC2 实例 启动;lab3 的代码则是在 docker container 里面运行的,所以需要将 [有 s3 bucket 访问权限的 IAM User] 的 Access Key ID 和 Secret Access Key 设置为 Environment Variables,供代码访问 S3 bucket。
Lecture 4 : Kubernetes
Docker 漏讲重点
-
Docker 本身是不包含 linux kernel 的,它只包含 user space 的 filesystem (mount), library 以及 application code. 我们之前也强调过:Container 和 VM 的一个区别就在于,Container是共享 host OS 的 kernel,而 VM 是隔离了个Guest OS出来但也好歹有个自己的 kernel。
-
Docker 的那些 image layers / container layer 只是关于
文件系统的,跟 namespace 这种 kernel feature 无关。事实上从上面的第1条我们也知道,docker 或是任何 container runtime 都是不包含 kernel 的,他们只是利用了 linux kernel 的 namespace feature 来实现 container 的 isolation。
2条,在docker run <image name> 的那一刻- Docker 向 Host OS Kernel 请求了一个
新的process,并且给这个 process 分配了一套新的、隔离的 namespaces (PID, network, uts, mount, etc.),其中就包含了mount - Docker 开始准备
文件系统- 找到我们指定的 image 所对应的所有
read-only image layers - 在这些 image layers 之上,创建一个
writable container layer
- 找到我们指定的 image 所对应的所有
- 最后,Docker 把这些全部 layers 统一起来成一个完整的 filesystem,把这个文件系统给
挂载(mount)到这个 process 的 新的那个mount namespace里面
所以总的来说:
- namespace 是 isolation 机制本身
- layers 只是被隔离的内容之一,具体来说,就是 mount.
Why Kubernetes?
数据量太大,单个 server 无法存储 / 处理,只好分布式。
但分布式引发了新问题:
- 如何让这些机器
Highly Available? - 如何实现
容错(Fault Tolerance)? - 如何管理服务间
Communication,Data Sharing&Computation?
Kubernetes 就是来解决这些问题的编排(Orchestration)工具
Monolithic vs Microservices (单体 vs 微服务)
在讨论 K8s 如何管理服务之前,我们需要了解两种主要的软件架构风格。
- Monolithic: 整个应用被打包成一个 single executable file / deployment unit.
- 任何改动都需要重新build & deploy整个应用。
- Microservices: 整个应用被拆分成多个小的、独立的服务,各服务之间通过轻量级API(通常是HTTP/RESTful API)进行通信,
松散耦合(Loosely Coupled)。- 每个服务可以独立部署、扩展、更新。


Microservices Orchestration
当我们开始运行多个container, 比如一个web app container 和一个 database container, 我们如何管理他们?
对于单机器的简单场景,Docker Compose 可以满足我们的需求。
- 使用一个
YAML文件定义和运行多个container。 - 可以管理container之间的依赖关系,网络通信和环境变量等。
用一个.yml file加上一个docker-compose up -d就可以启动多个container.
但局限性也很大:
- 不支持remote deployment
- 不支持autoscaling
- 不支持cross-environment running containers
- 所有container都运行在同一个机器上,无法实现
Highly Available
所以真正要Highly Available、Distributed、Scalable的场景,我们需要一个更强大的工具:Kubernetes。
Kubernetes
K8s is a container orchestration platform that manages containerized applications across multiple machines, and abstracts the underlying hardware resources.
提供了:
- Highly Availability
- Scalability
- Fault Tolerance (Disaster Recovery)
- State Management
Kubernetes Key Concepts
- Node:一个 physical or virtual machine that can run a container (就是server).
- 一个 K8s Cluster 由多个 Node 组成。
- Kubelet: 运行在
每个Node上的agent.- 负责确保
Pod运行在 该 Node 上运行,并且与Control Plane通信。
- 负责确保
- Pod: 一个 K8s 的
最小 deployment unit of computation(最小可部署的计算单元).- 一个 Pod 包含 一个 Docker Container.
- 每个 Pod 都有自己的 IP address, 所以他们可以相互通信。
- Pod 是
ephemeral (短暂的), 所以他们可以被随时销毁并被新的 Pod 替代。
Kubernetes Architecture
两部分:
- Control Plane:
- 以前叫Master Node, 现在叫Control Plane.
- 至少需要一个!!!
- Cluster 的
大脑,负责调度和管理 Pod.
- Worker Nodes:
- 就是普通的Node,可以有很多个
- 负责实际运行 Pod.
Cluster 层面:
一个 K8s Cluster 由至少一个大脑也就是 Control Plane 和多个 Worker Nodes 组成。
Node 层面:
每个 Node 上运行着一个 Kubelet, 负责确保 Pod 运行在 该 Node 上运行,并且与 Control Plane 通信。
当然,一个 Node 上可以运行多个 Pod.
Pod 层面:
Pod 是 K8s 的最小 deployment unit of computation, 通常包含一个 Docker Container (当然也可以包含多个,但一般是1on1).
Control Plane 内部包含几个关键组件:
- API Server:
- 与 K8s Cluster 交互的
唯一入口.
- 与 K8s Cluster 交互的
- etcd:
- 一个 Highly Available 的 Key-Value Storage Database. 保存了整个 Cluster 的 Configuration &
状态(State).
- 一个 Highly Available 的 Key-Value Storage Database. 保存了整个 Cluster 的 Configuration &
- Scheduler:
- 负责调度 Pod 到合适的 Node 上运行。
- Controller Manager:
- 负责管理 Controller, 监控集群状态,努力使实际状态与期望保持一致(比如,一个Pod挂了,他就会启动一个新的Pod来替代他)
K8s 还创建了一个 Virtual Network, 覆盖了 Control Plane 和 Worker Nodes 之间的所有通信。使得 Cluster 中的所有 Pods & Services 可以在一个Flat Network中相互通信,即使它们在不同的物理机器上。
Kubernetes Configuration & YAML
如何告诉 K8s 我们要运行什么应用?
- 用
API Server来交互 - 用
YAML文件来Declaratively描述我们期望的状态(Desired State)

我们管 K8s 的 YAML 文件叫做 Manifest.
一般包含几个顶级字段:
apiVersion: 使用的 K8s API 版本kind: 要创建的资源类型 (Pod, Service, Deployment, etc.)metadata: 资源的名字、namespace、labels等spec: 最重要的部分 - Desired State. (比如 replicas: 3, image: nginx:latest, ports: [80, 443], etc.)status: 当前实际状态。由 K8s 自动维护。
当你用 kubectl apply 命令提交这个 YAML 文件后,Kubernetes 就会努力让“实际状态”去匹配你的“期望状态”。然后你通过 status 字段来查看“实际状态”,比如是不是真的有3个副本在运行。
在本地学习测试K8s,我们可以使用 minikube 来创建一个单节点的 K8s Cluster,然后使用 kubectl (K8s CLI, 去沟通Control Plane的API Server) 来管理它。
Lecture 5 : Kubernetes 2
K8s 有很多组件,之前学了 Nodes 和 Pods,现在学一下其他几个关键组件:
- Namespace: 一个 Cluster 可以包含多个 Namespace, 每个 Namespace 是 Cluster 中的一个逻辑隔离区域。
- Deployment: 管理
无状态(Stateless)的应用程序。 - StatefulSet: 管理
有状态(Stateful)的应用程序 (比如数据库)。 - Service: 用于Pod之间的通信以及
负载均衡(Load Balancing)。 - Volume: 用于持久化数据 (Persistent Data)。
- ConfigMap: 用于存储配置文件。
- Secret: 用于存储敏感信息 (Sensitive Data) (比如密码)。
- Ingress: 用于将集群内部的服务暴露(expose)给外部访问。
我们几乎从不直接创建 Pod, 比如去写一个 kind: Pod 的YAML file.
我们使用更高层次的抽象,比如 Deployment(部署)或 StatefulSet(有状态集).
因为 Pod 是“脆弱的”。如果一个 Pod 崩溃了,它就死了,不会自动回来。这不符合我们对健壮系统的要求。
而:一个 Deployment 会管理一组 Pod. 你在 Deployment 的 spec 中说“ 我想要3个副本”. Deployment 的控制器 (Controller) 就会去创建3个 Pod。如果其中一个 Pod 崩溃了,控制器会立刻发现,并马上启动一个新的 Pod 来替代它。
这个是 Kubernetes 的核心价值: Self-Healing & Maintaining Desired State.
State, Storage & Configurations
上面提到了,我们有两种基本的应用类型:
- Stateless(无状态) -
Deployment:像我们之前做的那个电影网站。它只是读取数据,本身不存储任何变化。这种应用非常容易扩展,用 Deployment 就行。我可以轻松地把它从3个副本扩展到100个。 - Stateful(有状态) -
StatefulSet:比如数据库。每个数据库实例的数据可能不一样(比如主库和从库),它们需要把数据