Ansible Study -1

LEE EUI JOO·2024년 1월 8일
0

Ansible & Vagrant

목록 보기
4/7
post-thumbnail

1. Ansible

  • 오픈소스이며 IT 자동화 도구

  • 코드 기반으로 작성하여 여러 환경에 동일하게 적용하도록 돕는 역할

  • 리눅스, MacOS, BSC 계열 유닉스, WSL을 지원하는 원도우에 파이썬과 앤서블 코어만 설치하면 어디에서나 플레이북(YAML 형식의 작업들은 순서대로 작성해 놓은 파일)을 작성하고 이를 실행할 수 있습니다.

  • 앤서블은 앤서블 코어가 설치되고 플레이북을 작성하여 실행할 수 있는 제어 노드 (Control Node)와 플레이북이 실행되어 애플리케이션 설치나 클라우드 시스템의 가상 서버 생성과 같은 작업이 수행되는 관리 노드 (Managed Node)로 구성되며, 앤서블은 제어노드에만 설치됩니다.

  • 간단하게 사용자가 정의한 플레이북과 관리할 대상의 노드들을 정의해놓은 파일인 인벤토리파일에 의해 SSH 프로토콜을 사용하여 다양한 환경의 대상 노드에 자동화를 수행시킬 수 있습니다.

  • 특징

    • 에이전트가 필요없다는 장점 : SSH 로 접속하여 대상서버들에게 접속하기 때문입니다!

    • 멱등성을 보장한다는 장점 : 시스템을 원하는 상태로 표현하여 유지하도록 설계되어 있어, 동일한 운영 작업을 여러 번 실행해도 같은 결과를 냅니다!

    • Easy : YAML 문법을 사용하기 때문에 에디터만 있으면 걱정 없으며, 시스템 관리 모듈 부터 다양한 환경의 퍼블릭 클라우드 관련 모듈 및 컬렉션 까지 제공하기 때문에 쉽게 예제를 많이 찾아볼 수 있습니다!

  • 커뮤니티 앤서블 아키텍처

  • 제어 노드 Control Node

    • 앤서블이 설치되는 노드로 운영체제가 리눅스라면 제어 노드가 될 수 있습니다.
    • 앤서블은 파이썬 모듈을 이용하므로 앤서블을 설치하고 실행하려면 꼭 파이썬이 함께 설치되어 있어야 합니다.
  • 관리 노드 Managed Node

    • 앤서블이 제어하는 원격 시스템 혹은 호스트를 의미합니다.
    • 그림처럼 리눅스 혹은 윈도우가 설치된 노드일 수 있습니다.
    • 관리 노드는 제어 노드와 SSH 통신이 가능해야 하며, 파이썬이 꼭 설치되어 있어야 합니다.
  • 인벤토리 Inventory

    • 제어 노드가 제어하는 관리 노드들의 목록을 나열해 놓은 File
    • 관리 노드의 성격별로 그룹화도 가능합니다.
$ cat inventory
192.168.10.101

[WebServer]
web1.example.com
web2.example.com

[DBServer]
db1.example.com
db2.example.com
  • 모듈 Modules

    • 앤서블은 관리 노드의 작업을 수행할 때 SSH를 통해 연결한 후 앤서블 모듈이라는 스크립트를 PUSH 하여 작동합니다.

    • 대부분의 모듈은 원하는 시스템 상태를 설명하는 매개 변수를 허용하며, 모듈 실행이 완료되면 제거되는 프로세스입니다.

  • 플러그인 Plugins

    • 모듈이 대상 시스템에서 별도의 프로세스로 실행되는 동안 플러그인은 제어 노드에서 실행됩니다.

    • 앤서블의 핵심 기능인 데이터변환, 로그 출력, 인벤토리 연결 등에 대한 옵션 및 확장 기능을 제공합니다.

  • 플레이북 Playbook

    • 관리 노드에서 수행할 작업들을 YAML 문법을 이용해 순서대로 작업해 놓은 파일입니다.

    • 작성된 플레이북을 활용하여 관리 노드에 SSH 로 접근해 작업을 수행합니다.

    • 사용자가 직접 작성해야하는 가장 중요한 파일이라고 할 수 있습니다.


2.환경 구축

AWS 환경으로 진행

  • VPC 1개
    • Pub-subnet 2개
  • EC2 Instance 4개
    • Spec : t3.medium, Ubuntu 22.04 img, 30GB Disk
    • 제어노드 1
    • 대상서버 3
    • Key-Pair 1(.pem)

Visula Studio Code SSH 설정

  • 실습 편의를 위해 VSCode 의 Extension 인 Remote-SSH 와 Root 권한으로 Ansible 서버에 접근하겠습니다.
  • 아래는 ~/.ssh/config 설정 부분입니다.
# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host ansible-server
    HostName {Your ansible-server Pub IP}
    User root
  • Visual Studio Code 에 자동 저장 설정
    • 설정 → ‘auto save’ 검색 ⇒ afterDelay, Auto Save Delay 1000ms(=1초)로 설정해줍니다.

3. Install Ansible

작업디렉토리 생성
mkdir my-ansible

pwd
/root/my-ansible

# 파이썬 버전 확인
python3 --version
Python 3.10.12

# 설치
apt install software-properties-common -y
add-apt-repository --yes --update ppa:ansible/ansible
apt install ansible -y

# 설치확인
ansible --version
ansible [core 2.15.8]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True

앤서블 접근을 위한 SSH 인증 구성

  • 앤서블은 로컬 사용자에게 개인 SSH 키가 있거나 관리 호스트에서 원격 사용자임을 인증 가능한 키가 구성될 경우 자동으로 로그인이 됩니다.

  • 먼저, ssh-keygen 명령어를 이용하여 SSH 키를 생성합니다.

ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa
Generating public/private rsa key pair.
...
  • 공개키를 관리 노드에 복사합니다.
# 공개 키를 관리 노드에 복사
for i in {1..3}; do ssh-copy-id root@tnode$i; done

# 복사 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i cat ~/.ssh/authorized_keys; echo; done

# ssh 접속 테스트 / 관리노드에 하나씩 접근해봅니다.
ssh tnode1
ssh tnode2
ssh tnode3

