[Ansible] 기본 개념, 사용 환경 구성, 기초 사용법 정리

[Ansible] 기본 개념, 사용 환경 구성, 기초 사용법 정리

이번 포스트에서는 Ansible(이하 앤서블)의 환경 구성, 기초 사용법에 대해서 다룬다.

1. 들어가기 전.

앤서블은 여러 개의 서버를 효율적으로 관리하기 위해 고안된 환경 구성 자동화 도구이다. 앤서블은 2012년에 출시되었으며, 2013년에 버전 1이 출시된 이후, 레드햇에 인수되어 개발되고 있다. 앤서블은 셰프(chef), 퍼펫(Puppet) 등과 같은 구성 관리 도구의 일종이라고 볼 수 있으나, 사용성 또는 확장성 측면에서 셰프 또는 퍼펫에 비해 더욱 많은 사람들에게 사랑받고 있는걸로 보인다. (적어도 내 주변에 앤서블을 사용한다는 사람은 봤어도, 셰프나 퍼펫을 쓰는 사람은 본 적이 없다) 실제로, 최근에 개발되고 있는 환경 자동화 툴 (ex. kubespray) 등은 셰프나 퍼펫이 아닌 앤서블을 택하고 있다.

2. 앤서블의 역할

사용법을 설명하기에 앞서, 앤서블의 역할, 정확히 말하자면 환경 구성 자동화 도구의 역할을 정확히 정의할 필요가 있다. 리눅스에서 동일한 환경을 구성하기 위해서 사용하는 가장 기초적인 방법은 Bash 쉘 스크립트이다. 많은 개발자들은 각종 패키지의 설치, 설정 파일의 수정 등을 위해 일괄 처리 목록을 쉘 스크립트에 나열하고 이를 실행해 본 경험이 있을 것이다. 그러나 클러스터에 존재하는 많은 서버들에 동시에, 동일한 환경을 배포해야 하는 상황에서 Bash 쉘 스크립트는 분명 한계점을 가진다. (물론 사용할 수도 있지만 Bash 쉘 스크립트는 그러한 목적을 위해서 존재하는 것은 아니며, 여러 서버를 제어하는 규격화된 양식이 존재하지 않아 설령 그러한 기능을 구현하더라도 개개인 모두가 다른 템플릿을 정의해 사용하게 될지도 모른다)

이를 위해 고안된 것이 Infrastructure as a Code라는 개념이며, 이는 환경의 배포와 구성을 규격화된 코드로 정의해 사용하는 것을 의미한다. 즉, Infrastructure as a Code의 개념을 내포하는 각종 환경 자동화 도구는 인프라의 상태를 코드로 선언하고 이를 모든 서버에 배포함으로써 특정 환경을 동일하게 유지할 수 있도록 돕는다. 그러한 환경 자동화 도구의 대표적인 예시가 앤서블이며, 앤서블은 환경의 배포뿐만 아니라 서버 클러스터의 체계적인 관리, 확장 가능한 모듈의 사용 등 다양한 측면에서 사용될 수 있는 도구로서 많은 개발자들에게 사랑받고 있다.

3. 앤서블 시나리오

앤서블의 간단한 활용 예시를 들어보자.
나는 삼성에서 서버실을 관리하고 있으며, 약 200대의 서버를 동시에 동일한 환경을 구성하는 임무를 맡게 되었다.
이 때 가장 먼저 수행해야 하는 것은 무엇일까? (물론 모든 서버는 포맷 및 IP 세팅은 완료되었다고 가정한다)

  • SET SSH
  • SET HOSTNAME
  • SET DISK WARM UP
  • SET ZABBIX AGENT

신규로 올릴 서버에는, PasswordAuthentication 을 모두 yes로 변경해주어야 한다.
Hostname을 모두 변경해주어야 한다.
ami를 이용하여 신규로 올린 서버기에 EBS 디스크 웜업 과정을 거쳐야 한다.
자빅스 agent의 configuration을 변경하고, 재시작 해주어야 한다.

