개발 공부 기록하기/03. AWS & Infra

패커 (Packer) 시작하기

lannstark 2020. 10. 1. 12:50

안녕하세요 여러분! 공부하는~ 개발자 입니다 :)
이번 시간에는 바로바로 하시코프(HashiCorp)에서 만든 Packer에 대해 알아보겠습니다!

 

Getting Started 공식 문서 : https://learn.hashicorp.com/collections/packer/getting-started

 

Packer란 여러 type의 머신 이미지 생성을 자동화하는 도구입니다. 가상 머신 이미지를 만들어주는 오픈소스라고 생각하시면 됩니다. 하나의 스크립트로 GCP, AWS, VMWare 등의 이미지를 한 번에 만들 수 있는거죠.

네, 저도 잘은 모르는데요 일단 바로 한 번 Getting Started를 따라해보겠습니다.

1. Packer 설치

첫 단계는 Packer 설치네요.. 저는 Mac을 사용하고 있기 때문에 brew install hasicorp/tap/packer 라는 명령어로 packer를 다운로드 받으려 했으나..

fatal: repository '[https://github.com/hasicorp/homebrew-tap/](https://github.com/hasicorp/homebrew-tap/)' not found

와 같은 에러가 나오며 다운로드에 실패해서 Manual하게 다운로드를 받게 되었습니다.

여기서 download를 누르고, zip 파일을 해제한 다음

mv ~/Downloads/packer /usr/local/bin 명령어로 bin 디렉터리로 옮겨주었습니다.

휴,, 설치를 확인했군요

2. 이미지 빌드하기

이제 이미지를 빌드할 건데요, packer에서 사용되는 몇 가지 기본적인 개념에 대해서 알아보겠습니다.

출처는 https://www.44bits.io/ko/post/building-docker-image-and-using-packer 이며, 원문의 많은 부분을 참고했습니다.

패커는 위에서 말씀드린 것처럼 '하나의 설정 소스로 여러 플랫폼의 머신/컨테이너 이미지'를 만드는 도구입니다.
AWS를 사용하신다면, 이미지라는 단어는 꽤나 익숙하실텐데요.. EC2를 만들 때 특정 Image를 설정해주고 생성하게 되고, 그 Image에 들어 있는 OS, 솔루션 등이 새로 만들어진 EC2 인스턴스에 들어있게 됩니다. 컴퓨터를 통채로 복사하는거죠. 여기에는 2가지 단점이 있습니다.

  1. 특정 시점만을 저장한다 (A깔고, B깔고 등등의 순서와 과정은 알지 못한다)
  2. 최신 상태를 위해 계속 이미지를 만들어야 하고, 관리 비용은 이미지 수에 비례해 늘어난다 (최신판, 가장최신판, 진짜최신판 등등...)

패커는 이러한 문제를 해결하기 위해 가상머신의 특정 상태를 저장하는 방법을 사용하지 않고, 이미지 생성 과정에 대한 모든 정보를 코드로 관리합니다 (docker-compose 느낌) 덕분에 이미지 생성 과정을 재현해 다양한 플랫폼에서 같은(유사한) 이미지를 만들어 사용할 수 있게 되죠. 패커에서 사용되는 3가지 용어인 빌더, 프로비저너, 템플릿에 대해서 간단히 살펴보겠습니다.

빌더

이미지를 생성할 플랫폼입니다. AWS, Docker, VMWare 등이 예시입니다.

프로비저너

이미지를 생성할 때 사용할 빌드 도구입니다. 쉘스크립트, 앤서블, 셰프 등이 예시입니다.

템플릿

프로비저너와 빌더 들의 설정이 담겨 있는 템플릿 파일입니다. JSON 포맷으로 작성되어 있습니다.

네, 이제 Getting Started로 돌아와서 따라해보겠습니다. AWS EC2 AMI를 만드는군요, 좋아요..

위에서 '템플릿'이라 불렸던 JSON 파일을 만들어 다음과 같은 정보를 입력해야 합니다. 아래는 Getting Started에 나와 있는 JSON 파일입니다.

{
  "variables": {
    "aws_access_key": "",
    "aws_secret_key": ""
  },
  "builders": [
    {
      "type": "amazon-ebs",
      "access_key": "{{user `aws_access_key`}}",
      "secret_key": "{{user `aws_secret_key`}}",
      "region": "us-east-1",
      "source_ami_filter": {
        "filters": {
          "virtualization-type": "hvm",
          "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
          "root-device-type": "ebs"
        },
        "owners": ["099720109477"],
        "most_recent": true
      },
      "instance_type": "t2.micro",
      "ssh_username": "ubuntu",
      "ami_name": "packer-example {{timestamp}}"
    }
  ]
}

