IT/Infra. & Arch. & Cloud

Ansible ์„ค์น˜ ๋ฐ Ansible๋กœ AWS EC2 ์ƒ์„ฑํ•˜๊ธฐ

Unused 2024. 3. 11. 15:19

๊ธฐ์กด์˜ ๋ฌผ๋ฆฌ์  ์„œ๋ฒ„, ์Šคํ† ๋ฆฌ์ง€, ๋„คํŠธ์›Œํฌ ๋“ฑ์„ ์ „๋ถ€ ํด๋Ÿฌ์Šคํ„ฐ๋กœ ๋ฌถ๊ณ  ์ถ”์ƒํ™”ํ•˜์—ฌ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฐํฌ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ๊ฐ€์ƒํ™”๋œ ์ธํ”„๋ผ๋ฅผ ์ฝ”๋“œ๋กœ ์ƒ์„ฑ, ๊ด€๋ฆฌ, ํ๊ธฐํ•˜๋Š” ์ผ๋ จ์˜ ๊ณผ์ •์„ '์ฝ”๋“œํ˜• ์ธํ”„๋ผ์ŠคํŠธ๋Ÿญ์ฒ˜ (IaC; Infrastructrure as Code)'๋ผ๊ณ  ํ•œ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” ํ•ด๋‹น ๊ณผ์ •์˜ ์ผ๋ถ€์ธ ์ž๋™ํ™”๋ฅผ Ansible๋ฅผ, AWS EC2 ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•˜์—ฌ ๋‹ค๋ฃจ์–ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

 

์ด ํฌ์ŠคํŠธ์—์„œ๋Š” ์œ ์ €์˜ Windows PC๊ฐ€ ๊ด€๋ฆฌ ๋…ธ๋“œ๊ฐ€ ๋˜๋ฉฐ, ์œ ์ €์˜ PC ==> WSL (Windows Subsystem for Linux) Ubuntu 22.04 LTS + Ansible๋กœ ์ง์ ‘ AWS์— ์ ‘๊ทผํ•˜์—ฌ EC2 ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๊ฒƒ์ด๋‹ค.

 

ํ™˜๊ฒฝ ๊ตฌ์„ฑ

Ansible์„ ์œ„ํ•œ ๊ฒฝ๋กœ ์ƒ์„ฑ

์ด์ œ EC2 ์ƒ์„ฑ์„ ์œ„ํ•œ playbook๊ณผ, ๊ทธ๋ฆฌ๊ณ  ์œ„์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ access key๋ฅผ ๋‹ด์„ ๊ฒฝ๋กœ๋ฅผ ์œ ์ €์˜ PC์— ์ƒ์„ฑํ•  ๊ฒƒ์ด๋‹ค. WSL Ubuntu์˜ ์…ธ์— ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ํ™ˆ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™ํ•œ๋‹ค.

cd ~

์ด์ œ ํ™ˆ์—๋‹ค๊ฐ€ `ansible_aws_tutorial` ํด๋”๋ฅผ ์ƒ์„ฑ, ๊ทธ๋ฆฌ๊ณ  ํ•˜์œ„ ํด๋”๋กœ `group_vars/all`๋„ ์ƒ์„ฑํ•œ๋‹ค. ์ƒ์„ฑํ•œ ๋’ค์—๋Š” `ansible_aws_tutorial`๋กœ ๋“ค์–ด๊ฐ€์„œ ์ด๋”ฐ๊ฐ€ ์‚ฌ์šฉํ•  `playbook.yml`์„ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋†“๋Š”๋‹ค.

mkdir -p ansible_aws_tutorial/group_vars/all/
cd ansible_aws_tutorial
touch playbook.yml

AWS ์ ‘๊ทผ ํ‚ค ์ƒ์„ฑ

