Postfix pipe 스크립트 작성하기

민정·2025년 9월 3일

pipe 스크립트

  • 스크립트에 아래의 단계가 포함되어야 함
    • GCP 인증&인가 정보를 가져옴 → queue에 task 생성 가능하다는 인증&인가 필요
    • GCP 인증 및 인가
    • Queue로 데이터 전송

GCP 인증 인가

  • GCP 인증&인가 정보를 어떻게 가져올 수 있는지?
  • 결론적으로 인증&인가 정보를 가져오는 것은 ADC가 있기 때문에 굳이 고려하지 않아도 됨

Cloud Task vs Pub/Sub

https://cloud.google.com/pubsub/docs/choosing-pubsub-or-cloud-tasks?hl=ko

  • 지금 원하는 큐 서비스는
    • MTA는 pipe 스크립트를 통해 큐로 메시지를 보내는 역할만 수행, MDA가 메시지 소비를 어떻게 할 지 자유롭게 선택할 수 있어야 함
    • MTA가 MDA의 역할에 간섭하지 않으며, 큐가 둘 간의 결합도만 낮춰주기를 바람
    • AWS의 SQS와 유사한 서비스이기를 바람
  • 이는 Cloud Task보다는 Pub/Sub에 가까움
    • Cloud Task는 게시자가 명시적 호출을 함
      • 이는 게시자(MTA)가 실행에 대해 완전한 제어를 유지
      • 따라서 게시자(MTA)는 소비자(MDA)의 메시지 소비 행동을 직접적으로 제어함
    • Pub/Sub은 게시자가 암시적 호출을 함
      • 게시자(MTA)는 구독자(MDA)에 대한 정보가 없어도 됨
      • 게시자(MTA)는 이벤트를 게시하기만 함, 구독자의 실행을 암시적으로 유지
  • 따라서 Pub/Sub을 사용하기로 결정
    • Pub/Sub에서 토픽을 생성하기만 하면 바로 사용 가능

VM 메타데이터

  • Pub/Sub 인증&인가 정보까지는 ADC를 통해 해결 가능
  • Cloud Pub/Sub API를 요청하기 위한 정보(Project ID, Topic ID)가 추가적으로 필요
    • Project ID는 VM 메타데이터 서버를 통해 가져올 수 있지만, Pub/Sub Topic ID는 불가능
    • Pub/Sub Topic ID를 사용자 메타데이터로 VM 메타데이터 서버에 저장 후 가져오는 방식도 가능
  • Project ID를 메타데이터 서버에서 가져올 생각이라면 Pub/Sub Topic ID도 메타데이터로 저장 후 가져오는 방식을 채택하는게 좋아 보임
  • 보안상 노출되면 위험한 값은 아니지만 그래도 그냥 메타데이터 값으로 저장해서 가져오는 것으로 설정

스크립트

  • python과 go 중 고민했는데, 사용한 경험이 있는 go를 쓰기로 선택
  • google cloud go API에서 지원 버전을 확인했는데 go 최신 버전인 1.2.5가 지원이 안된다...
  • home 디렉토리에서 작업 후 빌드
  • 빌드 된 파일을 /usr/local/bin로 이동 후 권한 및 소유자 수정

작성한 스크립트

package main

import (
 "context"
 "io"
 "log"
 "os"

 "cloud.google.com/go/compute/metadata"
 pubsub "cloud.google.com/go/pubsub/v2"
)

func main() {
 ctx := context.Background()

 projectID, err := metadata.ProjectIDWithContext(ctx)
 if err != nil {
  log.Fatalf("Failed to get project ID from metadata: %v", err)
 }
 topicName, err := metadata.ProjectAttributeValueWithContext(ctx, "pubsub-topic-id")
 if err != nil {
  log.Fatalf("Failed to get pubsub topic name from metadata: %v", err)
 }

 client, err := pubsub.NewClient(ctx, projectID)
 if err != nil {
  log.Fatalf("Failed to create pubsub client: %v", err)
 }
 defer client.Close()

 publisher := client.Publisher(topicName)
 defer publisher.Stop()

 data, err := io.ReadAll(os.Stdin)
 if err != nil {
  log.Fatalf("read stdin: %v", err)
 }
 result := publisher.Publish(ctx, &pubsub.Message{Data: data})

 msgID, err := result.Get(ctx)
 if err != nil {
  log.Fatalf("Failed to publish message to pubsub: %v", err)
 }

 log.Printf("Published message with ID: %s", msgID)
}
profile
시스템 + 리눅스 + 클라우드

0개의 댓글