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
Kosko - 改用 JavaScript 來管理 Kubernetes YAML (Kube...
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Tommy Chen
December 22, 2021
Technology
1.5k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Kosko - 改用 JavaScript 來管理 Kubernetes YAML (Kubernetes Summit 2021)
GitHub:
https://github.com/tommy351/kosko/
More info:
https://kosko.dev/
Tommy Chen
December 22, 2021
More Decks by Tommy Chen
See All by Tommy Chen
Kosko - 改用 JavaScript 來管理 Kubernetes YAML (COSCUP 2021)
tommy351
0
150
Kubernetes 101
tommy351
2
350
Socket.io 即時通訊實作
tommy351
0
130
Fast Web Development with Express
tommy351
0
160
An Introduction to Node.js
tommy351
1
380
Other Decks in Technology
See All in Technology
Gifu WordPress Meetup #200 に向けて、私たちには何ができるだろうか?/ 2026-11-07 Gifu WordPress Meetup
torounit
0
250
サボる子はいねぇがー!AgentCoreハーネスの脆弱性に学ぶ、エージェントの入力バリデーション
iwamot
PRO
5
320
Cloudflareの向き先
chimame
1
160
Software Engineering in an AI-Driven World
erikjhordan_rey
0
130
DBTS2026 盛り上がってますか!?Databricksが実現するAI時代のデータ基盤
akuwano
1
200
evcc & Home Assistant
naltatis
0
480
【dbts2026】AIエージェントの 判断と探索を変える、 データベース エンジニアリング― 既存DBの処理と依存関係から作る、オペレーショナルオントロジー ―
shisyu_gaku
0
270
少ない人手 限られた予算 それでも守る 消せない・見つける・戻れる オールハザード型BCP on AWS / 20261107 Mitsutoshi Matsuo
shift_evolve
PRO
0
330
Shared Signals Framework 仕様解説
oidfj
0
330
なぜ東京にいる私が、新潟の技術コミュニティを運営するのか by 八雲慎之助
yakumo
0
230
SREのためのFinOps入門
muziyoshiz
2
940
Kiro Crew 入門 (手を離しても進む仕事) | 目指せ Kiro マスター 11
inariku
PRO
4
660
Featured
See All Featured
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.7k
A Modern Web Designer's Workflow
chriscoyier
699
190k
sira's awesome portfolio website redesign presentation
elsirapls
0
500
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
470
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
3
3.9k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.5k
Building Flexible Design Systems
yeseniaperezcruz
330
41k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
370
The SEO identity crisis: Don't let AI make you average
varn
0
630
Accessibility Awareness
sabderemane
1
290
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
600
Music & Morning Musume
bryan
48
7.5k
Transcript
Kosko 改⽤ JavaScript 來管理 Kubernetes YAML Tommy Chen @ Kubernetes
Summit 2021
About Me ⽬前在 Dcard 當 Architect,是個前後端 都在寫的雜⾷性⼯程師 Blog: https://zespia.tw GitHub:
@tommy351 Twitter: @tommy351
很久以前
2016 年 6 ⽉ • Dcard 剛搬到 Kubernetes 上 •
⼤約有 20 個 components • 分成兩個 Git branch 對應 staging 和 production 環境 • 檔案結構⼤概像這樣 👉
不到⼀年後
Git Branch 無法合併 • 有些 component 只會在其中 ⼀個環境佈署 • Staging
資料量不⾜所以不佈署 • Production 的 DB 佈署在 VM • 有些 config 在不同環境間的差 異很⼤ • Production 的 DB 是 cluster • Staging 會共⽤ DB Production Staging
操作失誤 • 更新到錯的 Kubernetes cluster • 可能會造成 downtime • 改到錯的
Git branch • 因為 branch 無法合併,所以全靠 copy & paste • 沒有事前驗證 YAML 內容 • 即使有 PR review 依然很難避免錯誤發⽣
難以重複使⽤ • YAML anchor 能夠重複使⽤,但無法跨檔案引⽤ • 只能透過 ConfigMap 或 Secret
來共⽤設定 • 只能以環境變數或 volume 的形式使⽤ • 但是設定以外的部分就無法重複使⽤了 • Sidecar • CronJob • 變數 (e.g., domain, image registry) • Component (e.g., PostgreSQL, Redis)
⼜過了⼀年半
現成⽅案 • Helm • Kustomize • Ksonnet (2018 年底)
Helm 👍 優點 • 有很多現成的 chart • 版本管理 • 透過指定不同的
values,即可 佈署到不同的環境 • 內建 Linter 和測試⼯具 👎 缺點 • ⽤ template 寫 YAML 很⿇煩 • ⽐較複雜,需要花時間上⼿ • Helm 佈署的⽅式不同,從 YAML 轉移到 Helm ⽐較困難
Source: ingress-nginx 3.34.0 · kubernetes/ingress-nginx (artifacthub.io) 縮排 😰
Kustomize 👍 優點 • 內建在 kubectl,不須額外安 裝其他⼯具 • 使⽤ YAML
學習成本低 • 可以 Patch 任意資源 • 利⽤ Overlay 可以佈署到不同 環境 👎 缺點 • 沒有內建驗證功能 • YAML 不易重複使⽤ • 有些情況不⽅便 Patch
apiVersion: apps/v1 kind: Deployment metadata: name: example spec: replicas: 1
selector: matchLabels: app: example template: metadata: labels: app: example spec: containers: - name: nginx image: nginx Base apiVersion: apps/v1 kind: Deployment metadata: name: example spec: replicas: 3 Patch apiVersion: apps/v1 kind: Deployment metadata: name: example spec: replicas: 3 selector: matchLabels: app: example template: metadata: labels: app: example spec: containers: - name: nginx image: nginx Result
Ksonnet 👍 優點 • Jsonnet ⽐較容易重複利⽤ • 內建驗證功能 • ⽀援多環境
👎 缺點 • Jsonnet 需要另外花時間學習, 且編輯器⽀援較差 • 概念⽐較複雜,需要花時間上 ⼿ • 已停⽌維護💀(2019/2),後繼 專案:kubecfg, Tanka
Kosko • 使⽤ JavaScript • 容易上⼿ • ⽀援多環境 • 資料驗證
• 無痛轉移 https://kosko.dev
Why JavaScript? • 學習成本低 • Dcard 後端主要使⽤ Go 和 JavaScript
• JavaScript ⽐起 Go 更適合⽤來寫 config • 容易重複利⽤ • 可以直接重複使⽤變數和函數 • 現成資源多 • 有很多現成的 library 可以直接⽤ • 編輯器整合極佳
https://youtu.be/5ip4uUUhtu4
import { Pod } from "kubernetes-models/v1/Pod"; API Version Kind 更多範例
import { Deployment } from "kubernetes- models/apps/v1/Deployment"; import { Certificate } from "@kubernetes- models/cert-manager/cert-manager.io/v1/Certificate";
Example: Pod import { Pod } from "kubernetes-models/v1/Pod"; const pod
= new Pod({ metadata: { name: "busybox" }, spec: { containers: [ { name: "busybox", image: "busybox", command: ["sleep", "10000"] } ] } }); export default pod; apiVersion: v1 kind: Pod metadata: name: busybox spec: containers: - name: busybox image: busybox command: - sleep - '10000'
Example: Deployment + Service import { Deployment } from "kubernetes-models/apps/v1/Deployment";
import { Service } from "kubernetes-models/v1/Service"; const deployment = new Deployment({ metadata: { name: "nginx" }, spec: { // ... } }); const service = new Service({ metadata: { name: "nginx" }, spec: { // ... } }); export default [deployment, service]; --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx --- apiVersion: v1 kind: Service metadata: name: nginx
Example: Secret import { Secret } from "kubernetes-models/v1/Secret"; const secret
= new Secret({ metadata: { name: "api-key" }, type: "Opaque", data: { secret: Buffer.from("confidential").toString("base64") } }); export default secret; apiVersion: v1 kind: Secret metadata: name: api-key type: Opaque data: secret: Y29uZmlkZW50aWFs
Example: YAML import { loadFile, loadUrl, loadString } from "@kosko/yaml";
const manifest = loadFile("manifest.yaml"); const certManager = loadUrl( "https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert- manager.yaml" ); const pod = loadString(` apiVersion: v1 kind: Pod metadata: name: my-pod `); export default [manifest, certManager, pod];
Example: Helm Chart import { loadChart } from "@kosko/helm"; const
prometheus = loadChart({ chart: "prometheus", repo: "https://prometheus-community.github.io/helm-charts", version: "15.0.1", name: "prom-demo", namespace: "prom", values: { server: { ingress: { enabled: true } } } }); export default prometheus;
Example: Kustomize import { loadKustomize } from "@kosko/kustomize"; // Current
folder const manifest = loadKustomize({ path: __dirname }); // GitHub repo const promOperator = loadKustomize({ path: "github.com/prometheus-operator/prometheus-operator" }) export default [manifest, promOperator];
Environment • 存放針對不同 Kubernetes cluster 設定的環境變數 • Global variables •
在多個 component 裡共享的環境變數 • 例如:image registry, domain name, namespace • Component variables • 僅在單⼀ component 裡使⽤的環境變數 • 例如:API key, database name, replicas
export default { namespace: "dev" }; Global vars export default
{ replicas: 1 }; Component vars import env from "@kosko/env"; // { namespace: "dev", replicas: 1 } const params = env.component("nginx"); const deployment = new Deployment({ metadata: { name: "nginx", namespace: params.namespace }, spec: { replicas: params.replicas, template: { spec: { containers: [{ name: "nginx", image: "nginx" }] } } } }); Component apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: dev spec: replicas: 1 template: spec: containers: - name: nginx image: nginx $ kosko generate --env dev
export default { namespace: "prod" }; Global vars export default
{ replicas: 15 }; Component vars import env from "@kosko/env"; // { namespace: "prod", replicas: 15 } const params = env.component("nginx"); const deployment = new Deployment({ metadata: { name: "nginx", namespace: params.namespace }, spec: { replicas: params.replicas, template: { spec: { containers: [{ name: "nginx", image: "nginx" }] } } } }); Component apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: prod spec: replicas: 15 template: spec: containers: - name: nginx image: nginx $ kosko generate --env prod
資料驗證 • 使⽤ Kubernetes OpenAPI Spec 產⽣ TypeScript declaration 和
JSON schema • ⽀援 Kubernetes 內建資源和第三⽅ CRD • https://github.com/tommy351/kubernetes-models-ts
OpenAPI spec TypeScript declaration JSON schema
使⽤經驗
轉移到 Kosko • ⼤約花了⼀個⽉多 (2018/12~2019/1) • Kosko 內建 migrate 指令,能夠把
YAML 轉換成 JavaScript • 花了⼀個⽉把變數抽到 environment • ⽐較轉換前後的 YAML,只要相同的話就能保證相容 • 實際環境測試
Environment • 只把必要的變數放到 environment • 降低維護成本 • 避免 environment 過於冗⻑
• 改變資料夾結構 👉 • 根據 component 來區分更易讀 Group by type Group by component
佈署 • CI 上只驗證內容是否正確 • 在本機佈署到 Kubernetes • ⽬前還是使⽤ kubectl
apply • 寫了⼀個 script 來避免佈署到錯的 cluster • 重要 component 在佈署前會額外檢查版本狀態
重複利⽤
Example: Selector const labels = { app: "demo" }; const
deployment = new Deployment({ spec: { selector: { matchLabels: labels }, template: { metadata: { labels } } } }); const service = new Service({ spec: { selector: labels } });
Example: Port const httpPort = 80; const deployment = new
Deployment({ spec: { template: { spec: { containers: [{ ports: [{ containerPort: httpPort }] }] } } } }); const service = new Service({ spec: { ports: [{ port: httpPort }] } });
Example: Environment Variables export function envVars(envs: Record<string, string>): IEnvVar[] {
return Object.entries(envs).map(([name, value]) => { return { name, value }; }); } // Before [ { name: "LOG_LEVEL", value: "info" }, { name: "API_URL", value: "https://example.com" } ]; // After envVars({ LOG_LEVEL: "info", API_URL: "https://example.com" }); • 避免 name 重複 • 寫起來⽐較簡短
Example: Sidecar function withEnvoy(spec: IPodSpec): IPodSpec { return { ...spec,
containers: [...spec.containers, { name: "envoy", image: "envoyproxy/envoy:v1.17.0" }] }; } const deployment = new Deployment({ spec: { selector: {}, template: { spec: withEnvoy({ containers: [{ name: "demo", image: "demo" }] }) } } }); apiVersion: apps/v1 kind: Deployment spec: selector: {} template: spec: containers: - name: demo image: demo - name: envoy image: envoyproxy/envoy:v1.17.0
Example: Component function createDatabase(name: string) { return [ new Deployment({
metadata: { name } }), new Service({ metadata: { name } }), new PersistentVolumeClaim({ metadata: { name } }) ]; } // components/post-api.js export default [ createDatabase("post-api-db"), new Deployment({ metadata: { name: "post-api" } }), new Service({ metadata: { name: "post-api" } }) ]; // components/user-api.js export default [ createDatabase("user-api-db"), new Deployment({ metadata: { name: "user-api" } }), new Service({ metadata: { name: "user-api" } }) ];
Thanks! Dcard 招募中 https://join.dcard.today Try Kosko! https://kosko.dev @tommy351