๊ฐ€์žฅ ๋จผ์ € ํ•ด์•ผ ํ•  ๊ฒƒ์€ Ansible์—์„œ AWS๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ† ํฐ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Š” AWS์˜ IAM ์„œ๋น„์Šค์—์„œ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” AWS์˜ root account๊ฐ€ ์•„๋‹Œ IAM์œผ๋กœ ๊ถŒํ•œ์„ ๋ถ€์—ฌ๋ฐ›์€ ๋ณ„๋„์˜ ์œ ์ €๊ฐ€ ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ์ „์ œํ•˜๊ณ  ์ ‘๊ทผ ํ‚ค ์ƒ์„ฑ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด, IAM์„ ๊ฒ€์ƒ‰ํ•˜์—ฌ ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

 

IAM Dashboard๋กœ ๊ฐ€์„œ, ์•„๋ž˜์™€ ๊ฐ™์ด, ์ ‘๊ทผ ํ‚ค๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๊ณ ์ž ํ•˜๋Š” ์œ ์ €๋ฅผ ์„ ํƒํ•œ๋‹ค.

 

์•„๋ž˜์™€ ๊ฐ™์ด, ํ•ด๋‹น ์œ ์ €์˜ Security credentials ํƒญ์œผ๋กœ ๊ฐ€์„œ Create access keys๋ฅผ ํด๋ฆญํ•œ๋‹ค.

 

Access key ์ƒ์„ฑ ๊ณผ์ •์—์„œ, ์•„๋ž˜์™€ ๊ฐ™์€ ์„ค๋ฌธ์„ ๋ฐ›๊ฒŒ ๋œ๋‹ค. ๋งจ ๋งˆ์ง€๋ง‰ 'Other' ์ด์™ธ์˜ ๋ชจ๋“  ์„ ํƒ์ง€๊ฐ€ 'Alternatives recommended'๋ผ๋Š” ๊ฒฝ๊ณ ๊ฐ€ ๋œฌ๋‹ค. ํ•˜์ง€๋งŒ ์œ ์ €์˜ PC์— ์„ค์น˜๋œ Ansible๋กœ AWS์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ 'Other'์— ํ•ด๋‹น๋˜๋ฏ€๋กœ ์ด๋ฅผ ํด๋ฆญํ•˜์ž. ๋‹ค๋งŒ, ์ด๋ฅผ ํ†ตํ•ด ๋ฐœ๊ธ‰๋ฐ›์€ access key๋Š” ์™ธ๋ถ€์— ์œ ์ถœ๋˜์ง€ ์•Š๋„๋ก ๊ทนํžˆ ์ฃผ์˜ํ•˜์—ฌ์•ผ ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ํ‚ค๋“ค์„ GitHub ์ €์žฅ์†Œ ๋“ฑ์— ์•„๋ฌด๋ ‡๊ฒŒ๋‚˜ ๋…ธ์ถœ์‹œํ‚ฌ ๊ฒฝ์šฐ, ์ง€๋‚˜๊ฐ€๋˜ ํฌ๋กค๋ง ๋ด‡์ด ์ด ํ‚ค๋ฅผ ์ˆ˜์ง‘ํ•˜์—ฌ, ๋ฉฐ์น ๋งŒ ์ง€๋‚˜๋„ ์œ ์ €์˜ Billing dashboard์— ์ฒœ๋ฌธํ•™์ ์ธ ๊ธˆ์•ก์ด ์ฐํžˆ๊ฒŒ ๋งŒ๋“ค์ง€๋„ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์ƒ์„ฑ๋˜๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด access key์™€ secret access key๋ฅผ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

EC2 ์ธ์Šคํ„ด์Šค๋“ค์— ์ ‘๊ทผ์„ ์œ„ํ•œ ํ‚ค์Œ (Key Pair) ์ƒ์„ฑ

