Skip to content

Commit

Permalink
My first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahmed ElBakry committed Sep 5, 2019
0 parents commit 5bc580b
Show file tree
Hide file tree
Showing 20 changed files with 1,635 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__
.idea
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
From ubuntu:16.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 \
&& 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
RUN pip3 install --upgrade pip requests setuptools pipenv
RUN pip3 install pykube
RUN pip3 install python-crontab
RUN pip3 install croniter
RUN apt-get update && apt-get install -y apt-transport-https curl gnupg sudo \
&& curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
RUN sudo touch /etc/apt/sources.list.d/kubernetes.list \
&& echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
RUN sudo apt-get update \
&& sudo apt-get install -y kubectl cron

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
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

117 changes: 117 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Kubernetes Schedule Scaler

This Application/ Kubernetes controller is used to schedule scale deployments and other custom resources in the cluster like Stackset based in annotations.
The controller can work in conjunction with hpa. if hpa is configured the controller can adjust minReplicas and maxReplicas.
At the moment it supports reading the scaling definitions from:
- directly in the annotations
- JSON files in S3 bucket
- The S3 bucket should be exist and the controller/pod should have read access to the bucket. by
Using this way you do not have to redeploy your application if you need to change the scaling definitions


## Usage


Just add the annotation to either your `Deployment` or `Stackset`.

```
annotations:
zalando.org/schedule-actions: '[{"schedule": "10 18 * * *", "replicas": "3"}]'
```

or

you can add your scaling definitions in json file and upload the file to S3 bucket.

```
annotations:
zalando.org/schedule-actions: s3://schedule-scaling/catalog.json
```
Note:
- The controller should have access to the bucket s3://schedule-scaling/
- Example of the JSON files are in the folder s3-json-files/
## Available Fields

The following fields are available
* `schedule` - Typical crontab format
* `replicas` - the number of replicas to scale to
* `minReplicas` - in combination with an `hpa` will adjust the `minReplicas` else be ignored
* `maxReplicas` - in combination with an `hpa` will adjust the `maxReplicas` else be ignored

### Deployment Example

```bash
kind: Deployment
metadata:
name: nginx-deployment
labels:
application: nginx-deployment
annotations:
zalando.org/schedule-actions: |
[
{"schedule": "30 4 * * 1,2,3,4,5", "minReplicas": "{{{HIGH_LOAD_REPLICAS}}}"},
{"schedule": "00 8 * * 1,2,3,4,5", "minReplicas": "{{{REPLICAS}}}"},
{"schedule": "00 21 * * 1,2,3,4,5", "minReplicas": "{{{MIN_REPLICAS}}}"},
{"schedule": "30 5 * * 6,7", "minReplicas": "{{{HIGH_LOAD_REPLICAS}}}"},
{"schedule": "00 9 * * 6,7", "minReplicas": "{{{REPLICAS}}}"},
{"schedule": "00 21 * * 6,7", "minReplicas": "{{{MIN_REPLICAS}}}"}
]
```



### StackSet Example

```bash
apiVersion: zalando.org/v1
kind: StackSet
metadata:
name: {{{APPLICATION_NAME}}}
labels:
application: "{{{APPLICATION}}}"
stage: "{{{STAGE}}}"
annotations:
zalando.org/schedule-actions: '[{"schedule": "00 06 * * *", "replicas": "20"}, {"schedule": "30 14 * * *", "replicas": "{{{REPLICAS}}}", "minReplicas": "{{{REPLICAS}}}"}]'
```

## Debugging

If your scaling action has not been executed for some reason, you can check with the below steps:

```bash
kubectl get pod | grep kube-schedule
kube-schedule-scaler-75644b8f79-h59s2 1/1 Running 0 3d
```
Check the logs for your specific deployment/stack
```bash
kubectl logs kube-schedule-scaler-75644b8f79-h59s2 | grep scale | grep node-live
Stack pegasus-node-live has been scaled successfully to 40 minReplicas at 11-03-2019 21:00 UTC
Stack pegasus-node-live has been scaled successfully to 120 minReplicas at 12-03-2019 05:30 UTC
Stack pegasus-node-live has been scaled successfully to 80 minReplicas at 12-03-2019 07:00 UTC
Stack pegasus-node-live has been scaled successfully to 40 minReplicas at 12-03-2019 21:00 UTC
Stack pegasus-node-live has been scaled successfully to 120 minReplicas at 13-03-2019 05:30 UTC
Stack pegasus-node-live has been scaled successfully to 80 minReplicas at 13-03-2019 07:00 UTC
Stack pegasus-node-live has been scaled successfully to 40 minReplicas at 13-03-2019 21:00 UTC
Stack pegasus-node-live has been scaled successfully to 120 minReplicas at 14-03-2019 05:30 UTC
Stack pegasus-node-live has been scaled successfully to 80 minReplicas at 14-03-2019 07:00 UTC
Stack pegasus-node-live has been scaled successfully to 40 minReplicas at 14-03-2019 21:00 UTC
Stack pegasus-node-live has been scaled successfully to 120 minReplicas at 15-03-2019 05:30 UTC
Stack pegasus-node-live has been scaled successfully to 80 minReplicas at 15-03-2019 07:00 UTC

```

<p align="center">
<img src="img/pods.png" alt="Pods" title="Pods" />
</p>


