主题
部署云咖啡官网
前置知识
本课程需要以下基础知识:
- Kubernetes 基础概念:了解 Pod、Deployment、Service 等核心概念。推荐学习 Kubernetes架构和核心概念
- K8S 环境搭建:已准备好可用的 K3S 集群环境。参考 K8S学习环境搭建与初体验
- Docker 基础:了解容器和镜像的基本概念。推荐学习 Docker概念和架构
提示:如果你已经掌握这些知识,可以直接开始实战。
业务场景
云咖啡公司刚刚成立,需要一个展示咖啡产品和品牌形象的官网。作为新入职的运维工程师,你的第一个任务是使用 Kubernetes 部署这个官网。
需求:
- 部署一个静态网站(云咖啡官网)
- 网站需要能够被访问
- 确保服务稳定运行
学习目标
完成本课程后,你将掌握:
- Pod 的基本概念和生命周期
- Deployment 的使用方法
- Service 的类型和作用
- kubectl 常用命令
- 如何部署一个简单的应用
前置准备
1. 确认环境正常
bash
# 登录虚拟机
vagrant ssh k3s
# 确认集群正常
kubectl get nodes
# 查看所有命名空间的 Pod
kubectl get pods -A预期输出:
kubectl get nodes应该显示一个 Ready 状态的节点kubectl get pods -A应该显示系统组件正常运行
2. 创建命名空间
为了更好地管理资源,我们为云咖啡项目创建一个独立的命名空间:
bash
# 创建命名空间
kubectl create namespace cloud-cafe
# 查看命名空间
kubectl get namespaces📌 关于
-n参数的解释
-n是--namespace的缩写,用于指定命令操作的命名空间。为什么要使用命名空间?
- 资源隔离:不同项目的资源互不干扰
- 权限控制:可以为不同命名空间设置不同的访问权限
- 资源配额:可以限制每个命名空间的资源使用量
使用方式:
bash# 查看指定命名空间的 Pod kubectl get pods -n cloud-cafe # 查看所有命名空间的 Pod(使用 -A 或 --all-namespaces) kubectl get pods -A如果不指定
-n:默认使用default命名空间
实战步骤
Step 1: 理解 Pod - 最小的部署单元
概念: Pod 是 Kubernetes 中最小的部署单元,一个 Pod 可以包含一个或多个容器。
让我们先手动创建一个 Pod 来理解它的基本概念:
bash
# 创建一个简单的 nginx Pod
kubectl run nginx-pod --image=nginx:latest --restart=Never -n cloud-cafe
# 查看 Pod 状态
kubectl get pods -n cloud-cafe
# 查看 Pod 详细信息
kubectl describe pod nginx-pod -n cloud-cafe
# 查看 Pod 日志
kubectl logs nginx-pod -n cloud-cafe📌 关于
--restart=Never参数的解释
--restart=Never表示创建一个独立的 Pod,而不是 Deployment。对比:
方式 命令 特点 Pod kubectl run ... --restart=Never一次性创建,不会自动重启 Deployment kubectl create deployment ...自动管理 Pod,支持扩缩容、滚动更新 为什么这里使用
--restart=Never?
- 本步骤是为了理解 Pod 的基本概念
- 实际生产环境推荐使用 Deployment(见 Step 2)
Pod 失败会怎样?
- 使用
--restart=Never时,Pod 失败后不会自动重启- 使用 Deployment 时,Pod 失败会自动创建新的 Pod 替代
观察要点:
- Pod 的状态变化(Pending → Running)
- Pod 的 IP 地址
- Pod 的重启次数
思考: 为什么我们使用 --restart=Never?(提示:Deployment 会自动管理 Pod 的重启)
Step 2: 使用 Deployment 部署应用
概念: Deployment 是用于管理 Pod 的控制器,它可以确保指定数量的 Pod 副本始终运行。
在实际生产环境中,我们通常使用 YAML 文件来定义 Deployment,并通过 Git 进行版本管理。
2.1 创建 Deployment 文件
首先,创建 deployment.yaml 文件:
点击查看 deployment.yaml 内容
yaml
# 云咖啡官网 Deployment
# API 版本:apps/v1 是 Deployment 的稳定版本
apiVersion: apps/v1
# 资源类型:Deployment 用于管理 Pod
kind: Deployment
# 元数据:定义资源的名称、命名空间等
metadata:
# Deployment 的名称
name: cloud-cafe-web
# 所属的命名空间
namespace: cloud-cafe
# 标签:用于标识和选择资源
labels:
app: cloud-cafe-web
# 规格:定义 Deployment 的具体配置
spec:
# 副本数:运行 3 个 Pod 副本
replicas: 3
# 选择器:用于匹配 Pod 的标签
selector:
matchLabels:
app: cloud-cafe-web
# Pod 模板:定义 Pod 的规格
template:
# Pod 的元数据
metadata:
# Pod 的标签,必须与 selector 匹配
labels:
app: cloud-cafe-web
# Pod 的规格
spec:
# 容器列表
containers:
# 容器名称
- name: nginx
# 容器镜像:使用 nginx 最新版本
image: nginx:latest
# 端口:容器暴露的端口
ports:
- containerPort: 80📌 YAML 字段解释
对于初学者,理解 YAML 的每个字段很重要:
字段 说明 示例 apiVersionAPI 版本 apps/v1是 Deployment 的稳定版本kind资源类型 Deployment表示这是一个 Deployment 资源metadata.name资源名称 cloud-cafe-web是 Deployment 的名字metadata.namespace命名空间 cloud-cafe是资源所属的命名空间metadata.labels标签 用于标识和选择资源 spec.replicas副本数 3表示运行 3 个 Pod 副本spec.selector选择器 用于匹配哪些 Pod 属于这个 Deployment spec.templatePod 模板 定义 Pod 的具体配置 spec.template.spec.containers容器列表 定义容器的镜像、端口等 关键概念:
selector.matchLabels必须与template.metadata.labels匹配replicas决定了运行的 Pod 数量- 修改
image可以更新应用版本
2.2 应用 Deployment
bash
# 应用 Deployment
kubectl apply -f deployment.yaml
# 查看 Deployment
kubectl get deployment cloud-cafe-web -n cloud-cafe
# 查看 ReplicaSet(Deployment 会自动创建)
kubectl get rs -n cloud-cafe
# 查看 Pod(应该有 3 个副本)
kubectl get pods -n cloud-cafe观察要点:
- Deployment 创建了 3 个 Pod 副本
- 每个 Pod 都有唯一的名称(deployment-name-random-string)
- Pod 的状态都是 Running
- 当前使用 nginx 默认页面
思考: 为什么需要多个副本?(提示:高可用、负载均衡)
Step 3: 使用 Service 暴露服务
概念: Service 为一组 Pod 提供稳定的网络访问入口,即使 Pod 重新创建,Service 的 IP 也不会改变。
3.1 创建 ClusterIP Service
bash
# 创建 ClusterIP 类型的 Service(默认类型)
kubectl expose deployment cloud-cafe-web \
--port=80 \
--target-port=80 \
--name=cloud-cafe-svc \
-n cloud-cafe
# 查看 Service
kubectl get svc -n cloud-cafe
# 查看 Service 详细信息
kubectl describe svc cloud-cafe-svc -n cloud-cafe观察要点:
- Service 有一个 ClusterIP(集群内部 IP)
- Service 会自动选择对应的 Pod
- Service 的 Endpoints 列出了所有后端 Pod 的 IP
3.2 测试 Service 访问
bash
# 获取 Service 的 ClusterIP
SVC_IP=$(kubectl get svc cloud-cafe-svc -n cloud-cafe -o jsonpath='{.spec.clusterIP}')
# 在集群内部访问 Service
curl http://$SVC_IP
# 或者使用 Pod 的 DNS 名称
kubectl run test-pod --image=busybox --rm -it -n cloud-cafe -- wget -qO- http://cloud-cafe-svc📌 关于
--rm和-it参数的解释这组参数用于创建一个临时调试 Pod,执行完命令后自动删除。
参数说明:
参数 全称 作用 --rm--remove 命令执行完毕后自动删除 Pod -i--interactive 保持标准输入打开(交互式) -t--tty 分配一个伪终端 使用场景:
- 临时测试网络连通性(如本例的
wget测试)- 临时进入容器执行调试命令
- 执行一次性任务,不需要保留容器
对比:
bash# 临时 Pod(自动删除) kubectl run test --rm -it --image=busybox -- /bin/sh # 普通 Pod(需要手动删除) kubectl run test --image=busybox -n cloud-cafe kubectl delete pod test -n cloud-cafe
📌 关于
-o jsonpath的解释
-o jsonpath='{...}'用于从 kubectl 输出中提取特定字段的值,避免手动解析。语法说明:
-o=--output,指定输出格式jsonpath='{...}'= 使用 JSONPath 表达式提取数据{.spec.clusterIP}= 提取spec下的clusterIP字段如何找到字段路径?
- 先用
-o yaml查看完整结构:bashkubectl get svc cloud-cafe-svc -n cloud-cafe -o yaml- 找到需要的字段,例如:
yamlspec: clusterIP: 10.43.123.45 # ← 这就是我们要的- 构建表达式:
{.spec.clusterIP}常用示例:
bash# 获取 Pod IP kubectl get pod <pod-name> -o jsonpath='{.status.podIP}' # 获取节点 IP(第 1 个节点) kubectl get nodes -o jsonpath='{.items[0].status.addresses[0].address}' # 获取 Service 的 NodePort 端口 kubectl get svc <svc-name> -o jsonpath='{.spec.ports[0].nodePort}' # 获取 Pod 所在节点 kubectl get pod <pod-name> -o jsonpath='{.spec.nodeName}'
预期输出: 应该看到 nginx 的默认欢迎页面
Step 4: 使用 NodePort 暴露服务到外部
概念: NodePort 类型的 Service 会在每个节点上开放一个端口,外部可以通过 节点IP:端口 访问服务。
bash
# 创建 NodePort 类型的 Service
kubectl expose deployment cloud-cafe-web \
--port=80 \
--target-port=80 \
--name=cloud-cafe-nodeport \
--type=NodePort \
-n cloud-cafe
# 查看 Service
kubectl get svc cloud-cafe-nodeport -n cloud-cafe
# 获取 NodePort 端口号
NODE_PORT=$(kubectl get svc cloud-cafe-nodeport -n cloud-cafe -o jsonpath='{.spec.ports[0].nodePort}')
# 获取节点 IP
NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
echo "访问地址: http://$NODE_IP:$NODE_PORT"测试访问:
bash
# 在虚拟机内部测试
curl http://$NODE_IP:$NODE_PORT
# 在宿主机浏览器访问
# http://192.168.56.10:xxxxx预期输出: 应该看到 nginx 的默认欢迎页面
Step 5: 自定义网站内容
现在让我们将默认的 nginx 页面替换为云咖啡公司的官网内容。
📁 生产实践:使用独立的配置文件
在实际生产环境中,我们会将 YAML 配置和 HTML 页面放在独立的文件中,便于版本管理和维护。
本课程的操作方式:
- 点击下方的折叠块查看 YAML/HTML 内容
- 将内容复制保存到本地文件(如
deployment.yaml)- 使用
kubectl apply -f <文件名>应用配置版本管理说明:
- 使用 Git 管理配置文件的版本
- 通过
kubectl rollout history查看 Deployment 的变更历史
5.1 创建 ConfigMap
首先,创建 index.html 文件:
点击查看 index.html 内容
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>云咖啡公司</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 50px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
h1 { font-size: 48px; margin-bottom: 20px; }
p { font-size: 24px; margin-bottom: 30px; }
.coffee { font-size: 80px; margin: 30px 0; }
</style>
</head>
<body>
<div class="coffee">☕</div>
<h1>欢迎来到云咖啡公司</h1>
<p>用心制作每一杯咖啡</p>
<p>我们的咖啡豆来自世界各地,经过精心烘焙</p>
<p>为您提供最优质的咖啡体验</p>
</body>
</html>bash
# 保存上述内容到 index.html 文件,然后创建 ConfigMap
kubectl create configmap cloud-cafe-html \
--from-file=index.html \
-n cloud-cafe
# 查看创建的 ConfigMap
kubectl get configmap cloud-cafe-html -n cloud-cafe5.2 更新 Deployment 添加 ConfigMap 挂载
📌 配置更新说明
现在我们将更新 Deployment,添加 ConfigMap 卷挂载,使用自定义首页替换默认的 nginx 页面。
更新 deployment.yaml 文件(添加 volumes 和 volumeMounts 配置):
点击查看更新后的 deployment.yaml 内容
yaml
# 云咖啡官网 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: cloud-cafe-web
namespace: cloud-cafe
labels:
app: cloud-cafe-web
spec:
replicas: 3
selector:
matchLabels:
app: cloud-cafe-web
template:
metadata:
labels:
app: cloud-cafe-web
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
# 挂载自定义页面
volumeMounts:
- name: html-content
mountPath: /usr/share/nginx/html
volumes:
- name: html-content
configMap:
name: cloud-cafe-html
items:
- key: index.html
path: index.htmlbash
# 应用更新后的配置
kubectl apply -f deployment.yaml
# 等待滚动更新完成
kubectl rollout status deployment/cloud-cafe-web -n cloud-cafe
# 查看新的 Pod
kubectl get pods -n cloud-cafe
# 查看 Deployment 历史版本
kubectl rollout history deployment/cloud-cafe-web -n cloud-cafe📌 关于版本化管理
生产环境版本管理最佳实践:
- Git 版本控制 - 所有 YAML 文件纳入版本管理,通过 Git 历史查看变更
- Kubernetes 原生版本管理 - 使用
kubectl rollout history查看 Deployment 变更历史- 回滚能力 - 使用
kubectl rollout undo快速回滚到之前的版本查看和回滚版本:
bash# 查看 Deployment 的变更历史 kubectl rollout history deployment/cloud-cafe-web -n cloud-cafe # 回滚到上一个版本 kubectl rollout undo deployment/cloud-cafe-web -n cloud-cafe
测试访问:
bash
# 再次访问服务
curl http://$NODE_IP:$NODE_PORT预期输出: 应该看到云咖啡公司的自定义页面
验证和测试
1. 检查所有资源状态
bash
# 查看 Deployment
kubectl get deployment -n cloud-cafe
# 查看 Pod
kubectl get pods -n cloud-cafe
# 查看 Service
kubectl get svc -n cloud-cafe
# 查看 ConfigMap
kubectl get configmap -n cloud-cafe2. 测试高可用性
bash
# 删除一个 Pod,观察 Deployment 是否自动创建新的 Pod
kubectl delete pod -l app=cloud-cafe-web -n cloud-cafe
# 立即查看 Pod 状态
kubectl get pods -n cloud-cafe -w📌 关于
-l和-w参数的解释
-l/--selector:按标签选择资源bash# 删除带有标签 app=cloud-cafe-web 的所有 Pod kubectl delete pod -l app=cloud-cafe-web -n cloud-cafe # 其他常用示例 kubectl get pods -l app=nginx # 查看标签为 app=nginx 的 Pod kubectl get pods -l 'app in (nginx, mysql)' # 查看多个标签值的 Pod kubectl get pods -l '!app' # 查看没有 app 标签的 Pod
-w/--watch:持续监视资源变化bash# 实时监视 Pod 状态变化(类似 tail -f) kubectl get pods -n cloud-cafe -w # 按标签监视 kubectl get pods -l app=cloud-cafe-web -n cloud-cafe -w # 按资源名称监视 kubectl get pod nginx-pod -n cloud-cafe -w提示:按
Ctrl+C退出监视模式
观察要点:
- 被删除的 Pod 状态变为 Terminating
- Deployment 自动创建新的 Pod
- 最终仍然保持 3 个副本
3. 测试负载均衡
由于默认的 nginx 页面不显示 Pod 信息,我们可以通过以下方式验证负载均衡:
方式一:查看 Service 的 Endpoints 变化
bash
# 查看 Service 的后端 Pod 列表(Endpoints)
kubectl get endpoints cloud-cafe-svc -n cloud-cafe
# 多次执行,观察 Endpoints 是否包含所有 Pod 的 IP
for i in {1..5}; do
echo "=== 第 $i 次查询 ==="
kubectl get endpoints cloud-cafe-svc -n cloud-cafe
sleep 2
done方式二:通过 Pod 名称验证(需要进入 Pod 查看日志)
bash
# 查看各个 Pod 的访问日志
for pod in $(kubectl get pods -l app=cloud-cafe-web -n cloud-cafe -o jsonpath='{.items[*].metadata.name}'); do
echo "=== $pod 的日志 ==="
kubectl logs $pod -n cloud-cafe --tail=5
done方式三:修改页面显示 Pod 名称(进阶)
使用 sed 命令快速修改现有的 index.html,添加 Pod 名称显示:
bash
# 获取当前 index.html 内容并修改
kubectl get configmap cloud-cafe-html -n cloud-cafe -o jsonpath='{.data.index\.html}' > index-with-pod.html
# 使用 sed 在 </body> 前添加 Pod 名称显示
sed -i 's|</body>|<div style="font-size: 24px; color: #ffeb3b; margin-top: 30px;">Pod: '$HOSTNAME'</div></body>|' index-with-pod.html
# 创建新的 ConfigMap
kubectl create configmap cloud-cafe-html-with-pod --from-file=index.html=index-with-pod.html -n cloud-cafe
# 更新 Deployment 使用新的 ConfigMap
kubectl set env deployment/cloud-cafe-web -n cloud-cafe HOSTNAME_FROM_POD=true
# 然后多次访问,观察 Pod 名称变化
for i in {1..10}; do
echo "=== 第 $i 次请求 ==="
curl -s http://$NODE_IP:$NODE_PORT | grep "Pod:"
sleep 1
done📌 关于
sed命令的解释
sed是流编辑器,用于对文本进行过滤和转换。本例中的用法:
bashsed -i 's|旧内容|新内容|g' 文件名
-i:直接修改文件(in-place)s|...|...|:替换命令,使用|作为分隔符(避免与 HTML 标签冲突)- 在
</body>前插入 Pod 名称显示其他常用示例:
bash# 替换文件中的所有 "nginx" 为 "apache" sed -i 's/nginx/apache/g' deployment.yaml # 删除包含 "test" 的行 sed -i '/test/d' deployment.yaml # 在第 5 行后插入新内容 sed -i '5a\ replicas: 5' deployment.yaml
📌 为什么需要验证负载均衡?
Service 的负载均衡是 Kubernetes 的核心功能之一,它会将流量均匀分发到所有后端 Pod。
验证方法:
- 查看 Endpoints:确认 Service 关联了所有 Pod
- 查看日志:观察请求是否分发到不同 Pod
- 自定义响应:在响应中包含 Pod 标识(如 Pod 名称)
负载均衡算法:
- Kubernetes Service 默认使用 随机轮询(Random)
- 每次请求会随机选择一个后端 Pod
- 如果 Pod 未就绪,会自动从 Endpoints 列表中移除
📝 总结和思考
本课程学到的知识点
- Pod: Kubernetes 中最小的部署单元
- Deployment: 管理 Pod 的控制器,确保指定数量的副本运行
- Service: 为 Pod 提供稳定的网络访问入口
- ConfigMap: 存储配置数据
- kubectl: Kubernetes 的命令行工具
关键概念
- 副本数: 通过多个副本实现高可用
- 服务发现: Service 提供稳定的访问入口
- 自愈能力: Deployment 会自动重启失败的 Pod
- 配置管理: ConfigMap 将配置与镜像分离
思考题
- 为什么在生产环境中推荐使用 Deployment 而不是直接创建 Pod?
- Service 的 ClusterIP 和 NodePort 有什么区别?分别在什么场景下使用?
- 如果 Pod 中的容器崩溃了,会发生什么?
- ConfigMap 和 Secret 有什么区别?
下一步
本课程完成了云咖啡公司官网的部署。
下一课程将学习如何更新网站内容,实现零停机部署。
下一课程: 02-网站内容更新.md
清理环境
如果你想清理本课程创建的资源:
bash
# 删除所有资源
kubectl delete deployment cloud-cafe-web -n cloud-cafe
kubectl delete svc cloud-cafe-svc cloud-cafe-nodeport -n cloud-cafe
kubectl delete configmap cloud-cafe-html -n cloud-cafe
# 删除命名空间(会删除该命名空间下的所有资源)
kubectl delete namespace cloud-cafe提示: 如果你要继续学习下一个课程,建议保留这些资源,因为下一个课程会在此基础上进行。