Ansible์€ ๊ธฐ๋ณธ์ ์œผ๋กœ 'agentless'๋กœ, ํƒ€๊นƒ ์„œ๋ฒ„์—๋‹ค๊ฐ€ ๋ณ„๋„์˜ agent๋ฅผ ๋‘๋Š” ๋Œ€์‹  SSH ์ ‘์†์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ๋‚ด PC์—์„œ SSH๋กœ EC2 ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ํ‚ค์Œ์„ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์…ธ์— ์ž…๋ ฅํ•˜์—ฌ `my_ec2_key`๋ผ๋Š” ๊ณต๊ฐœํ‚ค ๋ฐ ๋น„๋ฐ€ํ‚ค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. Passphrase๋Š” ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ์ž…๋ ฅํ•˜๊ฒ ์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ์ƒ๋žตํ•œ๋‹ค.

ssh-keygen -t rsa -b 4096 -f my_ec2_key

์ƒ์„ฑ ํ›„, ์•„๋ž˜์™€ ๊ฐ™์ด `ls -al`์„ ์ž…๋ ฅํ•˜๋ฉด ์‹ค์ œ๋กœ ๋งŒ๋“ค์–ด์ง„ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Ansible ์„ค์น˜

์ด์ œ ์œ ์ €์˜ PC์— Ansible์„ ์„ค์น˜ํ•œ๋‹ค. ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์…ธ์— ์ž…๋ ฅํ•˜์—ฌ ์—…๋ฐ์ดํŠธํ•˜๊ณ  Ansible์„ ์„ค์น˜ํ•œ๋‹ค.

sudo apt update;sleep 1;sudo apt upgrade -y;sleep 1
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible

์ดํ›„ ์…ธ์— `ansible --version`์„ ์‹คํ–‰ํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฒ„์ „์„ ํ™•์ธํ•œ๋‹ค.

AWS Access Key ์ €์žฅ

AWS Access Key๋ฅผ ์•”ํ˜ธํ™”ํ•จ๊ณผ ๋™์‹œ์— playbook์— ๋งˆ์น˜ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” `ansible-vault`์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์ด๋•Œ, `ansible-vault`๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์•”ํ˜ธํ™”๋ฅผ ์œ„ํ•œ ํŒจ์Šค์›Œ๋“œ, ๋˜๋Š” ํŒจ์Šคํ‚ค ํŒŒ์ผ์„ ํ•„์š”๋กœ ํ•œ๋‹ค.

์ด ํฌ์ŠคํŠธ์—์„œ๋Š” ํŒจ์Šค์›Œ๋“œ๋กœ ์•”ํ˜ธํ™”ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•œ๋‹ค.  ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ํ˜„์žฌ ํด๋”์˜ ํ•˜์œ„์— ์œ„์น˜ํ•œ `group_vars/all`์— `pass.yml`์„ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ๋‹ค.

ansible-vault create ./group_vars/all/pass.yml

์ด๋•Œ, ์•„๋ž˜์™€ ๊ฐ™์ด, ๊ทธ ์œ ๋ช…ํ•œ(...) `vim` ์—๋””ํ„ฐ๊ฐ€ ๋“ฑ์žฅํ•  ๊ฒƒ์ด๋‹ค. ๊ฐ€๊ธ‰์  `vim` ํŠœํ† ๋ฆฌ์–ผ์„ ํ•œ๋ฒˆ ๋ณด๊ณ  ์ง„ํ–‰ํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž€๋‹ค.

๋˜๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ์—๋””ํ„ฐ๋ฅผ `nano`๋กœ ์ง์ ‘ ์ง€์ •ํ•˜์—ฌ ์—ด ์ˆ˜๋„ ์žˆ๋‹ค.

env EDITOR=nano ansible-vault create group_vars/all/pass.yml

์•„๋ฌดํŠผ ์—๋””ํ„ฐ๊ฐ€ ์—ด๋ ธ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด AWS ํ‚ค๋ฅผ ๋„ฃ๊ณ  ์ €์žฅํ•œ๋‹ค.

ec2_access_key: AK****************7                                      
ec2_secret_key: KeJ/sg**************************HT8

