最近针对“按业务的需求激活业务应用程序多个复本来执行跑批任务的处理业务数据,单个业务应用程序复本执行完后自动退出”这类需求解决方案的驱使下,最近学习与测试了一下开源 Serverless 项目 Knative,本文将基于 Knative Serving 功能模块方案来实现,后续再更新Knative Eventing 实现方案实践;
主要需求场景说明:
- 单个业务应用程序执行一个请求(长处理任务)
- 可按需启动多个业务应用程序
- 业务应用程序处理后自动退出
本实例环境: kubernetes 1.22 + knative 1.5
一、创建"业务应用"镜像
实例代码,用于模拟业务应用程序;注意这里有一个“WAITSECOND”参数用于模拟长处理任务情况;
# hellotest code for Golang
package main
import (
"fmt"
"log"
"net/http"
"os"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
log.Print("helloworld: received a request")
target := os.Getenv("TARGET")
if target == "" {
target = "World"
}
# WAITSECOND 系统参数定义与处理,如值"30s"
waitSec := os.Getenv("WAITSECOND")
if waitSec != "" {
ws, err := time.ParseDuration(waitSec)
if err != nil {
fmt.Fprintf(w, "please to specify a available WAITSECOND value. %s!\n", err)
}
time.Sleep(ws)
fmt.Fprintf(w, "Hello %s! wait time %s\n", target, waitSec)
return
}
fmt.Fprintf(w, "Hello %s!\n", target)
}
func main() {
log.Print("helloworld: starting server...")
http.HandleFunc("/", handler)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("helloworld: listening on port %s", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}
将代码编译后制作成镜像(hellotest),并上传至镜像仓库
FROM alpine:latest
MAINTAINER "SA <itservice@xxxxx.com>"
RUN apk add --no-cache tzdata curl && \
mkdir -p /var/log/ /lib64 && \
ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
ENV TZ="Asia/Shanghai" PATH=$PATH:/bin/hellotest
WORKDIR /bin
COPY hellotest /bin/
EXPORT 8080
RUN chmod +x /bin/hellotest
CMD ["/bin/hellotest"]
二、创建 knative Service 实例
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: ksvr-samples
namespace: default
spec:
template:
spec:
imagePullSecrets:
- name: habor-registry-secret
containerConcurrency: 1
containers:
- image: registry-dev.xxxxxx.com/ops/hellotest:1.0 #私有镜像库仓
env:
- name: TARGET
value: "Sample V1"
- name: WAITSECOND
value: "60s"
三、测试验证
- 查看 ksvc 运行状态与生成域名信息
[k8s/]# kubectl get rt
NAME URL READY REASON
ksvr-samples http://ksvr-samples.default.example.com True
[k8s /]# kubectl get ksvc
NAME URL LATESTCREATED LATESTREADY READY REASON
ksvr-samples http://ksvr-samples.default.example.com ksvr-samples-00002 ksvr-samples-00002 True
- 在环境(POD)内向sample应用发起两个http请求
# http://kourier-internal.kourier-system.svc.cluster.local 为ingress地址
# jenkins-sa-84cf764768-hjb89 为另外的一个应用pod,仅为执行访问之用
kubectl exec -it jenkins-sa-84cf764768-hjb89 -- curl -H "Host: ksvr-samples.default.example.com" http://kourier-internal.kourier-system.svc.cluster.local
- 查看sample POD的扩容状态(2+1)
[k8s/]# kubectl get pod
NAME READY STATUS RESTARTS AGE
ksvr-samples-00002-deployment-6f6dc75579-grgbh 0/2 ContainerCreating 0 11s
ksvr-samples-00002-deployment-6f6dc75579-wkcpd 2/2 Running 0 25s
ksvr-samples-00002-deployment-6f6dc75579-nsqd5 2/2 Running 0 25s
- 查看无请求空闲状态下缩容状态
[k8s /]# kubectl get pod -w
ksvr-samples-00002-deployment-6f6dc75579-grgbh 2/2 Terminating 0 84s
ksvr-samples-00002-deployment-6f6dc75579-wkcpd 2/2 Terminating 0 96s
ksvr-samples-00002-deployment-6f6dc75579-grgbh 0/2 Terminating 0 116s
ksvr-samples-00002-deployment-6f6dc75579-grgbh 0/2 Terminating 0 116s
ksvr-samples-00002-deployment-6f6dc75579-grgbh 0/2 Terminating 0 116s
ksvr-samples-00002-deployment-6f6dc75579-nsqd5 2/2 Terminating 0 2m8s
ksvr-samples-00002-deployment-6f6dc75579-wkcpd 0/2 Terminating 0 2m8s
ksvr-samples-00002-deployment-6f6dc75579-wkcpd 0/2 Terminating 0 2m8s
ksvr-samples-00002-deployment-6f6dc75579-wkcpd 0/2 Terminating 0 2m8s
ksvr-samples-00002-deployment-6f6dc75579-nsqd5 0/2 Terminating 0 2m40s
ksvr-samples-00002-deployment-6f6dc75579-nsqd5 0/2 Terminating 0 2m40s
ksvr-samples-00002-deployment-6f6dc75579-nsqd5 0/2 Terminating 0 2m40s
四、其它
默认 Serving 在无请求状态下将POD缩容至'零',在零POD状态下由activator接管,当新的请求到来时会有一个init初始化应用POD时间请求延迟问题。如果需要保留最小一个复本来解决init延迟,可能通过全局配置来改变 knative serving的默认行为。
关闭 自动缩容至 0 个复本;关闭后默认最小缩容复本为 1
kubectl edit configmaps -n knative-serving config-autoscaler
# 自动缩容至零参数开关;默认值为true,调整为false
enable-scale-to-zero: "false"
完整的autoscaler全局ConfigMap配置yaml
[k8s /]# cat knative/config-autoscaler.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: config-autoscaler
namespace: knative-serving
data:
container-concurrency-target-percentage: "70"
container-concurrency-target-default: "100"
requests-per-second-target-default: "200"
target-burst-capacity: "211"
stable-window: "60s"
panic-window-percentage: "10.0"
panic-threshold-percentage: "200.0"
max-scale-up-rate: "1000.0"
max-scale-down-rate: "2.0"
enable-scale-to-zero: "false" # 自动缩容至零
scale-to-zero-grace-period: "30s"
scale-to-zero-pod-retention-period: "0s"
pod-autoscaler-class: "kpa.autoscaling.knative.dev"
activator-capacity: "100.0"
initial-scale: "1"
allow-zero-initial-scale: "false"
min-scale: "0"
max-scale: "0"
scale-down-delay: "0s"
max-scale-limit: "0"
总结:
此实践中基于对http协议的请求来触发应用服务资源的扩容需求,此实践中最核心的是对Knative Service 的定义指定请求并数为1(containerConcurrency: 1),即每个应用POD并发请求为1,多个请求将创建多POD复本。实践中也常通过事件来触发应用服务资源如事件源 MQ 、Kafka、Github等等,后续将另外更新说明Eventing模块实践。
~~~ FINISH ~~~
网友评论