4. 호스트 선정

  • 인벤토리(inventory)를 이용하겠습니다.
    • 이 파일은 INI 스타일 형식(이름 = 값) 또는 YAML을 포함한 다양한 형식을 사용하여 작성할 수 있습니다.
    • 가장 간단한 형식의 INI 스타일 인벤토리 파일은 다음과 같이 관리 호스트의 호스트명 또는 IP 주소가 한 줄에 하나씩 있는 목록 형태입니다.
web1.example.com
web2.example.com
db1.example.com
db2.example.com
192.0.2.42
  • IP 를 이용한 인벤토리 파일생성
# inventory 파일 생성
cat <<EOT > inventory
10.10.1.11
10.10.1.12
10.10.1.13
EOT
root@server:~/my-ansible# ls
Easy-Ansible  inventory

## 인벤토리 검증
root@server:~/my-ansible# ansible-inventory -i ./inventory --list | jq
{
  "_meta": {
    "hostvars": {}
  },
  "all": {
    "children": [
      "ungrouped"
    ]
  },
  "ungrouped": {
    "hosts": [
      "10.10.1.11",
      "10.10.1.12",
      "10.10.1.13"
    ]
  }
}
  • 호스트명을 이용한 인벤토리 생성
cat /etc/hosts
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
10.10.1.10 server
10.10.1.11 tnode1
10.10.1.12 tnode2
10.10.1.13 tnode3
root@server:~/my-ansible# cat <<EOT > inventory
tnode1
tnode2
tnode3
EOT

## 인벤토리 검증
root@server:~/my-ansible# ansible-inventory -i ./inventory --list | jq
{
  "_meta": {
    "hostvars": {}
  },
  "all": {
    "children": [
      "ungrouped"
    ]
  },
  "ungrouped": {
    "hosts": [
      "tnode1",
      "tnode2",
      "tnode3"
    ]
  }
}

호스트별로 역할(롤)을 주고 롤별로 특정 작업을 수행해야 하는 경우가 있습니다.

  • 그룹별 호스트 설정

    • 그룹별로 호스트를 설정하여 사용하면 앤서블 플레이북 실행 시 그룹별로 작업을 처리할 수 있어서 좀 더 효과적입니다.

    • 이 경우 다음과 같이 그룹명을 대괄호 ([]) 내에 작성하고 해당 그룹에 속하는 호스트명이나 IP를 한 줄에 하나씩 나열합니다.

    • 아래 인벤토리는 두 개의 호스트 그룹인 webservers와 db-servers를 정의한 것입니다.

[webservers]
web1.example.com
web2.example.com

[db-servers]
db01.example.com
db02.example.com
  • 또는 호스트는 여러 그룹에 있을 수 있으며, 실제 호스트를 여러 그룹으로 구성하면 호스트의 역할, 실제 위치, 프로덕션 여부 등에 따라 다양한 방식으로 구성할 수 있습니다.

  • 그러면 특성, 용도 또는 위치에 따라 특정 호스트 집합에 앤서블 플레이북을 쉽게 적용할 수 있습니다.

[webservers]
web1.example.com
web2.example.com
192.0.2.42

[db-servers]
db01.example.com
db02.example.com

[east-datacenter]
web1.example.com
db01.example.com

[west-datacenter]
web2.example.com
db02.example.com

[production]
web1.example.com
web2.example.com
db01.example.com
db02.example.com

[development]
192.168.0.42
  • 중첩 그룹 정의

    • 앤서블 인벤토리는 호스트 그룹에 기존에 정의한 호스트 그룹을 포함할 수도 있습니다.

    • 이 경우 호스트 그룹 이름 생성 시 :children 이라는 접미사를 추가하면 됩니다.

    • 다음은 webservers 및 db-servers 그룹의 모든 호스트를 포함하는 datacenter 그룹을 생성하는 예시입니다.

[webservers]
web1.example.com
web2.example.com

[db-servers]
db01.example.com
db02.example.com

[datacenter:children]  ## 호스트 그룹인 webservers 와 dbservers 를 포함하고 있습니다.
webservers
dbservers
  • 범위를 사용한 호스트 사양 간소화

    • 인벤토리의 호스트 이름 또는 IP 주소를 설정할 때 범위를 지정하여 호스트 인벤토리를 간소화 할 수 있습니다.

    • 숫자 또는 영문자로 범위를 지정할 수 있으며, 대괄호 사이에 시작 구문과 종료 구문을 포함합니다.

[webservers]
web[1:2].example.com

[db-servers]
db[01:02].example.com
  • 이 외에도 IP 주소 범위를 표현할 때나 여러 호스트의 호스트명을 지정할 때, 혹은 DNS와 같이 호스트의 어미 부분을 범위로 지정하면 IPv6의 범위 설정에도 사용할 수 있습니다.
# IP 범위 설정 : 192.168.4.0 ~ 192.168.4.255 사이의 IP 범위를 표현
[defaults]
192.168.4.[0:255]

# 호스트명 범위 설정 : com01.example.com ~ com20.example.com 의 범위를 표현
[compute]
com[01:20].example.com

# DNS 범위 설정 : a.dns.example.com , b.dns.example.com , c.dns.example.com 을 의미함
[dns]
[a:c].dns.example.com

# IPv6 범위 설정 : 2001:db08::a ~ 2001:db08::f 사이의 IPv6 범위를 표현
[ipv6]
2001:db8::[a:f]

실습을 위해 인벤토리 그룹을 구성해보겠습니다.

cat <<EOT > inventory
[web]
tnode1
tnode2

[db]
tnode3

[all:children]
web
db
EOT

## 검증
ansible-inventory -i ./inventory --list | jq
{
  "_meta": {
    "hostvars": {}
  },
  "all": {
    "children": [
      "ungrouped",
      "web",
      "db"
    ]
  },
  "db": {
    "hosts": [
      "tnode3"
    ]
  },
  "web": {
    "hosts": [
      "tnode1",
      "tnode2"
    ]
  }
}
  • 위의 스크립트로 검증하는 과정에서 현재 프로젝트 디렉터리 내에 ansible.cfg 라는 앤서블 환경 설정 파일을 구성 시, -i 옵션을 사용하지 않아도 ansible.cfg 설정 파일에 정의된 인벤토리의 호스트 정보를 확인할 수 있습니다.