์ด์ œ ์ด `pass.yml`์—๋Š” ํ•ด๋‹น ํ‚ค์Œ (key pair)์ด ์•”ํ˜ธํ™”๋œ ์ฑ„๋กœ ์ €์žฅ๋œ๋‹ค. ์‹ค์ œ๋กœ `nano group_vars/all/pass.yml`์„ ํ†ตํ•ด `pass.yml`์„ ๊ทธ๋ƒฅ ์—ด ๊ฒฝ์šฐ ๊ทธ ์›๋ณธ์„ ๋ณผ ์ˆ˜ ์—†๋‹ค.

 

์ด๋ ‡๊ฒŒ ๋ชจ๋“  ํ™˜๊ฒฝ ๊ตฌ์„ฑ์ด ๋๋‚ฌ๋‹ค. ๋‹ค์Œ์€ Ansible์˜ playbook์„ ์ž‘์„ฑํ•˜๊ณ  ์ด๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ฒ ๋‹ค.

Ansible ๊ตฌ์„ฑ ๋ฐ ์‹คํ–‰

Ansible Playbook YAML ์ž‘์„ฑ

์•„๊นŒ ์ž‘์„ฑํ–ˆ๋˜ `playbook.yml`ํŒŒ์ผ์„ ์—ด๊ธฐ ์œ„ํ•ด, ์…ธ์— `nano playbook.yml`์„ ์ž…๋ ฅํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•˜์—ฌ ์ €์žฅํ•œ๋‹ค.

์•„๋ž˜ region, AMI ์ด๋ฏธ์ง€ ๊ณ ์œ  ID, ์„œ๋ธŒ๋„ท ๊ณ ์œ  ID, ๋ณด์•ˆ๊ทธ๋ฃน ๊ณ ์œ  ID, EC2์— ์‚ฌ์šฉํ•  ํ‚ค์Œ ํŒŒ์ผ ๊ฒฝ๋กœ ๋“ฑ์€ ๋ณธ์ธ ์ƒํ™ฉ์— ๋งž๋„๋ก ์ˆ˜์ •ํ•œ๋‹ค. ์ด๋•Œ AMI ์ด๋ฏธ์ง€ ๊ณ ์œ  ID๋Š” EC2 ์„œ๋น„์Šค์˜ ์ขŒ์ธก ๋ฉ”๋‰ด์— ์žˆ๋Š” 'AMI Catalog'๋ฅผ ๋ณด๋ฉด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค (์•„๋‹ˆ๋ฉด Amazon Linux 2023 AMI ami-081a36454cdf357cb, ๋˜๋Š” Ubuntu Server 22.04 LTS (HVM) ami-0382ac14e5f06eb95, ๋˜๋Š” ๋ณธ์ธ์ด ๋ฏธ๋ฆฌ ์ €์žฅํ•ด๋†จ๋˜ AMI)

# AWS playbook
---

- hosts: localhost
  connection: local
  gather_facts: False

  vars:
    key_name: my_ec2_key             # Key used for SSH
    region: ap-northeast-2       # Region may affect response and pricing
    image: ami-<์ด๋ฏธ์ง€ ๊ณ ์œ  ID> # look in ec2 > ami (filter owner alias: amazon) or amis of manually launched instances
    id: "example testing"
    instance_type: t2.micro       # Choose instance type, check AWS for pricing
    vpc_subnet_id: subnet-<์„œ๋ธŒ๋„ท ๊ณ ์œ  ID>
    sec_group: "sg-<๋ณด์•ˆ๊ทธ๋ฃน ๊ณ ์œ  ID>"

  tasks:
    - name: Provisioning EC2 instances
      block:
      - name: Amazon EC2 | Create Key Pair      # Create key pair for ssh
        ec2_key:
          name: "{{ key_name }}"
          region: "{{ region }}"
          aws_access_key: "{{ec2_access_key}}"  # From vault as defined
          aws_secret_key: "{{ec2_secret_key}}"  # From vault as defined
          key_material: "{{ item }}"
        with_file: ~/ansible_aws_tutorial/my_ec2_key.pub

      - name: Start an instance with a public IP address
        ec2_instance:
          name: "public-compute-instance"
          key_name: "{{ key_name }}"
          vpc_subnet_id: "{{ vpc_subnet_id }}"
          instance_type: "{{ instance_type }}"
          security_group: "{{ sec_group }}"
          aws_access_key: "{{ ec2_access_key }}"
          aws_secret_key: "{{ ec2_secret_key }}"
          region: "{{ region }}"
          network:
            assign_public_ip: true
          image_id: "{{ image }}"
          tags:
            Environment: Testing

      # Always require the 'create_ec2' tag to provision EC2 instance
      tags: ['never', 'create_ec2'] 

    - name: Facts
      block: # this block prints out instance data

      - name: Get instances facts
        ec2_instance_info:
          aws_access_key: "{{ ec2_access_key }}"
          aws_secret_key: "{{ ec2_secret_key }}"
          region: "{{ region }}"
        register: result

      - name: Instances ID
        debug:
          msg: "ID: {{ item.instance_id }} - State: {{ item.state.name }} - Public DNS: {{ item.public_dns_name }}"
        loop: "{{ result.instances }}"
        
      - name: Gather information about all subnets
        ec2_vpc_subnet_info:
          aws_access_key: "{{ ec2_access_key }}"
          aws_secret_key: "{{ ec2_secret_key }}"
          region: "{{ region }}"
        register: subnets

      - name: Print the subnet information
        debug:
          msg: "{{ subnets }}"

        
      tags: always

