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
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Tommy Chen
December 22, 2021
Technology
1.4k
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
120
Kubernetes 101
tommy351
2
320
Socket.io 即時通訊實作
tommy351
0
120
Fast Web Development with Express
tommy351
0
140
An Introduction to Node.js
tommy351
1
360
Other Decks in Technology
See All in Technology
あるけみー式LTスライド作成術
alchemy1115
2
220
ソフトウェアDNAとクラウドエージェントのススメ
cloudace
0
110
2026-09-11 【Snowflake World Tour Tokyo 2026】Snowflakeを起点に、AI Agentが自律稼働し続ける未来へ / Driving AI Agents with Snowflake
civitaspo
0
680
幾何アルゴリズムで なめらかなピン操作を / iOSDC Japan 2026 / smoothpin
kazumanagano
0
350
データ_AIの事業の勝敗をわけるもの
nek0128
1
430
事業課題から技術的負債に向き合う
sansantech
PRO
2
1.9k
映像変換サーバーなしで端末内でHLSを生成してライブ配信
hikarusato
0
120
生成AIエージェントを用いた、 手動テスト手順書から自動テストへの 変換手法の検討
magicpod
0
160
リアーキテクチャ後の障害ゼロを目指したShadow Testingの取り組み
nihonbuson
PRO
1
130
Minecraft JavaのMODをSwiftで作る
1mash0
0
180
30座EKS, 180次升級淬煉的EKS Upgrade Skill 的歷程
eric8230
0
170
研究開発部の紹介 / Sansan R&D Profile
sansan33
PRO
5
25k
Featured
See All Featured
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
390
Product Roadmaps are Hard
iamctodd
55
13k
How GitHub (no longer) Works
holman
316
150k
Deep Space Network (abreviated)
tonyrice
0
310
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
570
Writing Fast Ruby
sferik
630
63k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
300
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
Mobile First: as difficult as doing things right
swwweet
225
10k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
690
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