[packer] packer를 사용해서 프로비저닝된 AMI를 만들기

June Lim
onthelook
Published in
11 min readOct 10, 2023

문제상황

프라이빗 서브넷을 사용한 인스턴스에서 nginx aws cli 등등 패키지를 다운받아야 하는 상황인데 NAT가 안 붙어있는데 어떻게 해결해야할 것인가?

시행착오

처음에는 ec2 인스턴스를 만들 때 Userdata에 스크립트를 넣어서 인스턴스를 만들면 될 줄 알았는데, 이것또한 NAT가 없으니 프로비저닝이 되지 않았습니다.

해결방법

packer를 사용해서 프로비저닝 된 AMI를 만들어서 해결합니다!

MAC Packer 설치 가이드

https://developer.hashicorp.com/packer/tutorials/docker-get-started/get-started-install-cli

Install Packer | Packer | HashiCorp Developer Packer must first be installed on the machine you want to run it on. developer.hashicorp.com

brew tap hashicorp/tap

Hashicorp tap 을 다운받아야 합니다. 그에 대한 명령어

brew install hashicorp/tap/packer

packer를 hashicorp/tap/packer를 사용해서 설치합니다.

packer

설치 되었는지는, packer 명령으로 확인할 수 있어요!

이제 제가 만들어볼까요!

디렉토리 구조입니다.

install-aws-cli.sh

이 스크립트 파일은 우분투 환경에서 AWS Cli설치, Credential 설정, 그리고 nginx설치와 config파일 입력까지 포함합니다.

#!/bin/bash
# AWS CLI 설치
sudo apt-get update -y
sudo apt-get install -y nginx python3-pip
# Install AWS CLI using pip
sudo pip3 install awscli
# AWS Credential 설정
mkdir -p /home/ubuntu/.aws
cat > /home/ubuntu/.aws/credentials <<EOL
[default]
aws_access_key_id = ${AWS_ACCESS_KEY}
aws_secret_access_key = ${AWS_SECRET_KEY}
EOL
cat > /home/ubuntu/.aws/config <<EOL
[default]
region = ${AWS_REGION}
EOL
# 설정 파일의 소유권 변경
sudo chown -R ubuntu:ubuntu /home/ubuntu/.aws
echo "AWS_ACCESS_KEY: $AWS_ACCESS_KEY"
echo "AWS_SECRET_KEY: $AWS_SECRET_KEY"
echo "AWS_REGION: $AWS_REGION"
# Configure nginx
sudo bash -c "cat > /etc/nginx/nginx.conf" <<'EOL'
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http { ##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
#ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on; # gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
#include /etc/nginx/sites-enabled/*;
##
# Server Configs
##
server {
listen 80;
server_name office.onthelook.internal;
##
# Location Configs
##
location / {
}
location /<엔드포인트1> {
alias /home/ubuntu/<경로>;
index index.html;
}
location /<엔드포인트2> {
alias /home/ubuntu/<파일경로>/build;
index index.html;
}
##
# Error Pages Configs
##
error_page 404 /404.html;
location = /404.html {
internal;
}
##
# Redirects Configs
##
# Redirect non-www to www
if ($host !~* ^(www)) {
rewrite ^(.*)$ <http://www.$host$1> permanent;
}
# Redirect HTTP to HTTPS
#if ($scheme != "https") {
# return 301 https://$server_name$request_uri;
#}
##
# SSL Configs
##
#ssl_certificate /etc/ssl/certs/your_cert.crt;
#ssl_certificate_key /etc/ssl/private/your_key.key;
#ssl_session_timeout 5m;
#ssl_protocols TLSv1.1 TLSv1.2;
#ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
#ssl_prefer_server_ciphers on;
}
}
EOL# Start and enable nginx
sudo systemctl start nginx
sudo systemctl enable nginx

aws-ubuntu.pkr.hcl

이 hcl 파일은 우분투 20.04 이미지를 기반으로 만들고, scripts 디렉토리안에있는 install-aws-cli.sh를 이용하여 프로비저닝합니다.

AWS credential 에 들어갈 내용들을 환경변수로 선언해주었습니다.

packer {
required_plugins {
amazon = {
version = ">= 0.0.1"
source = "github.com/hashicorp/amazon"
}
}
}
source "amazon-ebs" "ubuntu" {
ami_name = "${var.ami_prefix}-${local.timestamp}"
instance_type = "t2.micro"
region = "ap-northeast-2"
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"]
}
ssh_username = "ubuntu"
}
build {
sources = [
"source.amazon-ebs.ubuntu"
]
provisioner "shell" {
script = "scripts/install-aws-cli.sh"
environment_vars = [
"AWS_ACCESS_KEY=${var.aws_access_key}",
"AWS_SECRET_KEY=${var.aws_secret_key}",
"AWS_REGION=${var.aws_region}"
]
}
}
variable "ami_prefix" {
type = string
default = "private-backoffice-correct-ami"
}
locals {
timestamp = regex_replace(timestamp(), "[- TZ:]", "")
}

variables.pkr.hcl

변수에 대해서 값을 넣어줍니다. variable에 값에서 default를 비워주겠습니다.

variable "aws_access_key" {
type = string
default = ""
}
variable "aws_secret_key" {
type = string
default = ""
}
variable "aws_region" {
type = string
default = ""
}

variables.auto.pkvars.hcl

variables.auto.pkvars.hcl에서 디폴트에 들어갈 값들을 넣어주면 packer bulid를 할 때 그 값들이 적용되어서 들어가게됩니다.

aws_access_key = "AXXXXXXXXXXXXX"
aws_secret_key = "XXXXXXXXXXXaXXXXXXXXX"
aws_region = "ap-northeast-2"

VScode SSH 연결 config

Host private-backoffice-fixed
HostName <프라이빗 서브넷>
User ubuntu
IdentityFile /<pem키 경로>
ProxyCommand ssh -W %h:%p backoffice-bastion

이 부분은 따로 다른 페이지에서 정리해놓겠습니다.

그 후 이렇게 만들어진 프라이빗 인스턴스 안에서

aws configure list

명령을 하게 되면, variables.auto.pkvars.hcl에 넣었던 내용들이 잘 들어가서 프로비저닝되었음을 확인할 수 있다.

뿐만아니라 aws 명령어가 입력이 되는것을 확인하여서 쉘 스크립트로 userdata에 넣었던 내용들(aws 명령어)도 잘 프로비저닝되어서 들어간 것을 확인할 수 있습니다!

variables.pkr.hcl 에서 default에 값을 넣어서 프로비저닝을 할 수도 있지만, variables.auto.pkvars.hcl에 값을 넣고 사용하면서 깃이나 어딘가에 코드를 공유할 때 커밋 안하면 되니까 재사용성도 높은것같아서 packer 잘 사용하게 될 것 같습니다!

--

--