[Ansible] Ansible 용어

728x90

Ansible?

IT 인프라 구성 관리 자동화 도구

Ansible: OpenSSH 기반이면 모두 관리할 수 있다. 즉, SSH 로 연결만 되면 Ansible 에서 관리를 할 수 있다는 것이다. 또한, YAML 을 사용하여 구성이 쉽다.

공식문서 : https://docs.ansible.com/ ⇒ Community Document 만 보면 된다.

용어

제어 노드

Ansible 패키지가 설치되는 곳으로 Control Node, Controller, Ansible Engine 으로 불린다.

제어 노드가 되기 위해선 무조건 Unix 계열이어야 한다.

관리 노드

제어 노드에 의해 관리되는 노드로 Managed Node, Target Node/Host 으로 불린다.

SSH 로 통신할 수 있는 BM, VM, Instance, Network Device 등이 관리 노드가 될 수 있다.

조건:

  • 일반적으로 SSH 가 가능한 모든 시스템 + Python 이 설치되어야 관리 노드로 사용될 수 있다.
  • Windows는 예외적으로 WinRM(Windows Remote Management) 을 사용해서 관리 노드가 될 수 있다.

인벤토리

  • 정적 인벤토리 : 관리 노드의 목록을 가지고 있는 파일
  • 동적 인벤토리 : CMDB 나 Public / Private Cloud 로 부터 관리 노드 목록을 동적으로 가져온다.

플러그인

Ansible 기능 확장

모듈

Ansible 작업 실행 할 수 있는 기본 단위로 Python 으로 작성되어 있다.

Ad-hoc

Ansible 임시 실행하는 것으로 하나의 모듈만 실행할 수 있다.

태스크

하나의 모듈을 실행하면 하나의 태스크(작업)이 된다.

플레이

하나 이상의 태스크의 모음을 플레이라고 한다.

플레이북

하나 이상의 플레이 모음을 플레이북이라고 한다. 플레이북은 YAML 파일이고 이 파일에는 한 개 이상의 플레이가 있다.

인벤토리

https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#intro-inventory

기본 인벤토리 파일 위치 : /etc/ansible/hosts

  • /etc/ 디렉토리 밑에 있는 파일들은 시스템 전체에 대한 설정 파일들이다.
  • 기본 인벤토리 파일은 보통 사용하지 않는 것을 권장한다.

기본 인벤토리 파일에 있지 않고 다른 인벤토리 파일이 있을 경우에는 -i [path] 로 경로를 잡아줘야 한다.

인벤토리 파일 작성하는 포맷이 두 가지가 있다.

  • ini : 일반적으로 ini 을 선호한다.
  • yaml

ini 형식의 예

key=value

[Section]
key=value
key

ini 형태

foo.example.com, bar.example.com 은 webservers 그룹이고, dbservers 그룹에는 one.example.com, two.example.com, three.example.com 이 있다.

mail.example.com 은 그룹이 없는 호스트이다.

[] 를 인벤토리 그룹이라고 부른다.

하나의 노드는 하나의 그룹에만 속할 필요는 없다. 즉, 하나의 노드가 여러 그룹에 속할 수 있다.

mail.example.com

[webservers]
foo.example.com
bar.example.com
three.example.com

[dbservers]
one.example.com
two.example.com
three.example.com

YAML 형태로 위의 ini 와 똑같은 뜻이다.

all 그룹 및에 webservers 그룹, dbservers 그룹이 있다. 이를 네스티드 그룹이라고 한다.

all:
  hosts:
    mail.example.com:
  children:
    webservers:
      hosts:
        foo.example.com:
        bar.example.com:
    dbservers:
      hosts:
        one.example.com:
        two.example.com:
        three.example.com:

기본 그룹

  • all : 다른 그룹에 속한 그룹들이 속하는 기본 그룹이다.
  • ungrouped : 그룹에 속하지 않은 관리 노드들이 속하는 기본 그룹이다.

인벤토리 생성 원칙 ⇒ 간결하게 작성해야 한다!

