本来 k8s 的 crontab 是启动一个容器来运行的,很简单,如下:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: curl-cron
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: curl-cron
image: radial/busyboxplus:curl
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date;echo "run crontab";curl http://www.baidu.com
restartPolicy: OnFailure
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 2
上面就跑了一个 busybox 的 pod,每分钟去访问百度,然后在 stdout 输出结果
这个没什么,注意上面文件的最后两行。限制成功以及失败 job 的 History 数量,如果不加限制,kubectl get pods 会看到无穷无尽的completed 状态的 curl-cron pod。
分割线,部署 crontab 的 yaml 很简单。但是,现在产品部有个需求,他们要在某一天进行促销活动,大概2天,期间会流量大增,于是想应用 hpa 来伸缩 pod,活动结束后关闭 hpa。之后他们还会有不断的促销,研发不知道什么时候开始,什么时候结束;但是研发又不想产品部看到 yaml,并且随时配合部署 hpa。
还有个问题,如果用crontab,那么活动开始运行一次,活动结束一次,最后研发还得清理删除掉这两个 crontab 来恢复正常。
这下麻烦了,有什么页面管理 crontab 的神器,能让产品部自己运行,然后权限分离,而且能指定再未来的某天运行一次或多次,且不用手工清理就好了。
还真的有一个,kala 就是了!!!
Kala 是一个cron管理配置工具,项目地址:

卡拉是基于 Airbnb 的 Chronos 翻写的 Go 程序。
它比 crontab 更好一些的是,可以指定未来某天的一次性执行任务,有个使用界面
Kala 可以执行本地的命令,也可以发起 http 的请求。
注意,kala 的源代码里有一个地方需要修改,否则参数bolt-path不生效,我们改掉它自己编译个2进制程序出来。
Modify cmd/server.go
switch viper.GetString("jobdb") {
case "boltdb":
db = boltdb.GetBoltDB(viper.GetString("boltpath"))
Change to
db = boltdb.GetBoltDB(viper.GetString("bolt-path"))
Run it :
./kala serve --jobdb=boltdb --bolt-path=/data/db
我们用 Dockerfile 造一个镜像出来:
FROM alpine:3.12
RUN apk add --update bash && rm -rf /var/cache/apk/*
COPY . /data/
RUN mkdir /lib64 && \
ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 && \
mv /data/kubectl /bin && \
mv /data/.kube /root && \
rm -rf /data/Dockerfile
WORKDIR /data
EXPOSE 8000
CMD ["/data/kala", "serve","--jobdb=boltdb","--bolt-path=/data/db"]
#CMD /bin/sh -c "while true; do echo hi; sleep 10; done"
注意上面我们把 kubectl 和 .kube 配置一起放进了镜像,当然一些 yaml 和脚本也可以都打进去,然后推到阿里云镜像仓库去(注意安全问题)。
备注 :kala默认的端口是8000,访问 url 是 /webui
然后我们生成一个 secret 放进 k8s
htpasswd -c auth kala-auth
New password:
Re-type new password:
Adding password for user kala
kubectl create secret generic kala-auth --from-file=kala-auth
secret "kala-auth" created
kubectl get secret kala-auth -o yaml
然后我们定义一系列的资源文件,Deployment、SVC、Ingress,其中 ingress 引用了 kala-auth 的 secret,并且指定了 app-root 是 /webui/。
另外 kala 使用了 k8s-kala-5g 的持久化卷,务必事先准备好 pv 和 pvc,不持久化的话 pod 一重启,之前保存的配置信息就全没了。
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kala-deploy
labels:
app: kala
spec:
replicas: 1
selector:
matchLabels:
app: kala
template:
metadata:
labels:
app: kala
spec:
containers:
- name: kala
image: registry.cn-shanghai.aliyun.com/xxx/kala:latest
imagePullPolicy: Always
ports:
- containerPort: 8000
volumeMounts:
- mountPath: /data/db
name: kala-data
volumes:
- name: kala-data
persistentVolumeClaim:
claimName: k8s-kala-5g
---
apiVersion: v1
kind: Service
metadata:
name: kala-svc
labels:
app: kala
spec:
ports:
- name: http
protocol: TCP
port: 8000
targetPort: 8000
selector:
app: kala
type: ClusterIP
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: kala-com-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/block-cidrs: 111.201.134.93/32
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: kala-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - Kala'
nginx.ingress.kubernetes.io/app-root: '/webui/'
spec:
rules:
- host: kala.rendoumi.com
http:
paths:
- path: /
backend:
serviceName: kala-svc
servicePort: 80
这样 kala 就可以从公网访问了,http://kala.rendoumi.com:8000/ ,且需要提供密码才能进入。
下面说一下具体的用法,还是有一些技巧性的,登录进去后的页面:

进入后左上角点击 Create 建立新任务

要填写内容如下:
Job name:起个名字,叫:增大HPA
Command:要运行的脚本:/data/resize.sh 35 (固定扩大ECI的脚本)
Schedule:R0/2021-07-07T06:00:00+08:00/PT0S
这个最重要
这行的格式是这样的:Number of times to repeat/Start Datetime/Interval Between Runs
R0 重复0次,即只执行一次,不重复
2021-07-06T06:00:00+8:00 时间戳,注意时区中国+8:00
PT0S 无延迟0S启动
合起来就是
R0/2021-07-07T06:00:00+08:00/PT0S 就是在2021年7月7日中国时间6点无任何延迟执行一次脚本 resize.sh
- Reset Form 这个一定要选掉,保持空,否则下次进来上次的数据都没了,还得手动输入,麻烦
其他都不填写,然后 Create 就行了
然后我们可以再建一个恢复的任务

我们去界面就可以看到多了两个任务,增大HPA和恢复HPA,这样就 OK 了

注意:JOB一旦建立,以后就可以直接从界面上手动执行,Run Manually

这东西真是个神器,产品部的同事可以随时修改hpa和恢复,而不用通过研发部了,善莫大焉。