Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Kubernetes CronJob Implementation in Detail #k8sjp
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Shimpei Otsubo
September 28, 2018
Programming
3.1k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Kubernetes CronJob Implementation in Detail #k8sjp
Shimpei Otsubo
September 28, 2018
More Decks by Shimpei Otsubo
See All by Shimpei Otsubo
Copy Kubernetes Clusters Really Fast
potsbo
3
5.2k
Go と Wantedly の関係 / How Wantedly uses Go
potsbo
1
910
Deploy Flow at Wantedly
potsbo
2
1.1k
Wrap every method with just one line
potsbo
1
5.6k
Zero yen Keyboard
potsbo
6
3.3k
Kube - The core tool at Wantedly
potsbo
1
8.3k
k8s - Kubernetes 8 Factors
potsbo
12
11k
コンテンツ作成に集中するためのプレゼンテーション Tips / Presentation with Confidence
potsbo
7
42k
ConfigMap vs Secret #k8sjp
potsbo
1
1.5k
Other Decks in Programming
See All in Programming
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
150
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
AIエージェントの隔離技術の徹底比較
kawayu
0
470
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
180
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
3.4k
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
130
AIチームを指揮するOSS「TAKT」活用術 / How to Use “TAKT,” an OSS Tool for Orchestrating AI Teams
nrslib
6
850
Contextとはなにか
chiroruxx
0
150
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
180
JavaDoc 再入門
nagise
0
310
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
220
Old Dog, New Tricks: The Java 25 Reinvention - JNation
bazlur_rahman
0
150
Featured
See All Featured
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
380
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
450
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
140
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
22k
My Coaching Mixtape
mlcsv
0
140
The Cult of Friendly URLs
andyhume
79
6.9k
Designing for Performance
lara
611
70k
GitHub's CSS Performance
jonrohan
1033
470k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
0
1.6k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.3k
Transcript
©2018 Wantedly, Inc. CronJob Implementation in Detail ίʔυ͔ΒಡΈղ͘ CronJob ͷৄࡉ༷
Kubernetes Meetup Tokyo #13 28.Sep.2018 - Shimpei Otsubo - @potsbo
CronJob ʹ·͞Ε͖ͯͨʜ ࣮ߦ࿙Ε ࣮ߦΕ ҙਤ͠ͳ͍࣮ߦ ਂ༻ͷॏ͍+PC͕னؒʹಈ͍ͯ*ODJEFOU &SSPSʹ$PNQMFUFʹ͍ͳ͍ʜ ఔฏؾͰΕΔ BQQMZͨ͠ॠؒʹಈ͍ͯ͠·͏ EFMFUFDSFBUFͩͱൃੜ͠ͳ͍
©2018 Wantedly, Inc.
ຊ൪Ϋϥελͷ$SPO+PCͷԆΛܭଌͯ͠Έͨ ඵ༨༟ඵฏؾͰΕΔ n = 475 $SPO+PCԆώετάϥϜ 0 30 60 Ԇ
ඵ <5 <10 <15 <20 <25 <30 <35 <40 <45 <50 <55 <60 <65 <70 <75 <80 ݸ ˞4UBSUJOH%FBEMJOF4FDPOET͕ͷͷ ©2018 Wantedly, Inc.
// Run the main goroutine responsible for watching and syncing
jobs. func (jm *CronJobController) Run(stopCh <-chan struct{}) { defer utilruntime.HandleCrash() glog.Infof("Starting CronJob Manager") // Check things every 10 second. go wait.Until(jm.syncAll, 10*time.Second, stopCh) <-stopCh glog.Infof("Shutting down CronJob Manager") } $SPO+PC$POUSPMMFS͕ಈ͖࢝ΊΔGVOD ©2018 Wantedly, Inc.
// Run the main goroutine responsible for watching and syncing
jobs. func (jm *CronJobController) Run(stopCh <-chan struct{}) { defer utilruntime.HandleCrash() glog.Infof("Starting CronJob Manager") // Check things every 10 second. go wait.Until(jm.syncAll, 10*time.Second, stopCh) <-stopCh glog.Infof("Shutting down CronJob Manager") } FWFSZTFDPOEͱॻ͍ͯ͋Δ͕࣮શ෦ॲཧඵεϦʔϓ $SPO+PC͕ଟ͍ͱ୯ҐͰΕΔ͜ͱ͋Γͦ͏ ˞ҰճͷTZOD"MMʹຊʹͦΜͳʹ͕͔͔͍࣌ؒͬͯΔͷ͔ະܭଌ ©2018 Wantedly, Inc.
func syncOne(sj *batchv1beta1.CronJob, js []batchv1.Job, now time.Time, jc jobControlInterface, sjc
sjControlInterface, pc podControlInterface, recorder record.EventRecorder) { // 50+ lines omitted times, err := getRecentUnmetScheduleTimes(*sj, now) if err != nil { return } // 10+ lines omitted scheduledTime := times[len(times)-1] tooLate := false if sj.Spec.StartingDeadlineSeconds != nil { tooLate = scheduledTime.Add(time.Second * time.Duration(*sj.Spec.StartingDeadlineSeconds)).Before(now) } if tooLate { return } // 30 lines omitted jobReq, err := getJobFromTemplate(sj, scheduledTime) if err != nil { return } jobResp, err := jc.CreateJob(sj.Namespace, jobReq) if err != nil { return } // 20+ lines omitted return } ˞దٓ؆ུԽ
func syncOne(sj *batchv1beta1.CronJob, js []batchv1.Job, now time.Time, jc jobControlInterface, sjc
sjControlInterface, pc podControlInterface, recorder record.EventRecorder) { // 50+ lines omitted times, err := getRecentUnmetScheduleTimes(*sj, now) if err != nil { return } // 10+ lines omitted scheduledTime := times[len(times)-1] tooLate := false if sj.Spec.StartingDeadlineSeconds != nil { tooLate = scheduledTime.Add(time.Second * time.Duration(*sj.Spec.StartingDeadlineSeconds)).Before(now) } if tooLate { return } // 30 lines omitted jobReq, err := getJobFromTemplate(sj, scheduledTime) if err != nil { return } jobResp, err := jc.CreateJob(sj.Namespace, jobReq) if err != nil { return } // 20+ lines omitted return } ະ࣮ߦ࣌ࠁҰཡΛऔಘ ˞దٓ؆ུԽ
func syncOne(sj *batchv1beta1.CronJob, js []batchv1.Job, now time.Time, jc jobControlInterface, sjc
sjControlInterface, pc podControlInterface, recorder record.EventRecorder) { // 50+ lines omitted times, err := getRecentUnmetScheduleTimes(*sj, now) if err != nil { return } // 10+ lines omitted scheduledTime := times[len(times)-1] tooLate := false if sj.Spec.StartingDeadlineSeconds != nil { tooLate = scheduledTime.Add(time.Second * time.Duration(*sj.Spec.StartingDeadlineSeconds)).Before(now) } if tooLate { return } // 30 lines omitted jobReq, err := getJobFromTemplate(sj, scheduledTime) if err != nil { return } jobResp, err := jc.CreateJob(sj.Namespace, jobReq) if err != nil { return } // 20+ lines omitted return } ൃݟ͕͗ͨ͢ʁఆ ະ࣮ߦ࣌ࠁҰཡΛऔಘ ˞దٓ؆ུԽ
func syncOne(sj *batchv1beta1.CronJob, js []batchv1.Job, now time.Time, jc jobControlInterface, sjc
sjControlInterface, pc podControlInterface, recorder record.EventRecorder) { // 50+ lines omitted times, err := getRecentUnmetScheduleTimes(*sj, now) if err != nil { return } // 10+ lines omitted scheduledTime := times[len(times)-1] tooLate := false if sj.Spec.StartingDeadlineSeconds != nil { tooLate = scheduledTime.Add(time.Second * time.Duration(*sj.Spec.StartingDeadlineSeconds)).Before(now) } if tooLate { return } // 30 lines omitted jobReq, err := getJobFromTemplate(sj, scheduledTime) if err != nil { return } jobResp, err := jc.CreateJob(sj.Namespace, jobReq) if err != nil { return } // 20+ lines omitted return } +PCൃߦ ൃݟ͕͗ͨ͢ʁఆ ະ࣮ߦ࣌ࠁҰཡΛऔಘ ˞దٓ؆ུԽ
func getRecentUnmetScheduleTimes(sj batchv1beta1.CronJob, now time.Time) ([]time.Time, error) { starts :=
[]time.Time{} sched, err := cron.ParseStandard(sj.Spec.Schedule) if err != nil { return starts, fmt.Errorf("Unparseable schedule: %s : %s", sj.Spec.Schedule, err) } var earliestTime time.Time if sj.Status.LastScheduleTime != nil { earliestTime = sj.Status.LastScheduleTime.Time } else { earliestTime = sj.ObjectMeta.CreationTimestamp.Time } if sj.Spec.StartingDeadlineSeconds != nil { // Controller is not going to schedule anything below this point schedulingDeadline := now.Add(-time.Second * time.Duration(*sj.Spec.StartingDeadlineSeconds)) if schedulingDeadline.After(earliestTime) { earliestTime = schedulingDeadline } } if earliestTime.After(now) { return []time.Time{}, nil } for t := sched.Next(earliestTime); !t.After(now); t = sched.Next(t) { starts = append(starts, t) } return starts, nil } ˞దٓ؆ུԽ
func getRecentUnmetScheduleTimes(sj batchv1beta1.CronJob, now time.Time) ([]time.Time, error) { starts :=
[]time.Time{} sched, err := cron.ParseStandard(sj.Spec.Schedule) if err != nil { return starts, fmt.Errorf("Unparseable schedule: %s : %s", sj.Spec.Schedule, err) } var earliestTime time.Time if sj.Status.LastScheduleTime != nil { earliestTime = sj.Status.LastScheduleTime.Time } else { earliestTime = sj.ObjectMeta.CreationTimestamp.Time } if sj.Spec.StartingDeadlineSeconds != nil { // Controller is not going to schedule anything below this point schedulingDeadline := now.Add(-time.Second * time.Duration(*sj.Spec.StartingDeadlineSeconds)) if schedulingDeadline.After(earliestTime) { earliestTime = schedulingDeadline } } if earliestTime.After(now) { return []time.Time{}, nil } for t := sched.Next(earliestTime); !t.After(now); t = sched.Next(t) { starts = append(starts, t) } return starts, nil } Ͳͷఔաڈ͔Β୳͔͢ʁ ˞దٓ؆ུԽ
func getRecentUnmetScheduleTimes(sj batchv1beta1.CronJob, now time.Time) ([]time.Time, error) { starts :=
[]time.Time{} sched, err := cron.ParseStandard(sj.Spec.Schedule) if err != nil { return starts, fmt.Errorf("Unparseable schedule: %s : %s", sj.Spec.Schedule, err) } var earliestTime time.Time if sj.Status.LastScheduleTime != nil { earliestTime = sj.Status.LastScheduleTime.Time } else { earliestTime = sj.ObjectMeta.CreationTimestamp.Time } if sj.Spec.StartingDeadlineSeconds != nil { // Controller is not going to schedule anything below this point schedulingDeadline := now.Add(-time.Second * time.Duration(*sj.Spec.StartingDeadlineSeconds)) if schedulingDeadline.After(earliestTime) { earliestTime = schedulingDeadline } } if earliestTime.After(now) { return []time.Time{}, nil } for t := sched.Next(earliestTime); !t.After(now); t = sched.Next(t) { starts = append(starts, t) } return starts, nil } Ͳͷఔաڈ͔Β୳͔͢ʁ ͦͷաڈ͔Βࠓ·ͰϚον͢Δ࣌ࠁΛϦετ ˞దٓ؆ུԽ
$SPO+PC͔Β+PCൃߦ·ͰͷྲྀΕ ʮ࠷ޙͷ࣮ߦ࣌ࠁcc࡞࣌ࠁʯ͔Βࠓ·Ͱͷ࣌ࠁީิͷ࠷ޙ͕ StartingDeadlineSeconds ҎͳΒ࣮ߦ ©2018 Wantedly, Inc.
$SPO+PCͷBQQMZ࣌ʹ͍͖ͳΓKPC͕Γग़͢ ໌͔ΒAM 3:00 ʹಈ͍ͯ΄͍͠ 1:00 AM 3:00 AM ୳͢ൣғ 3:00
AM ະ࣮ߦఆ ?:?? ?? ҙਤ͠ͳ͍Job࣮ߦ ࠓͷAM 1:00 ͔Β apply ͷॠؒ·ͰʹࠓͷAM 3:00 ͕ೖͬͯ͠·͏ apply ͷޙʮະ࣮ߦͷ+PCͩʯͱೝࣝ͞Εͯͦͷॠؒಈ͖ग़͢ apply StartingDeadlineSeconds͕খ͚͞Ε͜͜ͰTLJQͯ͠Β͑Δ ࠓ ໌ ࡢ ࠷ޙ 1:00 AM ©2018 Wantedly, Inc.
$SPO+PCͷBQQMZ࣌ʹ͍͖ͳΓKPC͕Γग़͢ ໌͔ΒAM 3:00 ʹಈ͍ͯ΄͍͠ delete/createͩͱ࡞ΒΕͨ࡞ΒΕͨॠ͔ؒΒ୳࢝͠ΊΔͷͰ࣍ͷ".·Ͱ࣮ߦ͞Εͳ͍ ͨͩ͠Ұॠͱ͍͑ CronJob ͕ଘࡏ͠ͳ͍Մೳੑ͕͋ΔͷͰ·ͱΊͯΔͱ࣮ߦ࿙ΕϦεΫ 1:00 AM
3:00 AM delete/create ࠓ ໌ ࡢ 1:00 AM ©2018 Wantedly, Inc.
·ͱΊ ίʔυҙ֎ͱಡΊΔ CronJob ؆୯ʹΕΔ 4UBSUJOH%FBEMJOF4FDPOET৻ॏʹ ©2018 Wantedly, Inc.