cat <<EOT > ansible.cfg
[defaults]
inventory = ./inventory
EOT
root@server:~/my-ansible# ls
Easy-Ansible  ansible.cfg  inventory
root@server:~/my-ansible# ansible-inventory --list | jq
{
  "_meta": {
    "hostvars": {}
  },
  "all": {
    "children": [
      "ungrouped",
      "web",
      "db"
    ]
  },
  "db": {
    "hosts": [
      "tnode3"
    ]
  },
  "web": {
    "hosts": [
      "tnode1",
      "tnode2"
    ]
  }
}

5. PlayBook 작성

  • 앤서블 프로젝트 디렉토리에 ansible.cfg 파일을 생성하면 다양한 앤서블 설정을 적용할 수 있습니다.
  • 파일에는 키-값 쌍으로 정의된 설정이 포함되며, 여러개의 섹션으로 구분할 수 있습니다.
# cat ansible.cfg 
[defaults]
inventory = ./inventory
remote_user = root
ask_pass = false

[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false

[defaults] 섹션 : 앤서블 작업을 위한 기본값 설정

매개 변수설명
inventory인벤토리 파일의 경로를 지정함.
remote_user앤서블이 관리 호스트에 연결할 때 사용하는 사용자 이름을 지정함. 이때, 사용자 이름을 지정하지 않으면 현재 사용자 이름으로 지정됨.
ask_passSSH 암호를 묻는 메시지 표시 여부를 지정함. SSH 공개 키 인증을 사용하는 경우 기본값은 false임.

[privilege_escalation] 섹션 : 보안/감사로 인해 원격 호스트에 권한 없는 사용자 연결 후 관리 액세스 권한을 에스컬레이션하여 루트 사용자로 가져올 때 사용합니다.

매개 변수설명
become기본적으로 권한 에스컬레이션을 활성화할 때 사용하며, 연결 후 관리 호스트에서 자동으로 사용자를 전환할지 여부를 지정함.
일반적으로 root로 전환되며, 플레이북에서도 지정할 수 있음.
become_method권한을 에스컬레이션하는 사용자 전환 방식을 의미함. 일반적으로 기본값은 sudo를 사용하며, su는 옵션으로 설정할 수 있음.
become_user관리 호스트에서 전환할 사용자를 지정함. 일반적으로 기본값은 root임.
become_ask_passbecome_method 매개 변수에 대한 암호를 묻는 메시지 표시 여부를 지정함. 기본값은 false임.
권한을 에스컬레이션하기 위해 사용자가 암호를 입력해야 하는 경우, 구성 파일에 become_ask_pass = true 매개 변수를 설정하면 됨.
  • 앤서블은 리눅스에서 기본적으로 SSH 프로토콜을 사용하여 관리 호스트에 연결합니다.
  • 앤서블에서 관리 호스트에 연결하는 방법을 제어하는 가장 중요한 매개 변수는 [defaults] 섹션에 설정되어 있습니다.
  • 또한, 별도로 설정되어 있지 않으면 앤서블은 실행 시 로컬 사용자와 같은 사용자 이름을 사용하여 관리 호스트에 연결합니다.
  • 이때 다른 사용자를 지정하려면 remote_user 매개 변수를 사용하여 해당 사용자 이름으로 설정할 수 있습니다.

앤서블 ping 모듈

  • ping 모듈을 이용하여 web 그룹의 호스트롤 정상 연결(pong을 반환)이면 "SUCCESS" 가 출력됩니다.
    • 가장 중요한 것은 ICMP 가 아닌 python 테스트 모듈이라는 것입니다.
ansible -m ping web

# ansible -m ping web
tnode2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
tnode1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
  • 옵션 설정으로 암호 입력 후 실행 확인 방법
ansible -m ping --ask-pass web
SSH password: 
tnode2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
tnode1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
  • 다른 User 계정으로 실행 확인해보겠습니다.
ansible -m ping web -u ubuntu
tnode1 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ubuntu@tnode1: Permission denied (publickey,password).",
    "unreachable": true
}
tnode2 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ubuntu@tnode2: Permission denied (publickey,password).",
    "unreachable": true
}

---
ansible -m ping web -u ubuntu --ask-pass
SSH password: 
tnode1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
tnode2 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

앤서블 shell 모듈

  • shell은 노드들에 명령 구문을 전달하고 해당 결과를 반환하는 모듈입니다.
# ansible -m shell -a "free -h" web
tnode2 | CHANGED | rc=0 >>
               total        used        free      shared  buff/cache   available
Mem:           3.8Gi       195Mi       2.6Gi       0.0Ki       994Mi       3.3Gi
Swap:             0B          0B          0B
tnode1 | CHANGED | rc=0 >>
               total        used        free      shared  buff/cache   available
Mem:           3.8Gi       200Mi       2.6Gi       0.0Ki       995Mi       3.3Gi
Swap:             0B          0B          0B

Playbook 작성하기

  • 플레이북은 YAML 포맷으로 작성된 텍스트 파일이며, 일반적으로 .yml 이라는 확장자를 사용하여 저장됩니다.

  • 플레이북은 대상 호스트나 호스트 집합에 수행할 작업을 정의하고 이를 실행합니다. 이때 특정 작업 단위를 수행하기 위해 모듈을 적용합니다.

  • debug 모듈을 사용하여 문자열을 출력해보겠습니다.

    • 아래 2개의 플레이북 first-playbook.yml, first-playbook-error.yml 파일은 직접 작성합니다.
first-playbook.yml
---
- hosts: all
  tasks:
    - name: Print message
      debug:
        msg: Hello CloudNet@ Ansible Study
        
---
first-playbook-error.yml 

---
- hosts: all
  tasks:
    - name: Print message
      debug:
      msg: Hello CloudNet@ Ansible Study
  • 문법 체크도 가능합니다.
ansible-playbook --syntax-check first-playbook.yml

playbook: first-playbook.yml