각 필드들이 무엇을 의미하는지는 document에서 찾아볼 수 있습니다.

  • variables : 변수를 지정합니다. {{user '변수이름'}} 으로 그 자리에 변수를 넣을 수 있습니다. 기본 값은 null
  • builders : 머신 이미지를 만들기 위한 기본정보들의 배열입니다.
    • 원하는 플랫폼 별로 사용되는 필드들이 다릅니다.. AWS의 AMI를 EBS에 만들려는 경우 type에 amazon-ebs가 들어가게 됩니다.
  • region : 지역입니다. 쉽죠? ^^;;
  • source_ami_filter : Source AMI Filter 옵션을 지정합니다. Source AMI란 새로운 이미지를 만들기 위한 기본 이미지? 라고 생각하면 됩니다. 도화지 사서 그림 그릴 건데 무슨 도화지 쓸래 느낌 ..
    • 그냥 source AMI를 지정하는 방법도 있을 것 같아 찾아보니 source_ami를 지정할 수 있어 저는 source_ami로 대체했습니다. source_ami에는
  • instance_type : 말 그대로 instace_type 입니다 ㅋㅋㅋ t2.micro 같은게 들어가면 됩니다.
  • ssh_username : SSH를 사용할 유저이름 (Linux AMI는 ec2-user를 넣으면 된다)
  • ami_name : AMI 이름

최종적으로 제가 작성한 example.json은 이렇습니다!

{
  "builders": [
    {
      "type": "amazon-ebs",
      "access_key": "알맞는 access key",
      "secret_key": "알맞는 secret key",
      "region": "ap-northeast-2",
            "source_ami": "ami-03b42693dc6a7dc35",
      "instance_type": "t2.micro",
      "ssh_username": "ec2-user",
      "ami_name": "packer-example {{timestamp}}"
    }
  ]
}

source_ami는 EC2를 생성할때 후보군으로 나오는 AMI인 Linux AMI 2의 id를 넣어주었습니다.

packer validate example.json으로 확인해주니 별다른 에러가 나오지는 않았습니다.

그러면 pakcer build example.json으로 build를 한 번 해보죠!

이런 로그가 나오면서 EC2 인스턴스가 생겼습니다... 음? ㅋㅋㅋㅋㅋ

그리고 인스턴스가 잘 만들어진 것을 확인하자 인스턴스를 종료하고 AMI를 만들었네요

동일한 id임을 확인할 수 있습니다. 오-호..

제가 설정한 옵션 외에도 vpc나 security group을 설정할 수 있습니다.

  • vpc_id : 인스턴스가 올라갈 VPC id
  • subnet_id : 서브넷의 id
  • security_group_id 또는 security_group_ids : 보안 그룹의 id (문자열 또는 문자열 배열)

엇 여기서 java를 미리 깔아두고 싶은데..? 일단 Getting Started를 이어서 해보겠습니다.

3. Provision

아 이 단계에서 필요한 S/W 등을 미리 깔아두는군요...

참고로, 프로비저닝이란 사용자의 요구에 맞게 서버를 설정해 두었다가 필요 시 서버를 즉시 사용할 수 있는 상태로 미리 준비해 두는 것을 말한다고 합니다.

아까 만들었던 example.json을 변경해봅시다!

builders 항목 아래에 provisioners array를 추가하고 type과 inline 필드를 가지고 있는 객체를 만들 수 있습니다. 아래는 문서에 나와 있는 예시입니다.

{
  "variables": ["..."],
  "builders": ["..."],

  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "sleep 30",
        "sudo apt-get update",
        "sudo apt-get install -y redis-server"
      ]
    }
  ]
}

아하 생각보다 간단하네요? type으로 shell을 지정해주고 (shell script를 사용하겠다는 의미), inline에 차례로 실행될 명령어들을 적어주면 됩니다.

sleep 30은 매우 중요하다고 합니다. 그 이유는, 패커가 EC2로 들어가는 순간은 SSH가 가능해질때인데 그 전에 OS가 적절히 초기화 하는 시간을 벌어주기 위해서라고 합니다.

type을 다르게 지정해주시면 앤서블, 셰프 등을 사용하실 수 있습니다.

4. Vagrant boxes

vagrant란 가상 SW 개발 환경을 build하고 유지보수할 수 있는 오픈 소스 S/W입니다! 패커의 post-processor 기능을 이용해 vagrant box를 만들 수 있다고 합니다.

{
  "builders": ["..."],
  "provisioners": ["..."],
  "post-processors": ["vagrant"]
}

저도 vagrant가 무엇인지는 잘 모르지만, post-processor에 다양한 기능이 있다는 것이 중요해보입니다!!

5. 마무리

이상으로 packer를 이용해 AWS AMI를 후딱 만들어봤습니다 ㅎㅎ

생각보다 간단하고 코드를 이용해 기본 AMI에서 새로운 AMI를 만드는 것은 활용도가 높아 보입니다. AMI로만 관리하게 되면 이 AMI가 어떤 AMI였는지, 솔루션을 하나 더 깔아야 하는데 일일히 만들어줘야 한다든지 등의 어려움이 있을 수 있기 때문이죠.

긴 글 읽어주셔서 감사합니다 :)