Skip to content

Commit

Permalink
Merge pull request #2 from chatwork/change_kubernetes_client
Browse files Browse the repository at this point in the history
Change kubernetes client
  • Loading branch information
cw-sakamoto authored Jun 10, 2022
2 parents 7291470 + 71b7f8f commit 46ce19d
Show file tree
Hide file tree
Showing 14 changed files with 696 additions and 356 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Publish Docker image

on:
push:
tags:
- '*'

jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v2

- name: Set up QEMU
uses: docker/setup-qemu-action@v1

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1

- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Prepare Build Arg
id: prepare_build_arg
run: |
CURRENT_TAG=${GITHUB_REF#refs/tags/}
echo ::set-output name=CURRENT_TAG::${CURRENT_TAG}
- name: Log in to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build and push Docker image to Docker Hub
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/arm64,linux/amd64
push: true
tags: chatwork/kube-schedule-scaler:${{ steps.prepare_build_arg.outputs.CURRENT_TAG }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new

- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
12 changes: 6 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
FROM ubuntu:20.04
FROM ubuntu:22.04
MAINTAINER "[email protected]"

# Install python tools and dev packages
RUN apt-get update \
&& apt-get install -q -y --no-install-recommends python3-pip python3-setuptools python3-wheel gcc cron \
&& apt-get install -q -y --no-install-recommends python3-pip python3-setuptools python3-wheel gcc cron tini \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# set python 3 as the default python version
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1 \
&& update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1

COPY ./requirements.txt /root/
RUN pip3 install --upgrade pip requests setuptools pipenv
RUN pip3 install pykube-ng
RUN pip3 install python-crontab
RUN pip3 install croniter
RUN pip3 install -r /root/requirements.txt

ADD schedule_scaling /root/schedule_scaling
COPY ./run_missed_jobs.py /root
RUN chmod a+x /root/run_missed_jobs.py
COPY ./startup.sh /root
RUN chmod a+x /root/startup.sh
CMD /root/startup.sh
ENTRYPOINT ["tini", "--", "/root/startup.sh"]
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ At the moment it supports reading the scaling definitions from directly in the a

## Usage

### install

https://github.com/chatwork/charts/tree/master/kube-schedule-scaler#tldr

### deployment

Add the annotation to either your `Deployment`.
Expand All @@ -27,7 +31,7 @@ Add the annotation to either your `Deployment`.
zalando.org/schedule-actions: '[{"schedule": "10 18 * * *", "minReplicas": "3"}]'
```

## Available Fields
## Available Fields

The following fields are available
* `schedule` - Typical crontab format
Expand Down Expand Up @@ -102,4 +106,4 @@ spec:
type: Utilization
averageUtilization: 50
```

79 changes: 0 additions & 79 deletions deploy/deployment.yaml

This file was deleted.

53 changes: 53 additions & 0 deletions examples/example-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
zalando.org/schedule-actions: |
[
{"schedule": "45 22 * * *", "replicas": "1"},
{"schedule": "45 1 * * *", "replicas": "0"}
]
labels:
app.kubernetes.io/instance: example
app.kubernetes.io/name: example
name: example-deployment
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/instance: example
app.kubernetes.io/name: example
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/instance: example
app.kubernetes.io/name: example
spec:
containers:
- image: k8s.gcr.io/pause:latest
imagePullPolicy: IfNotPresent
name: example-pause
resources:
limits:
cpu: 100
memory: 128Mi
requests:
cpu: 100
memory: 128Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
priorityClassName: low
restartPolicy: Always
schedulerName: default-scheduler
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
26 changes: 26 additions & 0 deletions examples/example-hpa.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: example-hpa
namespace: default
annotations:
zalando.org/schedule-actions: |
[
{"schedule": "00 08 * * *", "minReplicas": "1", "maxReplicas": 3},
{"schedule": "30 23 * * *", "minReplicas": 2, "maxReplicas": "3"},
{"schedule": "00 09 * * *", "minReplicas": 1, "maxReplicas": "4"}
]
spec:
maxReplicas: 2
minReplicas: 1
metrics:
- resource:
name: cpu
target:
averageUtilization: 50
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: example-deployment
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kubernetes==23.6.0
croniter==1.3.5
python-crontab==2.6.0
29 changes: 17 additions & 12 deletions run_missed_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@
from datetime import datetime
from datetime import timedelta

scaling_cron = CronTab(user='root')
scale_jobs = scaling_cron.find_comment('Scheduling_Jobs')

scaling_cron = CronTab(user="root")
print("[INFO]", datetime.now(), "Running the Jobs of the last 5 minutes")

for job in scale_jobs:
schedule = job.schedule(date_from=datetime.now())
schedule = str(schedule.get_prev())
schedule = time.strptime(schedule, "%Y-%m-%d %H:%M:%S")
retry_execution_threshold = str(datetime.now() - timedelta(minutes=5))
retry_execution_threshold = time.strptime(retry_execution_threshold, "%Y-%m-%d %H:%M:%S.%f")
for target in ["Deployment", "HPA"]:
scale_jobs = scaling_cron.find_comment("Scheduling_Jobs_" + target)

for job in scale_jobs:
# print(job)
schedule = job.schedule(date_from=datetime.now())
schedule = str(schedule.get_prev())
schedule = time.strptime(schedule, "%Y-%m-%d %H:%M:%S")
retry_execution_threshold = str(datetime.now() - timedelta(minutes=5))
retry_execution_threshold = time.strptime(
retry_execution_threshold, "%Y-%m-%d %H:%M:%S.%f"
)

if schedule > retry_execution_threshold:
schedule_to_execute = str(job).split(";")[2]
os.system(schedule_to_execute)
if schedule > retry_execution_threshold:
# 5 7 * * * . /root/.profile ; /usr/bin/python /root/schedule_scaling/deployment-script.py --namespace ... --deployment ... --replicas 9 2>&1 | tee -a ... # Scheduling_Jobs
schedule_to_execute = str(job).split(";")[1]
os.system(schedule_to_execute)
75 changes: 75 additions & 0 deletions schedule_scaling/deployment-script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from kubernetes import client, config
from kubernetes.client.rest import ApiException
import time
import datetime
import random
import os
import sys
import argparse


def patch_deployment(client, deployment, namespace, replicas):
body = {"spec": {"replicas": replicas}}

try:
client.patch_namespaced_deployment(deployment, namespace, body)
except ApiException as err:
print(
"[ERROR]",
datetime.datetime.now(),
"deployment {}/{} has not been patched".format(namespace, deployment),
err,
)
return
except Exception as err:
print(
"[ERROR]",
datetime.datetime.now(),
"Exception! Something went wrong... HPA {}/{} has not been scaled with body: {}".format(
namespace,
deployment,
body,
err,
),
)
return

print(
"[INFO]",
datetime.datetime.now(),
"Deployment {}/{} has been updated to {}".format(namespace, deployment, body),
)


def main():
parser = argparse.ArgumentParser(description="deployment scaling replicas")
parser.add_argument(
"--namespace", "-n", type=str, required=True, help="deployment namespace"
)
parser.add_argument(
"--deployment", "--deploy", type=str, required=True, help="deployment name"
)
parser.add_argument(
"--replicas", type=int, required=True, help="replicas number", default=-1
)
args = parser.parse_args()

time.sleep(random.uniform(1, 10))

if os.getenv("KUBERNETES_SERVICE_HOST"):
config.load_incluster_config()
else:
config.load_kube_config()

v1 = client.AppsV1Api()

patch_deployment(
client=v1,
deployment=args.deployment,
namespace=args.namespace,
replicas=args.replicas,
)


if __name__ == "__main__":
main()
Loading

0 comments on commit 46ce19d

Please sign in to comment.