ansible-playbook --syntax-check first-playbook-with-error.yml
ERROR! the playbook: first-playbook-with-error.yml could not be found
  • 플레이북 실행하기
    • 플레이북을 실행할 때는 ansible-playbook 명령어를 이용합니다. 환경 설정 파일인 ansible.cfg가 존재하는 프로젝트 디렉터리 내에서 실행할 경우에는 ansible-playbook 명령어와 함께 실행하고자 하는 플레이북 파일명을 입력하면 됩니다.
ansible-playbook first-playbook.yml
  • 서비스를 재시작하는 플레이북을 작성해보겠습니다.
    • restart-service.yml
# (신규터미널) 모니터링 : 서비스 재시작 실행 여부 확인
ssh tnode1 tail -f /var/log/syslog

# 실행 전 check 옵션으로 플레이북의 실행 상태를 미리 점검 가능 : 출력 중 changed=1 확인
ansible-playbook --check restart-service.yml 


# 플레이북 실제 실행
ansible-playbook restart-service.yml

# 작성한 yml 파일들 삭제
rm -r *.yml
  • 새로운 터미널을 열어서 시스템 로그를 확인해본 결과 입니다.


6. 변수

  • 앤서블은 변수를 사용하여 사용자, 설치하고자 하는 패키지, 재시작할 서비스, 생성 또는 삭제할 파일명 등 시스템 작업 시 사용되는 다양한 값을 저장할 수 있습니다.

  • 이런 변수를 활용하면 얼마든지 플레이북을 재사용할 수 있으며, 사용자로부터 받은 값도 쉽게 적용할 수 있습니다.

  • 앤서블에서 사용되는 변수는 그룹 변수, 호스트 변수, 플레이 변수, 추가 변수가 있으며 플레이 결과를 저장하기 위한 작업 변수도 있습니다.

ansible.buitin.user 모듈

  • 그룹 변수 : 인벤토리에 정의된 호스트 그룹에 적용하는 변수

    • 그룹 변수는 인벤토리에 정의된 호스트 그룹에 적용하는 변수를 의미합니다. 따라서 인벤토리에 선언해야 하고, 선언하고자 하는 그룹명과 함께 :vars 라는 문자열을 추가해 변수를 선언한다는 것을 알려줍니다. 예제를 통해 알아보겠습니다.
  • [ansible-server]의 my-ansible 디렉터리에 있는 inventory 파일 하단에 [all:vars] 섹션을 선언하고 해당 섹션 아래에 user=ansible이라는 변수와 값을 선언합니다.

    • 이렇게 하면 all이라는 그룹에서 user라는 변수를 사용할 수 있습니다. 다음 예제에서 all 그룹에는 web 그룹과 db 그룹이, web 그룹에는 tnode1-ubuntu.local, tnode2-ubuntu.local이 포함되며, db그룹에는 tnode3 호스트가 포함되는 식입니다.
cat inventory 
[web]
tnode1
tnode2

[db]
tnode3

[all:children]
web
db

[all:vars]
user=ansible
  • 이번에는 create-user.yml 이라는 파일을 생성합니다. 해당 파일은 사용자를 생성하는 태스크를 포함합니다.

    • 앤서블에서 시스템 사용자(account)를 생성하기 위해서는 ansible.builtin.user라는 모듈을 사용합니다.
  • 그리고 인벤토리에서 선언한 user라는 변수를 겹중괄호 사이에 넣어주면, 해당 변수를 플레이북에서 사용할 수 있습니다.

    • 이때 겹 중괄호와 변수명 사이는 항상 한 칸씩 띄워주어야 하며 주의해줍시다.
cat create-user.yml 
---

-  hosts: all
   tasks:
   -  name: Create User {{ user }}
      ansible.builtin.user:
         name: "{{ user }}"
         state: present
  • 앞에서 생성한 플레이북을 ansible-playbook 명령어와 함께 실행합니다. 그러면 태스트명으로 “Create User {{ user }}” 라고 변수를 사용한 부분에 해당 변수의 값인 ansible 이라는 문자열이 보이는 것을 확인할 수 있습니다.
# (터미널2) 모니터링
watch -d "ssh tnode1 tail -n 3 /etc/passwd"

# 실행
ansible-playbook create-user.yml
...
TASK [Create User ansible] *********
...

# 한번 더 실행 : 멱등성 확인
ansible-playbook create-user.yml

# 대상 호스트 ansible 사용자 생성 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i tail -n 3 /etc/passwd; echo; done
  • 새 터미널을 열어줘서 사용자 추가가 됐는지 확인해줍니다.

  • 수동으로 ansible 사용자 삭제 후 다시 플레이북 실행
ssh tnode1 userdel -r ansible
ssh tnode1 tail -n 2 /etc/passwd
  • 삭제 후

  • 플레이북 실행 후 ansible-playbook create-user.yml
    • tnode1 이 changed 된 것을 확인할 수 있습니다.

  • 호스트 변수 : 말 그대로 해당 호스트에서만 사용할 수 있음
    • 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언
cat inventory
[web]
tnode1
tnode2

[db]
tnode3 user=ansible1

[all:children]
web
db

[all:vars]
user=ansible
  • 플레이북 작성
    • create-user1.yml
---

- hosts: db ## hosts를 all -> db
  tasks:
  - name: Create User {{ user }}
    ansible.builtin.user:
      name: "{{ user }}"
      state: present

# 실행
ansible-playbook create-user1.yml

# 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i tail -n 3 /etc/passwd; echo; done
  • 터미널을 열고 모니터링
    • tnode3 에만 ansible1 user 가 생성됐음을 확인할 수 있습니다.

  • 플레이 변수 : 플레이북 내에서 선언되는 변수
    • 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
cat create-user2.yml
---

- hosts: all
  vars:
    user: ansible2

  tasks:
  - name: Create User {{ user }}
    ansible.builtin.user:
      name: "{{ user }}"
      state: present
      
# 터미널 모니터링
watch -d "ssh tnode3 tail -n 3 /etc/passwd"

# 실행
ansible-playbook create-user2.yml

# 3개의 노드 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i tail -n 3 /etc/passwd; echo; done

  • 또한 플레이 변수를 별도의 파일로 분리하여 작성한 후 플레이북에서 선언할 수 있습니다.
mkdir vars
echo "user: ansible3" > vars/users.yml 
  • 플레이북 작성
    • create-user3.yml
---

