🍣
PodをCronJobで停止・起動する
テスト環境などでFargateなどを利用している場合、Podが夜間や休日に起動しているとお金がかかるため停止したいということがあるかと思います。
そういった際に利用できるCronJobで停止・起動をスケジュール化する方法についてです。
Shellなどでも実現できると思いますが、複数のDeploymentのReplicasを変更したいため、client-goを利用してコードを書いていきます。
ツール(イメージの作成)
概要
利用するライブラリは以下になります。
- client-go(v0.27.3)
- gopkg.in/yaml.v3(v3.0.1)
実現方法は、config.yamlに以下のような設定を書けば、deploymentを指定したreplicasに変更するようにします。
config.yaml
deployments:
- namespace: auth
name: auth-deployment
replicas: 0
コード
main.go
package main
import (
"log"
)
func main() {
log.Println("start")
config := getConfig()
for _, v := range config.Deployments {
scale(&v)
}
log.Println("end")
}
config.go
package main
import (
"log"
"os"
"gopkg.in/yaml.v3"
)
type Deployment struct {
Namespace string
Name string
Replicas int
}
type Config struct {
Deployments []Deployment
}
func getConfig() Config {
config := Config{}
b, _ := os.ReadFile("config.yaml")
err := yaml.Unmarshal(b, &config)
if err != nil {
log.Panic(err)
}
return config
}
cluster-operator.go
package main
import (
"context"
"log"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
func scale(deploymentConfig *Deployment) {
clusterConfig, err := rest.InClusterConfig()
if err != nil {
log.Panic(err.Error())
}
clientset, err := kubernetes.NewForConfig(clusterConfig)
if err != nil {
log.Panic(err.Error())
}
deploymentsClient := clientset.AppsV1().Deployments(deploymentConfig.Namespace)
s, err := deploymentsClient.GetScale(context.TODO(), deploymentConfig.Name, v1.GetOptions{})
if err != nil {
log.Panic(err)
}
sc := *s
sc.Spec.Replicas = int32(deploymentConfig.Replicas)
_, err = deploymentsClient.UpdateScale(context.TODO(), deploymentConfig.Name, &sc, v1.UpdateOptions{})
if err != nil {
log.Panic(err)
}
log.Printf("namespace:%s, deployment:%s scaled to %d", deploymentConfig.Namespace, deploymentConfig.Name, deploymentConfig.Replicas)
}
# Build
FROM golang:1.20-buster As Build
WORKDIR /app
COPY go.mod ./
COPY go.sum ./
RUN go mod download
COPY *.go ./
RUN go build -o /deployment-scaler
# Deploy
FROM gcr.io/distroless/base-debian11:latest
WORKDIR /
COPY /deployment-scaler /deployment-scaler
USER nonroot:nonroot
ENTRYPOINT ["/deployment-scaler"]
イメージの作成
$ docker build -t deployment-scaler:1.0.0 ./
マニフェストの作成
実際にJobを作成し確認する
まずはJobで簡単に確認します。
job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: deployment-scaler
spec:
template:
spec:
restartPolicy: Never
serviceAccountName: deployment-scaler-service-account
containers:
- name: deployment-scaler
image: deployment-scaler:1.0.0
volumeMounts:
- mountPath: /config.yaml
subPath: config.yaml
name: config-volume
readOnly: true
volumes:
- name: config-volume
configMap:
name: deployment-scaler-config
backoffLimit: 4
---
apiVersion: v1
kind: ConfigMap
metadata:
name: deployment-scaler-config
data:
config.yaml: |
deployments:
- namespace: default
name: web-nginx
replicas: 0
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: deployment-scaler-service-account
rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-scaler-role
rules:
- apiGroups:
- "apps"
resources:
- deployments/scale
verbs:
- get
- list
- patch
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: deployment-scaler-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: deployment-scaler-role
subjects:
- kind: ServiceAccount
name: deployment-scaler-service-account
namespace: default
実行
$ k get pods
NAMESPACE NAME READY STATUS RESTARTS AGE
default web-nginx-669489d776-wwnqn 1/1 Running 2 (42m ago) 4d19h
$ k apply -f rbac.yaml
clusterrolebinding.rbac.authorization.k8s.io/deployment-scaler-role-binding created
$ k apply -f job.yaml
job.batch/deployment-scaler created
configmap/deployment-scaler-config created
serviceaccount/deployment-scaler-service-account created
$ k get pods
NAMESPACE NAME READY STATUS RESTARTS AGE
default deployment-scaler-9zr8w 0/1 ContainerCreating 0 2s
default web-nginx-669489d776-wwnqn 0/1 Terminating 2 (43m ago) 4d19h
$ k logs deployment-scaler-9zr8w
2023/07/25 20:47:48 start
2023/07/25 20:47:48 namespace:default, deployment:web-nginx scaled to 0
2023/07/25 20:47:48 end
CronJobを作成する
今度は実際にCronJobで確認します。
configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: deployment-scaler-start-config
data:
config.yaml: |
deployments:
- namespace: default
name: web-nginx
replicas: 1
---
apiVersion: v1
kind: ConfigMap
metadata:
name: deployment-scaler-stop-config
data:
config.yaml: |
deployments:
- namespace: default
name: web-nginx
replicas: 0
serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: deployment-scaler-service-account
cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: deployment-scaler-stop
spec:
schedule: "55 20 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: Never
serviceAccountName: deployment-scaler-service-account
containers:
- name: deployment-scaler
image: deployment-scaler:1.0.0
volumeMounts:
- mountPath: /config.yaml
subPath: config.yaml
name: config-volume
readOnly: true
volumes:
- name: config-volume
configMap:
name: deployment-scaler-stop-config
backoffLimit: 4
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: deployment-scaler-start
spec:
schedule: "56 20 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: Never
serviceAccountName: deployment-scaler-service-account
containers:
- name: deployment-scaler
image: deployment-scaler:1.0.0
volumeMounts:
- mountPath: /config.yaml
subPath: config.yaml
name: config-volume
readOnly: true
volumes:
- name: config-volume
configMap:
name: deployment-scaler-start-config
backoffLimit: 4
実行結果
5時54分
$ k get pods
NAME READY STATUS RESTARTS AGE
web-nginx-669489d776-dkjvn 1/1 Running 0 74s
5時55分
$ k get pods
NAME READY STATUS RESTARTS AGE
deployment-scaler-stop-28171975-phjs4 0/1 Completed 0 1s
5時56分
$ k get pods
NAME READY STATUS RESTARTS AGE
deployment-scaler-start-28171976-6swjz 0/1 Completed 0 16s
deployment-scaler-stop-28171975-phjs4 0/1 Completed 0 76s
web-nginx-669489d776-j7rh7 1/1 Running 0 16s
今回のコード
Discussion