0. 사전 준비

서버는 WSL2 ubuntu 20.04, 호스트는 CentOS 7 기준으로 작성하였습니다.

  • AWS Cli v2 (API 호출하여 EBS 변경 상태가 완료인지 확인)
  • jmespath (API 호출하였을 때 응답 값 Parse)
0.1 AWS Cli v2 설치

최신 AWS Cli v2를 설치합니다. 

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

AWS credentials을 추가합니다.

sudo aws configure

리전을 포함하여 순서대로 값을 입력합니다.

AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: ap-southeast-1
Default output format [None]:

0.2 jmespath 설치

JSON parsing에 사용할 라이브러리를 설치합니다.

sudo python3 -m pip install jmespath

1. EBS 추가

# 코드 업데이트

사용자가 보기 위한 정보는 shell 모듈을 활용하여 결과를 가져옵니다.

실제 작업은 filesystem, file, mount 모듈을 활용하여 업데이트 전보다 OS에 더 유연합니다.

---
- name: Attatch a volume to new instance
  hosts: test
  vars:
    device_name: nvme1n1
    directory_name: /mydir
  become: yes
  tasks:
    - name: Find a device which will be attatched.
      shell: lsblk
      register: lsblk
    - debug: var=lsblk.stdout_lines
    - name: Create a file system on the volume.
      community.general.filesystem:
        fstype: xfs
        dev: /dev/{{ device_name }}
        state: present
    - name: Create a directory for the volume.
      ansible.builtin.file:
        path: "{{ directory_name }}"
        state: directory
    - name: Mount a volume to the above directory
      ansible.posix.mount:
        path: "{{ directory_name }}"
        src: /dev/{{ device_name }}
        opts: defaults,nofail
        fstype: xfs
        state: mounted
    - name: Get information about filesystem which is mounted on a directory
      shell: df -h
      register: df
    - debug: var=df.stdout_lines
    - name: Get information from fstab
      shell: cat /etc/fstab
      register: fstab
    - debug: var=fstab.stdout_lines
    
# 코드 업데이트 전

AWS Console에서 EBS 추가를 먼저 한 다음 진행해주세요.

EC2 인스턴스에 파일 시스템을 생성하고, 볼륨을 Mount합니다.

작업 할 장치 이름(device_name)과 폴더 이름(directory_name)을 변경하여 상황에 맞게 적용할 수 있습니다. 

---
- name: Attatch a volume to new instance
  hosts: test
  vars:
    device_name: nvme1n1
    directory_name: mydir
  become: yes
  tasks:
    - name: Find a device which will be attatched.
      shell: lsblk
      register: lsblk
    - debug: var=lsblk.stdout_lines
    - name: Determine whether there is a file system on the volume.
      shell: file -s /dev/{{ device_name }}
      register: filesystem
    - debug: var=filesystem.stdout_lines
    - name: Create a file system on the volume.
      shell: mkfs -t xfs /dev/{{ device_name }}
      register: mkfs
    - debug: var=mkfs.stdout_lines
    - name: Create a directory for the volume.
      file:
        path: /{{ directory_name }}
        state: directory
    - name: Mount a volume to the above directory
      shell: mount /dev/{{ device_name }} /{{ directory_name }}
    - name: Get information about filesystem which is mounted on a directory
      shell: df -h
      register: df
    - debug: var=df.stdout_lines
    - name: Get information about UUID of the attatched device
      shell: blkid | grep {{ device_name }} | grep -oE "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"
      register: uuid
    - debug: var=uuid.stdout_lines
    - name: Attatch the volume automatically
      shell: echo UUID={{ uuid.stdout_lines[0] }} /{{ directory_name }} xfs defaults,nofail 0 2 >> /etc/fstab
1.1 설정

Play의 이름과 대상 서버, 사용할 변수를 지정합니다.

Root 권한을 필요로 할 때는 become 키워드를 yes로 설정합니다.

