Skip to content

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 模組,需要使用包含此模組的自訂映像或第三方映像。

安全性設計

部署中的安全機制包括:

  1. Samba 帳號密碼:透過 Kubernetes Secret 注入環境變數,避免明碼寫在 YAML 中
  2. Nginx Basic Auth:htpasswd 格式的密碼檔同樣以 Secret 管理
  3. Azure Internal LoadBalancer:僅限 VNet 內部存取,不暴露至公網
  4. 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 瀏覽與下載檔案。適用於內部文件分發、部署產物暫存、跨團隊檔案交換等場景。

部署設定參考

以下為實際部署時使用的完整設定,供日後查詢與複製使用。

環境參數

項目
Namespaceingress-basic
Storage Classmanaged-csi
PVC 容量10Gi
Samba Imagedockurr/samba:latest
Nginx Imagenginx:alpine
LoadBalancer IP10.30.196.60
SMB Port445
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
KeyBase64 值解碼值
userc2FtYmE=samba
passc2VjcmV0secret

PersistentVolumeClaim

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: samba-pvc
  namespace: ingress-basic
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: managed-csi

ConfigMap — 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用途PortVolume 掛載
sambadockurr/samba:latestSMB 檔案分享445/storage(讀寫)
nginxnginx:alpineWeb 目錄瀏覽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

相關概念

來源