Search

[Packer + Terraform] Jenkins EC2 자동화

Date
2025/11/09
Category
Devops
Tag
IaC
AWS
목차
팀 프로젝트에서 CI/CD 환경을 구축하기 위해 Jenkins를 도입했다.
하지만 AWS Free-Tier 환경에서는 비용 절감을 위해 빈번한 terraform apply/destroy 작업이 발생했고, 매번 수동으로 Jenkins를 재설치하는 과정은 비효율적이라고 판단했다.
이를 해결하기 위해 Packer와 Terraform을 조합해 Jenkins EC2 자동화 파이프라인을 설계했다.
이번 글에서는 Jenkins EC2를 자동화하는 세 가지 방법을 비교하고, 가장 범용적이고 실무적인 접근인 “Packer로 Docker 기반 AMI를 생성하고 Terraform으로 Jenkins 컨테이너를 실행하는 방식”을 구현한다.

 Jenkins EC2 자동화의 세 가지 방법

 Packer로 Jenkins까지 설치된 AMI 생성

설명: Jenkins를 EC2 이미지에 직접 설치해 AMI로 만들어 둔다.
장점: 배포 즉시 Jenkins 실행 가능구성 단순
단점: Jenkins 버전 변경 시 AMI 재빌드 필요환경 유연성 낮음
권장 대상: 개인 프로젝트, 단일 서버

 Packer로 Docker + Jenkins를 함께 설치한 AMI 생성

설명: Docker를 설치하고 Jenkins 컨테이너까지 포함한 AMI를 만든다.
장점: 컨테이너 기반 Jenkins빠른 기동
단점: Jenkins 컨테이너 버전 고정AMI 교체 주기 여전히 필요
권장 대상: 소규모 DevOps 환경

 Packer로 Docker만 설치된 AMI 생성 + Terraform에서 Jenkins 컨테이너 실행

설명: Packer는 Docker 환경만 구성하고, Terraform이 런타임에 Jenkins 컨테이너를 실행한다.
장점: AMI 범용성 높음Jenkins 교체 간편IaC 관리 용이
단점: 초기 구성 복잡
권장 대상: 일반적인 현대 DevOps 환경

 Docker 기반 AMI 생성 + Terraform으로 Jenkins 컨테이너 실행

이번 글에서는 ③번 구조를 실습한다. 즉, Packer는 Docker 환경만 구축하고, Terraform이 Jenkins를 컨테이너로 실행한다. 이 방식은 Jenkins뿐 아니라 다른 서비스에도 동일하게 적용할 수 있다.

 전체 구조 개요

Packer → (Docker 설치된 AMI 빌드) Terraform → (해당 AMI 기반 EC2 생성 + Jenkins 컨테이너 실행)
Plain Text
복사
Packer: 표준 Docker 베이스 AMI 생성
Terraform: 인스턴스 생성 후 user_data로 Jenkins 컨테이너 자동 실행
결과: EC2 부팅 시 Jenkins가 컨테이너 형태로 즉시 실행됨

 Packer로 Docker 기반 AMI 빌드

docker-base.pkr.hcl 파일을 생성한다.
packer { required_plugins { amazon = { source = "github.com/hashicorp/amazon" version = ">= 1.2.0" } } } source "amazon-ebs" "docker_base" { region = "ap-northeast-2" ami_name = "docker-base-{{timestamp}}" instance_type = "t3.micro" ssh_username = "ubuntu" source_ami_filter { filters = { name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } owners = ["099720109477"] most_recent = true } tags = { Name = "docker-base-ami" } } build { sources = ["source.amazon-ebs.docker_base"] provisioner "shell" { inline = [ "sudo apt update -y", "sudo apt install -y ca-certificates curl gnupg lsb-release", "sudo mkdir -m 0755 -p /etc/apt/keyrings", "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg", "echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null", "sudo apt update -y", "sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin", "sudo usermod -aG docker ubuntu", "sudo systemctl enable docker" ] } }
HCL
복사
구성 요소
설명
source.amazon-ebs
AWS EC2용 AMI 빌더
provisioner.shell
Docker를 설치하고 부팅 시 자동 실행되도록 설정
ami_name
docker-base-<timestamp> 형태로 AMI 이름 지정

 Packer 빌드 실행

packer init . packer validate docker-base.pkr.hcl packer build docker-base.pkr.hcl
Bash
복사
완료되면 AWS 콘솔의 EC2 → AMI 메뉴에서 docker-base-<timestamp> 이름의 이미지가 생성된다.
이제 이 AMI가 모든 배포의 공통 베이스가 된다.

 Terraform으로 Jenkins 컨테이너 실행

main.tf 파일을 작성한다.
data "aws_ami" "docker_base" { most_recent = true owners = ["self"] filter { name = "name" values = ["docker-base-*"] } } resource "aws_instance" "jenkins" { ami = data.aws_ami.docker_base.id instance_type = "t3.micro" subnet_id = aws_subnet.public_a.id vpc_security_group_ids = [aws_security_group.jenkins.id] key_name = var.key_name user_data = <<-EOF #!/bin/bash docker pull jenkins/jenkins:lts-jdk17 docker run -d \ -p 8080:8080 -p 50000:50000 \ -v /var/jenkins_home:/var/jenkins_home \ --name jenkins \ jenkins/jenkins:lts-jdk17 EOF tags = { Name = "jenkins-docker-ec2" } }
HCL
복사
Terraform이 docker-base AMI로 EC2 인스턴스를 생성한다.
부팅 후 user_data 스크립트가 Jenkins 컨테이너를 자동 실행한다.
Jenkins는 8080 포트에서 접근 가능하며, /var/jenkins_home에 데이터가 저장된다.

 배포 실행

terraform init terraform apply
Bash
복사
배포 후 EC2에 SSH 접속하여 Jenkins 컨테이너가 정상 기동 중인지 확인한다.
ssh -i <keypair> ubuntu@<ec2_ip> sudo docker ps
Bash
복사
결과 예시:
CONTAINER ID IMAGE COMMAND STATUS PORTS a13c3c... jenkins/jenkins:lts-jdk17 "/usr/bin/tini -- /u…" Up 2 minutes 0.0.0.0:8080->8080/tcp
Bash
복사

 Jenkins 업데이트 전략

Docker 기반 Jenkins의 장점은 버전 교체가 AMI 재빌드 없이 가능하다는 점이다.
EC2 내 혹은 Terraform 변수로 Jenkins 이미지를 관리할 수 있다.
# Bash sudo docker pull jenkins/jenkins:lts-jdk17 sudo systemctl restart docker
Bash
복사
# Terraform variable "jenkins_image" { default = "jenkins/jenkins:lts-jdk17" }
HCL
복사

 마무리

이번 구축을 통해 Packer와 Terraform을 활용한 Jenkins EC2 완전 자동화 구조를 만들었다.
덕분에 terraform apply/destroy를 반복해도 Jenkins 환경이 일관되게 유지되며, Docker 기반으로 Jenkins를 컨테이너화했기 때문에 업데이트나 재배포 시에도 빠르고 유연한 관리가 가능하다.
다만 Jenkins의 데이터를 지속적으로 유지하려면 EBS 볼륨 스냅샷 또는 외부 스토리지 마운트 등의 추가 구성이 필요하다.
또한 Terraform의 user_data첫 부팅 시 1회만 실행되기 때문에, 초기 컨테이너 실행이 실패할 경우에는 Ansible 등을 함께 사용하는 것이 일반적이다.
참고 영상: YouTube | HashiCorp Packer, Terraform, and Ansible to Set Up Jenkins