[오픈소스] Ansible (앤써블) - Ansible ad-hoc(에드 훅) 명령어 & Playbok(플레이북)

2022. 12. 19. 13:43오픈소스(Open Source)

Ansible ad-hoc 명령어
$ ad-hoc 명령어 
   - /usr/bin/ansible 명령행 도구를 사용하여 하나 이상의 Host 노드를 관리
   - 단일 태스크를 실행하여 자동화가능
   - 쉽고 빠르게 실행할 수 있으나, 재사용 할 수는 없다
   - 반복적이지 않고, 일시적인 작업에 유용하다 ( 1회성 실행 )
   - 서버 재부팅, 파일 관리, 사용자 및 그룹 관리, 패키지 관리, 서비스 관리 등에 주로 사용

 

# vi ~/.ansible/inventory
[server]
Compute    ansible_host=192.168.1.150
Network    ansible_host=192.168.1.200

[server:vars]
ansible_connection=ssh
ansible_user=root
   - Invertory 파일 확인 위 2개의 Host 노드를 관리하는 형식으로 작업 진행

$ Shell Module 

# ansible all -m shell -a "date" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
2021. 02. 26. (금) 13:32:32 KST
Network | CHANGED | rc=0 >>
2021. 02. 26. (금) 13:32:32 KST

# ansible all -a "date" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
2021. 02. 26. (금) 13:32:59 KST
Network | CHANGED | rc=0 >>
2021. 02. 26. (금) 13:32:59 KST
   - shell 모듈을 사용 할 경우 Host노드에 기본 shell 명령어를 전달 할 수 있다.
   - shell 모듈을 지정 후 -a 옵션을 이용하여 실제 수행 할 명령어를 옵션과 함께 작성 ( 반드시 쌍따옴표를 함께 사용 )
   - 또한 앤서블의 기본 모듈은 shell로 지정되어있으므로, -m shell 구문은 생략하여도 정상적으로 동작

$ System Reboot 

# ansible all -a "/usr/sbin/reboot" -i ~/.ansible/inventory

Network | FAILED | rc=-1 >>
Failed to connect to the host via ssh: ssh: connect to host 192.168.1.200
port 22: Connection refused

Compute | FAILED | rc=-1 >>
Failed to connect to the host via ssh: ssh: connect to host 192.168.1.150
port 22: Connection refused
   - 해당 작업을 수행 할 경우 에러 메시지가 출력 되지만, 실제 작업은 정상적으로 수행
   - 시스템이 재부팅되면서, SSH 연결이 끊기면서 나오는 에러 메시지

$ 파일관리

# echo "Ansible Copy TEST" > ./file1
# cat ./file1
Ansible Copy TEST

# ansible all -m copy -a "src=./file1 dest=./file1" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
Network | CHANGED | rc=0 >>

# ansible all -a "ls -ld ~/file1" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 18 2월 26 15:11 /root/file1
Network | CHANGED | rc=0 >>
-rw-r--r-- 1 root root 18 2월 26 15:11 /root/file1

# ansible all -m file -a "dest=~/file1 mode=600" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
Network | CHANGED | rc=0 >>

# ansible all -a "ls -ld ~/file1" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
-rw------- 1 root root 18 2월 26 15:11 /root/file1
Network | CHANGED | rc=0 >>
-rw------- 1 root root 18 2월 26 15:11 /root/file1
   - File 모듈을 이용하여 해당 파일의 권한 정보를 변경
   
# ansible all -m file -a "dest=~/download/mkdir state=directory" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
Network | CHANGED | rc=0 >>

# ansible all -a "ls -lR ~/download" -i ~/.ansible/inventory
Network | CHANGED | rc=0 >>
/root/download:
/root/download/mkdir:

Compute | CHANGED | rc=0 >>
/root/download:
/root/download/mkdir:
   - Stat 인자를 directory로 사용 할 경우 해당 디렉터리의 존재 유무를 확인 할 수 있으며, mkdir –p 옵션과 같은 효과.

# ansible all -m file -a "dest=~/download state=absent" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
Network | CHANGED | rc=0 >>

# ansible all -a "ls -lR ~/download" -i ~/.ansible/inventory
Network | CHANGED | rc=0 >>
ls: cannot access /root/download: 그런 파일이나 디렉터리가 없습니다non-zero return code
Compute | CHANGED | rc=0 >>
ls: cannot access /root/download: 그런 파일이나 디렉터리가 없습니다non-zero return code
   - Stat 인자를 absent로 사용 할 경우 지정 디렉터리 하위 개체 포함 삭제 작업이 진행 된다, rm –r 옵션과 같은 효과.

 

