iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
Software Development

Python 數據專案從頭做起:跟著一個專案學資料工程系列 第 7

Day 6|Stage 2(1/5):用 Amazon S3 建立原始資料層(Raw Data Layer)

  • 分享至 

  • xImage
  •  

前一個 Stage,我們用少量樣本進行資料剖析(Data Profiling),確認臺北捷運 OD 資料的結構、資料粒度與可能存在的品質問題。接下來要進入 Stage 2,建立一條從政府資料來源、Amazon S3 到 PostgreSQL 的資料管線(Data Pipeline)。這一篇的目標不是把資料送進 PostgreSQL,而是先建立一個能長期保留原始檔案、需要時可以重新處理的起點Raw Data Layer(原始資料層)

     政府資料來源
          ↓
Amazon S3---Raw Data Layer
          ↓
PostgreSQL---結構化資料

Raw Data Layer 解決什麼問題?

開發初期把少量 CSV 放在本機 data/ 很方便,但臺北捷運 OD 資料每月都有數百 MB。如果資料管線未來要定期執行,原始資料不能只存在某位開發者的電腦。這不只是硬碟空間問題。假設資料已經載入 PostgreSQL,後來才發現:

  • 載入程式有 Bug。
  • 資料表設計需要調整。
  • Cleaning 或轉換規則寫錯。
  • 某個歷史月份需要重新處理。

如果沒有保留當時的原始檔案,就只能再次向政府網站下載。但我們無法保證來源檔案永遠存在,也無法保證相同網址未來仍提供完全相同的內容。因此,Raw Data Layer 的重點是保留一份尚未修改的原始資料,讓下游流程出錯時可以重新執行。

  原始檔案保留在 S3
        ↓
   載入或轉換出錯
        ↓
     修正程式
        ↓
從同一份原始檔案重新處理

為什麼 Raw Data Layer 使用 S3?

Amazon S3 是一種物件儲存服務(Object Storage Service),適合保存 CSV、JSON、Parquet、圖片等非結構化檔案。它不依賴某台特定電腦,也能用一致的 Key 組織不同年份與月份的資料。Amazon S3、Google Cloud Storage 與 Azure Blob Storage 都能滿足這類需求。本專案選擇 Amazon S3,原因是它能透過 IAM 控制權限,並能使用 Boto3 與 Python 整合。S3 不是唯一答案,而是符合目前需求的實作選擇。Google Drive 雖然也能放檔案,但主要用途是人員共享與文件管理,不適合作為資料管線的原始資料層。

為什麼不直接只存 PostgreSQL?

S3 和 PostgreSQL 解決的問題不同。

Amazon S3:保存從來源取得、尚未修改的原始 CSV
PostgreSQL:保存已有欄位結構、資料型別與查詢需求的資料

PostgreSQL 裡的資料是「載入結果」,S3 裡的 CSV 是「重新處理的起點」。只保留 PostgreSQL 的資料,一旦載入邏輯或資料模型有誤,就可能失去重新處理的依據。至於 PostgreSQL 的資料表如何設計,以及如何載入大型 CSV,會在後面的文章正式進入 Load 流程時說明。

S3 裡的資料如何組織?

決定使用 S3 後,先認識四個概念:

  • Bucket(儲存貯體):存放物件的最上層容器。
  • Object(物件):實際保存的檔案內容與中繼資料。
  • Key(鍵):Object 在 Bucket 中的完整名稱。
  • Prefix(前綴):Key 的共同開頭,用來組織與篩選 Object。

這個專案將 2026 年 6 月的資料存成:ridership/year=2026/202606.csv在 AWS Console 裡看起來很像資料夾:

ridership/
└── year=2026/
    └── 202606.csv

但 S3 不是傳統檔案系統。對 S3 來說:

完整 Key:ridership/year=2026/202606.csv
Prefix:ridership/
Prefix:ridership/year=2026/

固定的 Key 規則很重要,因為之後 Python 只要取得 yearmonth,就能推導出檔案位置,不需要人工尋找。

程式如何安全存取 S3?

Bucket 建立好後,本機 Python 程式仍不能直接讀寫資料。S3 預設不應公開,因此 AWS 必須先回答三個問題:

誰提出請求?
可以執行什麼操作?
可以操作哪些資源?

本專案仍在本機開發,所以建立一個專用 IAM User,讓資料管線用這個身分存取 S3。其中有兩個容易混淆的東西:

  • Access Key:讓 AWS 辨識「你是誰」。
  • IAM Policy:決定這個身分「可以做什麼」。
     Access Key
         ↓
    辨識 IAM User
         ↓
     IAM Policy
         ↓
判斷是否允許操作指定資源

Access Key 本身不是權限。即使有 Access Key,IAM Policy 沒有允許某項操作,請求仍會被拒絕。

最小權限:只開放 Pipeline 需要的操作

最簡單的做法是直接授予 AmazonS3FullAccess,但這會讓程式取得遠超過目前需求的權限。本專案採用最小權限原則(Principle of Least Privilege):**只提供完成工作所需的最少權限。**目前 Pipeline 需要三個 S3 操作:

s3:ListBucket  # 列出指定 Prefix 下的物件
s3:GetObject   # 讀取物件
s3:PutObject   # 上傳物件