- name: Attatch a volume to new instance
  hosts: test
  vars:
    device_name: nvme1n1
    directory_name: mydir
  become: yes
1.2 작업

작업은 한 개 이상으로 구성할 수 으며 구분은 Dash( – )로 합니다.

첫번째 작업을 살펴보면, 작업의 이름, 사용하는 모듈, 변수 등록으로 구성하였습니다. 모듈은 대상 서버에서 Shell Command를 실행할 수 있는 빌트인 모듈 Shell을 사용하였습니다. Register 키워드는 작업의 결과를 변수로 등록할 수 있습니다. Shell command의 입력으로 나온 결과를 lsblk 변수로 등록하였습니다.

두번째 작업은 첫번째 작업과 비슷하나, 1.1 설정에서 미리 설정해둔 변수를 사용하였습니다. 변수를 사용할 때에는 중괄호 두개로 변수를 감싸 사용합니다.

  tasks:
    - name: Find a device which will be attatched.
      shell: lsblk
      register: lsblk
    - debug: var=lsblk.stdout_lines
    - name: Determine whether there is a file system on the volume.
      shell: file -s /dev/{{ device_name }}
      register: filesystem
    - debug: var=filesystem.stdout_lines

2. EBS 확장

# 코드 업데이트 후

3. Password에서 단일 암호화 변수를 지정하여, root 패스워드를 관리합니다.

볼륨 확장시 filesystem 모듈을 활용합니다.

---
- name: Describe the EBS volume state after expanding a volume size.
  hosts: localhost
  vars_files:
    - "../VARS/vars.yaml"
  vars:
    volume_id: vol-036ce259af02fff40
    region: ap-southeast-1
    ansible_become_password: "{{ localhostPassword }}"
  become: yes
  tasks:
    -
    - name: Describe the EBS volume state.
      shell: aws ec2 describe-volumes-modifications --volume-ids {{ volume_id }} --region {{ region }}
      register: volume_state
      environment:
        PATH: "{{ lookup('env', 'PATH') }}:/usr/local/bin/aws"
      until: volume_state.stdout | from_json | json_query('VolumesModifications[0].ModificationState') == 'completed'
      retries: 30
      delay: 30
- name: Expand a volume
  hosts: test
  vars:
    device_name: nvme1n1
    directory_name: mydir
  become: yes
  gather_facts: no
  tasks:
    - name: Expand a volume on the selected directory.
      community.general.filesystem:
        dev: /dev/{{ device_name }}
        fstype: xfs
        resizefs: yes
        state: present
    - name: Get information about filesystem which is mounted on a directory
      shell: df -h
      register: df
    - debug: var=df.stdout_lines
# 코드 업데이트 전

볼륨 확장은 크게 2개의 Play로 구성하였습니다. Play는 순차적으로 진행합니다.

첫번째 Play는 AWS Cli로 API를 호출하여 EBS 변경 상태가 완료되었는지 확인합니다. AWS Cli는 환경에 영향을 받지 않아 localhost에서 진행하였습니다.

두번째 Play는 해당 디렉토리의 볼륨을 확장하고, 확인하는 과정입니다.

---
- name: Describe the EBS volume state after expanding a volume size.
  hosts: localhost
  vars:
    volume_id: vol-0923cd24
  become: yes
  gather_facts: no
  tasks:
    - name: Describe the EBS volume state.
      shell: aws ec2 describe-volumes-modifications --volume-ids {{ volume_id }} --region ap-southeast-1
      register: volume_state
      environment:
        PATH: "{{ lookup('env', 'PATH') }}:/usr/local/bin/aws"
      until: volume_state.stdout | from_json | json_query('VolumesModifications[0].ModificationState') == 'completed'
      retries: 30
      delay: 30