$ 사용자 및 그룹 관리

# ansible all -m user -a “name=ansible_testuser" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
Network | CHANGED | rc=0 >>

# ansible all -a “tail -1 /etc/passwd" -i ~/.ansible/inventory
Network | CHANGED | rc=0 >>
ansible_testuser:x:1002:1002::/home/ansible_testuser:/bin/bash
Compute | CHANGED | rc=0 >>
ansible_testuser:x:1002:1002::/home/ansible_testuser:/bin/bash
   - user 모듈을 이용하여 ansible_testuser 생성
   - 관리 대상 호스트에서 “/etc/passwd” 파일에 새로운 사용자 정보가 추가되었는지 확인
   
# ansible all -m group -a “name=ansible_group" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
Network | CHANGED | rc=0 >>

# ansible all -a “tail -1 /etc/group" -i ~/.ansible/inventory
Network | CHANGED | rc=0 >>
ansible_group:x:1003:
Compute | CHANGED | rc=0 >>
ansible_group:x:1003:
   - group 모듈을 이용하여 ansible_group 생성
   - 관리 대상 호스트에서 “/etc/group” 파일에 새로운 사용자 정보가 추가되었는지 확인

 

 

$ 사용자 및 그룹 관리

# ansible all -m yum -a "name=httpd state=present" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
Network | CHANGED | rc=0 >>

# ansible all -a "rpm -q httpd" -i ~/.ansible/inventory
Network | CHANGED | rc=0 >>
httpd-2.4.6-97.el7.centos.x86_64
Compute | CHANGED | rc=0 >>
httpd-2.4.6-97.el7.centos.x86_64
   - yum 모듈을 이용하여 Apache Web Server 프로그램 설치 ( “present” : 설치, “absent” : 삭제 )
   - Ansible에서는 하나의 작업을 여러 번 나누어 진행, “|” : 파이프 라인 작업 시 제대로 된 파이프 처리가 진행되지 않는다.
   - 함께 출력되는 메시지는 경고 메시지이므로, 무시해도 상관없다 ( yum 모듈 사용 권장 메시지 )
   
# curl httpd.apache.org -o index.html
100 9708 100 9708 0 0 1258 0 0:00:07 0:00:07 --:--:-- 2628

# ansible all -m copy -a "src=index.html dest=/var/www/html/index.html" -i ~/.ansible/inventory

# ansible all -m service -a "name=firewalld state=stopped" -i ~/.ansible/inventory

# ansible all -m service -a "name=httpd state=started" -i ~/.ansible/inventory
   - Apache 기본 인덱스 페이지를 다운로드 후 관리대상 노드에게 copy 모듈을 이용하여 복사작업을 진행
   - Service 모듈을 이용하여 Firewalld 방화벽을 중지 시킨 후 Apache Web Server 서비스 시작
   
# ansible all -m yum -a "name=httpd state=absent" -i ~/.ansible/inventory
Compute | CHANGED | rc=0 >>
Network | CHANGED | rc=0 >>

# ansible all -a "rpm -q httpd" -i ~/.ansible/inventory
Network | CHANGED | rc=0 >>
httpd 패키지가 설치되어 있지 않습니다non-zero return code
Compute | CHANGED | rc=0 >>
httpd 패키지가 설치되어 있지 않습니다non-zero return code

 

 

Ansible Playbook 구성요소

 

$ Playbook
   - 복잡한 자동화 구성 및 재사용을 위한 구성 파일을 만들기 위해 사용.
   - 사람이 읽을 수 있도록 설계되었으며, 기본 텍스트 언어로 개발되어 있다.
   - YAML 형식의 텍스트를 사용.
   - Playbook의 구성요소로는 “Plays, Hosts, Tasks”로 구성된다

 

$ Plays 
   - 호스트 그룹을 잘 정의된 역할에 매핑하여 자동화 작업이 이루어 질 수 있도록 한다.
   - 하나의 Playbook에는 여러 plays 가 존재할 수 있다.

 

$ Hosts
   - Playbook의 개별 plays에 대해 자동화 작업을 할 대상 호스트 그룹을 지정한다.
   - 하나 이상의 그룹 또는 호스트 패턴을 콜론(:) 구분자로 지정할 수 있다.

 