Check for specific deployment at specific time
```bash
kubectl logs kube-schedule-scaler-87f9649f5-btnt7 | grep nginx-deployment-2 | grep "28-12-2018 09:50"
Deployment nginx-deployment-2 has been scaled successfully to 4 replica at 28-12-2018 09:50 UTC
```

You can also check from scalyr side
```bash
$application == "kube-schedule-scaler" 'nginx-deployment-2'
```
37 changes: 37 additions & 0 deletions deploy/production/apply/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: operator
namespace: default

apiVersion: apps/v1beta1
kind: Deployment
metadata:
labels:
application: kube-schedule-scaler
version: v0.1
name: kube-schedule-scaler
spec:
replicas: 1
selector:
matchLabels:
application: kube-schedule-scaler
template:
metadata:
labels:
application: kube-schedule-scaler
version: v0.1
annotations:
iam.amazonaws.com/role: "s3-scaling-definitions"
spec:
serviceAccountName: operator
containers:
- name: kube-schedule-scaler
image: "{{{IMAGE}}}"
resources:
limits:
cpu: 1000m
memory: 500Mi
requests:
cpu: 500m
memory: 500Mi
34 changes: 34 additions & 0 deletions deploy/production/apply/iam.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Metadata:
StackName: "s3-scaling-definitions"
AWSTemplateFormatVersion: "2010-09-09"
Description: "Example IAM Role"
Resources:
IAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: "s3-scaling-definitions"
Path: /
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: ec2.amazonaws.com
- Action: sts:AssumeRole
Effect: Allow
Principal:
AWS: "arn:aws:iam::415793546:role/kube-1-worker"
Version: '2012-10-17'
Policies:
- PolicyName: "AllowS3BucketAccess"
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "s3:PutObject"
- "s3:GetObject"
- "s3:DeleteObject"
- "s3:PutObjectAcl"
Resource:
- "arn:aws:s3:::schedule-scaling-production/*"
37 changes: 37 additions & 0 deletions deploy/staging/apply/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: operator
namespace: default

apiVersion: apps/v1beta1
kind: Deployment
metadata:
labels:
application: kube-schedule-scaler
version: v0.1
name: kube-schedule-scaler
spec:
replicas: 1
selector:
matchLabels:
application: kube-schedule-scaler
template:
metadata:
labels:
application: kube-schedule-scaler
version: v0.1
annotations:
iam.amazonaws.com/role: "s3-scaling-definitions"
spec:
serviceAccountName: operator
containers:
- name: kube-schedule-scaler
image: "{{{IMAGE}}}"
resources:
limits:
cpu: 1000m
memory: 500Mi
requests:
cpu: 500m
memory: 500Mi
34 changes: 34 additions & 0 deletions deploy/staging/apply/iam.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Metadata:
StackName: "s3-scaling-definitions"
AWSTemplateFormatVersion: "2010-09-09"
Description: "Example IAM Role"
Resources:
IAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: "s3-scaling-definitions"
Path: /
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: ec2.amazonaws.com
- Action: sts:AssumeRole
Effect: Allow
Principal:
AWS: "arn:aws:iam::1316120916:role/kube-1-worker"
Version: '2012-10-17'
Policies:
- PolicyName: "AllowS3BucketAccess"
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "s3:PutObject"
- "s3:GetObject"
- "s3:DeleteObject"
- "s3:PutObjectAcl"
Resource:
- "arn:aws:s3:::schedule-scaling-staging/*"
Binary file added img/pods.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions run_missed_jobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
import time
from crontab import CronTab
from datetime import datetime
from datetime import timedelta

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

print("Running the Jobs of the last 5 minutes")

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)
46 changes: 46 additions & 0 deletions s3-json-files/production/catalog.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[
{
"schedule": "30 4 * * 1,2,3,4,5",
"minReplicas": "120"
},
{
"schedule": "00 8 * * 1,2,3,4,5",
"minReplicas": "80"
},
{
"schedule": "30 9 * * 1,2,3,4,5",
"minReplicas": "120"
},
{
"schedule": "00 11 * * 1,2,3,4,5",
"minReplicas": "80"
},
{
"schedule": "30 14 * * 5",
"minReplicas": "120"
},
{
"schedule": "30 15 * * 1,2,3,4,6,7",
"minReplicas": "120"
},
{
"schedule": "00 17 * * 1,2,3,4,5,6,7",
"minReplicas": "80"
},
{
"schedule": "00 21 * * 1,2,3,4,5",
"minReplicas": "40"
},
{
"schedule": "30 5 * * 6,7",
"minReplicas": "120"
},
{
"schedule": "00 9 * * 6,7",
"minReplicas": "80"
},
{
"schedule": "00 21 * * 6,7",
"minReplicas": "40"
}
]
30 changes: 30 additions & 0 deletions s3-json-files/production/checkout.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[
{
"schedule": "50 4 * * 1-5",
"minReplicas": "6"
},
{
"schedule": "50 7 * * 1-5",
"minReplicas": "3"
},
{
"schedule": "30 9 * * 1-5",
"minReplicas": "6"
},
{
"schedule": "00 11 * * 1-5",
"minReplicas": "3"
},
{
"schedule": "30 14 * * 5",
"minReplicas": "6"
},
{
"schedule": "50 5 * * 6-7",
"minReplicas": "6"
},
{
"schedule": "50 8 * * 6-7",
"minReplicas": "3"
}
]
Loading

0 comments on commit 5bc580b

Please sign in to comment.