物件的讀寫範圍也只開放到本專案使用的路徑:arn:aws:s3:::<bucket-name>/ridership/*這代表程式可以讀寫 ridership/ 下的捷運資料,但不能任意操作其他 Bucket 或不相關的 Object。

AWS Console:建立儲存位置與權限

以下會說明完整的設定與驗證流程,但不會逐一使用截圖帶大家操作。這個系列會把重點放在每項設定背後的原因,以及它在資料管線中的作用,而不是特定版本的介面位置。如果實際操作時仍覺得需要圖片引導,歡迎在留言區告訴我;我會再依需求整理一篇獨立的圖文操作說明,並將連結補充在留言。雲端端的設定都在 AWS Management Console 完成,順序如下:

1. 建立 S3 Bucket
2. 設定 Bucket 不公開
3. 建立專用 IAM User
4. 建立最小權限 IAM Policy
5. 為 IAM User 建立 Access Key

建立 Bucket 時,本專案採用以下設定:

  • 封鎖所有公開存取,因為原始資料不需要公開。
  • 暫不啟用 Versioning,因為目前沒有保存同一 Key 多個版本的需求。
  • 使用 AWS 管理金鑰的 SSE-S3 加密靜態資料。
  • 不啟用 Object Lock,因為本專案沒有法規或不可修改保存需求。

這些選項不是開得越多越完整,而是要**根據需求選擇。**接著在 IAM 建立專用 User 與 Policy,將操作限制為 ListBucketGetObjectPutObject,資源限制在指定 Bucket 的 ridership/ Prefix。最後為這個 IAM User 建立 Access Key,供本機 AWS CLI 與 Boto3 識別身分。

本機 PowerShell:設定 AWS 憑證

Access Key 不能寫進 Python 程式,也不能提交到 GitHub。本專案透過 AWS CLI 將憑證保存在本機,再由 Boto3 的標準憑證機制讀取。AWS CLI 是獨立的命令列工具,不是本專案的 Python 套件,因此不使用 pip install。Windows 安裝方式可參考 AWS 官方文件
安裝後重新開啟 PowerShell,確認指令可用:aws --version
看到 aws-cli/2 開頭的版本資訊後,執行:aws configure
依序輸入 Access Key ID、Secret Access Key、預設 Region 與輸出格式。這些實際值不應出現在文章、程式碼或 Git Repository 中。
Bucket 名稱則放在專案根目錄的 .env S3_BUCKET=<你的 bucket 名稱>
.env 已加入 .gitignore;RepO只保留不含真實值的 .env.example

如果未來將 Pipeline 部署到 EC2、ECS 或其他 AWS 運算服務,就不應把本機 Access Key 一起搬上去,而應改用 IAM Role 與臨時憑證。

如何確認權限真的設定正確?

設定完成不代表一定正確。我們要驗證兩件事:

  1. 允許的操作真的成功。
  2. 超出範圍的操作真的被拒絕。

先建立一個不含敏感資料的測試檔案:Set-Content -Path .\s3_test.txt -Value "S3 permission test"

1. 確認目前身分

aws sts get-caller-identity 這一步驗證身分(Authentication),AWS 是否知道請求者是誰。輸出的 ARN 應對應到本專案建立的 IAM User。

2. 測試允許的操作

列出 ridership/ Prefix:aws s3 ls s3://<bucket-name>/ridership/
上傳測試檔案:aws s3 cp .\s3_test.txt s3://<bucket-name>/ridership/s3_test.txt
讀取物件資訊:

aws s3api head-object `
  --bucket <bucket-name> `
  --key ridership/s3_test.txt

這些操作成功,代表 IAM User 能在授權範圍內列出、上傳與讀取 Object。

3. 測試禁止的操作

只測成功還不夠。Policy 規定物件只能寫入 ridership/*,因此刻意嘗試上傳到未授權路徑:
aws s3 cp .\s3_test.txt s3://<bucket-name>/other/s3_test.txt

預期結果AccessDenied,這次失敗才是正確結果,因為它證明 Policy 不只允許正確路徑,也確實阻止範圍外的寫入。這是在驗證 Authorization(授權):目前身分被允許執行哪些操作。

Day 6 完成了什麼?

回到一開始的架構:

        政府資料來源
              ↓
Amazon S3--Raw Data Layer← 今天完成
              ↓
        PostgreSQL

今天完成的是:

  • 建立保存原始 CSV 的 S3 Raw Data Layer。
  • 定義依年份與月份組織資料的 Object Key。
  • 讓本機 Pipeline 使用專用 IAM User 存取 S3。
  • 用最小權限限制可執行的操作與資源範圍。
  • 驗證允許的操作成功、禁止的操作被拒絕。

目前資料仍是手動上傳,還沒有真正從政府來源自動進入 S3。

下一篇會把擷取與上傳流程寫進 extract.py,讓 Python 根據年月取得政府 CSV,直接串流上傳到 S3,並驗證來源檔案是否完整寫入。

Day 7|Stage 2(2/5):資料上傳 S3 就算成功了嗎?建立原始資料驗證(Raw Validation)


上一篇
Day 5|Stage 1(2/2):異常資料真的異常嗎?資料剖析(Data Profiling)- 2
系列文
Python 數據專案從頭做起:跟著一個專案學資料工程7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言