Appearance
Samba + Nginx 檔案分享服務(Kubernetes 部署)
在 Kubernetes 上部署 Samba 檔案分享服務,搭配 Nginx 提供 Web 目錄瀏覽介面(含 Basic Auth),以 Sidecar 模式共享儲存空間。
概述
在企業環境中,經常需要一個簡單的檔案分享平台,讓團隊成員能透過 SMB 協定上傳檔案,同時也能用瀏覽器瀏覽下載。本部署在 Kubernetes 上結合 Samba 與 Nginx 兩個容器,以 Sidecar 模式共享同一個 PVC 儲存空間:Samba 負責 SMB 檔案讀寫,Nginx 負責 Web 目錄瀏覽。
部署架構精巧:單一 Pod 內包含兩個容器,Samba 容器以讀寫模式掛載 PVC 供使用者透過 \\IP\Data 路徑存取檔案;Nginx 容器以唯讀模式掛載同一 PVC,透過 fancyindex 模組提供美化的目錄瀏覽頁面,並以 HTTP Basic Authentication 保護存取權限。整體透過 Azure Internal LoadBalancer 以固定 IP 同時暴露 SMB (445) 與 HTTP (4445) 兩個埠。
核心內容
Sidecar 共享儲存架構
本部署的核心設計是讓兩個容器共享同一份 PVC(samba-pvc):
- Samba 容器:以讀寫模式掛載
/storage,透過 SMB 協定提供檔案上傳與下載 - Nginx 容器:以唯讀模式掛載
/storage,透過 HTTP 提供瀏覽器存取
這種 Sidecar 模式確保兩個存取通道看到的是完全相同的檔案,使用者透過 SMB 上傳的檔案可立即在 Web 介面上看到。PVC 使用 ReadWriteOnce 存取模式,因此兩個容器必須在同一個 Pod(同一個 Node)中。
Nginx 目錄瀏覽與認證
Nginx 使用 fancyindex 模組(非內建,需專用映像檔或自行編譯)提供美化的目錄列表頁面,支援自訂 header/footer 樣板。同時搭配 auth_basic 實現 HTTP Basic Authentication,密碼檔以 Kubernetes Secret 形式管理,掛載至 /etc/nginx/auth/.htpasswd。
注意: 原生
nginx:alpine映像檔不含fancyindex模組,需要使用包含此模組的自訂映像或第三方映像。
安全性設計
部署中的安全機制包括:
- Samba 帳號密碼:透過 Kubernetes Secret 注入環境變數,避免明碼寫在 YAML 中
- Nginx Basic Auth:htpasswd 格式的密碼檔同樣以 Secret 管理
- Azure Internal LoadBalancer:僅限 VNet 內部存取,不暴露至公網
- Nginx 唯讀掛載:Web 介面僅能瀏覽,無法透過 HTTP 修改檔案
正式環境提醒: 素材中的預設密碼(
samba/secret)僅供測試,正式環境務必更換。
關鍵要點
- 單一 Pod 內 Samba + Nginx 兩個容器共享同一 PVC,實現 SMB 上傳 + Web 瀏覽
- Nginx
fancyindex模組提供美化目錄瀏覽,需使用包含此模組的映像檔 - 雙重認證:Samba 帳密 + Nginx Basic Auth,均以 Kubernetes Secret 管理
- Azure Internal LoadBalancer 同時暴露 SMB (445) 與 HTTP (4445) 兩個埠
fsGroup: 1000確保兩個容器對共享儲存有正確的檔案權限
實際應用
本服務部署於 AKS 叢集 ingress-basic namespace,作為團隊內部的輕量檔案分享平台。使用者可透過 Windows 檔案總管以 \\10.30.196.60\Data 存取 SMB 分享,或透過瀏覽器造訪 http://10.30.196.60:4445 瀏覽與下載檔案。適用於內部文件分發、部署產物暫存、跨團隊檔案交換等場景。
部署設定參考
以下為實際部署時使用的完整設定,供日後查詢與複製使用。
環境參數
| 項目 | 值 |
|---|---|
| Namespace | ingress-basic |
| Storage Class | managed-csi |
| PVC 容量 | 10Gi |
| Samba Image | dockurr/samba:latest |
| Nginx Image | nginx:alpine |
| LoadBalancer IP | 10.30.196.60 |
| SMB Port | 445 |
| HTTP Port(外部) | 4445 → 容器 80 |
| Samba 分享名稱 | Data |
Secret — Nginx Basic Auth 憑證
yaml
apiVersion: v1
kind: Secret
metadata:
name: samba-nginx-auth
namespace: ingress-basic
type: Opaque
data:
auth: c2FtYmE6JGFwcjEkOE5HZ01ENFokTG96UDZFcnhGQmtJQXlNREROd0hQMAo=Secret — Samba 帳號密碼
yaml
apiVersion: v1
kind: Secret
metadata:
name: samba-credentials
namespace: ingress-basic
type: Opaque
data:
user: c2FtYmE=
pass: c2VjcmV0| Key | Base64 值 | 解碼值 |
|---|---|---|
user | c2FtYmE= | samba |
pass | c2VjcmV0 | secret |
PersistentVolumeClaim
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: samba-pvc
namespace: ingress-basic
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: managed-csiConfigMap — Nginx 設定檔
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: samba-nginx-config
namespace: ingress-basic
data:
default.conf: |
server {
listen 80;
server_name _;
charset utf-8;
location / {
try_files $uri $uri.html $uri.xhtml $uri/ =404;
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/auth/.htpasswd;
root /storage;
fancyindex on;
fancyindex_header "/theme/header.html";
fancyindex_footer "/theme/footer.html";
fancyindex_show_path off;
fancyindex_name_length 255;
fancyindex_exact_size off;
fancyindex_localtime on;
}
location /theme/ {
alias /etc/nginx/theme/;
}
}Deployment YAML
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: samba-server
namespace: ingress-basic
spec:
replicas: 1
selector:
matchLabels:
app: samba
template:
metadata:
labels:
app: samba
spec:
securityContext:
fsGroup: 1000
containers:
- name: samba
image: dockurr/samba:latest
env:
- name: NAME
value: "Data"
- name: USER
valueFrom:
secretKeyRef:
name: samba-credentials
key: user
- name: PASS
valueFrom:
secretKeyRef:
name: samba-credentials
key: pass
ports:
- containerPort: 445
name: smb
volumeMounts:
- name: samba-data
mountPath: /storage
- name: nginx
# ⚠️ 原生 nginx:alpine 不含 fancyindex 模組,須替換為包含此模組的映像
# 例如:ghcr.io/alpinelinux/nginx-extras:latest 或組織自建映像
image: nginx:alpine # TODO: 替換為含 fancyindex 的映像
ports:
- containerPort: 80
name: http
volumeMounts:
- name: samba-data
mountPath: /storage
readOnly: true
- name: samba-nginx-config
mountPath: /etc/nginx/conf.d/default.conf
subPath: default.conf
- name: nginx-auth
mountPath: /etc/nginx/auth
readOnly: true
volumes:
- name: samba-data
persistentVolumeClaim:
claimName: samba-pvc
- name: samba-nginx-config
configMap:
name: samba-nginx-config
- name: nginx-auth
secret:
secretName: samba-nginx-auth
items:
- key: auth
path: .htpasswd容器架構
| 容器 | Image | 用途 | Port | Volume 掛載 |
|---|---|---|---|---|
samba | dockurr/samba:latest | SMB 檔案分享 | 445 | /storage(讀寫) |
nginx | nginx:alpine | Web 目錄瀏覽 | 80 | /storage(唯讀) |
Service YAML(Azure Internal LoadBalancer)
yaml
apiVersion: v1
kind: Service
metadata:
name: samba-service
namespace: ingress-basic
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
service.beta.kubernetes.io/azure-load-balancer-ipv4: 10.30.196.60
spec:
selector:
app: samba
ports:
- port: 445
targetPort: 445
protocol: TCP
name: smb
- port: 4445
targetPort: 80
protocol: TCP
name: http
type: LoadBalancer存取方式
| 協定 | 連線位址 |
|---|---|
| SMB | \\10.30.196.60\Data |
| Web 瀏覽 | http://10.30.196.60:4445 |
相關概念
- Caddy 靜態檔案伺服器 — 另一種 Web 檔案伺服器方案,使用 Caddy 取代 Nginx
- Shadowsocks Sidecar 代理 — 同樣使用 Sidecar 容器架構的部署模式
- Squid Proxy(Kubernetes 部署) — 同樣使用 Azure Internal LoadBalancer 暴露服務
- SMTP 郵件伺服器(Kubernetes 部署) — 同部署於
ingress-basicnamespace 的基礎設施服務 - SFTP on Kubernetes 部署 — 類似的檔案傳輸服務,以 SFTPGo + Nginx Sidecar 提供 SFTP + HTTP 存取
- Nginx 檔案服務 Server — 單機 Docker 的 Nginx 靜態目錄服務,為本文 K8s 方案的輕量替代