이 글에서는 Immutable Infrastructure가 무엇인지 이해하고, 이를 구현하기 위한 첫 단계로 Packer와 Ansible을 사용하여 골든 이미지를 만든다. 이후 Github Actions을 사용해 변경사항이 Ansible Playbook에 푸시될 때마다 자동으로 Packer를 실행하는 Golden Image 파이프라인을 구성한 다음, Terraform을 사용하여 변경된 이미지로 인프라를 교체하도록 설정하여 자동화된 Immutable Infra를 구현하는 것을 목표로 한다.
완성하면 요런느낌 ✨
시리즈는 다음과 같이 계획되어있다.
1. Packer와 Ansible로 이미지 만들기
2. GitHub Actions로 이미지 생성 자동화
3. Terraform을 사용하여 AWS에 변경된 인프라 배포
AWS를 사용중인 사람이라면 인스턴스를 생성할 때 AMI(Amazon Machine Image)를 사용해봤을 것이다. AMI는 미리 구성된 운영 체제와 설치된 소프트웨어를 포함하고 있는 머신 이미지인데, 덕분에 인스턴스를 시작할 때마다 수동으로 구성하는 절차 없이 빠르게 리소스를 프로비저닝 할 수 있다. 이 AMI에 대한 일종의 마스터 템플릿을 골든 이미지라고 한다.
DevOps 관점에서 이미지, 특히 골든 이미지는 변경 불가능한 인프라(Immutable Infrastructure)를 구현하는 데 중요한 역할을 한다. 필요한 구성과 소프트웨어가 모두 포함된 완벽한 골든 이미지를 생성한 다음 해당 이미지를 사용하여 인프라를 생성한다는 아이디어로, 서버에 업데이트 또는 수정이 필요한 경우 이미 사용 중인 서버를 업데이트하는 대신 새로운 이미지를 사용하여 새 서버를 배포하는 방식을 선택한다. 즉 한번 실행된 인스턴스는 변경되지 않고, 변경이 필요한 경우에는 업데이트된 이미지를 가지고 아예 새로운 인스턴스로 교체한다. 때문에 구성 드리프트가 발생할 틈이 없다.
이렇게 인프라를 관리하면 다음과 같은 이점이 있다.
Packer를 한 마디로 정의하자면 '머신 이미지 빌더'라고 할 수 있을 것 같다. Template을 사용해 여러 플랫폼의 머신 이미지를 생성할 수 있는 Hashicorp의 오픈소스로, AWS Image builder와 유사한 기능을 한다. Packer는 이미지를 만들 때 가상 머신의 특정 시점의 상태만을 저장하는 것이 아니라 이미지가 생성되는 과정도 코드로 저장되기 때문에 유사한 이미지를 반복 생성할 때 도움이 된다.
Template 은 빌드하려는 이미지와 빌드 방법을 정의한 구성파일로, Builder와 Provisioner를 조합하여 구성한다. 초기에는 JSON 형식(.pkr.json)으로 템플릿을 작성했으나 현재는 Terraform과 같은 HCL2를 사용하도록 장려하고 있다. 이 글에서는 HCL로 템플릿을 작성한다.
Ansible은 원격으로 서버를 구성하고 관리할 수 있는 RedHat의 오픈소스이다. Ansible은 Python을 기반으로 개발되었으며, YAML 포
맷을 기반으로 인프라를 정의한다. Ansible을 사용하면 관리할 서버에 별도의 데몬을 설치하지 않고 원격으로 접속해서 서버를 구성할 수 있다. Packer로 이미지를 빌드할 때 Ansible을 프로비저너로 사용하면 이미지에 필요한 모든 소프트웨어를 사전에 설치할 수 있고, playbook을 작성해 여러번 재사용할 수 있어 효율적인 인프라 관리가 가능하다.
macOS를 사용중이라 brew로 설치했다.
# install packer
brew tap hashicorp/tap
brew install hashicorp/tap/packer
# install ansible
brew install ansible
provisioner로 ansible을 사용할 것이기 때문에 playbook을 미리 작성한다.
playbook은 원격 host에서 실행할 일련의 작업을 yaml로 작성한 스크립트이다. 다음 스크립트는 ec2의 timezone을 서울로 변경하고, 최신 버전으로 git을 설치하고, 특정 버전의 nginx를 설치하고, nginx를 시작한다.
# playbook.yml
- name: Start Playbook
hosts: all
become: yes
tasks:
- name: Set Asia/Seoul timezone
timezone:
name: Asia/Seoul
- name: Install git
yum:
name: git
state: latest
- name: Enable extras
command: amazon-linux-extras install -y nginx1.12
args:
creates: /etc/nginx/nginx.conf
- name: Start Nginx
ansible.builtin.systemd:
name: nginx
state: started
enabled: yes
1. packer 템플릿을 저장할 디렉토리를 생성한다.
mkdir packer-practice
cd packer-practice
2. 작성한 Packer 템플릿은 다음과 같다.
source_ami는 AMI 카탈로그에서 참조하거나 private으로 사용하는 ami가 있다면 해당 ami를 사용해도 된다. 최신버전의 ami를 사용하고자 하는 경우 filter를 통해 조회 후 적용이 가능하다.
# packer-aws-linux.pkr.hcl
locals {
timestamp = regex_replace(timestamp(), "[- TZ:]", "")
}
source "amazon-ebs" "packer-ami" {
region = "ap-northeast-2" # AMI를 생성할 리전
ami_name = "packer-aws-${local.timestamp}"
source_ami = "ami-0a0064415cdedc552" # Amazon Linux 2 AMI (HVM)
vpc_id = "vpc-id" # AMI가 생성될 VPC
subnet_id = "subnet-id" # AMI가 생성될 Subnet
instance_type = "t2.micro"
ssh_interface = "public_ip"
ssh_username = "ec2-user" # Linux ssh user (ubuntu일 경우 admin)
ami_description = "Nginx with Amazon Linux2"
assume_role {
role_arn = "arn:aws:iam::account-id:role/admin"
}
tags = { # https://developer.hashicorp.com/packer/plugins/builders/amazon/ebs#build-shared-information-variables
Base_AMI_ID = "{{ .SourceAMI }}"
Base_AMI_Name = "{{ .SourceAMIName }}"
}
}
build {
sources = [
"source.amazon-ebs.packer-ami"
]
provisioner "ansible" {
playbook_file = "playbook/playbook.yml"
use_proxy = "false"
user = "ec2-user"
}
}
3. 구성을 Initialize 한다.
packer init .
init을 실행하면 packer는 구성 파일을 분석해서 필요한 플러그인을 식별하고 설치되어 있지 않다면 필요한 플러그인을 설치한다. 이때 빌더나 프로비저너와 관련된 항목은 관여하지 않고 오로지 플러그인만 확인한다.
4. packer 파일의 syntax에 문제가 없는지 확인하고 유효성 검사를 실시한다.
packer fmt packer-aws-linux.pkr.hcl
packer validate packer-aws-linux.pkr.hcl
1. pakcer build 명령을 통해 이미지를 빌드해보겠다. build를 실행하면 Packer는 머신 이미지를 생성하고 Provisioner를 실행시킨다.
packer build packer-aws-linux.pkr.hcl
2. 콘솔에서 결과를 확인해보자.
build 명령 후 출력된 ami-id와 동일한 id의 이미지가 생성된 것을 확인할 수 있다. 태그도 의도했던대로 추가되었다. packer 템플릿에서 packer-aws-${local.timestamp}와 같이 AMI 이름에 생성된 시간이 찍히게 설정해두는데 정상적으로 반영되었다.
생성한 AMI로 EC2를 시작하여 ansible로 구성한 내역이 잘 들어갔는지 확인해봤다.
모두 정상적으로 실행된 것을 확인할 수 있었다.
packer는 처음 사용해보았는데, terraform을 사용하고 있어서 그런지 무리 없이 사용할 수 있었다. 여기서는 간단히 nginx를 설치하는 등의 작업만 진행했지만 실제로 애플리케이션을 미리 배포하고 구동하는 등의 작업을 playbook으로 실행하고 프로비저닝 해둔다면 auto scaling용 golden ami를 유지 관리하는데 큰 도움이 되겠다고 느꼈다. 꼭 프로덕션용으로 사용하지 않더라도 사내 표준 test base ami를 구성해두면 엔지니어나 개발자가 동일 환경에서 테스트 할 수 있다는 장점도 있을 것으로 보인다.
다음 글에서는 github action을 사용해 packer나 ansible playbook에 변경사항이 있을 때 이를 감지하고 새롭게 이미지를 build하는 방법을 설명해보려 한다.
참고자료
https://www.44bits.io/ko/post/building-docker-image-and-using-packer
https://developer.hashicorp.com/packer/tutorials/aws-get-started/aws-get-started-build-image
Golden Image Pipeline 구성 - 2. GitHub Actions로 이미지 생성 자동화 (0) | 2023.06.26 |
---|---|
GitHub Actions Workflow 문법 정리 (0) | 2023.06.22 |
댓글 영역