跳转到内容

部署云咖啡官网

前置知识

本课程需要以下基础知识:

提示:如果你已经掌握这些知识,可以直接开始实战。

业务场景

云咖啡公司刚刚成立,需要一个展示咖啡产品和品牌形象的官网。作为新入职的运维工程师,你的第一个任务是使用 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。

对比

方式命令特点
Podkubectl run ... --restart=Never一次性创建,不会自动重启
Deploymentkubectl 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 字段

如何找到字段路径?

  1. 先用 -o yaml 查看完整结构:
    bash
    kubectl get svc cloud-cafe-svc -n cloud-cafe -o yaml
  2. 找到需要的字段,例如:
    yaml
    spec:
      clusterIP: 10.43.123.45  # ← 这就是我们要的
  3. 构建表达式:{.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-cafe

5.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.html
bash
# 应用更新后的配置
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

📌 关于版本化管理

生产环境版本管理最佳实践

  1. Git 版本控制 - 所有 YAML 文件纳入版本管理,通过 Git 历史查看变更
  2. Kubernetes 原生版本管理 - 使用 kubectl rollout history 查看 Deployment 变更历史
  3. 回滚能力 - 使用 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-cafe

2. 测试高可用性

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 是流编辑器,用于对文本进行过滤和转换。

本例中的用法

bash
sed -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。

验证方法

  1. 查看 Endpoints:确认 Service 关联了所有 Pod
  2. 查看日志:观察请求是否分发到不同 Pod
  3. 自定义响应:在响应中包含 Pod 标识(如 Pod 名称)

负载均衡算法

  • Kubernetes Service 默认使用 随机轮询(Random)
  • 每次请求会随机选择一个后端 Pod
  • 如果 Pod 未就绪,会自动从 Endpoints 列表中移除

📝 总结和思考

本课程学到的知识点

  1. Pod: Kubernetes 中最小的部署单元
  2. Deployment: 管理 Pod 的控制器,确保指定数量的副本运行
  3. Service: 为 Pod 提供稳定的网络访问入口
  4. ConfigMap: 存储配置数据
  5. kubectl: Kubernetes 的命令行工具

关键概念

  • 副本数: 通过多个副本实现高可用
  • 服务发现: Service 提供稳定的访问入口
  • 自愈能力: Deployment 会自动重启失败的 Pod
  • 配置管理: ConfigMap 将配置与镜像分离

思考题

  1. 为什么在生产环境中推荐使用 Deployment 而不是直接创建 Pod?
  2. Service 的 ClusterIP 和 NodePort 有什么区别?分别在什么场景下使用?
  3. 如果 Pod 中的容器崩溃了,会发生什么?
  4. 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

提示: 如果你要继续学习下一个课程,建议保留这些资源,因为下一个课程会在此基础上进行。

评论区

专业的Linux技术学习平台,从入门到精通的完整学习路径