- hosts: all
  vars_files:
    - vars/users.yml

  tasks:
  - name: Create User {{ user }}
    ansible.builtin.user:
      name: "{{ user }}"
      state: present
      

# 실행
ansible-playbook create-user3.yml

# 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i tail -n 4 /etc/passwd; echo; done
  • 모든 노드에 ansible3 사용자가 추가된 것을 확인할 수 있습니다.

  • 추가 변수 : 외부에서 ansible-playbook를 실행 할 때 함께 파라미터로 넘겨주는 변수를 의미. 앞에 변수 중 우선순위가 가장 높습니다.
    • 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
    • 방금 생성했던 플레이북인 create-user3.yml 파일을 사용하겠습니다.
# 실행
ansible-playbook -e user=ansible4 create-user3.yml

# 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i tail -n 5 /etc/passwd; echo; done
  • 모든 노드에 ansible4 사용자가 추가된 것을 확인할 수 있습니다.


변수 우선 순위 : 추가변수(실행 시 파라미터) > 플레이 변수 > 호스트 변수 > 그룹 변수


ansible.builtin.debug 모듈

  • 작업 변수 : 플레이북의 태스트 수행 결과를 저장. 특정 작업 수행 후 그 결과를 후속 작업에서 사용할 때 주로 사용됩니다.

    • 예를 들어 클라우드 시스템에 VM을 생성한다고 가정해보겠습니다. 이를 위해서는 네트워크나 운영체제 이미지와 같은 가상 자원이 필요합니다.
    • 가상 자원조회하고, 조회된 결과를 가지고 VM을 생성할 때는 작업 변수를 사용하면 좋습니다.
  • 파일 복사 후 수정하여 Create User 태스크에 register: result 라는 문구를 추가하겠습니다.

    • register 를 선언하면 태스크를 실행한 결과를 register 다음의 result 라는 변수에 저장하겠다는 의미가 됩니다.
    • 그리고 result 라는 변수에 저장한 결과를 debug 모듈을 통해 출력합니다.
  • create-user4.yml

---

- hosts: db
  tasks:
  - name: Create User {{ user }}
    ansible.builtin.user:
      name: "{{ user }}"
      state: present
    register: result
  
  - ansible.builtin.debug:
      var: result
  • 추가 변수와 함께 플레이북을 실행시키겠습니다.
# 터미널 열어 확인
watch -d "ssh tnode3 tail -n 3 /etc/passwd"

# 실행
ansible-playbook -e user=ansible5 create-user4.yml

  • 그럼 추가된 user : ansible5 를 ansible.builtin.user 모듈로 제거해보겠습니다.
    • remove-user.yml
---

- hosts: db
  tasks:
  - name: Create User {{ user }}
    ansible.builtin.user:
      name: "{{ user }}"
      state: absent
      remove: yes
    register: result
  
  - ansible.builtin.debug:
      var: result
      
---
# 터미널 확인
watch -d "ssh tnode3 tail -n 3 /etc/passwd"
# 플레이북 실행
ansible-playbook -e user=ansible5 remove-user.yml

  • 관리 대상에 uptime 을 ansible.builtin.debug 모듈을 통해서 확인해보겠습니다.
    • uptime.yml
---

- hosts: all
  tasks:
  - name: watch uptime
    ansible.builtin.shell: /usr/bin/uptime
    register: result

  - ansible.builtin.debug:
     var: result
     
---
# 실행

ansible-playbook uptime.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [tnode2]
ok: [tnode3]
ok: [tnode1]

TASK [watch uptime] ************************************************************
changed: [tnode1]
changed: [tnode3]
changed: [tnode2]

TASK [ansible.builtin.debug] ***************************************************
ok: [tnode1] => {
    "result": {
        "changed": true,
        "cmd": "/usr/bin/uptime",
        "delta": "0:00:00.006178",
        "end": "2024-01-10 23:24:10.556688",
        "failed": false,
        "msg": "",
        "rc": 0,
        "start": "2024-01-10 23:24:10.550510",
        "stderr": "",
        "stderr_lines": [],
        "stdout": " 23:24:10 up 2 days,  2:39,  1 user,  load average: 0.08, 0.02, 0.01",
        "stdout_lines": [
            " 23:24:10 up 2 days,  2:39,  1 user,  load average: 0.08, 0.02, 0.01"
        ]
    }
}
ok: [tnode2] => {
    "result": {
        "changed": true,
        "cmd": "/usr/bin/uptime",
        "delta": "0:00:00.007231",
        "end": "2024-01-10 23:24:10.580110",
        "failed": false,
        "msg": "",
        "rc": 0,
        "start": "2024-01-10 23:24:10.572879",
        "stderr": "",
        "stderr_lines": [],
        "stdout": " 23:24:10 up 2 days,  2:39,  1 user,  load average: 0.00, 0.00, 0.00",
        "stdout_lines": [
            " 23:24:10 up 2 days,  2:39,  1 user,  load average: 0.00, 0.00, 0.00"
        ]
    }
}
ok: [tnode3] => {
    "result": {
        "changed": true,
        "cmd": "/usr/bin/uptime",
        "delta": "0:00:00.006615",
        "end": "2024-01-10 23:24:10.586592",
        "failed": false,
        "msg": "",
        "rc": 0,
        "start": "2024-01-10 23:24:10.579977",
        "stderr": "",
        "stderr_lines": [],
        "stdout": " 23:24:10 up 2 days,  2:39,  1 user,  load average: 0.00, 0.04, 0.03",
        "stdout_lines": [
            " 23:24:10 up 2 days,  2:39,  1 user,  load average: 0.00, 0.04, 0.03"
        ]
    }
}

PLAY RECAP *********************************************************************
tnode1                     : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode2                     : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode3                     : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=

7. Ansible Vault

  • 패스워드나 API 키 등 중요한 데이터들은 인벤토리 변수나 일반 앤서블 플레이북에 텍스트로 저장됩니다.
  • 이때 앤서블 파일에 접근 권한이 있는 사용자라면 모두 파일 내용을 볼 수 있는데, 이런 파일은 외부로 유출될 수 있다는 보안상의 위험을 야기하게 때문에 앤서블은 사용되는 모든 데이터 파일을 암호화하고 암호화된 파일의 내용을 해독할 수 있는 Ansible Vault라는 기능을 제공합니다.

