- 环境准备
- docker
- minikube
- 启动minikube
- 其他命令
- kubectl
- kubernetes dashboard
- Kubernetes
- Pod
- Deployment
- 自动扩缩容
- 升级版本
- 版本回退
- 探针
- 探针配置项
- 启动探针(startupProbe)
- 就绪探针 (readinessProbe)
- 存活探针(livenessProbe)
- 配置示例
- Service
- 示例
- Service和Ingress的区别
- Ingress
- 示例
- Namespace
- 示例
- ConfigMap
- KV示例
- 文件示例
- 编辑ConfigMap
- CronJob
- 示例
- 其他
主要参考资料: https://k8s-tutorials.pages.dev/
环境准备
docker
使用docker-desktop安装即可。
minikube
地搭建 k8s 集群的方式推荐使用 minikube,可以根据 minikube 快速安装 来进行下载安装。
启动minikube
使用docker作为驱动引擎,在启动docker之后运行:
minikube start -d docker
因为网络原因,启动的过程中会有错误,但不影响基础组件运行:
😄 Microsoft Windows 11 Home China 10.0.26100.2314 Build 26100.2314 上的 minikube v1.34.0
✨ 根据现有的配置文件使用 docker 驱动程序
👍 Starting "minikube" primary control-plane node in "minikube" cluster
🚜 正在拉取基础镜像 v0.0.45 ...
E1128 12:03:53.302514 27036 cache.go:189] Error downloading kic artifacts: failed to download kic base image or any fallback image
🔄 正在为"minikube"重启现有的 docker container ...
❗ Failing to connect to https://registry.k8s.io/ from both inside the minikube container and host machine
💡 To pull new external images, you may need to configure a proxy: https://minikube.sigs.k8s.io/docs/reference/networking/proxy/
🐳 正在 Docker 27.2.0 中准备 Kubernetes v1.31.0…
🔎 正在验证 Kubernetes 组件...▪ 正在使用镜像 gcr.io/k8s-minikube/storage-provisioner:v5
🌟 启用插件: default-storageclass, storage-provisioner
🏄 完成!kubectl 现在已配置,默认使用"minikube"集群和"default"命名空间
执行完成后,运行minikube status
查看当前集群状态:
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
其他命令
minikube stop
不会删除任何数据,只是停止 VM 和 k8s 集群。
minikube delete
删除所有 minikube 启动后的数据。
minikube ip
查看集群和 docker enginer 运行的 IP 地址。
minikube pause
暂停当前的资源和 k8s 集群
kubectl
Kubernetes 命令行工具 kubectl, 让你可以对 Kubernetes 集群运行命令。 你可以使用 kubectl 来部署应用、监测和管理集群资源以及查看日志。
通过访问 Kubernetes 发布页面 直接下载特定于你的体系结构的二进制文件,配置环境变量即可使用。
kubernetes dashboard
dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群资源。
在本地minikube环境,可以通过以下命令开启:
minikube dashboard
然而,在中国大陆却不一定会很顺利,启动命令卡在“正在验证 proxy 运行状况 ...”,不能成功。解决过程:
-
kubectl get pod --all-namespaces
发现kubernetes-dashboard
命令空间下有两个启动失败的pod,原因是容器拉取失败(ErrImagePull) -
结合dashboard首次启动时打印的输出,可以确定缺失的两个镜像
🔌 正在开启 dashboard ...▪ 正在使用镜像 docker.io/kubernetesui/dashboard:v2.7.0▪ 正在使用镜像 docker.io/kubernetesui/metrics-scraper:v1.0.8
-
使用科学的方法拉取镜像后,通过
minikube image load xxx.tar
加载镜像到minikube虚拟环境 -
加载完镜像,等一会儿应该能成功。如果没成功,继续下面的步骤。
-
重新启动dashboard,仍然不能成功...怀疑是deployment的
imagePullPolicy
的原因,有镜像仍然拉取 -
导出deployment的yaml定义
# 先查一下,查到两个deployment kubectl get deploy -n kubernetes-dashboard # 导出yaml kubectl get deploy dashboard-metrics-scraper -n kubernetes-dashboard -o yaml > dashboard-metrics-scraper.yaml kubectl get deploy kubernetes-dashboard -n kubernetes-dashboard -o yaml > kubernetes-dashboard.yaml
-
发现imagePullPolicy是
IfNotPresent
,按理说不该有问题。不管了,直接改成never。# 修改imagePullPolicy为Never后,重建deployment kubectl apply -f dashboard-metrics-scraper.yaml -n kubernetes-dashboard kubectl apply -f kubernetes-dashboard.yaml -n kubernetes-dashboard
-
minikube dashboard
再次启动,应该能成功了。
Kubernetes
Pod
pod是Kubernetes 中创建和管理的、最小的可部署的计算单元。
编写一个名为pod-mvc-demo.yaml
的配置文件,内容如下:
# pod-mvc-demo.yaml
apiVersion: v1
kind: Pod
metadata:name: mvc-demo-pod
spec:containers:- name: mvc-demo-containerimage: mvc_demo:latestimagePullPolicy: IfNotPresent
其中mvc-demo是一个包含spring-mvc示例程序的镜像。
minikube内部由于网络原因镜像拉取会失败,通过以下命令离线加载镜像:
minikube image load xxx.tar
通过kubectl apply -f pod-mvc-demo.yaml
创建pod;
kubectl get pods
查看pod启动状态;
kubectl describe pod mvc-demo-pod
查看pod详情;
kubectl logs -f mvc-demo-pod
查看pod日志;
kubectl exec -it mvc-demo-pod -- bash
进入容器;
Deployment
deployment可以完成一些自动化操作,例如自动扩容或者自动升级版本,并可以保证容器的数量满足预期。
# deployment-mvc-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: mvc-demo-deployment # 资源名称annotations:kubernetes.io/change-cause: "mvc_demo:v2" # 变更原因: kubectl rollout history deployment $deployment_name,可以查看每个版本的变更原因,方面识别版本并回滚
spec:replicas: 3 # 容器副本数量strategy:rollingUpdate: # 滚动更新策略maxSurge: 1 # 最大峰值,用来指定可以创建的超出期望 Pod 个数的 Pod 数量maxUnavailable: 1 # 最大不可用,用来指定更新过程中不可用的 Pod 的个数上限 selector:matchLabels:app: mvc-demotemplate:metadata:labels:app: mvc-demo # metadata.labels 来和上面的 selector.matchLabels 对应spec: # pod定义containers:- image: mvc_demo:v2name: mvc-demo-containerimagePullPolicy: IfNotPresent
通过kubectl apply -f deployment-mvc-demo.yaml
创建deployment;
查看pod,可以看到deployment已经帮我们创建,并带有随机后缀:
NAME READY STATUS RESTARTS AGE
mvc-demo-deployment-85dc9d6f4d-fm7kz 1/1 Running 1 (20m ago) 32m
自动扩缩容
-
修改
spec.replicas
的数量,并kubectl apply -f
应用更新; -
通过命令行修改:
# kubectl scale --replicas=<new_replica_count> <resource_type>/<resource_name> kubectl scale --replicas=3 deployment/mvc-demo-deployment
通过
kubectl get pod -w (--watch)
可以监控pod变化。
升级版本
-
修改pod定义中的image版本,并
kubectl apply -f
应用更新; -
通过命令行修改:
# kubectl set image deployment/<deployment_name> <container_name>=<image>:<tag> kubectl set image deployment/mvc-demo-deployment mvc-demo-container=mvc_demo:v2
版本回退
-
回退到上一个版本:
# kubectl rollout undo deployment <deployment_name> kubectl rollout undo deployment mvc-demo-deployment
-
回退到指定版本
查看历史版本
# kubectl rollout history deployment <deployment_name> kubectl rollout history deployment mvc-demo-deployment
输出如下:
deployment.apps/mvc-demo-deployment REVISION CHANGE-CAUSE 9 mvc_demo:v1 11 mvc_demo:v2 12 mvc_demo:latest
回退到指定版本
kubectl rollout undo deployment/hellok8s-deployment --to-revision=11
探针
探针配置项
initialDelaySeconds
:容器启动后要等待多少秒后才启动存活和就绪探测器, 默认是 0 秒,最小值是 0。periodSeconds
:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。timeoutSeconds
:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。successThreshold
:探测器在失败后,被视为成功的最小连续成功数。默认值是 1。 存活和启动探测的这个值必须是 1。最小值是 1。failureThreshold
:当探测失败时,Kubernetes 的重试次数。 对存活探测而言,放弃就意味着重新启动容器。 对就绪探测而言,放弃意味着 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。terminationGracePeriodSeconds
: 配置kubelet在触发关闭失败容器和强制容器运行时停止该容器之间等待的宽限期。默认情况下,将继承terminationGracePeriodSeconds的pod级别值(如果未指定为30秒),最小值为1。
启动探针(startupProbe)
-
目的: 确定容器中的应用程序是否已经成功启动。--StartupProbe
-
行为: 在
startupProbe
成功之前,livenessProbe
和readinessProbe
不会被执行。 一旦startupProbe
成功,livenessProbe
和readinessProbe
将开始工作。 如果startupProbe
失败达到failureThreshold
指定的次数,容器将根据其重启策略进行处理。
就绪探针 (readinessProbe)
- 目的: 确定容器是否准备好接收流量。
- 行为: 当
readinessProbe
失败时,Kubernetes 会将该 Pod 从服务的 Endpoint 列表中移除,确保没有流量被路由到该 Pod。 只有当readinessProbe
成功时,Pod 才被视为就绪,并可以接收流量。
就绪探测器可以知道容器何时准备好接受请求流量,当一个 Pod 内的所有容器都就绪时,才能认为该 Pod 就绪。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 若 Pod 尚未就绪,会被从 Service 的负载均衡器中剔除。-- ReadinessProb
存活探针(livenessProbe)
- 目的: 确定容器是否还在运行,并且运行正常。
- 行为: 当
livenessProbe
失败时,Kubernetes 会重启容器。 这种探针通常用于检测容器是否进入了一个崩溃循环或不再响应的状态。
存活探测器来确定什么时候要重启容器。 例如,存活探测器可以探测到应用死锁(应用程序在运行,但是无法继续执行后面的步骤)情况。 重启这种状态下的容器有助于提高应用的可用性,即使其中存在缺陷。-- LivenessProb
配置示例
containers:- image: mvc_demo:v3name: mvc-demo-containerimagePullPolicy: IfNotPresentports:- name: app-portcontainerPort: 8080livenessProbe:httpGet:path: /healthport: app-portinitialDelaySeconds: 0periodSeconds: 3failureThreshold: 3periodSeconds: 3startupProbe:httpGet:path: /healthport: app-portinitialDelaySeconds: 30failureThreshold: 5periodSeconds: 3
Service
Service主要用于解决Pod动态变化时的IP变化问题,为Pod提供一个固定的访问接口。它通过DNS系统实现服务发现功能。
包含以下几种类型(spec.type):
-
ClusterIP:自动分配一个仅内部访问的虚拟IP,默认、常用。外部访问一般使用Ingress。
-
NodePort:在每个节点上开放一个固定端口,外部可以通过该端口访问服务。
-
LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。例如AWS 的 ELB (Elastic Load Balancer)。
-
ExternalName:将Service映射到外部DNS名称,例如集群外的数据库、baidu.com等。
-
Headless: 不分配ClusterIP,也不提供负载均衡,通过service域名返回所有pod地址。
示例
apiVersion: v1
kind: Service
metadata:name: service-mvc-demo-clusterip
spec:type: ClusterIPselector:app: mvc-demoports:- port: 3000targetPort: 8080
kubectl get svc
查看结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service-mvc-demo-clusterip ClusterIP 10.99.55.7 <none> 3000/TCP 28m
kubectl exec -it nginx-pod -- bash
,从集群内的其他容器访问验证:
# 通过service名称或ip访问, 可以看到负载均衡效果
curl http://service-mvc-demo-clusterip:3000/api/demo
# hello world, I am at mvc-demo-deployment-868d784569-cbgx5
# hello world, I am at mvc-demo-deployment-868d784569-xn2qd
# hello world, I am at mvc-demo-deployment-868d784569-wc8z5
Service和Ingress的区别
- 功能层次:Service提供四层(TCP/UDP)负载均衡,Ingress提供七层(HTTP/HTTPS)负载均衡。
- 用途:Service用于基本的网络访问和负载均衡,Ingress用于复杂的HTTP路由和反向代理。
- 外部访问:Service通过NodePort或LoadBalancer暴露服务,但端口管理复杂;Ingress通过统一入口实现,管理更方便。
Ingress
Ingress 公开从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。
Ingress是一个API对象,通过yaml文件来配置,ingress对象的作用是定义请求如何转发到service的规则,可以理解为配置模板。
Ingress通过http或https暴露集群内部service,给service提供外部URL、负载均衡、SSL/TLS以及基于域名的反向代理。ingress要依靠 ingress-controller 来具体实现以上功能。目前,ingress-controller的具体实现有ingress-nginx、ingress-kong等。
ingress高可用
ingress nginx
示例
-
首先,我们为nginx和mvc-demo部署service;
# 删除所有资源 kubectl delete deployment,service --all
# nginx.yaml apiVersion: apps/v1 kind: Deployment metadata:name: nginx-deployment spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginxname: nginx-containerimagePullPolicy: IfNotPresent---apiVersion: v1 kind: Service metadata:name: service-nginx-clusterip spec:type: ClusterIPselector:app: nginxports:- port: 4000targetPort: 80
# mvc-demo.yaml apiVersion: apps/v1 kind: Deployment metadata:name: mvc-demo-deployment # 资源名称annotations:kubernetes.io/change-cause: "mvc_demo:v4" # 变更原因: kubectl rollout history deployment $deployment_name,可以查看每个版本的变更原因,方面识别版本并回滚 spec:replicas: 3 # 容器副本数量strategy:rollingUpdate: # 滚动更新策略maxSurge: 1 # 最大峰值,用来指定可以创建的超出期望 Pod 个数的 Pod 数量maxUnavailable: 1 # 最大不可用,用来指定更新过程中不可用的 Pod 的个数上限selector:matchLabels:app: mvc-demotemplate:metadata:labels:app: mvc-demo # metadata.labels 来和上面的 selector.matchLabels 对应spec: # pod定义containers:- image: mvc_demo:v4name: mvc-demo-containerimagePullPolicy: IfNotPresentports:- name: app-portcontainerPort: 8080---apiVersion: v1 kind: Service metadata:name: service-mvc-demo-clusterip spec:type: ClusterIPselector:app: mvc-demoports:- port: 3000targetPort: 8080
-
启用minikube的ingress-controller功能
minikube addons enable ingress
镜像会下载失败,需要通过
minikube image load
加载以下两个镜像:REPOSITORY TAG IMAGE ID CREATED SIZE registry.k8s.io/ingress-nginx/controller v1.11.2 a80c8fd6e522 3 months ago 287MB registry.k8s.io/ingress-nginx/kube-webhook-certgen v1.4.3 ce263a8653f9 3 months ago 54.7MB
-
创建ingress
# ingress-demo.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata:name: ingress-demoannotations:# We are defining this annotation to prevent nginx# from redirecting requests to `https` for nownginx.ingress.kubernetes.io/ssl-redirect: "false" spec:rules:- http:paths:- path: /apipathType: Prefixbackend:service:name: service-mvc-demo-clusteripport:number: 3000- path: /pathType: Prefixbackend:service:name: service-nginx-clusteripport:number: 4000
kubectl apply -f hellok8s.yaml
-
验证
查看ingress地址
kubectl get ingress # NAME CLASS HOSTS ADDRESS PORTS AGE # ingress-demo nginx * 192.168.49.2 80 14m
192.168.49.2
即minikube容器ip,可通过docker inspect -f '{{.NetworkSettings.Networks.minikube.IPAMConfig.IPv4Address}}' minikube
验证;我是docker部署的minikube,
192.168.49.2
这个ip并不能直接访问。通过minikube ssh
进入容器内部后:curl http://192.168.49.2/ # <p><em>Thank you for using nginx.</em></p> curl http://192.168.49.2/api/demo # hello world, I am at mvc-demo-deployment-868d784569-xn2q
Namespace
在 Kubernetes 中,名字空间(Namespace) 提供一种机制,将同一集群中的资源划分为相互隔离的组。 同一名字空间内的资源名称要唯一,但跨名字空间时没有这个要求。 名字空间作用域仅针对带有名字空间的对象,例如 Deployment、Service 等。
示例
-
创建namespace
# namespace.yaml apiVersion: v1 kind: Namespace metadata: name: dev ---apiVersion: v1 kind: Namespace metadata: name: test
kubectl apply -f namespace.yaml
创建;kubectl get ns
查看 -
创建资源并指定namespace
kubectl apply -f deployment-mvc-demo.yaml -n dev kubectl get deployment,svc,pod -n dev
-
清空测试资源
kubectl delete deployment,svc,pod --all -n dev
ConfigMap
K8S 使用 ConfigMap 来将你的配置数据和应用程序代码分开,将非机密性的数据保存到键值对中。ConfigMap 在设计上不是用来保存大量数据的。在 ConfigMap 中保存的数据不可超过 1 MiB。如果你需要保存超出此尺寸限制的数据,你可能考虑挂载存储卷。
KV示例
-
创建configmap,配置两个key
# config-map-kv.yaml apiVersion: v1 kind: ConfigMap metadata:name: mvc-demo-kv-config data:SPRING_APPLICATION_NAME: my-mvc-demoCUSTOM_CONFIG_STR: "hello from config map."
kubectl apply -f config-map-kv.yaml
创建 -
修改程序,在springboot中获取变量
@Value("${custom.config.str:default}")private String customStr;
-
修改deployment(pod)配置,引入configmap
spec: # pod定义containers:- image: mvc_demo:v5name: mvc-demo-containerimagePullPolicy: IfNotPresentports:- name: app-portcontainerPort: 8080env:- name: SPRING_APPLICATION_NAMEvalueFrom:configMapKeyRef:name: mvc-demo-kv-configkey: SPRING_APPLICATION_NAME- name: CUSTOM_CONFIG_STRvalueFrom:configMapKeyRef:name: mvc-demo-kv-configkey: CUSTOM_CONFIG_STR
-
验证
-
pod日志中
spring.application.name
变更:2024-12-02T15:13:03.337+08:00 INFO 1 --- [my-mvc-demo] [ main] c.example.mvc_demo.MvcDemoApplication : Started MvcDemoApplication in 9.691 seconds (process running for 11.024)
-
程序内部customStr变量配置成功
curl http://192.168.49.2/api/demo # hello world, I am at mvc-demo-deployment-588479db7-fvf9w, custom config str: hello from config map.
-
文件示例
-
创建configmap,包含一个名为
application.yml
的文件# config-map-kv.yaml apiVersion: v1 kind: ConfigMap metadata:name: mvc-demo-file-config data:application.yml: |-spring:application:name: my-mvc-democustom:config:str: "hello from file config map."
-
通过卷挂载的方式引用configmap
spec: # pod定义volumes:- name: config-volume # 卷定义configMap:name: mvc-demo-file-configcontainers:- image: mvc_demo:v5name: mvc-demo-containerimagePullPolicy: IfNotPresentports:- name: app-portcontainerPort: 8080env:- name: SPRING_CONFIG_LOCATION # springboot加载外部配置文件value: /config/application.ymlvolumeMounts:- name: config-volume mountPath: /config # 卷挂载
-
验证方式和KV示例相同。
编辑ConfigMap
kubectl edit cm <ConfigMap name>
使用系统默认编辑器编辑保存,然后删除pod(deployment重建pod),即可应用更新:
kubectl get pod |grep mvc-demo |awk '{print $1}' |xargs kubectl delete pod
CronJob
CronJob 可以理解为定时任务,创建基于 Cron 时间调度的 Jobs。CronJob仅在有任务时启动pod,其他时间可以释放系统资源。
示例
# cronjob-demo.yaml
apiVersion: batch/v1
kind: CronJob
metadata:name: hello-cronjob
spec:schedule: "* * * * *" # 每分钟jobTemplate:spec:template:spec:restartPolicy: OnFailurecontainers:- name: echoimage: alpineenv:- name: TZvalue: Asia/Shanghaicommand:- "/bin/sh"args:- "-c"- "echo hello cronjob at $(date +'%Y-%m-%d %H:%M:%S')"
kubectl apply -f cronjob-demo.yaml
创建;
kubectl get cj
查看;
kubectl get pod -w
观察pod调度情况:
hello-cronjob-28885501-z9zgp 0/1 Pending 0 0s
hello-cronjob-28885501-z9zgp 0/1 Pending 0 0s
hello-cronjob-28885501-z9zgp 0/1 ContainerCreating 0 0s
hello-cronjob-28885501-z9zgp 0/1 Completed 0 3s
hello-cronjob-28885501-z9zgp 0/1 Completed 0 5s
hello-cronjob-28885501-z9zgp 0/1 Completed 0 6s
hello-cronjob-28885498-j76l8 0/1 Completed 0 3m6s
hello-cronjob-28885498-j76l8 0/1 Completed 0 3m6s
hello-cronjob-28885502-nf4pc 0/1 Pending 0 0s
hello-cronjob-28885502-nf4pc 0/1 Pending 0 0s
hello-cronjob-28885502-nf4pc 0/1 ContainerCreating 0 0s
hello-cronjob-28885502-nf4pc 0/1 Completed 0 4s
hello-cronjob-28885502-nf4pc 0/1 Completed 0 5s
hello-cronjob-28885502-nf4pc 0/1 Completed 0 6s
hello-cronjob-28885499-xhhb6 0/1 Completed 0 3m6s
hello-cronjob-28885499-xhhb6 0/1 Completed 0 3m6s
kubectl logs
查看pod日志,可以看到输出如下:
hello cronjob at 2024-12-02 09:04:03
hello cronjob at 2024-12-02 09:05:03
其他
存储、安全、监控、水平自动伸缩(Horizontal Pod Autoscaling)...太多了,先不看了。