- name: Expand a volume
  hosts: test
  vars:
    directory_name: mydir
  become: yes
  tasks:
    - name: Expand a volume on the selected directory.
      shell: xfs_growfs -d /{{ directory_name }}
      register: xfs_growfs
    - debug: var=xfs_growfs.stdout_lines
    - name: Get information about filesystem which is mounted on a directory
      shell: df -h
      register: df
    - debug: var=df.stdout_lines

until과 retries, delay 키워드로 상태가 완료될 때까지 확인합니다. 지금 구성 정보는 완료 상태가 아니라면, 30초 후에 재시도, 30번 시도합니다.

  tasks:
    - name: Describe the EBS volume state.
      shell: aws ec2 describe-volumes-modifications --volume-ids {{ volume_id }} --region ap-southeast-1
      register: volume_state
      environment:
        PATH: "{{ lookup('env', 'PATH') }}:/usr/local/bin/aws"
      until: volume_state.stdout | from_json | json_query('VolumesModifications[0].ModificationState') == 'completed'
      retries: 30
      delay: 30

테스트에서는 10번 실패 후에 상태가 완료된 것을 확인하고, 다음 Play를 진행하였습니다.

TASK [Describe the EBS volume state.] ******************************************
FAILED - RETRYING: Describe the EBS volume state. (30 retries left).
FAILED - RETRYING: Describe the EBS volume state. (29 retries left).
FAILED - RETRYING: Describe the EBS volume state. (28 retries left).
FAILED - RETRYING: Describe the EBS volume state. (27 retries left).
FAILED - RETRYING: Describe the EBS volume state. (26 retries left).
FAILED - RETRYING: Describe the EBS volume state. (25 retries left).
FAILED - RETRYING: Describe the EBS volume state. (24 retries left).
FAILED - RETRYING: Describe the EBS volume state. (23 retries left).
FAILED - RETRYING: Describe the EBS volume state. (22 retries left).
FAILED - RETRYING: Describe the EBS volume state. (21 retries left).
changed: [localhost]

3. Password 관리

민감한 정보는 암호화하여 관리합니다.

<Your Text> 문자를 암호화합니다. 상황에 맞게 변경할 수 있습니다.

ansible-vault encrypt_string <Your Text> --ask-vault-pass
New Vault password:
Confirm New Vault password:
!vault |
          $ANSIBLE_VAULT;1.1;AES256
          36353431643362383830353839303262373062366264343562653062656239613731613639313565
          3061373361306434646433663933613839636366643234630a386434633938656139343864333235
          33306365326230316236373832316463363937633966353332636635653934646339386136396439
          3666366337313837380a653534343031623961383337336330333162383162643636333563656636
          6163
Encryption successful

Vault 비밀번호를 입력하면 암호화된 문자가 출력됩니다.  복사합니다!

변수를 저장하는 yaml 파일을 만들어 저장합니다.

vi vars.yaml
---
localhostPassword: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          36353431643362383830353839303262373062366264343562653062656239613731613639313565
          3061373361306434646433663933613839636366643234630a386434633938656139343864333235
          33306365326230316236373832316463363937633966353332636635653934646339386136396439
          3666366337313837380a653534343031623961383337336330333162383162643636333563656636
          6163

저장한 변수 파일을 playbook에서 불러오는 것은 vars_files 키워드를 사용합니다.

---
- name: Describe the EBS volume state after expanding a volume size.
  hosts: localhost
  vars_files:
    - "../VARS/vars.yaml"

추가로 root 권한을 얻기 위한 password 설정은 ansible_become_password 키워드를 사용합니다. 이 때 값으로 vars.yaml 파일에서 정의한 변수를 불러옵니다.

  vars:
    volume_id: vol-036ce259af02fff40
    region: ap-southeast-1
    ansible_become_password: "{{ localhostPassword }}"

암호화 된 변수가 있는 경우 실행은 argument를 추가합니다.

ansible-playbook expand.yaml --ask-vault-pass

다음 글 보기

이전 글 보기