- 文档/教程
【免费下载链接】90DaysOfDevOps
This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.
Kubernetes 存在的核心意义就是应用交付:把容器镜像以 Pod 的形式调度到集群节点上,并借助 Deployment、Service、Namespace 等资源完成部署、暴露与伸缩。本文基于 90DaysOfDevOps 第 54 天内容,以 minikube 集群上的 nginx 无状态应用为完整示例,带你走通「编写 YAML → 创建资源 → 验证状态 → 弹性伸缩 → 对外暴露」的完整链路,最后介绍 Helm 这一 Kubernetes 包管理器的安装与使用思路。读完本文,你将掌握一份可直接复制的声明式部署方案,以及从零暴露一个 Web 应用的全部常用命令。
部署应用:Kubernetes 存在的理由
把容器镜像放进集群、交给 Kubernetes 调度,就是让 Kubernetes 作为容器编排器发挥价值的地方。整个 90DaysOfDevOps 的容器与 Kubernetes 章节一直在铺垫两件事:一是镜像(image)如何构建,二是 Kubernetes 平台如何让扩容变得非常轻松。现在终于可以动手把这些镜像部署成 Pod。
Kubernetes 集群中部署应用的方式有很多,Day54 聚焦其中最常见的两条路径:
- YAML 文件:用声明式清单一次定义 Namespace、Deployment、Service 等全部资源;
- Helm Charts:把一组预配置的应用资源打包成 chart,一条命令完成安装。
本篇文章所有实操都在minikube 集群上进行(本教程使用的 profile 名为mc-demo),但流程对所有 Kubernetes 集群通用。第一个示例是一个标准的无状态应用:nginx。我们会创建一个 Deployment 来产出 Pod,再创建一个 Service 让外部可以访问 nginx Pod 提供的 Web 服务,所有资源统一放进一个 namespace 中。
环境准备:确认集群中没有同名 Namespace
在部署任何资源之前,先确认集群中不存在名为nginx的 namespace,避免与已有资源冲突:
kubectl get namespace执行结果中如果没有nginx,就可以放心开始部署。
用 YAML 定义无状态应用:Namespace + Deployment + Service
第一种部署方式是用 YAML 声明所有要创建的资源。YAML 本身可以单独开一整章来讲解,这里直接给出可运行的清单。你既可以把下面的内容拆成 namespace、deployment、service 三个独立文件,也可以像本文这样用一个文件、用---分隔多个文档(multi-document YAML)。仓库中对应的完整文件是 nginx-stateless-demo.yaml,内容如下:
apiVersion: v1 kind: Namespace metadata: name: nginx "labels": { "name": "nginx" } --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: nginx spec: selector: matchLabels: app: nginx replicas: 1 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-service namespace: nginx spec: selector: app: nginx-deployment ports: - protocol: TCP port: 80 targetPort: 80逐个拆解这三段声明:
第一段:Namespace
apiVersion: v1、kind: Namespace声明这是一个命名空间对象,metadata.name为nginx,并打上name: nginx标签。namespace 的作用是把后续的 Deployment 和 Service 隔离在同一套逻辑分组内,后续所有查询命令都要用-n nginx指定它。
第二段:Deployment
apiVersion: apps/v1、kind: Deployment是工作负载(workload)控制器,它负责维持「期望状态」:
spec.replicas: 1:期望运行 1 个 Pod 副本;spec.selector.matchLabels.app: nginx:Deployment 通过标签选择器管理它名下的 Pod;spec.template:Pod 模板,template.metadata.labels.app: nginx给 Pod 打上与 selector 匹配的标签;- 模板内的容器定义:镜像使用
image: nginx(未指定 tag 时默认latest),容器名nginx,暴露containerPort: 80供 Service 转发。
第三段:Service
kind: Service为 Pod 提供稳定的访问入口:
spec.selector.app: nginx-deployment:注意这里的标签选择器写的是nginx-deployment,这是原文档与仓库文件中的实际写法,意味着 Service 会匹配带有app: nginx-deployment标签的 Pod——但 Deployment 模板给 Pod 打的标签是app: nginx。从源码结构看这是一个明显的标签不一致:要让流量真正路由到 Pod,Service 的 selector 应与 Pod 模板标签保持一致(都改为app: nginx);spec.ports:protocol: TCP、port: 80(Service 对外端口)、targetPort: 80(转发到容器的端口)。
把整个文件保存为nginx-stateless-demo.yaml,即完成部署前的全部定义工作。
部署应用:kubectl create 一次创建三个对象
导航到 YAML 文件所在目录,执行:
kubectl create -f nginx-stateless-demo.yaml命令执行后可以看到3 个对象被创建:namespace、deployment、service。这个命令在任意 Kubernetes 集群(不只是 minikube)上流程完全一致。
验证部署:从 namespace 到 Pod 的逐层检查
部署完成后,用一组查询命令逐层确认状态:
# 查看集群中所有 namespace,确认 nginx 已出现 kubectl get namespace # 查看 nginx namespace 中的 Pod,应为 1 个 Ready 且 Running kubectl get pods -n nginx # 查看已创建的 Service kubectl get service -n nginx # 查看 Deployment 及其维护的期望配置 kubectl get deployment -n nginx其中 Deployment 是我们保持「期望状态」的地方:它记录着希望运行多少副本、用哪个镜像、如何滚动更新。与其逐个执行上面几条命令,更高效的做法是一条命令看全所有资源:
kubectl get all -n nginx从截图输出可以看到,kubectl get all -n nginx一次性展示了四类资源:
- Pod:
pod/nginx-deployment-7848d4b86f-jpxwq,状态 Running,1/1就绪,重启 0 次; - Service:
service/nginx-service,类型 ClusterIP,集群内部 IP10.96.80.153,端口80/TCP,没有 External-IP; - Deployment:
deployment.apps/nginx-deployment,期望副本 1、当前就绪 1、可用 1; - ReplicaSet:
replicaset.apps/nginx-deployment-7848d4b86f,期望副本 1、就绪 1。
为什么会出现 ReplicaSet?
你可能会注意到输出中多了一个 ReplicaSet 资源。这是因为 Deployment 内部就是通过 ReplicaSet 来维持副本数的:Deployment 声明期望副本数,ReplicaSet 负责创建和回收对应的 Pod。这份清单里replicas初始设为 1,所以只出现 1 个副本——这正是后面弹性伸缩机制的基础。
弹性伸缩:快速扩容与缩容
借助 Deployment 的期望状态机制,扩容和缩容非常简单,有两种方式:
方式一:kubectl edit 修改清单
kubectl edit deployment nginx-deployment -n nginx该命令会在终端内打开一个文本编辑器(默认是$KUBERNETES_EDITOR或$EDITOR指定的编辑器),让你直接编辑 Deployment 的实时配置。把spec.replicas从 1 改成更大数值并保存退出;只要语法与缩进正确、没有报错,namespace 内就会立刻看到新增的 Pod 被调度出来。
方式二:kubectl scale 命令式伸缩
kubectl scale deployment nginx-deployment --replicas=10 -n nginx--replicas=10直接把副本数拉到 10。缩容回 1 用同一条命令即可:
kubectl scale deployment nginx-deployment --replicas=1 -n nginx两种方法的效果等价:edit适合顺带调整镜像、端口等其他字段,scale适合只改副本数。典型使用场景正如文中强调的:如果这是一个 Web 服务器,可以在访问高峰期快速扩容,流量下降后再缩容,整个过程是秒级的,这正是 Kubernetes 相比传统运维的巨大优势。
把应用暴露给外部:四种 Service 方案
回到上面kubectl get service的输出:Service 只有 ClusterIP、没有 External-IP,所以直接打开浏览器是无法访问的。要在集群外访问应用,有四种选择:
| 方案 | 说明 | 适用场景 |
|---|---|---|
| ClusterIP | Service 的默认类型,IP 位于集群内部网络,只有集群内部的对象能访问 | 集群内部服务互调,例如应用访问数据库 |
| NodePort | 通过 NAT 在集群中每个被选中节点的同一端口上暴露 Service | 快速对外暴露,端口范围通常受限(30000-32767) |
| LoadBalancer | 在当前云环境创建外部负载均衡器。minikube 受限;若在 VirtualBox 等自建集群上使用,需要自行部署 MetalLB 之类的负载均衡器 | 云上对外提供服务 |
| Port-Forward | 将集群内部进程转发到本机 localhost 访问 | 测试与排障,生产环境不推荐 |
实操一:kubectl port-forward 本地转发
最简单直接的测试方式是把 Deployment 的端口转发到本机:
kubectl port-forward deployment/nginx-deployment -n nginx 8090:80这条命令把本地 8090 端口转发到集群内nginx-deployment对应 Pod 的 80 端口。执行后输出类似:
Forwarding from 127.0.0.1:8090 -> 80 Forwarding from [::1]:8090 -> 80 Handling connection for 8090注意:kubectl port-forward是阻塞式命令,运行它的终端会被持续占用(因为它一直充当本地与集群之间的转发通道),需要另开一个终端执行后续命令或访问http://127.0.0.1:8090。
实操二:minikube 一键生成访问 URL
minikube 提供了更贴合本地环境的暴露方式——minikube service会自动创建隧道并生成 URL。步骤如下:
- 先删掉现有的 Service:
kubectl delete service nginx-service -n nginx- 重新创建一个 NodePort 类型的 Service:
kubectl expose deployment nginx-deployment --name nginx-service --namespace nginx --port=80 --type=NodePort注意这里改用kubectl expose命令式创建,并显式把--type指定为NodePort。
- 在新的终端中运行:
minikube --profile='mc-demo' service nginx-service --url -n nginx--profile='mc-demo'指定当前使用的 minikube 集群配置。执行后 minikube 会为服务启动隧道并输出可访问地址:
Starting tunnel for service nginx-service. |-----------|---------------|-------------|---------------------------| | NAMESPACE | NAME | TARGET PORT | URL | |-----------|---------------|-------------|---------------------------| | nginx | nginx-service | | http://127.0.0.1:36599 | |-----------|---------------|-------------|---------------------------|拿到 URL 后,打开浏览器(或在终端里按住 Ctrl 点击链接)即可访问 nginx 的默认欢迎页。需要提醒的是:minikube 在 Linux 上使用 Docker driver 时,隧道依赖该终端持续运行,关闭终端隧道就会终止、服务将无法访问——这是 minikube 与完整 Kubernetes 集群在暴露方式上的主要差异之一。
仓库延伸:从无状态到有状态应用
nginx 示例是无状态应用(数据不落盘、Pod 随时可被替换)。Day54 所属的 Kubernetes 系列后续还会覆盖 Ingress、Services、Persistent Storage 与 Stateful Apps,仓库中已经准备好了对应的演示清单,可以提前对照阅读:
- pacman-stateful-demo.yaml:一个完整的 Pacman 游戏有状态示例,包含 PodSecurityPolicy、ClusterRole/RoleBinding/ClusterRoleBinding 等 RBAC 资源、存储 MongoDB 凭据的 Secret、
ReadWriteOnce模式的 PersistentVolumeClaim,以及一个挂载 PVC 的StatefulSet(bitnami/mongodb:4.4.8,通过secretKeyRef注入数据库账号密码),外加 ClusterIP(mongo)与 LoadBalancer(pacman)两个 Service; - statefulset.yaml:独立的 StatefulSet 清单,展示了 initContainers 初始化卷权限、readinessProbe 探针等生产级细节;
- pacman-ingress.yaml:Ingress 示例,把
pacman.com域名的/路径路由到 pacman Service 的 80 端口,对应系列中的 Kubernetes Ingress 主题。
对比可见:无状态应用只需 Deployment + Service,而有状态应用还额外需要 StatefulSet、PVC、Secret 等资源配合,这正是系列后续章节「Persistent Storage」与「Stateful Apps」要深入展开的内容。
Helm:Kubernetes 的包管理器
第二种主流部署方式是 Helm,官方定位是「The package manager for Kubernetes」。可以把 Helm 理解成 Kubernetes 世界的 yum 或 apt:它通过部署chart来交付应用。chart 就像一个打包好的应用,是应用资源的蓝图(blueprint)——把预先配置好的整套资源打包成一个易于使用的单元,之后还可以用同一 chart 配上不同的配置集再部署出另一个版本。
Helm 的生态和使用体验有几个要点:
- 有专门的站点可以浏览所有可用的 Helm chart,也完全可以创建自己的 chart;
- 安装非常简单:官方提供各平台(包括 RaspberryPi 等 arm64 设备)的二进制下载,也可以直接用官方安装脚本,脚本会自动下载并安装最新版 Helm:
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh- 还可以借助操作系统包管理器安装:mac 用 homebrew、Windows 用 chocolatey、Ubuntu/Debian 用 apt,以及 snap 或 pkg。
在 90DaysOfDevOps 的实践语境下,Helm 是往集群里快速安装各种测试应用的首选方式。两个常用辅助资源:ArtifactHub 用于查找、安装和发布 Kubernetes 包;KubeApps 提供了可视化 UI 来展示和管理 helm chart。
本系列 Kubernetes 主题清单
Day54 是 Kubernetes 部署实战的起点,整个系列还会覆盖以下主题,其中部分在之前章节已开始涉及:
- Kubernetes 架构(Kubernetes Architecture)
- kubectl 常用命令(Kubectl Commands)
- Kubernetes YAML
- Kubernetes Ingress
- Kubernetes Services
- Helm 包管理器(Helm Package Manager)
- 持久化存储(Persistent Storage)
- 有状态应用(Stateful Apps)
接下来的 Day 55 将进入第二次集群部署的动手环节,随后就可以持续向集群内部署各种应用。对当前内容感兴趣的读者可以继续阅读 Day 55,或回到 Kubernetes 目录 查看 Vagrantfile 自建集群脚本、Rancher 部署脚本等更完整的配套资源。
参考资源
- Kubernetes 官方文档(Kubernetes Documentation)
- TechWorld with Nana:Kubernetes Tutorial for Beginners(完整 4 小时入门课程)
- TechWorld with Nana:Kubernetes Crash Course for Absolute Beginners
- Kunal Kushwaha:Kubernetes Tutorial for Beginners——Kubernetes 架构简化讲解
- 文档/教程
【免费下载链接】90DaysOfDevOps
This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.
相关推荐
90DaysOfDevOps 实战:用 YAML 清单与 Helm 在 Kubernetes 集群部署无状态应用(Day 54)
90DaysOfDevOps 实战:用 YAML 清单与 Helm 在 Kubernetes 集群部署无状态应用(Day 54) 本文是 90DaysOfDev
文档/教程90DaysOfDevOps 实践指南:使用 Minikube 与 YAML/Helm 在 Kubernetes 中部署无状态应用
90DaysOfDevOps 实践指南:使用 Minikube 与 YAML/Helm 在 Kubernetes 中部署无状态应用 本指南以 90DaysOfD
文档/教程90DaysOfDevOps Day 54:使用 YAML 与 Helm 在 Kubernetes 集群中部署应用
90DaysOfDevOps Day 54:使用 YAML 与 Helm 在 Kubernetes 集群中部署应用 90DaysOfDevOps 系列 Day
文档/教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考