상당히 간단해 보이는 작업이지만, 실제로 200대에 모두 동일한 환경을 구성할 때는 약 10단계 이상의 작업을 수행한다(!). 나는 서버 클러스터 관리에 앤서블을 도입하고 난 뒤 위와 같은 서버 기초 세팅 작업은 물론, 더욱 고도화된 요구사항 또한 손쉽게 제어할 수 있게 되었다. 클라우드 개발자라면 무엇이 되었든지간에 자동화가 답이란 것을 느끼고 있다.

4. 앤서블 설치

앤서블을 사용하려는 VM (이하 앤서블 실행 VM) 에서 앤서블 커맨드라인을 설치한다.
pip install ansible 을 수행해 간단히 설치할 수 있다.

[root@controller ansible-blog-post]# pip3.6 install ansible
....
Requirement already satisfied: cffi>=1.7; platform_python_implementation != "PyPy" in /usr/lib64/python3.6/site-packages (from cryptography->ansible)
Requirement already satisfied: pycparser in /usr/lib/python3.6/site-packages (from cffi>=1.7; platform_python_implementation != "PyPy"->cryptography->ansible)
You are using pip version 9.0.1, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
  • 앤서블 사용자 추가
[root@ansible-target home]# adduser ansible-alicek106

[root@ansible-target home]# passwd ansible-alicek106
ansible-alicek106 사용자의 비밀 번호 변경 중
새  암호:
새  암호 재입력:
passwd: 모든 인증 토큰이 성공적으로 업데이트 되었습니다.

[root@ansible-target home]# visudo

....
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
ansible-alicek106 ALL=(ALL)     NOPASSWD:ALL

Tip : 위에선 이해를 돕기 위해 앤서블 전용 사용자를 생성하지만, 기존에 존재하던 사용자를 사용해도 무관하다. root 계정을 그대로 사용해 앤서블 제어(SSH 접속)에 사용해도 되지만, 추후에 설명할 become 옵션의 설명을 위해 앤서블 전용 사용자를 생성하였다.

다음으로, 앤서블 실행 VM에서 앤서블 작업 대상 VM으로 비밀번호 없이 접근할 수 있도록 SSH 키를 복사한다. 기존에 사용하던 SSH 키가 없다면, ssh-keygen 명령어를 통해 생성할 수 있다.

[root@controller ansible-blog-post]# ssh-copy-id ansible-alicek106@192.168.1.100

/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
ansible-alicek106@192.168.1.100's password:

Number of ky(s) added: 1

Now try logging into the machine, with:   "ssh 'ansible-alicek106@192.168.1.100'"
and check to make sure that only the key(s) you wanted were added.
  • host.ini 파일 작성
[root@controller ansible-blog-post]# vim hosts.ini

ansible-target-host ansible_host=192.168.1.100 ansible_user=ansible-alicek106
  • 테스트

5. 앤서블 기본 개념

