📁 完全なコードはGitHubで公開:GitHub: pipeiac02
シリーズ一覧(全12回)
Phase 1: 基盤構築
Phase 2: ワークフロー
Phase 3: セキュリティ・運用
Phase 4: 開発効率化
1. はじめに
1-1. 今回のゴール
S3バケットを設計・構築して、データの保管場所を作ります。
| ゴール | 内容 |
|---|---|
| 設計 | Raw/Processedの役割を理解する |
| 実装 | Terraformでバケットを作成する |
| 確認 | 作成されたバケットを確認する |
1-2. 前回の振り返り
前回(第1回)では、パイプラインの全体像を「レストランの厨房」で理解しました。
| レストラン | AWS |
|---|---|
| 冷蔵庫(食材) | S3 Raw |
| 盛り付け済み料理 | S3 Processed |
今回は、この「冷蔵庫」と「盛り付け台」を設計していきます。
1-3. この記事で作るもの
2. 比喩で理解する
2-1. なぜバケットを2つに分けるのか?
レストランの厨房で考えてみます。
2-2. 比喩の図解(レストラン)
| 場所 | 役割 | 状態 |
|---|---|---|
| 冷蔵庫 | 食材を保管 | 生のまま、未加工 |
| 盛り付け台 | 調理済みを保管 | 調理済み、すぐ提供できる |
2-3. なぜ分けるのか?
2-4. 技術の図解(AWS)
| バケット | 役割 | 状態 |
|---|---|---|
| S3 Raw | 生データを保管 | JSON、未加工 |
| S3 Processed | 加工済みを保管 | Parquet、分析可能 |
2-5. 対応関係
| レストラン | AWS | 役割 |
|---|---|---|
| 冷蔵庫 | S3 Raw | 入ってきたものをそのまま保管 |
| 盛り付け台 | S3 Processed | 加工済み、すぐ使える状態 |
| 調理 | Lambda ETL | 変換処理 |
3. S3設計の考え方
3-1. 2つのバケットの役割
| バケット | 役割 | 入るもの | 出るもの |
|---|---|---|---|
| Raw | 生データの保管 | JSONファイル | Lambda が読み取り |
| Processed | 加工済みデータの保管 | Parquetファイル | Athena がクエリ |
3-2. データの流れ
3-3. Rawバケットの設計
| 項目 | 設計 | 理由 |
|---|---|---|
| 用途 | 生データの一時保管 | 加工前の状態を残す |
| 形式 | JSON | 入力データそのまま |
| 構造 |
input/ プレフィックス |
EventBridgeのトリガー条件に使う |
s3://dp-raw-XXXXXX/
└── input/
└── ec-sales.json
3-4. Processedバケットの設計
| 項目 | 設計 | 理由 |
|---|---|---|
| 用途 | 分析用データの保管 | Athenaから直接クエリ |
| 形式 | Parquet | 列指向で高速・低コスト |
| 構造 | パーティション分割 | クエリ効率化 |
s3://dp-processed-XXXXXX/
└── processed/
└── year=2025/
└── month=01/
└── data_20250115_123456.parquet
3-5. なぜパーティション分割?
3-6. 料理で例えると
| 技術 | 料理の例え |
|---|---|
| パーティションなし | 冷蔵庫に全部バラバラに入れる → 探すのに時間かかる |
| パーティションあり | 野菜室・肉室・飲み物棚に分ける → すぐ見つかる |
4. 命名規則
4-1. なぜ命名規則が大事か
4-2. 料理で例えると
| 状況 | 例え |
|---|---|
| ルールなし | 調味料にラベルがない → 塩と砂糖を間違える |
| ルールあり | 全部ラベル付き → 迷わず取れる |
4-3. バケット命名規則
{プロジェクト名}-{役割}-{サフィックス}
| 要素 | 値 | 例 |
|---|---|---|
| プロジェクト名 | dp |
data pipeline の略 |
| 役割 |
raw / processed
|
用途で決まる |
| サフィックス |
20250115 など |
一意にするため |
4-4. 実際のバケット名
| バケット | 名前 |
|---|---|
| Raw | dp-raw-20250115 |
| Processed | dp-processed-20250115 |
4-5. なぜサフィックスが必要?
S3バケット名は 全世界で一意 である必要があります。
4-6. プレフィックス規則
バケット内のフォルダ構造も統一します。
| バケット | プレフィックス | 用途 |
|---|---|---|
| Raw | input/ |
EventBridgeトリガー対象 |
| Processed | processed/year=/month=/ |
パーティション構造 |
4-7. タグ規則
リソース管理のためにタグを統一します。
| タグキー | 値 | 用途 |
|---|---|---|
| Environment |
dev / prod
|
環境識別 |
| Project | dp |
プロジェクト識別 |
| ManagedBy | Terraform |
管理方法識別 |
5. 実装
5-1. ファイル構成
今回作成するファイル:
pipeiac02/
└── tf/
├── main.tf # プロバイダ設定
├── variables.tf # 変数定義
└── s3.tf # ★今回作成
5-2. 変数定義(variables.tf)
まず、命名規則で決めた値を変数化します。
# variables.tf
# ================================
# 変数定義
# ================================
variable "project" {
description = "プロジェクト名"
type = string
default = "dp"
}
variable "environment" {
description = "環境名(dev/prod)"
type = string
default = "dev"
}
variable "aws_region" {
description = "AWSリージョン"
type = string
default = "ap-northeast-1"
}
variable "bucket_suffix" {
description = "S3バケット名のサフィックス(日付など)"
type = string
default = "20250115"
}
variable "alert_email" {
description = "アラート通知先メールアドレス"
type = string
}
5-3. S3バケット(s3.tf)
次に、2つのバケットを作成します。
# s3.tf
# ================================
# Rawバケット(生データ用)
# ================================
resource "aws_s3_bucket" "raw" {
bucket = "${var.project}-raw-${var.bucket_suffix}"
# 学習用:削除時に中身ごと消せるようにする
force_destroy = true
tags = merge(local.common_tags, {
Name = "${var.project}-raw"
})
}
# ================================
# Processedバケット(加工済み用)
# ================================
resource "aws_s3_bucket" "processed" {
bucket = "${var.project}-processed-${var.bucket_suffix}"
# 学習用:削除時に中身ごと消せるようにする
force_destroy = true
tags = merge(local.common_tags, {
Name = "${var.project}-processed"
})
}
| 設定 | 意味 | 料理で例えると |
|---|---|---|
bucket |
バケット名 | 冷蔵庫に貼るラベル |
force_destroy |
中身があっても削除可能 | 食材が残っていても廃棄OK(学習用) |
tags |
リソースの識別情報 | 管理台帳への記録 |
5-5. main.tf(Terraform/AWSプロバイダ設定)
# main.tf
# ================================
# Terraform/AWSプロバイダ設定
# ================================
terraform {
required_version = ">= 1.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
archive = {
source = "hashicorp/archive"
version = "~> 2.0"
}
}
}
# AWSプロバイダ
provider "aws" {
region = var.aws_region
}
# ================================
# 共通タグ
# ================================
locals {
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "Terraform"
}
}
6. 動作確認
6-1. ディレクトリ移動
cd pipeiac02/tf
6-2. 初期化
terraform init
期待される出力:
Terraform has been successfully initialized!
6-3. 計画(プレビュー)
terraform plan
期待される出力:
Plan: 2 to add, 0 to change, 0 to destroy.
2つのS3バケットが作成されることを確認します。
6-4. 適用(作成)
terraform apply
Enter a value: が出たら yes を入力。
期待される出力:
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
6-5. 作成されたバケットを確認
aws s3 ls | grep dp-
期待される出力:
2025-01-15 12:00:00 dp-raw-20250115
2025-01-15 12:00:00 dp-processed-20250115
6-6. AWSコンソールでも確認
- AWSコンソール → S3
-
dp-raw-*とdp-processed-*が存在することを確認 - タグが正しく設定されていることを確認
6-7. 確認チェックリスト
| 確認項目 | 期待値 |
|---|---|
| バケット数 | 2つ |
| Raw バケット名 | dp-raw-20250115 |
| Processed バケット名 | dp-processed-20250115 |
| タグ(Project) | dp |
| タグ(Environment) | dev |
| タグ(ManagedBy) | Terraform |
7. まとめ
7-1. この記事でやったこと
| 項目 | 内容 |
|---|---|
| 設計 | Raw/Processedの役割分担を理解 |
| 命名規則 |
dp-{役割}-{サフィックス} で統一 |
| 実装 | Terraformで2つのバケットを作成 |
| 確認 | バケットが作成されたことを確認 |
7-2. 比喩の振り返り
| レストラン | AWS | 今回やったこと |
|---|---|---|
| 冷蔵庫 | S3 Raw | ✅ 作成 |
| 盛り付け台 | S3 Processed | ✅ 作成 |
| 調理 | Lambda | 次回 |
7-3. 作成したリソース
7-4. 次回予告
第3回: Lambda ETL では、データ変換処理を実装していきます。
- JSON → Parquet 変換
- Pandas Layer の使い方
- 環境変数の設定
レストランで言うと「料理人の調理手順」を作っていきます。