Cloud Tech

Ansible과 Packer를 활용한 Golden Image 구성

Hanhorang31 2024. 2. 3. 21:26

 

A101(=Ansible 101 Study)는 Ansible 실무 실습 스터디입니다.
CloudNet@ 가시다 님이 진행하시며, 책 "앤서블로 시작하는 인프라 자동화"을 기반으로 진행하고 있습니다.

골든이미지(Goalden Image)는 특정 시점에서 완벽하게 구성(검증, 최적화, 보안, 필요한 패치, 시스템 설정)된 시스템의 이미지입니다. 이번 시간에는 도구 Ansible과 Packer를 통하여 Ubuntu OS 골든이미지를 구성하겠습니다.

 

Packer ?

Packer란 이미지(머신, 이미지, 컨테이너 이미지) 생성 자동화 도구입니다. 특징을 정리하면 다음과 같습니다.

  • 코드를 통한 이미지 구성 : 코드를 통해 이미지가 생성되어 코드 관리 및 불변 인프라 특징을 가집니다.
  • 다양한 플랫폼 제공 : 플랫폼(AWS, Google Cloud Platform, Azure, VMware, Docker 등)에 대한 이미지를 생성할 수 있으며, 한 번의 코드로 여러 환경에서 동일한 이미지를 구성할 수 있습니다.
  • 오픈소스 도구 : HashiCorp에서 개발한 오픈소스 도구로, 24년 기준 무료로 사용할 수 있으며 생성 예제 또한 쉽게 구할 수 있습니다.

 

Packer의 이해를 위해 동작 원리를 보면 다음 그림과 같습니다. Pakcer는 AMI를 생성하기 위한 서비스(인스턴스, 보안그룹, 키페어)를 임시로 생성하여 AMI를 구성한다음 임시 서비스를 삭제합니다. 최종적으로 AWS에는 AMI만 남습니다.

코드로 보면 이해가 더 빠른데요, 테라폼과 같은 HCL로 구성되어 있습니다.

  • provisinoers : builders 블록을 통해 구성한 환경에서 실행할 작업을 정의합니다. 작업에는 shell같은 쉘 스크립트나 앤서블을 사용할 수 있습니다.
  • builders : AMI를 생성하기 위한 구성 환경을 정의합니다. builder.type 에 따라 구성 환경을 달리하여 이미지를 생성할 수 있습니다.
  • post-processor : 이미지를 생성한 다음 구성 환경에서 처리할 작업을 정의합니다. 예제에서는 type(docker 이미지 생성 기준) 에서 태그를 설정하고 푸쉬로하도록 정의되어 있습니다.

 

 

Ansible과 Packer 를 같이 써야할까?

Packer로만 골든 이미지를 생성하기엔 충분할 수 있지만 고려할 점도 있습니다.

  • provisioner 작업 Task 간 변수 지원하지 않음 : Task1 에서 설정한 환경 변수를 Task2에 반영하여 사용할 수 없습니다. 예를 들어, 이미지 구성 내 버전에 따른 패키지 버전 설정을 해야할 경우 버전에 따라 packer에서 변수 설정이 필요합니다.
  • 이미지 생성 로직 미지원 : Packer에서는 if나 OS의 정보를 가져오는(ansible factor) 같은 기능은 지원하지 않습니다. OS에 따라 패키지 설치가 달리 구분되거나 구성 정보를 가져와서 설정해야 할 경우 다른 도구와 결합이 필요합니다.

 

이러한 측면에서 봤을 때, Packer로 골든 이미지를 생성을 위한 환경을 구성하고, Ansible로 그 이미지의 구성을 세밀하게 관리할 수 있게됩니다.

 

다만, 두 도구의 사용 옵션에 충분한 이해가 필요합니다. 정확한 구성 이해없이 오픈소스를 테스트한다면 필자처럼 트러블슈팅에 며칠 시간을 소비하게 됩니다. 자세한 내용은 하단 트러블슈팅에서 다시 말씀드리겠습니다.

 

Ubuntu Golden Image 구성

골든이미지를 구성하기 위해 다음의 오픈소스를 기반으로 구성하였습니다. 오픈소스에는 설치부터 구성 내용이 자세히 나와있습니다.

아래 내용부터는 필자가 오픈소스를 참고하여 로컬 환경(macOS)에서 최신 버전에 맞는 이미지를 구성한 내용을 작성하겠습니다.

 

구성 도구 설치

필자 환경(macOS) 에서 환경 설치는 다음과 같이 구성했습니다.

# 도구 설치
brew install ansible
brew install packer

# packer 플러그인 설치
packer plugins install github.com/hashicorp/amazon 
packer plugins install github.com/hashicorp/ansible 

 # 
git clone https://github.com/rumeshbandara/ansible-ubuntu-provisioning.git

 

골드이미지 구성

Ansible Role

Ansible 구성을 확인하면 골드이미지 구성을 위한 Role를 확인할 수 있습니다.

