tools
Packer의 큰 강점은 동일한 빌드 파이프라인으로 여러 클라우드 이미지를 동시에 만들 수 있다는 점입니다. 이번 글에서는 하나의 템플릿으로 AWS(AMI)와 GCP(Compute Engine Image)를 한 번에 생성하는 방법과, 각 빌더의 핵심 필드·자격 증명·네트워킹 주의 사항까지 정리합니다.
아래 템플릿은 AWS의 amazon-ebs
빌더와 GCP의 googlecompute
빌더를 함께 선언하고, 하나의 build
블록에서 두 이미지를 병렬로 빌드합니다.
packer {
required_plugins { # 최신 Packer(HCL2)에서는 Amazon, Google 빌더 모두 required_plugins로 명시해야 packer init이 동작
amazon = {
source = "github.com/hashicorp/amazon"
version = ">= 1.0.0"
}
googlecompute = {
source = "github.com/hashicorp/googlecompute"
version = ">= 1.0.0"
}
}
}
# -------- Variables
variable "image_prefix" { type = string, default = "multi-cloud" }
# AWS
variable "aws_region" { type = string, default = "us-east-1" }
variable "aws_instance_type"{ type = string, default = "t3.micro" }
# GCP
variable "gcp_project_id" { type = string, default = "my-gcp-project" }
variable "gcp_zone" { type = string, default = "us-central1-a" }
locals {
ts = timestamp()
}
# -------- AWS: amazon-ebs
source "amazon-ebs" "aws-image" {
ami_name = "${var.image_prefix}-aws-${local.ts}"
region = var.aws_region
instance_type = var.aws_instance_type
source_ami_filter {
filters = {
name = "ubuntu/images/*ubuntu-20.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
owners = ["099720109477"] # Canonical
most_recent = true
}
ssh_username = "ubuntu"
# (선택) 기본 VPC가 없다면 명시하세요
# subnet_id = "subnet-xxxx"
# security_group_ids = ["sg-xxxx"]
}
# -------- GCP: googlecompute
source "googlecompute" "gcp-image" {
image_name = "${var.image_prefix}-gcp-${lower(replace(local.ts, ":", "-"))}"
project_id = var.gcp_project_id
source_image_family = "ubuntu-2004-lts"
zone = var.gcp_zone
# Ubuntu 계열 기본 사용자
ssh_username = "ubuntu"
# (선택) 네트워크/서브넷/서비스 계정 지정
# network = "default"
# subnetwork = "default"
# service_account_email = "builder@${var.gcp_project_id}.iam.gserviceaccount.com"
}
# -------- Build (기본 병렬 실행)
build {
name = "aws-gcp-parallel"
sources = [
"source.amazon-ebs.aws-image",
"source.googlecompute.gcp-image",
]
# 두 플랫폼에 공통 적용되는 간단한 프로비저닝
provisioner "shell" {
inline = [
"echo 'Configured for multi-cloud!' | sudo tee /tmp/info.txt"
]
}
post-processor "manifest" {
output = "manifest.json"
strip_path = true
custom_data = {
aws_region = var.aws_region
gcp_project = var.gcp_project_id
image_prefix = var.image_prefix
}
}
}
멀티 클라우드 빌드를 도입하면 하나의 프로비저닝 스크립트를 AWS와 GCP 모두에 적용해 런타임 차이를 최소화할 수 있습니다. 여기서 런타임 차이를 최소화한다는 말은, 같은 애플리케이션이라도 클라우드 환경마다 기본 이미지, 네트워크 설정, 보안 옵션, 패키지 버전 등이 조금씩 달라 실행 동작에 미묘한 차이가 생길 수 있는데, 이를 줄인다는 뜻입니다.
또한, 단일 실행으로 두 이미지를 병렬 빌드해 파이프라인 전체 시간을 단축할 수 있다. sources 배열에 Azure, VMware 등 새로운 빌더를 손쉽게 추가할 수 있어 확장성과 유연성이 크게 향상된다.
source "amazon-ebs" "aws-image"
AWS에서 EBS 기반 AMI를 생성하는 빌더입니다.
ami_name
: AMI 이름. timestamp()
로 매 빌드마다 고유화
region
/ instance_type
: 빌드가 진행될 리전과 EC2 타입
source_ami_filter
: 베이스 AMI 검색 조건
name
: Ubuntu 20.04 이미지 패턴owners
: Canonical 공식 계정 ID 099720109477
most_recent
: 최신 이미지 선택ssh_username
: 우분투 공식 AMI의 기본 SSH 사용자(ubuntu
)
필요 시, VPC/서브넷/보안그룹을 고정하려면
subnet_id
,security_group_id(s)
등을 추가할 수 있습니다. 디폴트 VPC가 없는 계정이라면 반드시 명시하세요.
source "googlecompute" "gcp-image"
GCP에서 Compute Engine 이미지를 생성하는 빌더입니다.
image_name
: 최종 생성될 이미지 이름(영문 소문자·숫자·대시 권장)project_id
: 이미지를 만들 GCP 프로젝트source_image_family
: 베이스 이미지 패밀리(여기서는 ubuntu-2004-lts
)zone
: 빌드용 인스턴스를 띄울 존ssh_username
: 빌드 시 사용할 SSH 사용자명GCP에서는 Compute Engine API가 활성화되어 있어야 하며, 빌드 VM로의 SSH(포트 22) 접속을 허용하는 방화벽 규칙이 필요합니다. 프로젝트·VPC 보안 정책에 따라 추가 설정이 요구될 수 있습니다.
build
블록과 병렬 빌드sources
배열에 여러 source
블록을 나열하면, Packer는 각 빌더를 독립적으로 실행합니다. 일반적으로 동시에(병렬) 진행되므로 빌드 시간이 단축됩니다. Packer는 build
블록에 여러 source를 나열하면 기본적으로 병렬 실행하지만, 빌드 옵션에 따라 직렬(순차) 실행도 가능합니다. “기본적으로 병렬, 필요시 -parallel-builds=1
옵션으로 직렬화 가능합니다.
provisioner "shell"
은 각 빌드 머신 내부에서 동일하게 실행됩니다. 위 예제에서는 /tmp/info.txt
에 간단한 문자열을 기록합니다. AWS 인스턴스와 GCP 인스턴스에서 각각 이 명령이 수행되어 결과 이미지에 반영됩니다.
동일한 프로비저닝을 두 플랫폼에 모두 적용하면 일관성이 좋아지지만, 클라우드별 차이(패키지 관리자, 네트워킹, 메타데이터 서비스 등)가 있는 작업이라면 조건 분기(예: 쉘 스크립트 내부에서 클라우드 감지)를 고려하세요.
AWS에서 빌드를 하려면 내가 누구인지 증명할 방법이 필요합니다. 대표적으로 3가지 방법이 있습니다.
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
(필요 시AWS_SESSION_TOKEN
)
export AWS_ACCESS_KEY_ID=AKIA123...
export AWS_SECRET_ACCESS_KEY=abcd1234...
export AWS_SESSION_TOKEN=xyz... # (임시 자격일 때만 필요)
~/.aws/credentials 파일에 아래와 같이 셋팅합니다.
[default]
aws_access_key_id = AKIA123...
aws_secret_access_key = abcd1234...
EC2 인스턴스에 **역할(Role)**을 붙여주면, 키를 따로 저장하지 않아도 자동으로 권한이 생깁니다.
이미지 빌드를 위해선 EC2와 EBS 관련 권한이 필요합니다. 예를 들어, 최소한 이런 권한들이 있어야 합니다.
아래는 IAM 정책(JSON) 예시입니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:CreateImage",
"ec2:DeregisterImage",
"ec2:DescribeImages",
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:CreateSnapshot",
"ec2:DeleteSnapshot"
],
"Resource": "*"
}
]
}
aws sts get-caller-identity # 현재 내가 누구로 로그인했는지 확인
aws ec2 describe-images --owners self --max-results 1 # 내가 만든 AMI 확인
빌드 흐름을 다이어그램으로 표현하면 아래와 같습니다.
[사용자/빌드 도구]
│
│ (1) 자격 증명: 환경변수 / credentials 파일 / IAM Role
▼
┌───────────────┐
│ AWS STS/IAM │ ← 신분증 확인
└───────┬───────┘
│ (2) 권한 확인
▼
┌─────────────────────┐
│ Amazon EC2 (인스턴스) │
└───┬─────────────────┘
│
│ (3) 디스크/스냅샷 작업
▼
┌───────────────┐
│ Amazon EBS │
└───────────────┘
GCP에서는 보통 **서비스 계정(Service Account)**을 만들어 키(JSON 파일)를 발급합니다. 계정 키(JSON)를 직접 쓰는 방식은 보안상 취약할 수 있어, Workload Identity Federation(OIDC 기반)도 고려할 수 있습니다.
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/my-sa.json"
gcloud auth application-default login
gcloud 명령어는 아래와 같습니다.
gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:builder@my-project.iam.gserviceaccount.com" \
--role="roles/compute.instanceAdmin.v1"
gcloud auth list # 현재 인증된 계정
gcloud config list project # 현재 프로젝트 확인
gcloud compute images list --limit=1 # 접근 가능한 이미지 확인
빌드 흐름을 다이어그램으로 표현하면 아래와 같습니다.
[사용자/빌드 도구]
│
│ (1) 서비스 계정 키(JSON) 또는 gcloud 로그인
▼
┌───────────────────┐
│ Google IAM (ADC) │ ← 신분증 확인
└─────────┬─────────┘
│ (2) 역할(Role) 확인
▼
┌───────────────────┐
│ Compute Engine VM │
└───┬──────────────┘
│
│ (3) 디스크/이미지/스냅샷 조작
▼
┌───────────────────────┐
│ Compute Engine Images │
└───────────────────────┘
Packer HCL 파일(*.pkr.hcl)이 있는 프로젝트 폴더에서 실행하고, AWS/GCP 자격 증명은 이미 설정돼 있다고 가정하고 진행하겠습니다.
packer -v # Packer 버전 확인
aws sts get-caller-identity # (선택) AWS 자격 확인
gcloud config list project # (선택) GCP 현재 프로젝트 확인
required_plugins 블록에 선언된 플러그인을 내려받고, 구성이 맞는지 미리 점검합니다.
packer init .
packer validate .
템플릿에 여러 소스가 있으면 가능한 범위에서 병렬로 빌드됩니다.
packer build .
source.amazon-ebs.aws-image 와 source.googlecompute.gcp-image 두 개가 정의돼 있으면 둘 다 실행됩니다.
-only에 소스 주소(형식: source.<builder>.<name>)를 넘겨 원하는 것만 빌드합니다.
# AWS만 빌드
packer build -only=source.amazon-ebs.aws-image .
# GCP만 빌드
packer build -only=source.googlecompute.gcp-image .
# 여러 개 고를 땐 쉼표로 나열
packer build -only=source.amazon-ebs.aws-image,source.googlecompute.gcp-image .
문제 발생 시 로그 레벨을 올리거나 디버그 모드로 확인 할 수 있습니다.
# 터미널에 상세 로그 출력
PACKER_LOG=1 packer build .
# (추천) 파일로 저장
PACKER_LOG=1 PACKER_LOG_PATH=packer.log packer build .
프로젝트/리전/이미지 이름 등 환경 값을 관리가 가능합니다.
# 단일 변수
packer build -var 'aws_region=ap-northeast-2' .
# 변수 파일(HCL)
packer build -var-file=env/dev.pkrvars.hcl .
aws_region = "ap-northeast-2"
gcp_project_id = "my-dev-project"
image_prefix = "myapp-dev"
multi-cloud-aws-...
확인multi-cloud-gcp-...
확인각 이미지를 기반으로 인스턴스를 띄운 뒤 /tmp/info.txt
가 존재하는지 확인하면 프로비저닝이 반영되었는지 검증할 수 있습니다.
앱명-환경-OS-버전-타임스탬프
형태로 표준화하면 운영 가독성이 올라갑니다.이번 예제의 핵심은 하나의 Packer 템플릿으로 AWS와 GCP 이미지를 동시에 빌드할 수 있다는 점이며, build 블록의 sources 배열에 여러 source를 지정하면 동일한 프로비저닝이 각 클라우드 빌더에 적용되고 기본적으로 병렬로 진행되어 빌드 시간을 단축할 수 있습니다. 이 패턴을 익히면 동일한 빌드 파이프라인을 Azure, VMware 등 다른 플랫폼으로도 손쉽게 확장할 수 있고, 멀티 클라우드 환경에서 이미지 표준화와 일관성을 자연스럽게 확보할 수 있습니다.