Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Kubernetes CronJob Implementation in Detail #k8sjp
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Shimpei Otsubo
September 28, 2018
Programming
3.2k
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.4k
Go と Wantedly の関係 / How Wantedly uses Go
potsbo
1
950
Deploy Flow at Wantedly
potsbo
2
1.1k
Wrap every method with just one line
potsbo
1
5.7k
Zero yen Keyboard
potsbo
6
3.4k
Kube - The core tool at Wantedly
potsbo
1
8.6k
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
Kawaiicon: Kubernetes, it's no longer cool, but let's secure it anyway!
barnbarn
0
130
Vue.jsで作る空間解析アプリとCapacitorプラグインのData Bridge
hal_spidernight
1
170
AI駆動開発4年目の現在地(『あなたはFDEになるべきか?』イベント資料)
kumaiu
0
500
自作Discord音声botをLambda MicroVMsに移行した話 / Migrating My Discord Voice Bot to Lambda MicroVMs
akihisaikeda
1
300
느린 네트워크와 저사양 디바이스 사용자를 위한 웹뷰 로딩 시간 개선기
kmkim
1
220
SFCで実現する病院・医療システムの動的組み立て式UI
koukimiura
1
170
protojson における文字化けの扱い
kazuki1023
0
220
そのデザイントークン、Flutterでも同じ見た目になりますか?
nakamizu
0
320
DroidKnights 2026 Android A2UI Jetpack Compose 기반의 안전한 AI UI 렌더링 - 박제창
itsmedreamwalker
1
210
Distance field of Julia set
kinakomoti321
0
310
Rails初心者がパスキーを実装してみて大変だったこと
ktombow
0
160
우리의 Nitro Modules는 당신의 Turbo Modules보다 아름답다
l2hyunwoo
0
260
Featured
See All Featured
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.4k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
560
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
43k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
470
Side Projects
sachag
456
43k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
510
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Building Better People: How to give real-time feedback that sticks.
wjessup
371
20k
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
280
Java REST API Framework Comparison - PWX 2021
mraible
34
9.8k
Balancing Empowerment & Direction
lara
6
1.4k
Utilizing Notion as your number one productivity tool
mfonobong
4
640
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.