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
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
140
Kubernetes 101
tommy351
2
340
Socket.io 即時通訊實作
tommy351
0
130
Fast Web Development with Express
tommy351
0
150
An Introduction to Node.js
tommy351
1
370
Other Decks in Technology
See All in Technology
価値について
gree_tech
PRO
0
110
ソフトウェア ファクトリー - 再現性のあるソフトウェアの工場づくり / Software factory
iktakahiro
7
5.1k
スキマバイトという雇用形態は存在しないので、雇用期間1日のアルバイト契約を事業者とワーカーが結ぶ手続きを支えるのがタイミーなんです
akitoshiga
0
210
Claude の新機能を、 出た日に触って社内に届けるまで
rfdnxbro
1
190
Active Record Connection Adaptersにおける長年の課題に再び取り組む
yahonda
0
300
AIカンパニーへの転換を支えた、エンジニアの仕事の再定義
kworkdev
PRO
2
1.3k
その Valkey 使いこなしていますか?
onk
PRO
5
1.6k
データエンジニアの次の戦場は "プロセスエンジニアリング"
sansantech
PRO
1
120
FinOps Agentが生んだ技術負債:コスト自動調査の落とし穴と解消までの道のり
oasis1994liveforever
2
160
JAWSUG TOHOKU 青森支部 「LoGoチャット」のAWS移行で 乗り越えたこと
taketakekaho
0
350
Post AI時代のリファクタリング実践記 / Refactoring in the post AI era
kaminashi
1
300
AI コーディングと人間の認知スループット / CTO Night & Day 2026 Morning Session / AI Coding and Human Cognitive Throughput
prog893
5
1.3k
Featured
See All Featured
Evolving SEO for Evolving Search Engines
ryanjones
0
330
A Tale of Four Properties
chriscoyier
163
24k
Designing for humans not robots
tammielis
254
26k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
1k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
570
Navigating Weather and Climate Data
rabernat
0
560
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
430
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
Bash Introduction
62gerente
615
220k
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