앤서블 요소 3가지

  • 인벤터리
    인벤터리는 앤서블에 의해 제어되어 Infrastructure as a Code의 대상이 될 서버들의 목록을 정의하는 파일이다. 일반적으로 hosts.ini 파일에 정의해 사용하는 듯 하며, 위 예시에서 작성했던 hosts.ini 파일이 바로 그것이다. 인벤터리에는 여러 서버들의 접속 정보 (SSH 접근 IP, 포트, 리눅스 사용자) 등을 정의한다. 위에서 사용했던 hosts.ini 파일을 다시 들여다보자.

    [deploytest]
    10.0.17.87 ansible_port=20022 ansible_user=ec2-user ansible_ssh_private_key_file=/home/aemuser/pem/kp_prd_ap_rdgw.pem
    [dr_test]
    10.0.17.95 ansible_port=20022 ansible_user=ec2-user ansible_ssh_private_key_file=/home/aemuser/pem/kp_prd_ap_rdgw.pem
    

    기본적으로, 호스트의 정보를 정의할 때는 서버의 이름을 가장 앞에 쓰고 (ansible-target-host) 그 다음 차례대로 해당 서버의 정보(앤서블 변수)를 나열한다. 즉, 인벤터리 파일에서 해당 서버를 고유하게 식별할 수 있는 이름이 ansible-target-host 이며, 해당 서버의 SSH에 접근하기 위해서는 192.168.1.100이라는 Endpoint를 사용하고, ansible-alicek106 이라는 리눅스 사용자를 통해 SSH로 접근한다는 것을 의미한다. 물론, SSH 포트 등과 같은 옵션 또한 정의할 수 있다 (ansible_port).

  • 플레이북
    플레이북은 yaml 포맷으로 되어 있는 파일로서, 인벤터리 파일에서 정의된 서버들에서 무엇을 해야할지를 정의한다. 일반적으로 앤서블을 사용한다고 하면 플레이북을 사용한다는 것을 의미하며, 플레이북 단독으로 사용되는 것이 아닌 플레이북 + 인벤터리의 조합으로 사용하게 된다. 즉, 인벤터리를 통해 어디에서(where) 작업을 수행할지를 명시하고, 플레이북을 통해 무엇을(what) 할지를 정의한다. (위에서 사용했던 예시는 플레이북을 사용하지 않았는데, 인벤터리에서 명시된 서버들에 정상적으로 접속할 수 있는지 단순히 테스트(ping) 하는 용도였기 때문이다)

    간단한 플레이북의 예시를 들어보면 위와 같다. 위 플레이북의 이름은 lets nginx install 이고, 인벤터리 파일에서 모든 호스트를 대상으로 (hosts: all) 수행함을 명시하고 있다. become: true는 인벤터리의 접속한 리눅스 사용자가 sudo 권한으로 수행할지를 의미한다.

    그 아래에 정의된 tasks 가 실제로 플레이북에서 실행되는 작업들을 나열한 것이며, 플레이북에서 가장 중요한 부분이다. tasks의 하위 항목에는 task를 나열할 수 있고, 위 예시에서는 1개의 task만이 정의되어 있다. 해당 task의 이름은 nginx package install 이고, yum을 통해 nginx를 (name: nginx) 설치해라 (state: installed) 라는 의미를 갖고 있다. 물론, “설치해라” 대신 “삭제해라” (state: removed) 라는 명령 또한 가능하다.

    - name: Set SSH
    hosts: "{{ host_name }}"
    gather_facts: no
    sudo: yes
    vars:
      user: "{{ user_id }}"
      passwd: "{{ user_passwd }}"
    
    tasks:
    - name: Set sshd_config
      become: yes
      become_method: sudo
      become_user: root
      lineinfile:
        path: /etc/ssh/sshd_config
        backrefs: yes
        state: present
        regexp: '^PasswordAuthentication no'
        line: 'PasswordAuthentication yes'
    
    - name: Set password
      become: yes
      become_method: sudo
      become_user: root
      user:
        name: "{{ user }}"
        password: "{{ passwd | password_hash('sha512') }}"
        update_password: always
        shell: /bin/bash
    
    - name: Restart sshd
      become: yes
      become_method: sudo
      become_user: root
      service: name=sshd state=restarted
    

    플레이북은 ansible-playbook 이라는 명령어를 통해 실행할 수 있으며, 가장 마지막 인자로 플레이북 파일의 이름을 입력한다.

    보통 튜토리얼에서는 이해를 돕기 위해 1개의 플레이북만을 사용하지만, 실제로는 롤(role) 이라는 앤서블의 요소를 사용해 여러 개의 플레이북을 정의해 사용한다. 롤에 대한 설명은 추후 포스팅할 예정이다.

    Tip : yaml 파일은 일반적으로 —로 시작하는데, 이는 yaml 파일임을 명시하기 위한 목적으로 쓰인다.2 또한, yaml에서 – name: nginx 와 같이 – 로 시작하는 항목은 리스트 (또는 배열) 로 사용됨을 나타낸다.

  • 모듈
    모듈은 플레이북에서 task가 어떻게(how) 수행될지를 나타내는 요소이다. 예를 들어 yum 명령어를 통해 패키지를 설치할 떄에는 yum 모듈을 사용할 수 있다. 위의 nginx.yaml 예시에서는 yum 모듈을 사용하였으며, task의 이름 (- name: nginx package install) 바로 밑에 모듈의 이름인 yum을 명시하였다.

    당연하지만, yum으로 패키지를 설치하려면 어떤 패키지를 설치할 것인지, 해당 패키지를 삭제할지 설치할지 업데이트할지 등을 명시해야 한다. 따라서 yum 모듈은 어떤 패키지를 (name: nginx) 설치할지 삭제할지 (state: installed)에 대한 옵션을 명시해야만 한다. 여기서 한 가지 알 수 있는 것은, 모듈마다 요구하는 옵션이 모두 다르기 때문에 사용하려는 모듈의 옵션 사용 방법을 미리 숙지해야만 한다는 점이다.

    다른 예시를 들어보자. debug 모듈은 인벤터리에 정의된 서버에서 디버깅을 위한 각종 값 또는 변수의 출력에 쓰이는 모듈이다.debug 모듈은 yum 모듈과 다르게 어떠한 내용을 출력할지에 대한 명시가 있어야 하기 때문에 msg: 라고 하는 옵션을 명시해줘야만 한다. 이와 같이 각 모듈은 사용하는 방법이 모두 제각각이기때문에, 사용하기 전 반드시 구글링을 통해 사용 방법을 숙지해야만 한다. 앤서블은 약 500개의 모듈을 제공하고 있다고는 하지만, 자주 쓰이는 모듈은 사실상 한정되어 있으며 그러한 모듈의 사용 방법은 구글링하면 stack overflow나 server fault 등에서 쉽게 찾을 수 있기 때문에 크게 걱정하지 않아도 된다.

    참고로, 위 debug 모듈의 결과값은 아래와 같다. debug 모듈은 꽤 자주 쓰이기 때문에 알아두면 편리하다.