암호화된 파일 만들기 :ansible-vault 명령어를 통해 파일 생성/암호화하여 사용 및 해독과 확인이 가능합니다.

  • ansible-vault create 로 생성하려는 플레이북 파일명을 입력하고, 해당 파일에서 사용할 패스워드 입력해줍니다.
ansible-vault create mysecret.yml
New Vault password: 
Confirm New Vault password: 

vi 편집기로 편집

  • ubuntu user 로 파일 확인을 해보겠습니다.
    • permission error 가 발생되며, 파일은 암호화 되어 있습니다.
su - ubuntu -c 'cat /root/my-ansible/mysecret.yml'
cat: /root/my-ansible/mysecret.yml: Permission denied

cat mysecret.yml 
$ANSIBLE_VAULT;1.1;AES256
62346266653762633361616632356166636161343138643065343762666639636233353230346533
3532366165613437636434653761633764346530326630620a323465366362316437313835643737
39346237373461393537356537346233623433303835396634386338373639626133353139623639
3564653732353264630a343566656538393766313039373338663363373630643130306332626332
39343665353037376134303337353662363235363739663031666564656533623932
  • 복호화 하려면 ansible-vault view mysecret.yml 를 실행시켜주면 됩니다.
ansible-vault view mysecret.yml 
Vault password: 
user: ansible
password: dmlwn
  • 별도의 암호가 저장된 파일도 생성하여 암호화된 플레이북을 만들 수 있습니다.
ansible-vault create --vault-pass-file ./vault-pass mysecret1.yml

cat mysecret1.yml 
$ANSIBLE_VAULT;1.1;AES256
37633337613965613938366631396231613434316232383666663439363533623239623964343861
3934616430393933643761313461623363313962353062390a373564626437653261666634396466
64303930633534373833363132636636613663323531643032393035353033343331666265353565
3538363437643364300a663461363232373965613136663937633261383665633665373936636637
6432

ansible-vault view --vault-pass-file ./vault-pass mysecret1.yml 
Hello!
  • 기존 파일도 암호화 할 수 있습니다. --output 옵션을 주어서 복호화된 플레이북을 하나 더 생성했지만, 기존파일을 그대로 원복하기 위해선 --output 옵션을 주지 않아도 됩니다.
ansible-vault encrypt create-user.yml
New Vault password: 
Confirm New Vault password: 
Encryption successful
root@server:~/my-ansible# cat create-user.yml 
$ANSIBLE_VAULT;1.1;AES256
63383731336464623964316261396565323234343864356134323432633236343832353730383631
3538303065623563353936653234373734393533663935360a353632316130623065646233366566
33383633323136323130633230616539363034643639363735363539313330313532393564656262
3466383366623462350a333331396663313639623963333237393164653537326634333066333665
65623637653832383931323834323639613236356134303933356530376135653232373938646634
66646433333362366631343462343434626137333337326133663330356265366465333066386665
35653432313430666337393161623131376438353035303236323766336562306631336335326536
31323532343435326133353661343133373866623737313331363133336135633238333566316366
38646530663339653030356635356538616139666463303438623766646561333635636362303238
61613337663962613537303735346337343036396462643033383466313664346136386561386562
65373239366463306435316338303661623932303664613565323032386635366364666562393636
30313036303538626134
root@server:~/my-ansible# ansible-vault decrypt create-user.yml --output=create-user-decrypted.yml
Vault password: 
Decryption successful
root@server:~/my-ansible# cat create-user-decrypted.yml 
---

-  hosts: all
   tasks:
   -  name: Create User {{ user }}
      ansible.builtin.user:
         name: "{{ user }}"
         state: present
  • 파일의 패스워드도 변경이 가능합니다. rekey 명령을 주면 됩니다.
ansible-vault rekey mysecret.yml
Vault password: 
New Vault password: 
Confirm New Vault password: 
Rekey successful

cat vault-pass
dmlwn
## 패스워드 파일을 이용해 패스워드 변경
ansible-vault rekey --new-vault-password-file=./vault-pass mysecret.yml
Vault password: 
Rekey successful
  • 암호화된 플레이북을 실행할 수 있습니다.
mv ./mysecret.yml ./vars/
root@server:~/my-ansible# ansible-vault view vars/mysecret.yml
Vault password: 
user: ansible
password: dmlwn

## 플레이북 작성
create-user5.yml
---

- hosts: db
  vars_files:
    - vars/mysecret.yml

  tasks: 
  - name: Create User {{ user }}
    ansible.builtin.user:
      name: "{{ user }}"
      state: present
      
## 실행확인
ansible-playbook create-user5.yml
ERROR! Attempting to decrypt but no vault secrets found
  • 암호화된 파일이 포함된 플레이북을 실행할 때는 vault-id @prompt 옵션을 사용해야 합니다.
ansible-playbook --vault-id @prompt create-user5.yml

# 패스워드 입력 없이 사용
ansible-playbook --vault-password-file=./vault-pass create-user5.yml

8. Facts

  • 팩트 Facts는 앤서블이 관리 호스트에서 자동으로 검색변수(자동 예약 변수)입니다.

  • 팩트에는 플레이, 조건문, 반복문 또는 관리 호스트에서 수집한 값에 의존하는 기타 명령문의 일반 변수처럼 사용 가능한 호스트별 정보가 포함되어 있습니다.

  • 관리 호스트에서 수집된 일부 팩트에는 다음 내용들이 포함될 수 있습니다.

    • 호스트 이름
    • 커널 버전
    • 네트워크 인터페이스 이름
    • 운영체제 버전
    • CPU 개수
    • 사용 가능한 메모리
    • 스토리지 장치의 크기 및 여유 공간
    • 기타

팩트 사용하기 : 기본 활성화로, 플레이북을 실행할 때 자동으로 팩트가 수집됨. ansible_facts 변수로 사용합니다.

  • 파일 생성
    • facts.yml
---

- hosts: db

  tasks:
  - name: Print all facts
    ansible.builtin.debug:
      var: ansible_facts
      
## 플레이북 실행
ansible-playbook facts.yml

PLAY [db] *********************************************************************************************

TASK [Gathering Facts] ********************************************************************************
ok: [tnode3]