패턴 대상 설명
all 또는 * 모든 호스트 모든 호스트
그룹명 또는 호스트명 지정한 그룹 또는 호스트 지정한 그룹 또는 호스트
host1:host2 host1 과 host2 를 대상으로 한다. 다중 그룹 또는 호스트
group1:!host1 group1의 host1을 제외한 호스트를 대상으로 한다. 지정 그룹에서 일부 호스트 제외
group1:&host1 group1의 host1을 대상으로 한다. 지정 그룹에서 특정 호스트 선택

$ Tasks 
   - plays에는 tasks가 포함되어 있다.
   - plays에서 수행해야 하는 자동화 작업을 tasks로 정의한다.
   - 여러 개의 tasks를 실행할 수 있으며, 여러 번 실행이 가능하다.
   - 동일한 tasks를 여러 번 실행하여도, 1회 실행하는 것과 같은 효과를 갖는다. ( 멱등성 )
   - 모든 tasks에는 이름이 있어야 한다.
   - tasks의 이름은 Playbook이 실행될 때 사람이 읽을 수 있는 출력을 만들어 준다.

 

Ansible Playbook Sample_1

# vi ~/Playbook_Sample_1.yml
---
- hosts: all
 gather_facts: no
 tasks:
  - name: playbook sample template
   ping:
   
   - 모든 호스트를 대상으로 Ping 모듈 작업 수행
   - 각 작업에 대한 이름을 명시한다.
   - gather_facts : no 옵션의 경우 Playbook 실행 시 불필요한 정보는 수집하지 않도록 하는 옵션
   
# ansible-playbook ~/Playbook_Sample_1.yml -i ~/.ansible/inventory
PLAY [all] ******************************************************************************************************

TASK [playbook sample template] ****************************************************************************
ok: [Compute]
ok: [Network]

PLAY RECAP **************************************************************************************************
Compute : ok=1   changed=0   unreachable=0   failed=0   skipped=0   rescued=0   ignored=0
Network : ok=1   changed=0   unreachable=0   failed=0   skipped=0   rescued=0   ignored=0
   - 위에서 작성 한 Playbook을 실행 후 결과를 확인
   - 정상적으로 실행되었을 경우 위와 같은 작업결과 화면이 출력된다.

 

Ansible Playbook Sample_2

# vi ~/Playbook_Sample_2.yml
---
- hosts: all
 gather_facts: no
 tasks:
  - name: playbook sample template
   shell: reboot
   
   - 모든 호스트를 대상으로 System Reboot 작업 수행
   - Shell 모듈을 이용하여 지정 된 호스트에서 특정 명령을 수행 할 수 있다.

# ansible-playbook ~/Playbook_Sample_2.yml -i ~/.ansible/inventory
PLAY [all] ******************************************************************************************************

TASK [playbook sample template] ****************************************************************************
fatal: [Compute]: UNREACHABLE!
fatal: [Network]: UNREACHABLE!

PLAY RECAP **************************************************************************************************
Compute : ok=0   changed=0   unreachable=1   failed=0   skipped=0   rescued=0   ignored=0
Network : ok=0   changed=0   unreachable=1   failed=0   skipped=0   rescued=0   ignored=0
   - 접속 실패 메시지가 출력되지만, 시스템 재부팅은 수행된다.
   - 시스템이 재부팅 되며, SSH 연결에 실패하여 위와 같은 메시지가 출력되는 것.

 

Ansible Playbook Sample_3

# ansible-galaxy collection install ansible.posix
# vi ~/Playbook_Sample_3.yml
---
- hosts: all
 gather_facts: no
 tasks:
  - name: FTP Package Install            
   yum: name=vsftpd state=present           
  - name: Service Started
   service: name=vsftpd state=started
  - name: Firewall Policy ADD
   ansible.posix.firewalld:
   service: ftp
   permanent: yes
   state: enabled
  - name: Firewall Reload
   shell: firewall-cmd --reload
   
# ansible-playbook ~/Playbook_Sample_3.yml -i ~/.ansible/inventory
PLAY [all] ******************************************************************************************************

TASK [playbook sample template] ****************************************************************************
ok: [Compute]
ok: [Network]

PLAY RECAP **************************************************************************************************
Compute : ok=4 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Network : ok=4 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
   - 총 4개의 작업을 정의하였고, 해당 작업이 수행 될 경우 Changed 표시
   - 각 작업이 정상적으로 수행되었으면, ok에서 최종적인 결과값을 표시한다
   - 각 Host에서 정상적으로 FTP 서비스가 동작하는지 알FTP를 이용하여 테스트작업 진행

Ansible Playbook Sample_4

   - Server(Linux1) : 192.168.1.100

   - Client(Linux2) : 192.168.1.150

   - Client(Linux3) : 192.168.1.151

