-
Notifications
You must be signed in to change notification settings - Fork 0
operations image snapshot
Factory A snapshot uploader, presigner, S3 metadata pipeline의 배포 확인과 장애 대응 절차다. 명령 예시에는 실제 token, certificate 내용, secret endpoint를 출력하지 않는다.
namespace: ai-apps
snapshot source: worker2:/var/lib/safe-edge/snapshots
snapshot-uploader: worker2 단일 Deployment
edge-iot-publisher: worker2 배치
outbox: Longhorn RWO PVC /var/lib/aegis/outbox
presigner route: POST /image-snapshot/presign
presigner Lambda: AEGIS-Lambda-SnapshotPresigner
data processor: AEGIS-Lambda-DataProcessor
이미지 binary는 presigned PUT으로 S3 image_snapshot/에 직접 들어간다. IoT Core에는 image_snapshot metadata JSON만 전송된다.
현재 배포 이미지 기준:
edge-iot-publisher: <account-id>.dkr.ecr.ap-south-1.amazonaws.com/aegis/edge-iot-publisher:sha-36eae8c
snapshot-uploader: <account-id>.dkr.ecr.ap-south-1.amazonaws.com/aegis/snapshot-uploader:sha-6d30ef2
edge-iot-publisher는 persistent MQTT 연결과 QoS 1 ack 기준으로 동작한다. AWS IoT Fleet
Indexing connectivity와 client ID 기준은 IoT Fleet 연결성을 따른다.
최근 검증 기준(2026-06-08): snapshot-uploader rollout, S3 original image 업로드, raw/processed metadata 적재, DynamoDB latest_image_snapshot 갱신, SnapshotPresigner/DataProcessor Lambda error check가 정상으로 확인됐다. Dashboard /image-snapshots API와 화면은 구현·배포됐지만 실제 저장 이미지 기준 수기 조회 검증은 별도 확인 항목으로 남아 있다.
K3s Secret 기본 이름과 key:
ai-apps/snapshot-uploader-presign
endpoint
token
등록 스크립트:
cd merge
PRESIGN_ENDPOINT='<presigner-endpoint>' \
PRESIGN_TOKEN='<shared-token-or-empty>' \
scripts/ops/register-snapshot-presigner-secret.shSecret 존재와 key 이름만 확인한다. 값은 출력하지 않는다.
kubectl -n ai-apps get secret snapshot-uploader-presign \
-o go-template='{{range $k, $v := .data}}{{$k}}{{"\n"}}{{end}}'Secret 변경 후 Deployment를 재시작한다.
kubectl -n ai-apps rollout restart deploy/aegis-spoke-snapshot-uploader
kubectl -n ai-apps rollout status deploy/aegis-spoke-snapshot-uploader현재 코드와 Terraform 기본값에서 PRESIGN_SHARED_TOKEN=""이면 Lambda 인증이 생략된다. 현재 Factory A MVP 운영 문서도 빈 값으로 기록되어 있어 token auth가 비활성화된 상태다. Token을 활성화할 때는 다음 두 값을 같은 maintenance window에 맞춘다.
Lambda environment PRESIGN_SHARED_TOKEN
K3s Secret snapshot-uploader-presign/token
한쪽만 먼저 바꾸면 presign 요청이 401 unauthorized로 실패한다.
kubectl -n ai-apps get deploy \
aegis-spoke-snapshot-uploader \
aegis-spoke-edge-iot-publisher
kubectl -n ai-apps get pod -o wide \
-l app.kubernetes.io/instance=aegis-spoke확인 기준:
-
snapshot-uploaderreplica가 1이다. - uploader Pod의 node가
worker2다. -
edge-iot-publisher도 outbox RWO PVC를 사용할 수 있는 worker2에 있다. - uploader의 snapshot volume은
/var/lib/safe-edge/snapshotshostPath이며 read-only다. - outbox volume은
aegis-spoke-outboxPVC다.
kubectl -n ai-apps describe deploy aegis-spoke-snapshot-uploader
kubectl -n ai-apps get pvc aegis-spoke-outboxWorker1 snapshot upload failover는 현재 지원하지 않는다. Worker2 장애 시 Pod를 worker1로 옮기는 것만으로 worker2의 node-local snapshot backlog에 접근할 수 없다.
Uploader 최근 로그:
kubectl -n ai-apps logs deploy/aegis-spoke-snapshot-uploader \
--since=30m주요 메시지:
| 로그 | 의미 |
|---|---|
uploaded ... -> s3://... |
S3 PUT, outbox metadata, state 기록 완료 |
snapshot upload failed |
presign, PUT, 파일 읽기, JSON/state 처리 실패 |
skip oversized snapshot |
5 MiB 등 설정 상한 초과 |
failed to read upload state |
state 손상, .bad 격리 후 빈 state로 진행 |
recovered upload state |
기존 outbox metadata로 state 복구 |
Publisher 최근 로그:
kubectl -n ai-apps logs deploy/aegis-spoke-edge-iot-publisher \
--since=30m| 로그 | 의미 |
|---|---|
published ... -> aegis/factory-a/image_snapshot |
MQTT publish 성공, outbox 파일 삭제 |
publish failed |
MQTT/TLS/네트워크 실패, 파일 유지 후 재시도 |
| schema/JSON 오류 | 해당 파일을 quarantine/으로 이동 |
Uploader 로그에 성공이 있고 publisher 로그가 없다면 outbox와 publisher 상태를 먼저 확인한다. Publisher 성공 뒤 outbox 파일이 삭제되는 것은 정상이다.
실제 secret 값은 조회하지 않고 Lambda 상태와 환경 변수 key만 확인한다.
aws lambda get-function-configuration \
--region ap-south-1 \
--function-name AEGIS-Lambda-SnapshotPresigner \
--query '{State:State,LastUpdateStatus:LastUpdateStatus,EnvironmentKeys:keys(Environment.Variables)}'API route:
aws apigatewayv2 get-apis \
--region ap-south-1 \
--query 'Items[?contains(Name, `SnapshotPresigner`)].{ApiId:ApiId,Name:Name}'
aws apigatewayv2 get-routes \
--region ap-south-1 \
--api-id <api-id>Lambda 로그:
aws logs tail /aws/lambda/AEGIS-Lambda-SnapshotPresigner \
--region ap-south-1 \
--since 30m
aws logs tail /aws/lambda/AEGIS-Lambda-DataProcessor \
--region ap-south-1 \
--since 30mCloudWatch metric:
aws cloudwatch get-metric-statistics \
--region ap-south-1 \
--namespace AWS/Lambda \
--metric-name Errors \
--dimensions Name=FunctionName,Value=AEGIS-Lambda-SnapshotPresigner \
--statistics Sum \
--period 300 \
--start-time <utc-start> \
--end-time <utc-end>400은 factory, filename, content type, size, SHA-256, timestamp validation을 확인한다. 401은 Lambda shared token과 K3s Secret token 불일치다. 5xx 또는 timeout은 Lambda 로그, IAM, API integration을 확인한다.
aws s3api head-object \
--bucket aegis-bucket-data \
--key 'image_snapshot/factory_id=factory-a/yyyy=<YYYY>/mm=<MM>/dd=<DD>/hh=<HH>/<filename>'ContentType이 image/jpeg 또는 image/png인지 확인한다.
Public ACL이 없는지 확인:
aws s3api get-object-acl \
--bucket aegis-bucket-data \
--key 'image_snapshot/factory_id=factory-a/yyyy=<YYYY>/mm=<MM>/dd=<DD>/hh=<HH>/<filename>'정상 기준은 owner FULL_CONTROL 외 public AllUsers/AuthenticatedUsers grant가 없는 것이다.
aws s3api list-objects-v2 \
--bucket aegis-bucket-data \
--prefix 'raw/factory-a/image_snapshot/yyyy=<YYYY>/mm=<MM>/dd=<DD>/' \
--max-items 10Raw 경로에는 현재 hh partition이 없다.
aws s3api list-objects-v2 \
--bucket aegis-bucket-data \
--prefix 'processed/factory-a/image_snapshot/yyyy=<YYYY>/mm=<MM>/dd=<DD>/hh=<HH>/' \
--max-items 10aws dynamodb get-item \
--region ap-south-1 \
--table-name AEGIS-DynamoDB-FactoryStatus \
--key '{"pk":{"S":"FACTORY#factory-a"},"sk":{"S":"LATEST"}}' \
--projection-expression 'last_image_snapshot_at,latest_image_snapshot'latest_image_snapshot.s3_key, source_timestamp, event_type, sha256, message_id가 processed metadata와 연결되는지 확인한다.
Dashboard Web의 /image-snapshots 화면과 Backend /image-snapshots/range,
/image-snapshots API는 S3 image_snapshot/factory_id=.../ 객체를 list하고 presigned GET URL을
발급한다. 이 경로는 System 권한 사용자에게만 노출되며, 비인증 호출은 401이어야 한다.
Backend ECS task role에는 다음 범위가 필요하다.
s3:ListBucket on image_snapshot/*
s3:GetObject on image_snapshot/*
운영 배포 이력상 API와 화면은 구현되어 있으나, 실제 저장된 이미지 데이터에 대한 수기 확인은 별도 검증 항목으로 남긴다.
State 파일:
/var/lib/aegis/outbox/.snapshot-uploader-state.json
State가 없는 최초 배포에서는 snapshot directory의 지원 이미지 전체가 backlog가 되어 오래된 파일부터 업로드된다. 파일 수와 S3 PUT/API 호출량을 먼저 확인하고 배포한다.
상태와 backlog를 확인하되 token이나 certificate를 출력하지 않는다.
kubectl -n ai-apps exec deploy/aegis-spoke-snapshot-uploader -- \
sh -c 'find /var/lib/safe-edge/snapshots -maxdepth 1 -type f \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" \) | wc -l'
kubectl -n ai-apps exec deploy/aegis-spoke-snapshot-uploader -- \
sh -c 'test -f /var/lib/aegis/outbox/.snapshot-uploader-state.json && wc -c /var/lib/aegis/outbox/.snapshot-uploader-state.json'
kubectl -n ai-apps exec deploy/aegis-spoke-snapshot-uploader -- \
sh -c 'find /var/lib/aegis/outbox -maxdepth 1 -type f -name "*.json" ! -name ".*" | wc -l'State를 수동 삭제하면 로컬 backlog가 다시 업로드될 수 있다. Outbox metadata가 아직 남은 항목은 matching SHA-256/size로 state를 복구할 수 있지만, 이미 publisher가 metadata를 삭제한 항목은 다시 PUT될 수 있다. State 초기화는 중복 object/metadata 영향을 검토한 뒤 수행한다.
Uploader는 원본 파일을 삭제하지 않는다. Snapshot directory 정리 문제는 Safe-Edge cleanup/purge 설정에서 해결한다.
| 관측 | 우선 확인 |
|---|---|
| 새 이미지가 scan되지 않음 | worker2 hostPath, 확장자, 파일 권한, uploader node |
Presign 400
|
allowed factory, basename, content type, size, SHA-256, timestamp |
Presign 401
|
Lambda token과 K3s Secret token 일치 여부 |
| S3 PUT 실패 | URL 만료, 필수 Content-Type, 네트워크, object prefix IAM |
| S3 original만 있고 raw 없음 | outbox metadata와 publisher MQTT 로그 |
| Raw만 있고 processed/DynamoDB 없음 | Data Processor invocation/error 로그 |
| Outbox 증가 | IoT endpoint/certificate/TLS, publisher 배치와 PVC |
| 같은 파일 재업로드 | state path, size/mtime 변경, state 손상 또는 초기화 |
현재 shared token은 선택 기능이며 빈 문자열이면 인증이 없다. 운영 강화 순서:
- 충분히 긴 무작위 token을 secret 관리 절차로 생성한다.
- Token을 repo, shell history, 위키, Terraform example에 평문으로 남기지 않는다.
- Terraform의
snapshot_presigner_shared_token을 안전한 입력 경로로 설정한다. -
snapshot-uploader-presign/token에 같은 값을 등록한다. - Lambda 적용과 uploader rollout을 같은 maintenance window에 수행한다.
- Token 없는 요청이
401, uploader 요청이200인지 확인한다. - Token rotation 절차와 주기를 운영 문서에 관리한다.
Shared bearer token은 MVP 보강책일 뿐이다. 장기적으로 API Gateway authorizer, mTLS, source network 제한, WAF/rate limit, token의 Secrets Manager 기반 주입을 검토한다. API Gateway에는 현재 throttle이 있지만 token이 비어 있으면 caller identity 인증을 대신하지 못한다.
- Raspberry Pi에 장기 AWS access key를 저장하지 않는다.
- Presigned URL과 bearer token을 로그나 문서에 남기지 않는다.
- IoT certificate와 private key 내용을 출력하지 않는다.
- S3 object에 public-read ACL을 설정하지 않는다.
- Presigned URL은 업로드 대상 key와 짧은 만료 시간으로 제한한다.
관련 문서
- 시스템 아키텍처
- 제어 & 데이터 플레인
- Dashboard VPC 설계
- 하드웨어 배치
- Hub EKS 네임스페이스
- Tailscale Mesh VPN
- 데이터 생명주기
- 데이터 조회 모델
- 실시간 갱신 구조
- IoT 데이터 계약
- Reporting Pipeline
- 로컬 스토리지
- 클라우드 스토리지
- Edge Agent
- Edge AI 탐지
- Factory-A Log Adapter
- Dummy Sensor
- Edge IoT Publisher
- Lambda Data Processor
- Risk Normalizer
- Risk Score Engine
- Pipeline Status Aggregator
- Graph Aggregator 5m
- Cloud Infra Collector
- Daily Report Generator
- Risk Alert Dispatcher
- Image Snapshot Pipeline
- Dashboard Backend
- Dashboard Web
- AI 채팅 어시스턴트