.
├── ansible.cfg
├── inventory
│   ├── group_vars
│   │   ├── vars.yml
│   │   └── vault.yml
│   └── hosts
├── provision.yml
└── roles
    ├── common
    │   └── tasks
    │       └── main.yml
    ├── motd
    │   ├── tasks
    │   │   └── main.yml
    │   └── templates
    │       └── motd.j2
    ├── ssh
    │   ├── handlers
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    ├── ufw
    │   └── tasks
    │       └── main.yml
    └── user
        └── tasks
            └── main.yml
  • common : 추가 패키지를 설치합니다.
  • motd : 서버 접근시 구성 화면(Motd) 를 구성합니다.
  • ssh : ssh 서버 구성 보안 강화로 루트 로그인 비활성화, 패스워드 인증 비활성화를 설정합니다.
  • ufw : 방화벽 설정 구성 role입니다. 필자의 경우 AWS 위에서 작성하기에 해당 role를 제외시켰습니다.
  • user : 기본 사용자 생성 및 SSH 키 구성을 위한 role입니다. 마찬가지 이유로 role를 제외하였습니다.
# ansible/provision.yml
---
-
  hosts: production
  roles:
    - common
    #- ufw  제외
    - motd
    #- user 제외
    - ssh
  user: "{{ initial_user }}"
  vars_files:
    - ./inventory/group_vars/vars.yml
    - ./inventory/group_vars/vault.yml

 

Packer build 설정

최신 버전에 맞게 Packer build 설정이 필요합니다. 필자의 경우 AWS가 제공하는 최신 ubuntu 22.04 이미지를 가져와서 골드이미지를 구성하도록 하였습니다.

# ubuntu-build.json
... 
"builders": [{
		"type": "amazon-ebs",
		"access_key": "{{user `aws_access_key`}}",
		"secret_key": "{{user `aws_secret_key`}}",
		"region": "{{user `aws_region`}}",
		"instance_type": "t2.micro",
		"force_deregister": "true",
		"ssh_username": "{{user `ssh_username`}}",
		"communicator": "ssh",
		"associate_public_ip_address": true,
		"subnet_id": "{{user `subnet_id`}}",
		"ami_name": "{{user `ami_name`}}",
		"source_ami": "ami-0f3a440bbcff3d043", # ubuntu 22.04 업데이트 
		"run_tags": {
			"Name": "packer-build-ubuntu-image"
		}
...

또한, 최신 Packer 버전 및 앤서블에 맞게 provisioners 블록을 업데이트해야합니다.

# ubuntu-build.json
...
"provisioners": [{
			"type": "shell",
			"inline": "while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done"
		},
		{
			"type": "shell",
			"script": "./provisioners/scripts/bootstrap.sh"
		},
		{
			"type": "ansible",
			"extra_arguments": ["-vvvv", "--scp-extra-args", "'-O'", "--user", "ubuntu"], # 업데이트 
			"playbook_file": "./provisioners/ansible/provision.yml",
			"ansible_env_vars": ["ANSIBLE_CONFIG=./provisioners/ansible/ansible.cfg"]
		}
...
  • privisinoers.ansible.extar_arguments : ansible 실행시 추가 명령어를 정의합니다. 여기서는 상세 로그(-vvvv), scp 포트 전부활성화, 구성 유저는 ubuntu로 구성하였습니다. 위와 같이 구성해야 에러가 안납니다. 최신 버전에서 옵션없이 실행하면 하단의 트러블슈팅의 고통을 맛보게 됩니다.

 

Ansible 실행을 위한 보안 키 생성

Packer 환경에서 앤서블을 실행하려면 vault 키가 필요합니다. ansible/inventory/gorup_vars/.vault_pass

를 생성하여 devopsvaultpass 입력해주세요.

 

테스트

구성이 끝났다면, 실행은 간단합니다.

packer build -machine-readable ubuntu-build.json

이미지를 새로 생성하는데 약 5분정도 소비됩니다. 구성 로그를 확인하면 앤서블 플레이북에 구성한 role에 맞게 처리한 결과를 확인할 수 있습니다. 이미지 생성이 끝나면 임시 구성 리소스(aws instance sg, keypair) 는 삭제됩니다.

구성된 AMI를 통해 인스턴스를 접근하면 서버 motd 가 설정된 것을 확인할 수 있습니다.

 

 

 

트러블슈팅

Packer와 Ansible 버전 호환 문제로 이슈가 발생하여 트러블슈팅에 많은 시간을 소비하였다. Packer와 Ansible에 대한 오픈소스를 10개정도 확인하였는데 모두 2년전 기준의 프로젝트이고 옵션 업데이트가 안되어 죄다 같은 문제가 발생하였다.

 

  1. SCP 설정 이슈
failed to transfer file to file name

앤시블플레이북에서 실행시 파일이 전달되지 않을 때 발생한다. 다음 깃이슈를 확인하여 --scp-extra-args", "'-O' 옵션을 반영하면 된다.

 

  1. Permission denied 및 username/password are wrong
"msg": "Failed to lock apt for exclusive operation: Failed to lock directory /var/lib/apt/lists/: E:Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)

ssh 접근시 권한이 없거나 사용자 정의가 잘못되어 발생한 이슈다. 무척 간단해보이지만 반영 옵션 설정 위치를 잘못 알고 있어 특히 시간을 많이 소비하였다. 아마 최근 버전으로 실행시 전부 발생한다고 보면 될 것이다.

 

 

 

해결 방법은 올바른 ssh_name 설정과 remote_user 설정인데 이 옵션을 ansible playbook에서 하는 것이 아니라 packer에서 provisinoer 블록에 넣어줘야 합니다.

 

packer 로그를 통해 원인을 분석해보면, 앤서블에서 동작하는 ssh가 local의 사용자 이름이나, 임의의 ssh이름으로 설정되어 그런것 같다. ssh파일을 확인하거나 로그를 확인하면 임의의 이름 및 keypair가 등록되어 있는 것을 확인할 수 있습니다.