TASK [Print all facts] ********************************************************************************
ok: [tnode3] => {
    "ansible_facts": {
        "all_ipv4_addresses": [
            "10.10.1.13"
        ],
        "all_ipv6_addresses": [
            "fe80::9a:acff:fee7:a0c"
        ],
        "ansible_local": {},
        "apparmor": {
            "status": "enabled"
        },
        "architecture": "x86_64",
        "bios_date": "10/16/2017",
        "bios_vendor": "Amazon EC2",
        "bios_version": "1.0",
        "board_asset_tag": "i-061e4fcc389f84510",
        "board_name": "NA",
        "board_serial": "NA",
        "board_vendor": "Amazon EC2",
        "board_version": "NA",
        "chassis_asset_tag": "Amazon EC2",
        "chassis_serial": "NA",
        "chassis_vendor": "Amazon EC2",
        "chassis_version": "NA",
        "cmdline": {
            "BOOT_IMAGE": "/boot/vmlinuz-6.2.0-1017-aws",
            "console": "ttyS0",
            "nvme_core.io_timeout": "4294967295",
            "panic": "-1",
            "ro": true,
            "root": "PARTUUID=d05003df-bf97-4623-bee3-09c11b95e3d4"
        },
        "date_time": {
            "date": "2024-01-12",
            "day": "12",
            "epoch": "1705069355",
            "epoch_int": "1705069355",
            "hour": "23",
            "iso8601": "2024-01-12T14:22:35Z",
            "iso8601_basic": "20240112T232235456155",
            "iso8601_basic_short": "20240112T232235",
            "iso8601_micro": "2024-01-12T14:22:35.456155Z",
            "minute": "22",
            "month": "01",
            "second": "35",
            "time": "23:22:35",
            "tz": "KST",
            "tz_dst": "KST",
            "tz_offset": "+0900",
            "weekday": "Friday",
            "weekday_number": "5",
            "weeknumber": "02",
            "year": "2024"
        },
        "default_ipv4": {
            "address": "10.10.1.13",
            "alias": "ens5",
            "broadcast": "",
            "gateway": "10.10.1.1",
            "interface": "ens5",
            "macaddress": "02:9a:ac:e7:0a:0c",
            "mtu": 9001,
            "netmask": "255.255.255.0",
            "network": "10.10.1.0",
            "prefix": "24",
            "type": "ether"
        },
        "default_ipv6": {},
        "device_links": {
            "ids": {
                "nvme0n1": [
                    "nvme-Amazon_Elastic_Block_Store_vol0bf6c9a74009c9b28",
                    "nvme-Amazon_Elastic_Block_Store_vol0bf6c9a74009c9b28_1",
                    "nvme-nvme.1d0f-766f6c3062663663396137343030396339623238-416d617a6f6e20456c617374696320426c6f636b2053746f7265-00000001"
                ],
...
  • 팩트로 수집된 변수 중 특정 값만 추출할 수 있습니다.
    • facts1.yml
---

- hosts: db

  tasks:
  - name: Print all facts
    ansible.builtin.debug:
      msg: >
        The default IPv4 address of {{ ansible_facts.hostname }}
        is {{ ansible_facts.default_ipv4.address }}
        
## 플레이북 실행
ansible-playbook facts1.yml

PLAY [db] *********************************************************************************************

TASK [Gathering Facts] ********************************************************************************
ok: [tnode3]

TASK [Print all facts] ********************************************************************************
ok: [tnode3] => {
    "msg": "The default IPv4 address of tnode3 is 10.10.1.13"
}

PLAY RECAP ********************************************************************************************
tnode3                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 변수로 사용할 수 있는 Ansible Facts : 엔서블 2. 버전에서는 ansible_facts. 네임스페이스 표기법을 따름니다.
팩트ansible_facts.* 표기법
호스트명ansible_facts.hostname
도메인 기반 호스트명ansible_facts.fqdn
기본 IPv4 주소ansible_facts.default_ipv4.address
네트워크 인터페이스 이름 목록ansible_facts.interfaces
/dev/vda1 디스크 파티션 크기ansible_facts.device.vda.partitions.vda1.size
DNS 서버 목록ansible_facts.dns.nameservers
현재 실행 중인 커널 버전ansible_facts.kernel
운영체제 종류ansible_facts.distribution
  • 구 표기법 : 권장하지 않습니다. 변수와 충돌 위험이 있거나, 팩트는 우선순위가 높기 때문입니다.
ansible_* 표기법ansible_facts.* 표기법
ansible_hostnameansible_facts.hostname
ansible_fqdnansible_facts.fqdn
ansible_default_ipv4.addressansible_facts.default_ipv4.address
ansible_interfacesansible_facts.interfaces
ansible_device.vda.partitions.vda1.sizeansible_facts.device.vda.partitions.vda1.size
ansible_dns.nameserversansible_facts.dns.nameservers
ansible_kernelansible_facts.kernel
ansible_distributionansible_facts.distribution
  • 현재 위 두 개의 표기법 모두 인지. 이는 앤서블 환경 설정 파일인 ansible.cfg [defaults] 섹션에 있는 inject_facts_as_vars 매개 변수 기본 설정 값이 true이기 때문이며, false로 설정하면 ansible_* 표기법을 비활성화 할 수 있습니다.

  • 다만, 대부분의 플레이북에서 이전 표기법인 ansible_* 표기법을 사용하므로 기본 설정 값인 true를 그대로 사용하는 것이 좋습니다.

  • 파일을 생성해줍니다.

    • facts2.yml
---

- hosts: db

  tasks:
  - name: Print all facts
    ansible.builtin.debug:
      msg: >
        The node's host name is {{ ansible_hostname }}
        and the ip is {{ ansible_default_ipv4.address }}

## 플레이북 실행
ansible-playbook facts2.yml
ansible-playbook facts2.yml

PLAY [db] *********************************************************************************************

TASK [Gathering Facts] ********************************************************************************
ok: [tnode3]

TASK [Print all facts] ********************************************************************************
ok: [tnode3] => {
    "msg": "The node's host name is tnode3 and the ip is 10.10.1.13"
}

PLAY RECAP ********************************************************************************************
tnode3                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • ansible.cfg 수정 후 실행해보겠습니다.
# ansible.cfg 파일 편집
[defaults]
inventory = ./inventory
remote_user = root
ask_pass = false
inject_facts_as_vars = false

[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false

# 실행
ansible-playbook facts2.yml

ansible-playbook facts2.yml

PLAY [db] *********************************************************************************************

TASK [Gathering Facts] ********************************************************************************
ok: [tnode3]

TASK [Print all facts] ********************************************************************************
fatal: [tnode3]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible_hostname' is undefined. 'ansible_hostname' is undefined\n\nThe error appears to be in '/root/my-ansible/facts2.yml': line 6, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n  - name: Print all facts\n    ^ here\n"}

PLAY RECAP ********************************************************************************************
tnode3                     : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
  • Error 가 발생합니다.

ansible.builtin.setup 모듈

Facts 수집 끄기 : 팩트 수집 기능 비활성화 가능

  • 팩트 수집을 위해 해당 호스트에 특정 패키지를 설치해야만 하는 경우가 있습니다.

    • 그런데 간혹 특정 이유로 패키지를 설치할 수 없는 경우에는 앤서블도 팩트 수집을 할 수 없게 됩니다.
    • 또는 사용자가 팩트 수집으로 인해 호스트에 부하가 걸리는 것을 원치 않을 수도 있기 때문에 이런 경우에는 팩트 수집 기능을 비활성화 할 수 있습니다.
  • 팩트 수집 실행 시 관리 호스트에 프로세스 확인

## (터미널2) tnode3에 SSH 접속 후 아래 모니터링
ssh tnode3
watch -d -n 1 pstree
## 플레이북 실행
ansible-playbook facts.yml
  • facts3.yml 을 작성
---

- hosts: db
  gather_facts: no

  tasks:
  - name: Print all facts
    ansible.builtin.debug:
      msg: >
        The default IPv4 address of {{ ansible_facts.hostname }}
        is {{ ansible_facts.default_ipv4.address }}

## 실행
ansible-playbook facts3.yml

PLAY [db] **********************************************************************

TASK [Print all facts] *********************************************************
fatal: [tnode3]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'hostname'. 'dict object' has no attribute 'hostname'\n\nThe error appears to be in '/root/my-ansible/facts3.yml': line 7, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n  - name: Print all facts\n    ^ here\n"}

PLAY RECAP *********************************************************************
tnode3                     : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
  • 팩트를 수집하지 않았는데, 팩트에서 수집해야만 하는 변수를 사용하려고 해서 에러가 발생합니다.
## 파일 복사
cp facts3.yml facts3-2.yml

## facts3-2.yml 파일 편집
---

- hosts: db
  gather_facts: no

  tasks:
  - name: Print message
    debug:
      msg: Hello!!!!!!!!!!!
      
ansible-playbook facts3-2.yml

PLAY [db] **********************************************************************

TASK [Print message] ***********************************************************
ok: [tnode3] => {
    "msg": "Hello!!!!!!!!!!!"
}

PLAY RECAP *********************************************************************
tnode3                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 이번에는 매뉴얼한 방법으로 플레이북에 팩트 수집을 설정해보겠습니다.
cp facts3.yml facts4.yml
ansible-playbook facts4.yml

PLAY [db] **********************************************************************

TASK [Manually gather facts] ***************************************************
ok: [tnode3]

TASK [Print all facts] *********************************************************
ok: [tnode3] => {
    "msg": "The default IPv4 address of tnode3 is 10.10.1.13"
}

PLAY RECAP *********************************************************************
tnode3                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

사용자 지정 facts 만들기 : 사용자에 의해 정의된 팩트를 이용하여 환경 설정 파일의 일부 항목을 구성하거나 조건부 작업을 진행할 수 있습니다.

  • 사용자 지정 팩트는 관리 호스트의 로컬에 있는 /etc/ansible/facts.d 디렉터리 내에 ‘*.fact’로 저장되어야만 앤서블이 플레이북을 실행할 때 자동으로 팩트를 수집할 수 있습니다.
mkdir /etc/ansible/facts.d

## my-ustom.fact 파일 생성
cat <<EOT > /etc/ansible/facts.d/my-custom.fact
[packages]
web_package = httpd
db_package = mariadb-server

[users]
user1 = ansible
user2 = gasida
EOT

cat /etc/ansible/facts.d/my-custom.fact
[packages]
web_package = httpd
db_package = mariadb-server

[users]
user1 = ansible
user2 = gasida
  • 플레이북 파일 생성
cp facts4.yml facts5.yml

## facts5.yml 파일 편집

cat facts5.yml
---

- hosts: localhost
  gather_facts: no

  tasks:
  - name: Manually gather facts
    ansible.builtin.debug:
      var: ansible_local

## 실행
ansible-playbook facts5.yml

PLAY [localhost] ***************************************************************

TASK [Manually gather facts] ***************************************************
ok: [localhost] => {
    "ansible_local": {}
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 실습 후 작성한 yml 파일 삭제 rm -r *.yml
  • 팩트를 사용하여 3개의 대상노드의 커널 버전과 운영체제 종류를 출력해봅시다.
cat kernal-os.yml 
---

- hosts: all

  tasks:
  - name: Print all node's kernell & OS
    ansible.builtin.debug:
      msg: >
        kernel : {{ ansible_facts.kernel }} ,
        OS : {{ ansible_facts.distribution }}

## 실행

ansible-playbook kernal-os.yml 

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [tnode1]
ok: [tnode2]
ok: [tnode3]

TASK [Print all node's kernell & OS] *******************************************
ok: [tnode1] => {
    "msg": "kernel : 6.2.0-1017-aws , OS : Ubuntu\n"
}
ok: [tnode2] => {
    "msg": "kernel : 6.2.0-1017-aws , OS : Ubuntu\n"
}
ok: [tnode3] => {
    "msg": "kernel : 6.2.0-1017-aws , OS : Ubuntu\n"
}

PLAY RECAP *********************************************************************
tnode1                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode2                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode3                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 실습 완료 후 AWS 리소스 삭제
    aws cloudformation delete-stack --stack-name mylab --region ap-northeast-2
profile
무럭무럭 자라볼까

0개의 댓글