그룹에 호스트를 분류할 때 고려할 점

  • 무엇 : 애플리케이션 단위로 그룹을 만들지, 데이터베이스 단위로 그룹을 만들 것인지 고려해야 한다.
  • 어디서 : 데이터센터, 리전 등 위치 별로 그룹을 만들 것인지 골려해야 한다.
  • 언제 : 개발 서버에 올리는지, 배포 서버에 올리는지, 테스트 서버에 올리는 지 등에 따라 그룹을 어떻게 만들 것인지 고려해야 한다.

호스트 범위

[01:50] → 1~50 까지

[webservers]
www[01:50].example.com
192.168.100.11
www[01:50:2].example.com

[databases]
db-[a:f].example.com

인벤토리 변수

[webservers]
www[01:50].example.com A=100 B=200
192.168.100.11

인벤토리 그룹 변수

atlanta 그룹의 host1, host2 에 atalanta:vars 그룹의 값들을 세팅한다.

[atlanta]
host1
host2

[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

중첩 그룹

[그룹명:children] 이런 포맷일 경우 해당 그룹 밑에 그룹이 속하게 된다.

즉, 아래 southeast 의 그룹은 atlanta 와 raleigh 그룹을 갖는다는 뜻이다.

[southeast:children] atlanta raleigh

[atlanta]
host1
host2

[raleigh]
host2
host3

[southeast:children]
atlanta
raleigh

[usa:children]
southeast
northeast
southwest
northwest

인벤토리 파일 확인

인벤토리 파일 계층 구조 확인

ansible-inventory -i [인벤토리 파일] --graph

[vagrant@controller ~]$ ansible-inventory -i a.ini --graph
@all:
  |--@alpah:
  |  |--@abc:
  |  |  |--b
  |  |  |--c
  |  |--@xyz:
  |  |  |--x
  |  |  |--y
  |  |  |--z
  |--@ungrouped:
  |  |--a

JSON 형식 및 호스트/그룹 변수 확인

ansible-inventory -i [인벤토리 파일] --list

[vagrant@controller ~]$ ansible-inventory -i a.ini --list
{
    "_meta": {
        "hostvars": {}
    },
    "abc": {
        "hosts": [
            "b",
            "c"
        ]
    },
    "all": {
        "children": [
            "alpah",
            "ungrouped"
        ]
    },
    "alpah": {
        "children": [
            "abc",
            "xyz"
        ]
    },
    "ungrouped": {
        "hosts": [
            "a"
        ]
    },
    "xyz": {
        "hosts": [
            "x",
            "y",
            "z"
        ]
    }
}

인벤토리 파일의 호스트에 설정된 변수 확인

ansible-inventory -i [인벤토리 파일] --host [호스트 명]

[vagrant@controller ~]$ ansible-inventory -i a.ini --host a
{}
[vagrant@controller ~]$ ansible-inventory -i a.ini --host x
{}
[vagrant@controller ~]$ ansible-inventory -i a.ini --host b
{}

인벤토리 파일의 호스트 목록 확인

ansible [그룹/호스트/all] -i [인벤토리 파일] --list-hosts

[vagrant@controller ~]$ ansible all -i a.ini --list-hosts
  hosts (6):
    a
    b
    c
    x
    y
    z
[vagrant@controller ~]$ ansible abc -i a.ini --list-hosts
  hosts (2):
    b
    c
[vagrant@controller ~]$ ansible xyz -i a.ini --list-hosts
  hosts (3):
    x
    y
    z
[vagrant@controller ~]$ ansible ungrouped -i a.ini --list-hosts
  hosts (1):
    a
[vagrant@controller ~]$ ansible z -i a.ini --list-hosts
  hosts (1):
    z

구성파일

공식 문서 : https://docs.ansible.com/ansible/latest/reference_appendices/config.html

설정파일 위치

숫자가 낮을수록 우선순위가 높다.

1번과 4번은 전역적으로 적용되고 3번은 현재 사용자에게 적용되고 4번은 현재 작업하고 있는 디렉토리에 있을 때만 적용된다.

2번을 제일 많이 사용한다.

  1. ANSIBLE_CONFIG(environment variable if set)
$ touch /tmp/ans.cfg
$ export ANSIBLE_CONFIG=/tmp/ans.cfg
$ ansible --version

$ unset ANSIBLE_CONFIG
  1. ansible.cfg(in the current directory, 현재 작업하고 있는 디렉토리에 위치)
  2. ~/.ansible.cfg(in the home directory, 사용자의 홈 디렉토리에 위치)
  3. /etc/ansible/ansible.cfg : 기본 설정 파일

ansible --version 을 입력하면 config file = /etc/ansible/ansible.cfg 으로 설정 파일이 지정된 것을 확인할 수 있다.

[vagrant@controller ~]$ ansible --version
ansible 2.9.27
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

touch 명령어로 .ansible.cfg 를 만들자 config file 이 변경된 것을 확인할 수 있다.

[vagrant@controller ~]$ touch .ansible.cfg
[vagrant@controller ~]$ ansible --version
ansible 2.9.27
  config file = /home/vagrant/.ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

사용자가 위치한 현재 디렉토리에 따라 config file 이 변경되는 것을 확인할 수 있다.

[vagrant@controller ~]$ mkdir a b
[vagrant@controller ~]$ touch a/ansible.cfg
[vagrant@controller ~]$ touch b/ansible.cfg
[vagrant@controller ~]$ cd a
[vagrant@controller a]$ ansible --version
ansible 2.9.27
  config file = /home/vagrant/a/ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
[vagrant@controller a]$ cd ~
[vagrant@controller ~]$ cd b
[vagrant@controller b]$ ansible --version
ansible 2.9.27
  config file = /home/vagrant/b/ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

ANSIBLE_CONFGI 로 환경 변수 세팅하여 구성 파일 생성하면 디렉토리 위치에 상관없이 생성한 파일이 설정 파일로 작동한다.

[vagrant@controller b]$ touch /tmp/a.cfg
[vagrant@controller b]$ export ANSIBLE_CONFIG=/tmp/a.cfg
[vagrant@controller b]$ ansible --version
ansible 2.9.27
  config file = /tmp/a.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
[vagrant@controller b]$ cd ~/a
[vagrant@controller a]$ ansible --version
ansible 2.9.27
  config file = /tmp/a.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
[vagrant@controller a]$ cd ~
[vagrant@controller ~]$ ansible --version
ansible 2.9.27
  config file = /tmp/a.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

설정 파일 구성

설정 파일에 어떤 것들을 설정할 수 있는지는 공식 문서(https://docs.ansible.com/ansible/latest/reference_appendices/config.html) 를 살펴보자.

[vagrant@controller ~]$ ansible --version
ansible 2.9.27
  config file = /home/vagrant/.ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
[vagrant@controller ~]$ vi .ansible.cfg
[vagrant@controller ~]$ cat .ansible.cfg
[defaults]
inventory=./inventory.ini
[vagrant@controller ~]$ ansible all --list-hosts
  hosts (3):
    192.168.100.11
    192.168.100.12
    15.164.213.82
[vagrant@controller ~]$ mkdir test1
[vagrant@controller ~]$ cd test
-bash: cd: test: No such file or directory
[vagrant@controller ~]$ cd test1
[vagrant@controller test1]$ vi ansible.cfg
[vagrant@controller test1]$ cat ansible.cfg
[defaults]
inventory=a.ini
[vagrant@controller test1]$ echo "192.168.100.11" > a.ini
[vagrant@controller test1]$ cat a.ini
192.168.100.11
[vagrant@controller test1]$ ansible all --list-hosts
  hosts (1):
    192.168.100.11
[vagrant@controller test1]$ ansible --version
ansible 2.9.27
  config file = /home/vagrant/test1/ansible.cfg
  configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]

관리 노드 접속

OpenSSH 로 접속을 한다.

SSH 접속 방법

  • 패스워드 인증
  • 키 페어 인증

sudo vi /etc/ssh/sshd_config 를 들여다 보면 #PermitRootLogin yes 루트로 바로 접속하는 것을 막아놓은 것을 확인할 수 있다.

권한 상승(Privilege Escalation)

  • su : 가능하면 절대 사용해서는 안되고 어차피 사용하지 못한다. su 명령어를 사용하면 root 의 비밀번호를 물어보게 되는데 만약 여러 관리자가 루트 비밀번호를 알게 되고, 책임 추적성에 맞지 않다. root 의 패스워드를 세팅하지 않으면 su 명령어를 실행할 수 없다.
  • sudo : sudo 명령어를 사용하면 비밀번호를 묻는데 현재 사용자의 비밀번호를 물어본다. 루트의 비밀번호를 묻지 않는다.
    • %wheel : wheel 그룹
    • ALL : 모든 시스템에서, 여기에 IP 를 설정하면 해당 IP 를 갖는 시스템에만 접근할 수 있다.
    • (ALL) : 모든 사용자로
    • ALL : 모든 명령어, 여기에 /usr/bin/ls 를 설정하면 해당 명령어만 sudo 로 실행할 수 있다는 것이다.
    • 즉, wheel 그룹에 속한 사용자들이 모든 시스템에서 모든 사용자로 모든 명령어를 사용할 수 있다.
    /etc/sudores.d/[사용자 이름으로 된 파일명]
    • NOPASSWD : 패스워드 묻지 않음(passwordless sudo)
    • 즉, vagrant 그룹이 모든 시스템에서 모든 사용자로 모든 명령어를 사용할 수 있고 sudo 명령어를 사용할 때 패스워드를 묻지 않는다.
  • %wheel ALL=(ALL) ALL vagrant 192.168.56.100=(root) /usr/bin/ls
  • [vagrant@node1 ~]$ sudo cat /etc/sudoers.d/vagrant %vagrant ALL=(ALL) NOPASSWD: ALL
  • /etc/sudoers

ansible 접속 관련 옵션

  • -u REMOTE_USER, --u REMOTE_USER : SSH 접속 계정(기본: 현재 사용자)
  • -k, --ask-pass : 기본값 False(옵션을 사용하지 않으면 key pair 인증), -k 옵션을 사용하게 되면 SSH 패스워드 인증을 사용하여 접속
    • ansible 의 기본 인증 방법 : SSH 키 인증
  • -b, --become : 권한 상승 옵션으로 root 계정 권한으로 실행하겠다. 즉 명령어에 sudo 를 붙여주겠다는 뜻
  • --become-method <sudo|su> : sudo 나 su 로 명령어를 실행한다. 기본값은 sudo
  • --become-user : 어떤 사용자로 실행할 것인지, 기본값은 root 이다.
  • -K, --ask-become-pass : sudo 패스워드 묻는 옵션, 이 옵션을 사용하지 않으면 기본적으로 Passwordless sudo 이다.

설정 파일

설정 파일에 접속 관련 옵션을 미리 설정할 수 있다. 설정 파일에 옵션을 어떻게 넣어야 하는지는 https://docs.ansible.com/ansible/latest/reference_appendices/config.html 공식 문서에 나와있다.

vi ~/.ansible.cfg

[defaults]
remote_user=<SSH_USER>
ask_pass=<True|False>
host_key_checking=<True|False>

[privilege_connection]
become=<True|False>
become_ask_pass=<True|False>
become_method=<sudo|su>
become_user=<SUDO_USER>

host_key_checking=<True|False> 은 이 접속하려는 호스트에 최초 접속 시 이 호스트의 finger print 가 맞는지 yes or no 로 물어보는데 기본값이 True 로 되어있다.

만약에 100개가 넘는 호스트의 그룹에 설정을 만들어서 실행시켰을 때 최초 접속 이라 finger print 가 맞냐고 물어보는데 이걸 하나하나 yes 하기는 힘들기 때문에 host_key_checking 을 False 로 세팅하면 finger print 를 묻지 않는다.

[vagrant@controller ~]$ vi ~/.ansible.cfg
[vagrant@controller ~]$ cat .ansible.cfg
[defaults]
inventory=./inventory.ini
remote_user=vagrant
host_key_checking=False

[privilege_connection]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

ansible-config

ansible 설정 파일 확인할 때 사용하는 명령어이다.

ansible-config list : 설정 파일에 설정 가능한 모든 항목들을 확인할 수 있다.

ansible-config dump : 모든 설정의 기본 값 및 변경 값 표시. 색깔별로 상태를 확인할 수 있다. 초록색은 정상, 주황색은 변경되었을 때, 빨강색은 문제가 발생한 것을 나타낸다.

ansible-config view : 현재 적용되는 설정 파일의 내용 표시

ansible-doc

ansible-doc -l : ansible 공식 문서 목록을 확인할 수 있다.

ansible-doc [모듈명] : 모듈에 대한 공식 문서를 확인할 수 있다.

Ad_hoc 명령어

공식문서 : https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html

ansible <HOST_PATTERN> -m <MODULE> -a <PARAMETER>

HOST_PATTERN 은 아래 설명처럼 설정 가능하다. 정규 표현식도 HOST_PATTERN 에 넣을 수 있다.

아래 예시를 살펴보면 이해가 갈 것이다.

Multiple groups → 합집합, Intersection of groups → 교집합, Excluding groups → not 을 표현한다.

Intersection of groups, Excluding groups 를 사용하다 보면 실수를 할 수 있기 때문에 사용을 지양하자.

[vagrant@controller ~]$ ansible '*' --list-hosts
  hosts (3):
    192.168.100.11
    192.168.100.12
    15.164.213.82
[vagrant@controller ~]$ ansible '192.168.100.*' --list-hosts
  hosts (2):
    192.168.100.11
    192.168.100.12
[vagrant@controller ~]$ ansible 192.168.100.11:192.168.100.12 --list-hosts
  hosts (2):
    192.168.100.11
    192.168.100.12
[vagrant@controller ~]$ ansible 192.168.100.11,192.168.100.12 --list-hosts
  hosts (2):
    192.168.100.11
    192.168.100.12
[vagrant@controller ~]$ ansible web:db --list-hosts
  hosts (4):
    weba
    webb
    dba
    dbb
[vagrant@controller ~]$ cat inventory.ini
192.168.100.11
192.168.100.12

[web]
weba
webb

[db]
weba
dba
dbb

[vagrant@controller ~]$ ansible web:db --list-hosts
  hosts (4):
    weba
    webb
    dba
    dbb
[vagrant@controller ~]$ ansible 'web:!db' --list-hosts
  hosts (1):
    webb
[vagrant@controller ~]$ ansible 'web:&db' --list-hosts
  hosts (1):
    weba

Wordpress 구성에 필요한 모듈들

module index 공식 문서 : https://docs.ansible.com/ansible/2.9/modules/modules_by_category.html

패키지 설치(yum): yum

서비스 제어(systemctl): service

텍스트 수정(sed): lineinfile, blockinfile, replace

호스트 네임 설정(hostnamectl): hostname

압축 해제(tar): archive, unarchive

방화벽(firewall-cmd): firewalld(레드햇 계열), ufw(데비안 계열), iptables

파일 복사(cp): copy, fetch(관리 노드에 있는 파일을 제어 노드로 복사해서 가져올 때)

디렉토리 생성, 파일 권한 변경 등..(mkdir, chmod): file

파일 다운로드(wget): get_url

네트워크 설정(nmcli): nmcli

데이터베이스(mysql): mysql_db, mysql_user, meysql_info, mysql_replica...

SSL 인증서(mod_ssl): openssl_certificate, openssl_csr, openssl_*...


  1. Ad-hoc 명령으로 wordpress 구성 명령 실행
  2. 제어 노드 → Bastion Host → Private EC2 인스턴스
how 🐋  ~
> cat .ssh/config
Host bastion
    HostName 3.35.37.34
    User ec2-user
    ForwardAgent yes
    IdentityFile /Users/csw/ec2-key-pair.pem

Host staging
    HostName 172.31.34.243
    User ec2-user
    IdentityFile /Users/csw/ec2-key-pair.pem
    ProxyCommand ssh bastion -W %h:%p

how 🐋  ~
> ssh staging
Last login: Wed Apr 13 08:21:51 2022 from ip-172-31-45-0.ap-northeast-2.compute.internal

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\\___|___|

<https://aws.amazon.com/amazon-linux-2/>
[ec2-user@ip-172-31-34-243 ~]$
728x90