6. 앤서블과 멱등성

일반적으로, 앤서블은 멱등성 (idempotence) 를 제공하는 환경 자동화 도구라고 언급된다. 멱등성이란 수학에서 쓰이는 용어로, 동일한 작업을 수행해도 변화가 없음을 뜻한다. 예를 들어 100에 1을 곱해도 이는 여전히 100이기 때문에 멱등성의 예시로 쓰일 수 있다. 이와 같이, 똑같은 작업을 몇번을 수행해도 동일한 결과를 얻을 수 있다면 이를 멱등성이라고 칭한다.

앤서블 및 셰프, 퍼펫과 같은 환경 배포 자동화 도구는 멱등성을 제공하는 것을 지침으로 한다. 앤서블의 플레이북에서는 모듈 실행 시 결과를 상태 (state) 로 정의함으로써 최종적으로 존재해야 하는 환경을 명시한다. 해당 상태가 만족된다면 앤서블은 다른 작업을 하지 않고 task를 종료하는데, 이는 플레이북을 몇번이라도 실행하더라도 동일하게 수행된다. 따라서 앤서블은 플레이북에서 정의된 바람직한 상태를 만족하도록 수행하기 때문에 동일한 플레이북을 몇 번이고 실행해도 동일한 최종 결과값을 얻을 수 있는, 이른바 멱등성의 성질을 띠게 된다.

앤서블이 제공하고 있는 모듈의 대부분은 멱등성을 제공하는 것을 원칙으로 하기 때문에 모듈의 옵션 또한 멱등성을 고려하여 명시하도록 되어 있다. 따라서 한 번 성공적으로 수행된 플레이북은 다시 재실행하더라도 서버에 전혀 영향을 끼치지 않게 된다. 이미 플레이북이 원하던 상태(state)에 도달하였기 때문에 더 이상 작업을 수행하지 않는 멱등성을 준수하게 되는 것이다. 예를 들어 yum 모듈을 통해 state: installed 로 명시된 플레이북이 실행될 때, 해당 패키지가 이미 설치되어 있다면 해당 task는 아무런 동작도 하지 않고 success로 처리된 뒤 종료된다.

https//blog.wonizz.tk

워니즈 블로그

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다