Containers, Kubernetes & CI/CD
Interview Context
當面試官問「你的 model 是怎麼上線的?」,他想聽的不是 notebook 分數,而是你能不能講出 Docker image → registry → Kubernetes deployment → CI/CD → canary rollout 這條完整的路。DS/MLE 面試不會要你背 kubectl 指令,但會考你懂不懂 container 為什麼解決 environment 問題、K8s 怎麼做 scaling、以及新 model 怎麼安全地 deploy。
What You Should Understand
- 能解釋 bare metal → VM → container 的演進,以及 container 為什麼適合 ML workloads
- 知道 Docker image 和 container 的差異、layers 如何運作、Dockerfile 的最佳實踐
- 能畫出 Kubernetes 的 control plane / worker node 架構,說明 pod、deployment、service 的角色
- 理解 HPA、VPA、Cluster Autoscaler 的差異,以及 resource requests/limits 對 scheduling 的影響
- 能比較 rolling、blue-green、canary、shadow 等 deployment strategies 的 risk 和 rollback tradeoffs
- 知道 CI/CD pipeline 的 stages,以及 continuous delivery 和 continuous deployment 的差別
Virtualization vs Containerization
From Bare Metal to Containers
計算資源的隔離方式經歷三個世代:
Bare metal: Application 直接跑在實體機器的 OS 上。效能最好(沒有任何 virtualization overhead),但一台機器只能服務一組應用 — 資源利用率低,environment 衝突(兩個 app 需要不同版本的 library)無解。
Virtual Machines: Hypervisor 在硬體之上切出多台虛擬機,每台 VM 有自己完整的 guest OS。Hypervisor 分兩種:
| Type | Runs On | Examples | Use Case |
|---|---|---|---|
| Type 1 (bare-metal) | Directly on hardware | VMware ESXi, Xen, KVM, Hyper-V | Data centers, cloud providers (EC2 底層) |
| Type 2 (hosted) | On top of a host OS | VirtualBox, VMware Workstation, Parallels | 開發者本機測試不同 OS |
Containers: 不虛擬化硬體,而是由 container engine(如 Docker)利用 Linux kernel 的 namespaces(隔離 process、network、filesystem 視圖)和 cgroups(限制 CPU/memory 用量)在同一個 OS kernel 上隔離出多個使用者空間。沒有 guest OS → 啟動快、體積小、密度高。
Comparison
| Dimension | Bare Metal | Virtual Machine | Container |
|---|---|---|---|
| Isolation | None (shared OS) | Strong (hardware-level, separate kernel) | Medium (process-level, shared kernel) |
| Startup time | Minutes (boot) | Minutes (boot guest OS) | Seconds or less |
| Image size | N/A | GBs (full OS) | MBs to hundreds of MBs |
| Density | 1 workload per machine | Tens per host | Hundreds per host |
| Overhead | None | High (guest OS + hypervisor) | Near-zero |
| Security boundary | Physical | Very strong | Weaker (kernel exploits cross containers) |
Why Containers Won for ML
- Reproducibility: ML 最痛的問題是「在我電腦上可以跑」— CUDA 版本、Python 版本、library 相依全部打包進 image,training 和 serving 用同一份環境,消除 environment skew。
- Fast iteration: Container 秒級啟動,適合 autoscaling(流量來了馬上開新 replica)和 batch training job(跑完就回收資源)。
- Density and cost: 一台 GPU 機器可以同時跑多個 serving containers,資源利用率遠高於一 VM 一 app。
- Ecosystem: Kubernetes、Kubeflow、Ray、SageMaker 等 ML infra 全部以 container 為部署單位。
VM 和 Container 不是二選一
實務上是疊起來用的:cloud provider 先用 Type 1 hypervisor 切出 VM(安全隔離不同客戶),你再在 VM 上跑 container(打包和調度你自己的 workloads)。EKS/GKE 的 worker node 就是 VM。
How Docker Works
Images vs Containers
| Concept | What It Is | Analogy |
|---|---|---|
| Image | Read-only template: filesystem + metadata (entrypoint, env vars) | Class(定義) |
| Container | A running instance of an image with a writable layer on top | Object(實例) |
| Registry | Central store for images (Docker Hub, ECR, GCR, Artifact Registry) | GitHub for images |
一個 image 可以同時跑出多個 containers;container 刪掉後 writable layer 消失,image 不變 — 這就是 immutable infrastructure 的基礎。
Layers and Union Filesystem
Docker image 由一疊 read-only layers 組成,每個 Dockerfile 指令(RUN、COPY 等)產生一層。Union filesystem(如 overlay2)把這些 layers「疊」成一個統一的檔案系統視圖;container 啟動時在最上面加一層 thin writable layer。
好處:
- Layer caching: rebuild 時只有變動的層(和它之後的層)需要重建 → build 快。
- Layer sharing: 十個 containers 共用同一個 base image,磁碟上只存一份。
- Fast distribution: pull image 時只下載本機沒有的 layers。
Dockerfile Anatomy
FROM python:3.11-slim # base image (choose small!)
WORKDIR /app # working directory inside the image
COPY requirements.txt . # copy deps file FIRST (cache-friendly)
RUN pip install --no-cache-dir -r requirements.txt # one layer
COPY . . # copy source code (changes often → last)
EXPOSE 8000 # documentation of the listening port
CMD ["uvicorn", "app:app", "--host", "0.0.0.0"] # default command
關鍵直覺:變動頻率低的指令放前面,變動頻率高的放後面 — 這樣改 code 不會 invalidate 安裝 dependencies 的 cache layer。
Registry Flow: Build → Push → Pull → Run
CI pipeline build 出 image、tag 上 version(例如 git commit SHA)、push 到 registry;production cluster 從 registry pull 指定 tag 來跑。永遠不要用 latest tag deploy production — 無法追蹤現在跑的是哪個版本,也無法精準 rollback。
Docker Best Practices
| Practice | Why | How |
|---|---|---|
| Small base image | 更快 pull、更小 attack surface | python:3.11-slim 或 distroless,不要用完整 ubuntu |
| Multi-stage builds | Build tools 不進最終 image | Stage 1 編譯/安裝,Stage 2 只 copy 產物 |
| Layer caching | Build 快 | Dependencies 先 COPY + install,source code 最後 COPY |
| Non-root user | Container 被攻破時降低權限 | USER appuser(建立專用 user) |
| .dockerignore | 避免把 data、.git、venv 打進 image | 排除 .git, pycache, data/, *.ipynb |
| Pin versions | Reproducible builds | requirements.txt 鎖版本,base image 用 digest 或明確 tag |
ML Image 常見錯誤
最常見的錯誤是把 training data、notebook、甚至 credentials COPY 進 image。Image 會被 push 到 registry、被很多人 pull — secrets 進了 layer 就算後面 RUN rm 掉也還在 layer history 裡。Data 用 volume mount 或 object storage,secrets 用 runtime 注入(K8s Secret、env vars)。
Kubernetes Architecture
Docker 解決「一台機器上跑 container」;Kubernetes(K8s)解決「幾百台機器上跑幾千個 containers」— 調度、自癒、擴縮、服務發現。
Control Plane vs Worker Nodes
| Component | Role | 直覺 |
|---|---|---|
| API Server | 所有操作的唯一入口(kubectl、controllers 都打它) | 集群的前台櫃檯 |
| etcd | Distributed key-value store,存整個 cluster 的 desired + actual state | 集群的資料庫(唯一的 source of truth) |
| Scheduler | 決定新 pod 要放到哪個 node(看 resources、affinity、taints) | 排班經理 |
| Controller Manager | 跑 reconciliation loops:actual state 不等於 desired state 就修正 | 自動糾錯的管家 |
| Kubelet (worker) | 每個 node 上的 agent,跟 API server 溝通、實際啟動/監控 containers | 工頭 |
| Kube-proxy (worker) | 維護 node 上的 network rules,讓 Service 的流量能導到 pods | 交通警察 |
核心設計哲學是 declarative + reconciliation:你在 YAML 宣告 desired state(「我要 3 個 replicas」),controllers 不斷比對現況並修正 — pod 掛了就補一個,node 掛了就把 pods 搬走。這就是 self-healing 的來源。
Core Objects
| Object | What It Is | Why You Need It |
|---|---|---|
| Pod | 最小部署單位:一個或多個共享 network/storage 的 containers | Container 的執行單位(通常一個 pod 一個主 container) |
| Deployment | 管理一組相同 pods 的 replicas + rolling update | 你幾乎不直接建 pod,都透過 Deployment |
| Service | 一組 pods 的穩定虛擬 IP + load balancing | Pod IP 會變(重啟就換),Service 提供穩定入口 |
| Ingress | HTTP(S) 層的路由:domain/path → Service | 對外暴露 API、TLS termination |
| ConfigMap / Secret | 設定與機密的注入 | Image 不變,環境設定可換 |
| Job / CronJob | 跑完就結束的 workload | Training jobs、batch inference、定時 retraining |
Pod Lifecycle
- Pending: Pod 已建立但還沒被排到 node(等 scheduler)或還在 pull image。卡在 Pending 最常見原因:沒有 node 有足夠的 CPU/memory/GPU 滿足 requests。
- Running: 至少一個 container 正在跑。
- Succeeded / Failed: 所有 containers 結束(Job 類 workload);serving pods 正常情況下永遠 Running。
三種 probes 決定 K8s 怎麼對待一個 running pod:
| Probe | Question It Answers | On Failure |
|---|---|---|
| Liveness | Process 還活著嗎(沒有 deadlock)? | Restart container |
| Readiness | 現在可以接流量嗎(model 載入好了嗎)? | 從 Service endpoints 移除(不送流量,不重啟) |
| Startup | 慢啟動的 app 開好了沒? | 在 startup 完成前不跑 liveness(避免大 model 載入中被誤殺) |
ML Serving 必懂:Readiness Probe
Model server 啟動要先載入幾 GB 的 model weights,可能要 30-120 秒。沒有設 readiness probe 的話,K8s 一看 container 起來就把流量導過去 → 大量 500 errors。正確做法:readiness endpoint 回傳 model 是否載入完成;rolling update 時新 pod ready 之前舊 pod 不會被砍。
Kubernetes Scaling
Three Autoscalers
| Autoscaler | What It Scales | Trigger | Best For |
|---|---|---|---|
| HPA (Horizontal Pod Autoscaler) | Pod replicas 數量 | CPU/memory utilization 或 custom metrics(QPS、queue length) | Stateless serving — 流量漲就加 replicas |
| VPA (Vertical Pod Autoscaler) | 單一 pod 的 CPU/memory requests | 歷史用量 | 不易水平擴展的 workload、right-sizing requests |
| Cluster Autoscaler | Node(VM)數量 | Pods 因資源不足卡在 Pending | 配合 HPA — pods 加了沒地方放時開新機器 |
三者常一起用:流量上升 → HPA 加 pods → node 塞不下、pods Pending → Cluster Autoscaler 開新 node。注意 HPA 和 VPA 不要同時對 CPU/memory 作用在同一個 workload(會互相打架)。
Resource Requests and Limits
resources:
requests: # what the scheduler reserves for you
cpu: "1"
memory: 2Gi
limits: # hard cap at runtime
cpu: "2" # exceed → throttled
memory: 4Gi # exceed → OOMKilled
- Requests 是 scheduler 排程的依據 — node 的可分配資源夠不夠放這個 pod。設太低 → pods 擠在一起互搶資源;設太高 → 資源閒置、cluster 成本爆炸。
- Limits 是 runtime 上限 — CPU 超過會被 throttle(變慢),memory 超過會被 OOMKilled(直接砍掉重啟)。
- Requests 等於 limits 的 pod 是 Guaranteed QoS,最不容易在資源壓力下被驅逐 — production serving 建議這樣設。
Why GPU Scheduling Matters for ML
GPU 和 CPU 在 K8s 的行為根本不同:
- GPU 是整數資源、不可超賣:nvidia.com/gpu 只能 request 整顆(除非用 MIG/time-slicing),沒有「requests 和 limits 不同」這回事。一個 inference pod 只用 30% GPU 也佔掉整顆 → 利用率問題。
- 貴且稀缺:GPU node 一小時數美元起跳,Cluster Autoscaler 開 GPU node 又慢(幾分鐘)→ 常用「保留 baseline + queue 排隊」而不是純 reactive autoscaling。
- Taints and tolerations:GPU nodes 通常設 taint,避免普通 CPU workload 被排上去浪費昂貴機器;ML pods 加 toleration + nodeSelector 指定 GPU 型號(A100 vs T4 差很多)。
- Bin packing:training 要整顆或多顆 GPU、serving 想共享 GPU — 混排時 fragmentation 會讓大 job 排不進去,所以常把 training pool 和 serving pool 分開。
CI/CD Pipeline
Stages
CI/CD 把「寫完 code 到跑在 production」自動化成一條 pipeline:
| Stage | What Happens | Typical Tools |
|---|---|---|
| Build | Compile / install deps / lint / type check | GitHub Actions, GitLab CI, Jenkins |
| Test | Unit + integration tests, coverage gate | pytest, coverage |
| Package | Build Docker image, tag with commit SHA, push to registry | Docker, ECR/GCR |
| Deploy staging | 部署到 staging 環境,跑 e2e / smoke tests | Helm, kubectl, ArgoCD |
| Deploy production | 漸進式 rollout + 監控 + 自動 rollback | Argo Rollouts, Spinnaker |
Continuous Delivery vs Continuous Deployment
| Term | Meaning | Human Involved? |
|---|---|---|
| Continuous Integration | 每次 commit 自動 build + test,快速發現整合問題 | No |
| Continuous Delivery | 每個通過測試的版本隨時可以部署,但按下 deploy 鈕是人 | Yes(最後一步手動核准) |
| Continuous Deployment | 通過所有 gates 就自動部署到 production,全程無人 | No |
大部分公司做到 continuous delivery;continuous deployment 需要極高的測試覆蓋和監控成熟度。
Testing Pyramid
| Layer | Scope | Speed | Quantity |
|---|---|---|---|
| Unit tests | 單一 function/class,mock 掉外部依賴 | 毫秒級 | 最多(底層) |
| Integration tests | 多個 components 一起(app + DB、feature pipeline) | 秒到分鐘 | 中等 |
| End-to-end tests | 整條 user flow 打真實(staging)環境 | 分鐘級、易 flaky | 最少(頂層) |
直覺:越往上越貴越慢越脆 — 所以數量呈金字塔。ML pipeline 還會多兩類:data validation tests(schema、分布)和 model validation gates(新 model 的 offline metrics 必須不輸 baseline 才准進 deploy stage)。
How Companies Ship Safely
安全上線的公式是:small changes(一次改一點,錯了好找)+ automated gates(tests、canary metrics 擋住壞版本)+ fast rollback(一鍵回滾比「不出錯」更務實)。面試講 deployment 時主動提 rollback plan,是 senior signal。
Deployment Strategies
Comparison
| Strategy | How It Works | Risk | Rollback Speed | Extra Cost | Best For |
|---|---|---|---|---|---|
| Big bang | 全部流量一次切到新版 | 最高 | 慢(要重新 deploy 舊版) | 無 | 內部工具、不得已的 breaking change |
| Rolling | 逐一替換 replicas(K8s Deployment 預設) | 中 | 中(re-roll 回舊 image) | 低 | 一般 stateless services |
| Blue-green | 兩套完整環境,流量在 load balancer 一次切換 | 低 | 秒級(切回舊環境) | 高(雙倍資源) | 需要瞬間切換 + 瞬間回滾 |
| Canary | 先給 1-5% 流量,看 metrics 再逐步放大 | 最低 | 快(把流量切回去) | 低-中 | 高風險變更、model deployment |
| Feature flags | Code 先上線但功能用開關控制、可按 user 分群開 | 低 | 即時(關 flag,不用 deploy) | 低(技術債:flag 清理) | 產品功能、A/B testing |
| Shadow (mirroring) | 複製真實流量給新版,但 response 不回給 user | 零(user 無感) | N/A(本來就沒接流量) | 中(雙倍 inference 成本) | 驗證新 model/系統的行為 |
Tie to Model Deployment
Model 是「行為由 data 決定」的 artifact,offline test 永遠不能完全保證 online 行為,所以 model deployment 幾乎都用 shadow → canary 的組合:
- Shadow mode: 新 model 對 production traffic 做推論但不影響 user → 比較新舊 predictions 的分布差異、latency、error rate。抓 engineering bugs(feature 拿錯、serialization 錯)。
- Canary: 1% → 5% → 25% → 100%,每一步看 online metrics(CTR、fraud loss、latency p99)。抓 offline 看不到的 model quality 問題。
- Rollback trigger 事先定義:例如 canary 群的 conversion 掉超過 X% 或 error rate 超過閾值就自動切回 — 不要臨場拍腦袋。
Feature flag 對 ML 的對應物是 model registry 的 stage 切換:serving code 不變,flag/config 決定載入哪個 model version。
Infrastructure as Code
What: 用宣告式的 code(而不是手動點 console)定義 infrastructure — servers、clusters、networks、IAM。Why: 可以 code review、版控、重現環境(dev/staging/prod 一致)、災難後快速重建;手動配置的環境是「snowflake」,沒人敢動也沒人能重建。
| Approach | Representative Tool | What It Manages | 一句話 |
|---|---|---|---|
| Provisioning (declarative IaC) | Terraform, CloudFormation, Pulumi | Cloud resources(VPC、EKS cluster、S3、IAM) | 宣告 desired state,工具算 diff 去 apply |
| Configuration management | Ansible, Chef, Puppet | 機器裡面的設定(套件、config files) | 對已存在的機器做設定(container 時代重要性下降) |
| GitOps | ArgoCD, Flux | K8s 上的 application manifests | Git 是唯一 source of truth,controller 自動把 cluster 同步到 repo 狀態 |
GitOps 的關鍵反轉:不是 CI pipeline push 變更到 cluster,而是 cluster 裡的 agent(ArgoCD)pull Git repo 並持續 reconcile — deploy 等於 merge 一個 PR,rollback 等於 revert 一個 commit,全部有 audit trail。這和 K8s 本身的 reconciliation 哲學一脈相承。
Real-World Use Cases
Case 1: 把 Notebook 模型包成 Docker Image 上 K8s Serving
你在 notebook 訓練好一個詐欺偵測模型(LightGBM + 前處理),要變成一個 p99 latency 100ms 以下的 API。步驟:
- 把 notebook 重構成 module:
train.py產出 model artifact,app.py(FastAPI)載入 artifact 提供/predict和/healthz。 - Multi-stage Dockerfile:builder stage 裝 dependencies,final stage 用 slim base + non-root user。Model artifact 不烘進 image,啟動時從 model registry / object storage 下載(image 和 model version 解耦)。
- K8s Deployment:3 replicas、readiness probe 等 model 載入完成、requests=limits 拿 Guaranteed QoS、HPA 以 QPS 為 metric。
- Service + Ingress 對內部系統暴露 API。
面試 follow-up:
- 為什麼 model artifact 不直接 COPY 進 image?(Model 每天 retrain,image 不用重 build;rollback model 不用 rollback code;image 保持小。)
- 一個 pod 可以扛多少 QPS,怎麼知道?(Load test 找出單 pod 容量 → 決定 replicas 和 HPA 上限。)
- Feature 從哪裡來?(Online feature store lookup — 注意這常是 latency bottleneck,不是 model inference。)
Case 2: Canary Release 一個新版推薦模型
推薦系統要上 v2 model(offline NDCG +2%)。你不敢直接全量切,設計如下:
- Shadow 一週:v2 對 100% 流量做推論但不 serve,比較 v1/v2 的 prediction 分布、latency p99、error rate — 抓 feature pipeline bug。
- Canary 開始:5% users 由 v2 serve(用 user id hash 分流,確保同一 user 體驗一致 — 這其實就是一個 A/B test)。
- 事先定義 guardrails:CTR 掉超過 1%、latency p99 超過 150ms、或 error rate 超過 0.1% → 自動把流量切回 v1。
- Metrics 顯著正向 → 5% → 25% → 50% → 100%,每一步觀察至少一個 business cycle(例如一整天,避開 day-of-week effect)。
面試 follow-up:
- Canary 和 A/B test 差在哪?(機制幾乎相同;canary 目的是 safety(找 regression、樣本小、看 guardrail metrics),A/B test 目的是 inference(統計顯著性、固定樣本數)。)
- 5% canary 的 metrics 要看多久才能下結論?(取決於 metric 的 variance 和 traffic 量 — 連到 power analysis;guardrail 用寬鬆閾值快速擋災難,精細比較留給正式 A/B。)
- 如果 v2 的 improvement 只在冷門 items 上,canary metrics 可能看不出來,怎麼辦?(Segment 分析、拉長觀察期、或用 interleaving。)
Case 3: Training Job 的資源配置與 Autoscaling
你的團隊每天在 K8s 上跑幾十個 training jobs(K8s Job 物件),常見兩個問題:有人的 job 卡 Pending 排不進去,有人的 job 跑到一半被 OOMKilled。你的設計:
- Right-size requests/limits:用 VPA recommendation mode 或歷史 metrics 找出每類 job 的真實用量。Memory limit 設太低 → OOMKilled(training 跑三小時後在第 80 epoch 被砍最痛);requests 設太高 → 卡 Pending 而且浪費配額。
- GPU pool 隔離:GPU nodes 設 taint,training jobs 加 toleration;training pool 和 serving pool 分開,避免 training 把 serving 的資源吃光。
- Cluster Autoscaler + spot instances:training 可容忍中斷(有 checkpointing)→ 用 spot GPU nodes 省 60-70% 成本;job 排進來時 autoscaler 開機器,跑完縮回去。
- Queue + priority:用 priority classes 或 job queue(Kueue、Volcano)讓 production retraining 優先於 ad-hoc 實驗。
面試 follow-up:
- Training job 被 spot instance 回收怎麼辦?(Checkpoint 到 object storage,job restart 後從 checkpoint 恢復。)
- 為什麼 GPU 利用率只有 30%?(常見原因是 data loading bottleneck — CPU requests 太低餵不飽 GPU;先 profile 再加 GPU。)
- 一個 8-GPU 的 job 一直 Pending 但 cluster 明明有 8 顆空 GPU?(Fragmentation — 8 顆散在 4 台機器上,job 要求同一台的 8 顆。需要 bin packing / gang scheduling。)
Hands-on: Dockerfile, K8s Manifests, and CI
這個主題的 hands-on 不是 Python,而是三個 production 必備的 artifacts。
Multi-stage Dockerfile for an ML Serving App
# ---------- Stage 1: builder ----------
FROM python:3.11-slim AS builder
WORKDIR /app
# Install deps into a virtualenv (easy to copy as one unit)
COPY requirements.txt .
RUN python -m venv /opt/venv && \
/opt/venv/bin/pip install --no-cache-dir -r requirements.txt
# ---------- Stage 2: runtime ----------
FROM python:3.11-slim
WORKDIR /app
# Copy only the installed packages, not build tools/caches
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Copy source code last (changes most often → best layer caching)
COPY app/ ./app/
# Run as non-root for security
RUN useradd --create-home appuser
USER appuser
EXPOSE 8000
# Model weights are downloaded at startup from the registry,
# so the image stays small and model versions are decoupled
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Kubernetes Deployment + Service with Probes and Resources
apiVersion: apps/v1
kind: Deployment
metadata:
name: fraud-model
spec:
replicas: 3 # HA: survive single pod/node failure
selector:
matchLabels: { app: fraud-model }
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0 # never drop below desired capacity
maxSurge: 1 # add one new pod at a time
template:
metadata:
labels: { app: fraud-model }
spec:
containers:
- name: server
image: registry.example.com/fraud-model:git-3fa2b1c # never :latest
ports:
- containerPort: 8000
resources:
requests: { cpu: "1", memory: 2Gi } # scheduler reserves this
limits: { cpu: "1", memory: 2Gi } # equal → Guaranteed QoS
startupProbe: # allow slow model loading
httpGet: { path: /healthz, port: 8000 }
failureThreshold: 30 # up to 30 * 5s = 150s to start
periodSeconds: 5
readinessProbe: # gate traffic until model is loaded
httpGet: { path: /ready, port: 8000 }
periodSeconds: 10
livenessProbe: # restart if process deadlocks
httpGet: { path: /healthz, port: 8000 }
periodSeconds: 15
---
apiVersion: v1
kind: Service
metadata:
name: fraud-model
spec:
selector: { app: fraud-model } # routes to ready pods only
ports:
- port: 80
targetPort: 8000
GitHub Actions CI Sketch
name: ci-cd
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.11" }
- run: pip install -r requirements.txt -r requirements-dev.txt
- run: ruff check . # lint
- run: pytest --cov=app # unit + integration tests
build-and-push:
needs: test # only runs if tests pass
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push image tagged with commit SHA
run: |
docker build -t $REGISTRY/fraud-model:${{ github.sha }} .
docker push $REGISTRY/fraud-model:${{ github.sha }}
deploy-staging:
needs: build-and-push
runs-on: ubuntu-latest
steps:
# GitOps style: update the image tag in the manifests repo;
# ArgoCD detects the change and syncs the cluster
- name: Bump image tag in k8s manifests
run: |
./scripts/update-manifest.sh staging ${{ github.sha }}
git commit -am "deploy ${{ github.sha }} to staging" && git push
# Production deploy = promote via PR + canary rollout (manual gate)
Interview Signals
What interviewers listen for:
- 你能講清楚 VM 和 container 的隔離層級差異(guest OS vs shared kernel),而不是背「container 比較輕」
- 你知道 image layer caching 怎麼影響 Dockerfile 的指令順序,以及為什麼不能用 latest tag deploy
- 你能解釋 K8s 的 declarative + reconciliation 模型,並用 readiness probe 說明 model server 的啟動流程
- 講 deployment 時主動提 rollback plan 和事先定義的 guardrail metrics,而不是只講 happy path
- 你能把 shadow / canary 連回 ML:offline metrics 不能保證 online 行為,所以 model deploy 需要漸進驗證
Practice
Flashcards
Flashcards (1/10)
VM 和 container 的核心差異是什麼?
VM 由 hypervisor 虛擬化硬體,每台 VM 有自己完整的 guest OS → 隔離強但重(GB 級、分鐘級啟動)。Container 共享 host OS kernel,用 namespaces + cgroups 做 process 層隔離 → 輕(MB 級、秒級啟動、高密度)但隔離較弱。實務上疊著用:cloud 用 VM 隔離客戶,客戶在 VM 上跑 containers。
Quiz
Container 比 VM 啟動快、體積小的根本原因是?