Python项目容器化实践(五) - Kubernetes基础篇二
/ / / 阅读数:8153接着上篇继续了解 Kubernetes (以下简称 k8s) 的相关内容。
HPA(HorizontalPodAutoscaling)
每天不同时刻应用的资源使用率通常是不同的,例如中午和晚上是访问的高峰,凌晨那几个小时是低峰。怎么提高集群的整体资源利用率,让 Service 中的 Pod 个数自动调整呢?这就依赖了 k8s 提供的 HPA (Horizontal Pod Autoscaler) 资源对象,也就是「使 Pod 水平自动缩放」。
铺垫一下,在上篇文章中已经创建过一个 deployment:
❯ kubectl get deployment k8s-demo-deployment NAME READY UP-TO-DATE AVAILABLE AGE k8s-demo-deployment 10/10 10 10 13h |
k8s-demo-deployment
里面有 10 个 Pod。怎么实现 Pod 的扩容缩容呢?最简单的方法是用kubectl scale
:
# 缩容 ❯ kubectl scale --replicas=5 -f deployment.yaml deployment.apps/k8s-demo-deployment scaled ❯ kubectl get deployment k8s-demo-deployment NAME READY UP-TO-DATE AVAILABLE AGE k8s-demo-deployment 5/5 5 5 13h # 扩容 ❯ kubectl scale --replicas=8 -f deployment.yaml deployment.apps/k8s-demo-deployment scaled ❯ kubectl get deployment k8s-demo-deployment # 期望8个Pod,现在只有5个可用 NAME READY UP-TO-DATE AVAILABLE AGE k8s-demo-deployment 5/8 8 5 13h # 稍等几秒,8个都可用了 ❯ kubectl get deployment k8s-demo-deployment NAME READY UP-TO-DATE AVAILABLE AGE k8s-demo-deployment 8/8 8 8 13h |
kubectl scale
是传统运维惯用的手动的调整方法,接着我们看看怎么用 HPA,首先是先部署 metrics-server:
❯ git clone https://github.com/kubernetes-incubator/metrics-server.git ❯ cd metrics-server ❯ kubectl create -f deploy/1.8+/ # 这样建的Metrics Server有证书问题,需要编辑配置 ❯ KUBE_EDITOR="emacsclient -t" kubectl edit deploy -n kube-system metrics-server # 在 spec.template.spec.containers.image 添加如下三行(不包含注释): # args: # - --kubelet-insecure-tls # - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname # 接着可以看到它的状态是Running: ❯ kubectl -n kube-system get pods -l k8s-app=metrics-server NAME READY STATUS RESTARTS AGE metrics-server-55857cd5dc-k59ln 1/1 Running 0 1m18s # 可以看一下目前Pod的资源占用排名(下面列了前3) ❯ kubectl top pod |head -4 NAME CPU(cores) MEMORY(bytes) k8s-demo 0m 2Mi k8s-demo-deployment-6bc5c77c85-5r5dm 0m 2Mi k8s-demo-deployment-6bc5c77c85-6gbd7 0m 2Mi |
接着修改 deployment.yaml,添加资源相关的修改:
... spec: containers: - name: k8s-demo-pod ... resources: # resources部分都是新增的 requests: memory: 64Mi cpu: 25m limits: memory: 128Mi cpu: 50m |
这是因为默认情况下,Pod 运行没有限制 CPU 使用量和内存使用量。这意味着 Pod 能够使用该 Pod 运行节点的所有 CPU 和内存资源。必须要加上述配置限制,才能让下面的 HPA 有效果,应用配置:
❯ kubectl apply -f deployment.yaml --record=true deployment.apps/k8s-demo-deployment configured |
然后写一个 HPA 配置文件 (hpa.yaml):
apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: k8s-demo-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: k8s-demo-deployment minReplicas: 6 maxReplicas: 12 metrics: - type: Resource resource: name: cpu targetAverageUtilization: 3 - type: Resource resource: name: memory targetAverageValue: 300Mi |
这里面设置了触发自动缩放的 2 种指标: CPU 阈值 3%,内存 300M,最小的 Pod 副本数为 10,最大为 15。HPA 会根据设定动态的增加或者减少 Pod 数量。
❯ kubectl create -f hpa.yaml horizontalpodautoscaler.autoscaling/k8s-demo-hpa created # 稍等几秒就可以看到HPA状态 ❯ kubectl get hpa k8s-demo-hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE k8s-demo-hpa Deployment/k8s-demo-deployment 2501017600m/300Mi, 0%/3% 6 12 10 25s |
HPA 通过监控分析 RS 或者 Deployment 控制的所有 Pod 的负载变化情况来确定是否需要调整 Pod 的副本数量,上面的命令创建了一个关联资源 k8s-demo-deployment 的 HPA。可以看 TARGETS 下,由于没有流量 CPU 还是用的 0%,低于阈值 3%。
这里说一下,刚才应用 deployment.yaml 后会让副本数变回 10,但是由于 HPA 的自动缩放效果,它觉得目前很闲会缩容到 6 个副本数,稍等一会再看:
❯ kubectl get hpa k8s-demo-hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE k8s-demo-hpa Deployment/k8s-demo-deployment 2486272/300Mi, 0%/3% 6 12 6 2m14s |
可以看到 REPLICAS 变成了 MINPODS 的数量 6! 接着要增大负载,引起 CPU 占用达到阈值以便提高 Pod,新开 2 个终端分别不断请求页面:
❯ while true; do wget -q -O- http://127.0.0.1:31112/ > /dev/null; done |
然后不断的刷新 HPA 状态,我截取了过程中 Pod 数量的变化:
❯ kubectl get hpa k8s-demo-hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE k8s-demo-hpa Deployment/k8s-demo-deployment 2510848/300Mi, 0%/3% 6 12 6 12m ... ❯ kubectl get hpa k8s-demo-hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE k8s-demo-hpa Deployment/k8s-demo-deployment 2520405333m/300Mi, 24%/3% 6 12 6 12m ... ❯ kubectl get hpa k8s-demo-hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE k8s-demo-hpa Deployment/k8s-demo-deployment 2520405333m/300Mi, 24%/3% 6 12 12 12m ❯ kubectl get pods |grep k8s-demo-deployment |grep Running | wc -l 12 |
可以看到由于不断的请求页面,CPU 负载超过设定的 3% 会一直加 Pod,直到达到 maxReplicas 的值。此时如果关掉刚才的 while true 循环进程并等待几分钟,副本数量将变回为 6。
内置的 HPA 操作由 CPU 或内存触发,还可以根据各种外部的和自定义指标来配置 HPA 以扩展 Pod。有需求的可以自行搜索。
当然,HPA 只是 k8s 自动缩放 (Autoscaling) 的方案之一,除此之外还有:
- VPA (Vertical Pod Autoscaler)。既然有水平缩放,当然也有垂直缩放 (VPA),即根据容器资源使用情况自动设置 Pod 的 CPU、内存的请求值 (配置文件中的 resources.requests 项目),从而允许在节点上进行适当的调度,以便为每个 Pod 提供适当的资源。它既可以缩小过度请求资源的容器,也可以根据其使用情况随时提升资源不足的容量。具体的可以延伸阅读链接 2
- CA (Cluster Autoscaler)。顾名思义,可以自动扩展和收缩 k8s 集群 Node,具体可以看延伸阅读链接 3
Job/CronJob
在日常开发中经常遇到跑一些临时脚本任务的需求,如果周期性的需要运行这些任务,会由 Crontab 调度任务,这个所谓的任务在 k8s 里面有专门的资源对象:
- Job。仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束。
- CronJob。定时任务,在指定的时间周期运行指定的任务。
先看一个 Job 例子 (job.yaml):
apiVersion: batch/v1 kind: Job metadata: name: k8s-demo-job spec: template: spec: containers: - name: python-38 image: python:3.8-alpine command: ["python", "-c", "import socket; print(socket.gethostbyname(socket.gethostname()))"] restartPolicy: Never backoffLimit: 4 |
这次用了一个新的镜像 (python:3.8-alpine), 如其名,容器自带 Python 解释器,command 是本次任务要执行的命令。backoffLimit 指定 job 失败后进行重试的次数,这个要配合restartPolicy: Never
(RestartPolicy 是重启策略,Never 表示不重启,另外还支持 OnFailure: 失败才重启)
❯ kubectl create -f job.yaml job.batch/k8s-demo-job created ❯ kubectl get pods --selector=job-name=k8s-demo-job # 获得Job的Pod名字, selector是字段选择器 NAME READY STATUS RESTARTS AGE k8s-demo-job-krfnx 0/1 Completed 0 5s # STATUS是完成的,因为这是一次性的 ❯ kubectl logs k8s-demo-job-krfnx # 查看Pod日志,可以看到代码中print语句输出打印到了日志里面 10.1.0.128 |
CronJob 的特点是「在给定时间点只运行一次」和「周期性地在给定时间点运行」,看一个例子来体会和 Job 的区别 (cronjob.yaml):
apiVersion: batch/v1beta1 kind: CronJob metadata: name: k8s-demo-cronjob spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: containers: - name: python-38 image: python:3.8-alpine command: ["python", "-c", "import socket; print(socket.gethostbyname(socket.gethostname()))"] restartPolicy: OnFailure |
CronJob 和 Job 主要区别就是:
- 多了 schedule (Linux crontab 格式一样,上例表示每分钟调用一次)
- 使用 jobTemplate 表示 Job 里面的 spec.template 部分,相当于多嵌套一层
运行一下:
❯ kubectl create -f cronjob.yaml cronjob.batch/k8s-demo-cronjob created # 可以看到CronJob状态: ❯ kubectl get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE k8s-demo-cronjob */1 * * * * False 0 <none> 9s # 等一会看Job: ❯ kubectl get jobs NAME COMPLETIONS DURATION AGE k8s-demo-cronjob-1571886360 1/1 3s 62s k8s-demo-cronjob-1571886420 0/1 2s 2s # 正好捕捉到第二个任务正在运行 k8s-demo-job 1/1 32s 45m ❯ pod=$(kubectl get pods --selector=job-name=k8s-demo-cronjob-1571886360 --output=jsonpath={.items..metadata.name}) ❯ kubectl logs $pod 10.1.0.143 ❯ kubectl delete -f cronjob.yaml # 不删掉会一直定时跑 cronjob.batch "k8s-demo-cronjob" deleted |
每分钟都会出现一个k8s-demo-cronjob
开头的 Job,这就是 CronJob。
服务发现 (Service Discovery)
由于 k8s 的调度机制,Pod 的 IP 不是固定的 (Pod 一直在经历动态创建和销毁)。如果其它 Pod 需要访问这个 Pod,要怎么知道这个 Pod 的 IP 呢?这就需要通过 Service 通过 VIP (虚拟 IP,ClusterIP) 访问 Pod 提供的服务:
❯ kubectl get svc k8s-demo-svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE k8s-demo-svc NodePort 10.97.121.169 <none> 80:31112/TCP 17h |
我们可以通过命令行获得 VIP,但是在内部,应用 A 怎么知道应用 B 的 VIP?举个非常常见的场景:一个是 API 应用,一个是 DB 应用,两个应用都是通过 Deployment 进行管理的,并且都通过 Service 暴露出了端口提供服务,而 API 应用需要连接到 DB 应用,但在代码层面我们只知道 DB 应用的名称的 DB 对应的 Service 的名称,但是并不知道它的 VIP 地址,怎么办?
通过 k8s 的服务发现机制能容易地获得 Service 对应 IP 和 Port。k8s 支持 2 种基本的服务发现模式:环境变量和 DNS。
环境变量
想一下,k8s-demo-svc
的集群 IP 和端口是怎么来的?当容器应用部署到集群时,其服务地址 (即 IP 和端口) 是由集群系统动态分配的。这是基于环境变量分配的。
当 Pod 运行在 Node 上,kubelet 会为每个活跃的 Service 添加一组环境变量。而 Pod 启动的时候,会通过环境变量设置所有服务相关 IP 和 Port 信息,为了让大家容易理解,基于 svc.yaml 新增 svc2.yaml,只改其中的 metadata.name 为k8s-demo2-svc
,然后创建服务:
❯ kubectl create -f svc2.yaml service/k8s-demo2-svc created ❯ kubectl get svc | grep k8s-demo k8s-demo-svc NodePort 10.97.121.169 <none> 80:31112/TCP 1d k8s-demo2-svc NodePort 10.104.26.124 <none> 80:32059/TCP 2m5s |
现在有了 2 个 Service。大家还记不记得最开始创建的一个 Podk8s-demo
标签也是app: k8s
? 我们进入重新创建 Pod 就可以找到关于服务的 VIP 的环境变量:
❯ kubectl delete -f pod.yaml && kubectl create -f pod.yaml ❯ kubectl exec -it k8s-demo sh / # env |grep SERVICE KUBERNETES_SERVICE_PORT=443 K8S_DEMO_SVC_SERVICE_HOST=10.97.121.169 K8S_DEMO_SVC_SERVICE_PORT=80 K8S_DEMO2_SVC_SERVICE_HOST=10.104.26.124 K8S_DEMO2_SVC_SERVICE_PORT=80 KUBERNETES_SERVICE_PORT_HTTPS=443 KUBERNETES_SERVICE_HOST=10.96.0.1 / # wget -q -O- http://$K8S_DEMO_SVC_SERVICE_HOST:$K8S_DEMO_SVC_SERVICE_PORT <h1>Hello Kubernetes!</h1> / # wget -q -O- http://$K8S_DEMO2_SVC_SERVICE_HOST:$K8S_DEMO2_SVC_SERVICE_PORT <h1>Hello Kubernetes!</h1> |
格式就是{SVCNAME}_SERVICE_HOST
和{SVCNAME**_SERVICE_PORT
的变量,但注意 Service 的名称需大写,横线被转换成下划\ 线。当然进入重新创建 k8s-demo-deployment 的 Pod 也是可以的。理解了吧?服务相关的环境变量被「注入」了 Pod。
这里说一下为什么k8s-demo
需要重建,这也是环境变量的最大问题:依赖的服务必须在 Pod 启动之前就存在,不然是不会出现在环境变量中的。之前的 Pod 创建时只有 k8s-demo2-svc 这个服务,所以环境变量是不全的
DNS
另外一种方案是用 DNS (域名解析系统),在 k8s 里面 DNS 是一种 Addon (附加组件,不是 k8s 集群必须安装,但强烈推荐安装), 目前可以选择 kube-dns 或 CoreDNS 为集群提供命名服务。从 v1.13 开始 CoreDNS 成为默认 DNS 服务,CoreDNS 的特点是效率更高,资源占用率更小,所谓本小节只介绍 CoreDNS 的使用。
DNS 服务会根据域名来访问相应的 IP,在 k8s 中就是根据相应的域名去获取相应的 Pod 的 IP,这样 API 应用根据域名就可以访问 DB 应用服务了。
看一下 k8s 系统空间 (kube-system) 下 CoreDNS 的 Pods:
❯ kubectl get pods -n kube-system |grep dns coredns-584795fc57-2llbd 1/1 Running 0 2d3h coredns-584795fc57-586wz 1/1 Running 0 2d3h |
假设在 k8s 集群的命名空间 bar 中,定义了一个 Service foo,同在这个命名空间下的 Pod 可以简单地通过 DNS 查询 foo 来找到该 Service,其他命令空间里的 Pod 需要通过 DNS 查询 foo.bar 找到该 Service。
为了体验 DNS 的效果,先在另外一个命名空间创建个服务,首先是写命名空间配置 (namespace.yaml):
{ "apiVersion": "v1", "kind": "Namespace", "metadata": { "name": "production", "labels": { "name": "production" } } } |
新加的命名空间叫做 production,创建它:
❯ kubectl create -f namespace.yaml namespace/production created ❯ kubectl create -f svc.yaml -n production service/k8s-demo-svc created ❯ kubectl create -f pod.yaml -n production pod/k8s-demo created ❯ kubectl get svc --all-namespaces | grep k8s-demo default k8s-demo-svc NodePort 10.97.121.169 <none> 80:31112/TCP 1d4h default k8s-demo2-svc NodePort 10.104.26.124 <none> 80:32059/TCP 3h57m production k8s-demo-svc NodePort 10.100.20.118 <none> 80:32292/TCP 10s |
现在默认的空间下有 2 个服务,在 production 也有个叫做 k8s-demo-svc 的服务。现在进一个和上述服务都无关的新 Pod,通过域名的方式看看怎么访问其他 Service:
❯ kubectl run --rm -it --image=busybox --generator=run-pod/v1 test-pod # 命令式创建Pod,名字test-pod,镜像用的是busybox # 普通的Service会生成 servicename.namespace.svc.cluster.local 格式的全限定域名(FQDN),会解析到Service对应的ClusterIP上 / # wget -q -O- http://k8s-demo-svc.default.svc.cluster.local # k8s-demo-svc 是服务名,default 是默认的命令空间,之后的作为域后缀直接使用 <h1>Hello Kubernetes!</h1> / # wget -q -O- http://k8s-demo2-svc.default.svc.cluster.local # k8s-demo2-svc 是另外服务名 <h1>Hello Kubernetes!</h1> / # wget -q -O- http://k8s-demo-svc.production.svc.cluster.local # 另外命名空间下的服务 <h1>Hello Docker!</h1> # 注意,pod.yaml用的是镜像是k8s-demo:0.1 / # wget -q -O- http://k8s-demo-svc.default # 相同命名空间可以省略域后缀 <h1>Hello Kubernetes!</h1> / # wget -q -O- http://k8s-demo-svc # 相同命名空间下空间名字都可以省 <h1>Hello Kubernetes!</h1> / # wget -q -O- http://k8s-demo-svc.production <h1>Hello Docker!</h1> |
用 DNS 的方式就可以访问 k8s 集群里面任何你想要访问的 Service 资源了。
外部路由
一共有 4 种方案让服务可以被外部用户访问 (更具体的内容可以看延伸阅读链接 4)
ClusterIP
ClusterIP 是默认的 Service 类型,当 Service 创建时,会被分配一个唯一的 IP 地址(也称为 clusterIP),内部可以直接访问,外部用户可以用 port-forward 访问:
❯ kubectl expose deployment/k8s-demo-deployment --name=my-service # expose可以在命令行创建服务 ❯ kubectl get svc my-service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-service ClusterIP 10.104.250.157 <none> 80/TCP 8s ❯ kubectl run --rm -it --image=busybox --generator=run-pod/v1 test-pod If you don't see a command prompt, try pressing enter. / # wget -q -O- http://10.104.250.157 # 内部访问 <h1>Hello Kubernetes!</h1> ❯ kubectl port-forward svc/my-service 7000:80 Forwarding from 127.0.0.1:7000 -> 80 Forwarding from [::1]:7000 -> 80 |
现在通过http://127.0.0.1:7000/就可以访问了,当然这种方案只适合在开发中的,因为维护线上转发关系非常麻烦。
NodePort
前面我们已经体验使用 NodePort 类型的 Service 把应用暴露给外部用户访问:
❯ kubectl get svc k8s-demo-svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE k8s-demo-svc NodePort 10.97.121.169 <none> 80:31112/TCP 1d5h |
这样就可以通过http://127.0.0.1:31112/访问 k8s-demo-svc 服务了
LoadBalancer
LoadBalancer 类型的 Service 是在 NodePort 的基础上,借助云服务商 (如 AWS、Azure、DigitalOcean、阿里云等) 创建一个外部的负载均衡器,并将请求转发到节点的 NodePort 上:
这种方式首先要求服务器有公网 IP,我的云服务器也都在容器中,没有直接包含公网 IP,所以不能演示,下面只是本地体验一下:
❯ kubectl expose deployment/k8s-demo-deployment --name=lb-service --port=8000 --target-port=80 --type=LoadBalancer service/lb-service exposed ❯ kubectl get svc lb-service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE lb-service LoadBalancer 10.104.247.244 localhost 8000:32097/TCP 3s |
注意 EXTERNAL-IP 一栏是 localhost,和 NodePort 类型一样,现在打开http://127.0.0.1:8000/就可以访问了
Ingress
对于小规模的应用我们使用 NodePort 可以满足基本需求,但是当你的应用越来越多的时候,你就会发现维护大量的 NodePort 非常麻烦,这就引出了 Ingress。Ingress 不是一种 Service 类型,而是独立的资源对象,它包含路由到 Service 的规则集合,这样会将外部的请求转发到集群内不同的 Service 上,其实就相当于 Nginx (upstream)、Haproxy 等负载均衡代理服务器的作用,如图所示:
为了使 Ingress 正常工作,集群中必须运行 Ingress Controller: 可以理解是一个监听器,通过不断地与 k8s API 交互,实时的感知后端 Service、Pod 的变化,当得到这些变化信息后,Ingress Controller 结合 Ingress 的配置,更新反向代理负载均衡器,达到服务发现的作用。其实这点和服务发现工具 Consul consul-template 非常类似。Ingress Controller 可选择的非常多,具体列表的可以看延伸阅读链接 6 的官网地址,我选的是 Traefik , Traefik 是一款开源的 HTTP 反向代理与负载均衡工具,架构图如下:
我们安装它。这次搞起来非常的麻烦了,容我细细道来。我在 macOS 上安装 Kubernetes 是 上篇文章提到的方法一: Docker Desktop for Mac + Enable Kubernetes 方案,但是这样拿不到虚拟机的 IP (如果有同学知道怎么找请赐教~),后面就没法体验了,好消息是 Docker Desktop 支持切换 Context,所以可以用我上文提到的「命令行安装」方案安装和启动 Minikube,安装后自动设置 Context 为 minikube:
❯ kubectl config current-context
minikube
# 如果输出的是docker-desktop,可以执行`kubectl config set current-context minikube`
|
切换上下文后,原来启动的 Deployment、Service 都没有了,需要重新创建。要注意,k8s-demo 镜像也需要重新 build,需要这样:
❯ eval $(minikube docker-env) ❯ docker build -t k8s-demo:0.2 . ❯ kubectl create -f deployment.yaml error: unable to recognize "deployment.yaml": no matches for kind "Deployment" in version "apps/v1beta1" |
我没有搜到使用 minikube 在 API 环境上和 docker-desktop 有什么区别,但需要修改 (deployment.yaml),看 diff 效果 (- 表示修改前,+ 表示修改后):
--- a/deployment.yaml +++ b/deployment.yaml @@ -1,8 +1,11 @@ -apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: k8s-demo-deployment spec: + selector: + matchLabels: + app: k8s replicas: 10 minReadySeconds: 3 strategy: |
这样就可以创建 Deployment 和 Service:
❯ kubectl create -f deployment.yaml ❯ kubectl create -f svc.yaml |
接着安装 Traefik:
❯ git clone https://github.com/containous/traefik ❯ cd traefik ❯ gco -b v1.7 origin/v1.7 # 切到v1.7分支 ❯ kubectl apply -f examples/k8s/traefik-rbac.yaml ❯ kubectl apply -f examples/k8s/traefik-ds.yaml # 使用Daemon Set版本 ❯ curl $(minikube ip) 404 page not found |
现在还没有配置路有规则,所以访问请求时 404,接着安装 Web UI,它就是一个 ingress:
❯ kubectl apply -f examples/k8s/ui.yaml # Traefik的Web UI ❯ kubectl get ing -n kube-system NAME HOSTS ADDRESS PORTS AGE traefik-web-ui traefik-ui.minikube 80 49m ❯ echo "$(minikube ip) traefik-ui.minikube" | sudo tee -a /etc/hosts # 写本地hosts,这样就可以通过域名的方式访问了 192.168.64.6 traefik-ui.minikube # 192.168.64.6就是minikube虚拟机的IP |
Minikube 和 Docker-desktop 的最大区别就是它有虚拟机 IP,运行的 Traefik 服务端口就绑定在这个 IP 上。接着访问http://traefik-ui.minikube就可以看到 Traefik 的 Web 页面:
ui.yaml
就是一个基于虚拟机主机方式的 Ingress,看一下这部分的配置:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: traefik-web-ui namespace: kube-system spec: rules: - host: traefik-ui.minikube http: paths: - path: / backend: serviceName: traefik-web-ui servicePort: web |
所以当请求traefik-ui.minikube
这个域名,就会基于这个配置去找traefik-web-ui
服务 (也在 ui.yaml 配置的)。接着把我们的 k8s-demo-svc 服务也暴露出来 (ingress.yaml):
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: k8s-demo-ingress spec: backend: serviceName: k8s-demo-svc servicePort: 80 |
创建并加 hosts 文件:
❯ kubectl apply -f ingress.yaml ingress.networking.k8s.io/k8s-demo-ingress created ❯ echo "$(minikube ip) k8s-demo.dongwm.com" | sudo tee -a /etc/hosts 192.168.64.6 k8s-demo.dongwm.com |
现在访问http://k8s-demo.dongwm.com/就可以到达 k8s-demo-svc 服务了。访问 Traefik 的面板也可以看到新增的配置了:
项目源码
本文提到的全部源码可以在 mp 找到。
延伸阅读
- https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
- https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler
- https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler
- https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0
- https://kubernetes.io/docs/concepts/services-networking/ingress/
- https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/#additional-controllers