Ansible ์‹คํ–‰

์ด์ œ ๋ชจ๋“  ์ค€๋น„๊ฐ€ ๋๋‚ฌ์œผ๋ฉฐ ์‹คํ–‰๋งŒ ํ•˜๋ฉด ๋œ๋‹ค. ์…ธ์—์„œ ์•„๋ž˜๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ์‹คํ–‰ํ•œ๋‹ค.

ansible-playbook playbook.yml --tags create_ec2  --ask-vault-pass

์ด๋•Œ Ansible๊ฐ€ ํŒจ์Šค์›Œ๋“œ๋ฅผ ์š”๊ตฌํ•  ๊ฒƒ์ด๋‹ค. Vault์— ์ €์žฅํ•ด๋‘” ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋œ๋‹ค.

๋งŒ์•ฝ, ํŒจ์Šค์›Œ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ํŒจ์Šคํ‚ค ํŒŒ์ผ์„ ๋”ฐ๋กœ ๋’€๋‹ค๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด ์ž…๋ ฅํ•˜๋ฉด ๋œ๋‹ค.

ansible-playbook playbook.yml --tags create_ec2 --vault-password-file vaultํŒŒ์ผ.pass

Ansible ์‹คํ–‰ ๊ฒฐ๊ณผ

๋งŒ์•ฝ ์„ฑ๊ณตํ•  ๊ฒฝ์šฐ ํ„ฐ๋ฏธ๋„์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜์˜จ๋‹ค.

๋งŒ์•ฝ ์‹คํŒจํ•  ๊ฒฝ์šฐ ํ„ฐ๋ฏธ๋„์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜์˜จ๋‹ค.

 

AWS ์ฝ˜์†”์—์„œ ๊ฒฐ๊ณผ ํ™•์ธ

์„ฑ๊ณตํ–ˆ์„ ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด AWS ์ฝ˜์†”์— ์ƒˆ๋กœ์šด EC2 ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์กŒ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ๋“ค์–ด์ง„ ์ž์› ์‚ญ์ œํ•˜๊ธฐ

์ผ๋‹จ ๊ฐ€์žฅ ๋จผ์ € AWS access key ์‚ญ์ œ ==> (ํ•ด๋‹น๋˜๋Š” ๊ฒฝ์šฐ) ์„œ๋ธŒ๋„ท ์‚ญ์ œ ==> VPC ์‚ญ์ œ ==> (ํ•ด๋‹น๋˜๋Š” ๊ฒฝ์šฐ) ์ง์ ‘ ์ƒ์„ฑํ•œ AMI ์‚ญ์ œ ==> EC2 ์ธ์Šคํ„ด์Šค ์‚ญ์ œ