# vi ./mem_check.sh
#!/bin/bash
#
Date=`date +%Y_%m_%d`
MEMLOG=Memcheck_${Date}_${HOSTNAME}.log

function Memory() {
sum1=0
sum3=0

for cnt in {1..4..1}
do
        memused1=`free | grep ^Mem | awk '{print $3}'`
        swapused1=`free | grep ^Swap | awk '{print $3}'`
        add1=`expr $memused1 + $sum1`
        sum1=$add1
        add3=`expr $swapused1 + $sum3`
        sum3=$add3
        sleep 1
done
memtotal=`free | grep ^Mem | awk '{print $2}'`
swaptotal=`free | grep ^Swap | awk '{print $2}'`
memtotal2=$((memtotal*4))
swaptotal2=$((swaptotal*4))

actual=$((100*sum1/memtotal2))
swap=$((100*sum3/swaptotal2))
TM=`free -m | grep ^Mem | awk '{print $2}'`
TSM=`free -m | grep ^Swap | awk '{print $2}'`

cat /proc/meminfo | egrep -i 'Memtotal|MemFree|Cached|Swap' | sed 's/: */ /g' | awk '{ for(i=1;i<=NF;i++) { if($i ~ /[0-9]/) { printf "%s  \t\t\t", $(i-1); printf "%.1f MB\n", $i/1024 }}}'    > ${MEMLOG}
echo "" >> ${MEMLOG}
echo -e "Total Actual Memory : ${TM}MB"         >> ${MEMLOG}
echo -e "Used        Momery : ${actual}%\n"     >> ${MEMLOG}
echo -e "Total Swap   Memory : ${TSM}MB"        >> ${MEMLOG}
echo -e "Used  Swap   Memory : ${swap}%"        >> ${MEMLOG}
}

Memory

Server_Name="root@192.168.1.100"
tar -czpf ~/Mem_check_${Date}_${HOSTNAME}.tar.gz ./*.log
Log_File=~/*.tar.gz
scp ${Log_File} ${Server_Name}:~/ > /dev/null

# vi ~/Playbook_Sample_4.yml
---
- hosts: all
 gather_facts: no
 tasks:
  - name: ShellScripts Copy
   copy: src=~/mem_check.sh dest=~/mem_check.sh
  - name: Change Script file Permissions
   file: dest=~/mem_check.sh mode=700
  - name: Run The Script File
   shell: ~/mem_check.sh
    
   - Copy , File , Shell 모듈을 이용하여 관리 노드에 존재하는 스크립트 파일을 관리대상 노드로 복사 후 실행
   - 재 전송 및 실제 스크립트 동작내용은 스크립트 파일 내에서 정의
   
   
[ Client(Linux2) 에서 진행 ]
# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): “enter”
Enter passphrase (empty for no passphrase): “enter”
Enter same passphrase again: “enter”
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:LmJ15gMjGzd9i0709PQbhHOc5IH2GyVO+ByiMZemDMg root@linux2
The key's randomart image is:

# chmod 600 ~/.ssh/*
# scp ~/.ssh/id_rsa.pub root@192.168.1.100:~/.ssh/linux2_authorized_keys

[ Client(Linux3) 에서 진행 ]
# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): “enter”
Enter passphrase (empty for no passphrase): “enter”
Enter same passphrase again: “enter”
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:LmJ15gMjGzd9i0709PQbhHOc5IH2GyVO+ByiMZemDMg root@linux3
The key's randomart image is:

# chmod 600 ~/.ssh/*
# scp ~/.ssh/id_rsa.pub root@192.168.1.100:~/.ssh/linux3_authorized_keys

[ Server(Linux1) 에서 진행] 
# vi /etc/ssh/sshd_config
47 AuthorizedKeysFile      .ssh/linux2_authorized_keys        .ssh/linux3_authorized_keys

# systemctl restart sshd

# ansible-playbook ~/Playbook_Sample_4.yml -i ~/.ansible/inventory
PLAY [all] ******************************************************************************************************

TASK [playbook sample template] ****************************************************************************
ok: [Compute]
ok: [Network]

PLAY RECAP **************************************************************************************************
Compute : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Network : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
   - 총 3개의 작업을 정의하였고, 해당 작업이 수행 될 경우 Changed 표시
   - 각 작업이 정상적으로 수행되었으면, ok에서 최종적인 결과값을 표시한다
   - 각 Host에서 정상적으로 Log 파일이 압축되어 전송되었는지 확인 한다.