티스토리 뷰
기시다님의 스터디 주도하에 이번주는 Ansible Community 버전을 기반으로 진행이 되었다.
다음주에 kubespray 수업을 원할하게 하기 위해서는 금주 Ansible 양이 많아도 따라하는 것을 추천해주셨다.
레드햇 Summit이나 Ansible Automation 행사에 참여한 이후로
Ansible이 어떤 도구인지 처음 인지했고
최근에 Ansible에 대한 관심이 있었는데 이번주차에 Ansible에 대한 전반적인 스터디가 진행되었다.
금주도 병원 및 응급실에 다녀오고 주말에 일정이 있어서 실습에 많은 시간을 할애하지 못하고
녹화본과 글을 병원 대기 및 차안에서 읽으면서 간간히 블로그를 정리하는걸 하기도 벅찬 한주였다.
향후에 몸이 안정되면 1,2주차 초안을 정리하는걸로 마무리해야겠다.
연초부터..... 쉽지 않은 것 같다.....
실습 환경 구성
가상 머신 구성
NodeOSKernelvCPUMemoryDiskNIC2 IP관리자 계정(기본) 일반 계정
| server | Ubuntu 24.04 | 6.8.0 | 2 | 1.5GB | 30GB | 10.10.1.10 | root / qwe123 | vagrant / qwe123 |
| tnode1 | 상동 | 상동 | 2 | 1.5GB | 30GB | 10.10.1.11 | root / qwe123 | vagrant / qwe123 |
| tnode2 | 상동 | 상동 | 2 | 1.5GB | 30GB | 10.10.1.12 | root / qwe123 | vagrant / qwe123 |
| tnode3 | Rocky Linux 9 | 5.14.0 | 2 | 1.5GB | 60GB | 10.10.1.13 | root / qwe123 | vagrant / qwe123 |
실습 환경 배포
mkdir ansible
cd ansible
curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/ansible/Vagrantfile
curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/ansible/init_cfg.sh
curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/ansible/init_cfg2.sh
vagrant up
Vagrantfile
# Variables
# max number of T nodes
N = 2
# Base Image https://portal.cloud.hashicorp.com/vagrant/discover/bento/ubuntu-24.04
BOX_IMAGE = "bento/ubuntu-24.04"
BOX_VERSION = "202510.26.0"
Vagrant.configure("2") do |config|
#-Server Node : Ubuntu
config.vm.define "server" do |subconfig|
subconfig.vm.box = BOX_IMAGE
subconfig.vm.box_version = BOX_VERSION
subconfig.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--groups", "/Ansible-Lab"]
vb.name = "server"
vb.cpus = 2
vb.memory = 1536 # 2048
vb.linked_clone = true
end
subconfig.vm.host_name = "server"
subconfig.vm.network "private_network", ip: "10.10.1.10"
subconfig.vm.network "forwarded_port", guest: 22, host: 60000, auto_correct: true, id: "ssh"
subconfig.vm.synced_folder "./", "/vagrant", disabled: true
subconfig.vm.provision "shell", path: "init_cfg.sh"
end
# Test Node : Ubuntu
(1..N).each do |i|
config.vm.define "tnode#{i}" do |subconfig|
subconfig.vm.box = BOX_IMAGE
subconfig.vm.box_version = BOX_VERSION
subconfig.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--groups", "/Ansible-Lab"]
vb.name = "tnode#{i}"
vb.cpus = 2
vb.memory = 1536 # 2048
vb.linked_clone = true
end
subconfig.vm.host_name = "tnode#{i}"
subconfig.vm.network "private_network", ip: "10.10.1.1#{i}"
subconfig.vm.network "forwarded_port", guest: 22, host: "6000#{i}", auto_correct: true, id: "ssh"
subconfig.vm.synced_folder "./", "/vagrant", disabled: true
subconfig.vm.provision "shell", path: "init_cfg.sh", args: [ N ]
end
end
# Test Node : Rocky Linux
config.vm.define "tnode3" do |subconfig|
subconfig.vm.box = "bento/rockylinux-9"
subconfig.vm.box_version = "202510.26.0"
subconfig.vm.provider "virtualbox" do |vb|
vb.customize ["modifyvm", :id, "--groups", "/Ansible-Lab"]
vb.name = "tnode3"
vb.cpus = 2
vb.memory = 1536 # 2048
vb.linked_clone = true
end
subconfig.vm.host_name = "tnode3"
subconfig.vm.network "private_network", ip: "10.10.1.13"
subconfig.vm.network "forwarded_port", guest: 22, host: 60003, auto_correct: true, id: "ssh"
subconfig.vm.synced_folder "./", "/vagrant", disabled: true
subconfig.vm.provision "shell", path: "init_cfg2.sh"
end
end
init_cfg.sh
#!/usr/bin/env bash
echo ">>>> Initial Config Start <<<<"
echo "[TASK 1] Setting Profile & Change Timezone"
echo 'alias vi=vim' >> /etc/profile
echo "sudo su -" >> /home/vagrant/.bashrc
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
echo "[TASK 2] Disable AppArmor"
systemctl stop ufw && systemctl disable ufw >/dev/null 2>&1
systemctl stop apparmor && systemctl disable apparmor >/dev/null 2>&1
echo "[TASK 3] Install Packages"
apt update -qq >/dev/null 2>&1
apt-get install tree sshpass unzip -y -qq >/dev/null 2>&1
echo "[TASK 4] Config account & ssh config"
echo 'vagrant:qwe123' | chpasswd
echo 'root:qwe123' | chpasswd
sed -i "s/^#PasswordAuthentication yes/PasswordAuthentication yes/g" /etc/ssh/sshd_config
sed -i "s/^#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
systemctl restart ssh
echo "[TASK 5] Setting Local DNS Using Hosts file"
sed -i '/^127\.0\.\(1\|2\)\.1/d' /etc/hosts
cat << EOF >> /etc/hosts
10.10.1.10 server
10.10.1.11 tnode1
10.10.1.12 tnode2
10.10.1.13 tnode3
EOF
echo ">>>> Initial Config End <<<<"
init_cfg2.sh
#!/usr/bin/env bash
echo ">>>> Initial Config Start <<<<"
echo "[TASK 1] Setting Profile & Change Timezone"
echo 'alias vi=vim' >> /etc/profile
echo "sudo su -" >> /home/vagrant/.bashrc
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
echo "[TASK 2] Disable firewalld and selinux"
systemctl stop firewalld && systemctl disable firewalld >/dev/null 2>&1
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
echo "[TASK 5] Install Packages"
dnf install -y yum sshpass jq git >/dev/null 2>&1
echo "[TASK 4] Config account & ssh config"
echo 'vagrant:qwe123' | chpasswd
echo 'root:qwe123' | chpasswd
sed -i "s/^#PasswordAuthentication yes/PasswordAuthentication yes/g" /etc/ssh/sshd_config
sed -i "s/^#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
systemctl restart sshd
echo "[TASK 5] Setting Local DNS Using Hosts file"
sed -i '/^127\.0\.\(1\|2\)\.1/d' /etc/hosts
cat << EOF >> /etc/hosts
10.10.1.10 server
10.10.1.11 tnode1
10.10.1.12 tnode2
10.10.1.13 tnode3
EOF
echo ">>>> Initial Config End <<<<"
# 계정 정보 확인
whoami
id
# Kernel, CPU, Mem, Disk, NIC 확인
uname -r
hostnamectl
htop
free -h
lsblk
df -hT /
ip -c addr
# /etc/hosts 확인
cat /etc/hosts
# 노드간 통신 확인
for i in {1..3}; do ping -c 1 tnode$i; done
Ansible 소개
- 소개 : 오픈소스 IT 자동화 도구, IT 업무를 코드 기반으로 작성하여 여러 환경에 동일하게 적용될 수 있도록 돕는 역할
- 마이클 데한에 의해 앤서블웍스 Ansiblework라는 이름으로 2014년 3월 4일 처음 소개. 그후 2015년 10월 레드햇이 인수하여 개발, 관리하고 있음
- 마이클 데한은 퍼펫 랩스 Puppet Labs에서 근무하며 좀 더 쉽게 자동화를 위해서 앤서블을 시작했다고 함.
- 앤서블은 리눅스, MacOS, BSC 계열 유닉스, WSL을 지원하는 원도우에 파이썬과 앤서블 코어만 설치하면 어디에서나 플레이북(YAML 형식의 작업들은 순서대로 작성해 놓은 파일)을 작성하고 이를 실행시킬 수 있습니다.

- 앤서블은 이렇게 앤서블 코어가 설치되고 플레이북을 작성하여 실행할 수 있는 제어 노드 Control Node와 플레이북이 실행되어 애플리케이션 설치나 클라우드 시스템의 가상 서버 생성과 같은 작업이 수행되는 관리 노드 Managed Node로 구성됩니다.
- 물론 앤서블은 제어 노드에만 설치되고 관리 노드에는 설치되지 않습니다.
- 제어 노드에는 앤서블 코어가 설치되며, 사용자에 의해 정의된 플레이북과 관리 노드를 정의해놓은 인벤토리 파일에 의해 SSH 프로토콜을 사용하여 다양한 환경의 관리 노드 업무 자동화를 수행할 수 있습니다.
- 특징 : No! 에이전트(Agentless) , 멱등성 , 쉬운 사용법과 다양한 모듈 제공
- No! 에이전트(Agentless)
- 기존 자동화 도구인 퍼펫 Puppet이나 셰프 Chef는 자동화 관리 대상 서버에 별도의 에이전트를 설치하고 이를 통해 자동화 업무를 수행합니다.
- 이러한 데몬 형식의 에이전트에 기반한 자동화 도구는 관리를 위한 복잡한 추가 작업이나 운영체제 버전에 따라 추가 패키지나 모듈을 설치하는 등의 작업이 발생합니다.
- 그러나 앤서블은 에이전트 설치 없이 SSH로 접속하여 쉽게 대상 서버들을 관리할 수 있습니다. 이것이 앤서블의 가장 큰 특징이자 장점입니다.
- 멱등성 Idempotent
- 멱등성은 동일한 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질로, 멱등법칙의 개념은 추상대수학과 함수형 프로그래밍의 여러 부분에서 사용하고 있습니다.
- 앤서블은 이러한 멱등성과 함께 시스템을 원하는 상태로 표현하여 유지하도록 설계되어 있어, 동일한 운영 작업을 여러 번 실행해도 같은 결과를 냅니다.
- 쉬운 사용법과 다양한 모듈 제공
- 다른 자동화 도구에 비해 복잡하지 않아 자동화 절차 및 과정을 이해하기 쉽습니다.
- 자동화 단계는 에디터만 있으면 YAML 문법을 사용하여 쉽게 작성하고 읽을 수 있습니다.
- 또한 파일 복사와 같은 일반 시스템 관리 모듈부터 다양한 환경의 퍼블릭 클라우드 관련 모듈 및 컬렉션까지 제공하므로, 쉽게 플레이북 예제를 찾아보고 자동화를 수행할 수 있습니다.
- 분류 : 커뮤니티 앤서블 vs 레드햇 앤서블 오토메이션 플랫폼
- 커뮤니티 앤서블 : 오픈소스 형태로 운영체제가 리눅스라면 어디에나 설치하여 사용할 수 있음
- 레드햇 앤서블 오토메이션 플랫폼 : 레드햇 서브스크립션을 통해 사용
- 커뮤니티 앤서블 아키텍처 : 제어 노드 + 관리 노드
- 앤서블 안에는 다양한 모듈과 플러그인이 함께 설치되어 있으며, 앤서블이 관리하는 노드 정보를 저장하고 있는 인벤토리와 관리 노드에서 수행될 작업 절차가 작성되어 있는 플레이북이 존재합니다.

- 제어 노드 Control Node
- 앤서블이 설치되는 노드로 운영체제가 리눅스라면 제어 노드가 될 수 있습니다.
- 앤서블은 파이썬 모듈을 이용하므로 앤서블을 설치하고 실행하려면 파이썬이 함꼐 설치되어 있어야 합니다.
- 관리 노드 Managed Node
- 관리 노드는 앤서블이 제어하는 원격 시스템 또는 호스트를 의미합니다.
- 관리 노드는 [그림 2-1]처럼 리눅스 or 윈도우가 설치된 노드일 수 있습니다.
- 앤서블은 별도의 에이전트를 설치하지 않으므로 관리 노드는 제어 노드와 SSH 통신이 가능해야 하며, 파이썬이 설치되어 있어야 합니다.
- 인벤토리 Inventory
- 제어 노드가 제어하는 관리 노드의 목록을 나열해놓은 파일입니다.
- 앤서블은 인벤토리에 사전에 정의되어 있는 관리 노드에만 접근할 수 있습니다.
- 또한 인벤토리 목록은 관리 노드의 성격별로 다음과 같이 그룹핑할 수 있습니다.
- 제어 노드 Control Node
- No! 에이전트(Agentless)
$ vi inventory
192.168.10.101
[WebServer]
web1.example.com
web2.example.com
[DBServer]
db1.example.com
db2.example.com
- 모듈 Modules
- 앤서블은 관리 노드의 작업을 수행할 때 SSH를 통해 연결한 후 ‘앤서블 모듈 Modules’이라는 스크립트를 푸시하여 작동합니다.
- 대부분의 모듈은 원하는 시스템 상태를 설명하는 매개 변수를 허용하며, 모듈 실행이 완료되면 제거됩니다.
- 플러그인 Plugins
- 픞러그인은 앤서블의 핵심 기능을 강화합니다. 모듈이 대상 시스템에서 별도의 프로세스로 실행되는 동안 플러그인은 제어 노드에서 실행됩니다.
- 플로그인은 앤서블의 핵심 기능(데이터 변환, 로그 출력, 인벤토리 연결 등)에 대한 옵션 및 확장 기능을 제공합니다.
- 플레이북 Playbook
- 플레이북은 관리 노드에서 수행할 작업들을 YAML 문법을 이용해 순서대로 작성해놓은 파일입니다.
- 엔서블은 이렇게 작성된 플레이북을 활용하여 관리 노드에 SSH로 접근해 작업을 수행합니다.
- 따라서 플레이북은 자동화를 완성하는 가장 중요한 파일이며 사용자가 직접 작성합니다.
---
- hosts: webservers
serial: 5 # 한 번에 5대의 머신을 업데이트하라는 의미
roles:
- common
- webapp
- hosts: content_servers
roles:
- common
- content
Ansible 설치
[ansible-server] 앤서블 설치 - Link
# 작업 기본 디렉터리 확인
whoami
pwd
# 파이썬 버전 확인
python3 --version
# 설치
apt install software-properties-common -y
add-apt-repository --yes --update ppa:ansible/ansible
apt install ansible -y
# 확인
ansible --version
ansible [core 2.19.5]
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.12.3 (main, Aug 14 2025, 17:47:21) [GCC 13.3.0] (/usr/bin/python3)
jinja version = 3.1.2
pyyaml version = 6.0.1 (with libyaml v0.2.5)
cat /etc/ansible/ansible.cfg
which ansible
# 작업 디렉터리 생성
mkdir my-ansible
cd my-ansible
앤서블 접근을 위한 SSH 인증 구성
- 앤서블은 로컬 사용자에게 개인 SSH 키가 있거나 관리 호스트에서 원격 사용자임을 인증 가능한 키가 구성된 경우 자동으로 로그인됩니다.
- 먼저 ssh-keygen 명령어를 이용하여 SSH 키를 생성합니다.
# 모니터링
tree ~/.ssh
watch -d 'tree ~/.ssh'
# Create SSH Keypair
ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa
2. 공개 키를 관리 노드에 복사
# 공개 키를 관리 노드에 복사
for i in {1..3}; do sshpass -p 'qwe123' ssh-copy-id -o StrictHostKeyChecking=no root@tnode$i; done
# 복사 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i cat ~/.ssh/authorized_keys; echo; done
# ssh 접속 테스트
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i hostname; echo; done
# python 정보 확인
for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i python3 -V; echo; done
Visual Studio Code 에 Remote-SSH 설치 후 root 계정으로 Ansible Server 연결 → 각자 편한 IDE 툴 사용하시면 됩니다.
보안상 권장하시는 않지만, 실습 편의를 위해 root 계정으로 실습을 진행합니다
- Extension : ‘remote development’ 입력 후 Remote - SSH 설치
- 커맨드창(Ctrl + Shift + P) 입력 후 “Remote-SSH: Open Config…” 선택 후 자신의 SSH Config 파일을 열기: ls ~/.ssh/config
# Read more about SSH config files: https://linux.die.net/man/5/ssh_config
Host ansible-server
HostName 10.10.1.10
User root
3. 커맨드창(Ctrl + Shift + P) 입력 후 “Remote-SSH: Connect…” 선택 후 자신의 ansible-server 선택 : 암호는 qwe123
4. 신규 창에서 좌측 Open Folder 버튼 누르고 /root/my-ansible 폴더에서 OK 로 열어주기
5. 터미널 - 신규 터미널 클릭해서 하단 뷰에 터미널 창 열기

VSCDOE 터미널창에서 기본 정보 확인
# 계정 정보 등 확인
whoami
id
pwd
tree
6. Visual Studio Code 에 자동 저장 설정 : 설정 → ‘auto save’ 검색 ⇒ afterDelay 선택, Auto Save Delay 1000ms(=1초)

호스트 선정
kubespary 인벤토리 (예시)
[all]
master01 ansible_host=192.168.10.10 ip=192.168.10.10 ansible_user=root
worker01 ansible_host=192.168.10.11 ip=192.168.10.11 ansible_user=root
worker02 ansible_host=192.168.10.12 ip=192.168.10.12 ansible_user=root
[kube_control_plane]
master01
[etcd]
master01
[kube_node]
worker01
worker02
[k8s_cluster:children]
kube_control_plane
kube_node
인벤토리를 이용한 자동화 대상 호스트 설정 - Link
인벤토리 파일은 텍스트 파일이며, 앤서블이 자동화 대상으로 하는 관리 호스트를 지정합니다.
-
- 이 파일은 INI 스타일 형식(이름 = 값) 또는 YAML을 포함한 다양한 형식을 사용하여 작성할 수 있습니다

- 가장 간단한 형식의 INI 스타일 인벤토리 파일은 다음과 같이 관리 호스트의 호스트명 또는 IP 주소가 한 줄에 하나씩 있는 목록 형태입니다.
web1.example.com
web2.example.com
db1.example.com
db2.example.com
192.0.2.42
IP를 이용한 인벤토리 파일 생성
my-ansible/inventory
# inventory 파일 생성
cat <<EOT > inventory
10.10.1.11
10.10.1.12
10.10.1.13
EOT
# inventory 검증 : -i 특정 인벤토리 지정
ansible-inventory -i ./inventory --list | jq
호스트명을 이용한 인벤토리 파일 생성
# /etc/hosts 파일 확인
cat /etc/hosts
# inventory 파일 생성
cat <<EOT > inventory
tnode1
tnode2
tnode3
EOT
# inventory 검증
ansible-inventory -i ./inventory --list | jq
역할에 따른 호스트 그룹 설정
호스트별로 롤 Role(역할)을 주고 롤별로 특정 작업을 수행해야 하는 경우가 종종 발생합니다.
# 참고 파일
cat /etc/ansible/hosts
그룹별 호스트 설정
- 그룹별로 호스트를 설정하여 사용하면 앤서블 플레이북 실행 시 그룹별로 작업을 처리할 수 있어서 좀 더 효과적입니다.
- 이 경우 다음과 같이 그룹명을 대괄화 ([]) 내에 작성하고 해당 그룹에 속하는 호스트명이나 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
범위를 사용한 호스트 사양 간소화
- 인벤토리의 호스트 이름 또는 IP 주소를 설정할 때 범위를 지정하여 호스트 인벤토리를 간소화 할 수 있습니다.
- 숫자 또는 영문자로 범위를 지정할 수 있으며, 대괄호 사이에 시작 구문과 종료 구문을 포함합니다.
**[start:end]**
- 다음과 같이 webservers는 대괄호 사이에 [1:2]로 범위를 지정했으며, db-servers는 [01:02]로 범위를 지정했습니다.
- 이렇게 지정하면 webservers의 경우 web1.example.com , web2.example.com 에 해당하는 호스트에 앤서블 플레이북 작업들이,
- db-servers의 경우 db01.example.com , db02.example.com 에 해당하는 호스트에 앤서블 플레이북 작업들이 실행됩니다.
[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]
- https://docs.ansible.com/ansible/latest/reference_appendices/config.html
- 실습을 위한 인벤토리 그룹 구성
- 현재 프로젝트 디렉터리 내에 ansible.cfg 라는 앤서블 환경 설정 파일을 구성 시, -i 옵션을 사용하지 않아도 ansible.cfg 설정 파일에 정의된 인벤토리의 호스트 정보를 확인할 수 있습니다.
(참고) ansible config 적용 우선 순위 - Link# ansible.cfg 파일 생성 cat <<EOT > **ansible.cfg** [**defaults**] inventory = ./inventory EOT # inventory 목록 확인 ansible-inventory --list | jq # ansible config 적용 우선 순위 확인 echo $ANSIBLE_CONFIG **cat $PWD/ansible.cfg** # kubespary 실행 시, 디렉터리 위치 고정 이유 ls ~/.ansible.cfg tree ~/.ansible cat /etc/ansible/ansible.cfg- ANSIBLE_CONFIG (environment variable if set)
- ansible.cfg (in the current directory)
- ~/.ansible.cfg (in the home directory)
- /etc/ansible/ansible.cfg
- # inventory 그룹 구성 cat <<EOT > **inventory** [**web**] tnode1 tnode2 [**db**] tnode3 [**all:children**] web db
- EOT # inventory 검증 ansible-inventory -i ./inventory --**list** | jq ansible-inventory -i ./inventory --**graph**
플레이북 작성
플레이북 환경 설정 (엔서블 환경 설정)
- 앤서블 프로젝트 디렉터리에 ansible.cfg 파일을 생성하면 다양한 앤서블 설정을 적용할 수 있습니다.
- 앤서블 환경 설정 파일에는 각 섹션에 키-값 쌍으로 정의된 설정이 포함되며, 여러개의 섹션으로 구성됩니다.
- 섹션 제목은 대괄호로 묶여 있으며, 기본적인 실행을 위해 다음 예제와 같이 [defaults]와 [privilege_escalation] 두 개의 섹션으로 구성합니다.
**[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_pass | SSH 암호를 묻는 메시지 표시 여부를 지정함. SSH 공개 키 인증을 사용하는 경우 기본값은 false임. |
[privilege_escalation] 섹션 : 보안/감사로 인해 원격 호스트에 권한 없는 사용자 연결 후 관리 액세스 권한을 에스컬레이션하여 루트 사용자로 가여올 때
| 매개 변수 | 설명 |
| become | 기본적으로 권한 에스컬레이션을 활성화할 때 사용하며, 연결 후 관리 호스트에서 자동으로 사용자를 전환할지 여부를 지정함. 일반적으로 root로 전환되며, 플레이북에서도 지정할 수 있음. |
| become_method | 권한을 에스컬레이션하는 사용자 전환 방식을 의미함. 일반적으로 기본값은 sudo를 사용하며, su는 옵션으로 설정할 수 있음. |
| become_user | 관리 호스트에서 전환할 사용자를 지정함. 일반적으로 기본값은 root임. |
| become_ask_pass | become_method 매개 변수에 대한 암호를 묻는 메시지 표시 여부를 지정함. 기본값은 false임. 권한을 에스컬레이션하기 위해 사용자가 암호를 입력해야 하는 경우, 구성 파일에 become_ask_pass = true 매개 변수를 설정하면 됨. |
- 앤서블은 리눅스에서 기본적으로 SSH 프로토콜을 사용하여 관리 호스트에 연결합니다.
- 앤서블에서 관리 호스트에 연결하는 방법을 제어하는 가장 중요한 매개 변수는 [defaults] 섹션에 설정되어 있습니다.
- 또한, 별도로 설정되어 있지 않으면 앤서블은 실행 시 로컬 사용자와 같은 사용자 이름을 사용하여 관리 호스트에 연결합니다.
- 이때 다른 사용자를 지정하려면 remote_user 매개 변수를 사용하여 해당 사용자 이름으로 설정할 수 있습니다.
실습을 위한 엔서블 환경 설정
my-ansible/ansible.cfg
cat <<EOT > 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
EOT
[ad-hoc] ansible ping 모듈 - https://docs.ansible.com/archive/ansible/2.3/ping_module.html
ping 모듈을 이용하여 web 그룹의 호스트로 정상 연결(pong반환)이면 ‘SUCCESS’ 출력 ← icmp(ping) 아니며, python 테스트 모듈
#
ansible -m ping web
# Ansible이 '지금은 잘 동작하지만 미래에 예기치 않게 Python 인터프리터가 바뀔 수 있다'는 점을 알려주는 예방용 경고
# 암묵적 Python 자동 선택을 지양하고, 명시적 설정을 권장 : 기본값(ansible_python_interpreter=auto)
# inventory 그룹 구성
cat <<EOT > inventory
[web]
tnode1 ansible_python_interpreter=/usr/bin/python3
tnode2 ansible_python_interpreter=/usr/bin/python3
[db]
tnode3 ansible_python_interpreter=/usr/bin/python3
[all:children]
web
db
EOT
ansible-inventory -i ./inventory --list | jq
#
ansible -m ping web
#
ansible -m ping db
2. 옵션 설정으로 암호 입력 후 실행 확인
# 암호 입력 후 실행
ansible -m ping --ask-pass web
SSH password: <암호입력>
3. 다른 사용자 계정으로 실행 확인
# root 계정 대신 vagrant 계정으로 실행
ansible -m ping web -u vagrant
ansible -m ping web -u vagrant --ask-pass
-----------------------------------------------
ssh vagrant@10.10.1.11 hostname
ssh vagrant@10.10.1.12 hostname
ssh vagrant@10.10.1.13 hostname
sshpass -p 'qwe123' ssh vagrant@tnode1 hostname
sshpass -p 'qwe123' ssh vagrant@tnode2 hostname
sshpass -p 'qwe123' ssh vagrant@tnode3 hostname
<CTRL+C>
sshpass -p 'qwe123' ssh vagrant@tnode3 -t hostname
exit
-----------------------------------------------
ansible -m ping web -u vagrant --ask-pass
ansible -m ping db -u vagrant --ask-pass
[ad-hoc] ansible shell 모듈 - https://docs.ansible.com/ansible/2.8/modules/shell_module.html
- shell은 노드들에 명령 구문을 전달하고 해당 결과를 반환하는 모듈
#
ansible -m shell -a uptime db
#
ansible -m shell -a "free -h" web
#
ansible -m shell -a "tail -n 3 /etc/passwd" all
첫 번째 플레이북 작성하기 - https://docs.ansible.com/ansible/latest/getting_started/get_started_playbook.html
- 플레이북은 YAML 포맷으로 작성된 텍스트 파일이며, 일반적으로 .yml이라는 확장자를 사용하여 저장됩니다.
- 플레이북은 대상 호스트나 호스트 집합에 수행할 작업을 정의하고 이를 실행합니다. 이때 특정 작업 단위를 수행하기 위해 모듈을 적용합니다.
- 용어 - Docs
- Playbook
- A list of plays that define the order in which Ansible performs operations, from top to bottom, to achieve an overall goal.
- Play
- An ordered list of tasks that maps to managed nodes in an inventory.
- Task
- A reference to a single module that defines the operations that Ansible performs.
- 플레이북 작성하기 : debug 모듈을 이용하여 문자열을 출력
- my-ansible/first-playbook.yml
2. my-ansible/first-playbook-with-error.yml--- - hosts: all tasks: - name: Print message **debug**: **msg**: Hello CloudNet@ Ansible Study- ---
- hosts: all
tasks:
- name: Print message
debug:
msg: Hello CloudNet@ Ansible Study
- 플레이북 문법 체크하기 : 자체 문법 체크 옵션 제공
- # 문법 체크 : 문법 오류 확인
ansible-playbook --syntax-check first-playbook.yml
ansible-playbook --syntax-check first-playbook-with-error.ymlModule- A unit of code or binary that Ansible runs on managed nodes.
- Ansible modules are grouped in collections with a Fully Qualified Collection Name (FQCN) for each module.플레이북 실행하기
-
- 플레이북을 실행할 때는 ansible-playbook 명령어를 이용합니다. 환경 설정 파일인 ansible.cfg가 존재하는 프로젝트 디렉터리 내에서 실행할 경우에는 ansible-playbook 명령어와 함께 실행하고자 하는 플레이북 파일명을 입력하면 됩니다.
**ansible-playbook first-playbook.yml** ...
- 서비스 재시작하는 플레이북 작성
- my-ansible/restart-service.yml
--- - hosts: all tasks: - name: Restart sshd service ansible.builtin.**service**: name: ssh # sshd state: **restarted**
- state - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html#parameter-state
- started : Start service httpd, if not started
- stooped : Stop service httpd, if started
- restarted : Restart service httpd, in all cases
- reloaded : Reload service httpd, in all cases
- # 문법 체크 : 문법 오류 확인
- 5. 플레이북 실행
- 플레이북 실행
- Playbook
# (신규터미널) 모니터링 : 서비스 재시작 실행 여부 확인
ssh tnode1 tail -f /var/log/syslog
# 실행 전 check 옵션으로 플레이북의 실행 상태를 미리 점검 가능 : 출력 중 changed=1 확인
ansible-playbook --check restart-service.yml
# 플레이북 실제 실행
ansible-playbook restart-service.yml
...
6. (참고) OS 별 조건 분리
- hosts: all
tasks:
- name: Restart SSH on Debian
ansible.builtin.service:
name: ssh
state: restarted
when: ansible_facts['os_family'] == 'Debian'
- name: Restart SSH on RedHat
ansible.builtin.service:
name: sshd
state: restarted
when: ansible_facts['os_family'] == 'RedHat'
# you can see the ‘raw’ information for any host in your inventory by running this ad-hoc ansible command at the command line:
ansible tnode1 -m ansible.builtin.setup | grep -iE 'os_family|ansible_distribution'
"ansible_distribution": "Ubuntu",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/os-release",
"ansible_distribution_file_variety": "Debian",
"ansible_distribution_major_version": "24",
"ansible_distribution_release": "noble",
"ansible_distribution_version": "24.04",
"ansible_os_family": "Debian",
ansible tnode3 -m ansible.builtin.setup | grep -iE 'os_family|ansible_distribution'
"ansible_distribution": "Rocky",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "9",
"ansible_distribution_release": "Blue Onyx",
"ansible_distribution_version": "9.6",
"ansible_os_family": "RedHat",
# 실행 전 check 옵션으로 플레이북의 실행 상태를 미리 점검
ansible-playbook --check restart-service.yml
# 플레이북 실제 실행
ansible-playbook restart-service.yml
변수
앤서블은 변수를 사용하여 사용자, 설치하고자 하는 패키지, 재시작할 서비스, 생성 또는 삭제할 파일명 등 시스템 작업 시 사용되는 다양한 값을 저장할 수 있습니다. 이런 변수를 활용하면 얼마든지 플레이북을 재사용할 수 있으며, 사용자로부터 받은 값도 쉽게 적용할 수 있습니다. 앤서블에서 사용되는 변수는 그룹 변수, 호스트 변수, 플레이 변수, 추가 변수가 있으며 플레이 결과를 저장하기 위한 작업 변수도 있습니다.
ansible.builtin.**user** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html
- 그룹 변수 : 인벤토리에 정의된 호스트 그룹에 적용하는 변수
- 그룹 변수는 인벤토리에 정의된 호스트 그룹에 적용하는 변수를 의미합니다. 따라서 인벤토리에 선언해야 하고, 선언하고자 하는 그룹명과 함께 :vars 라는 문자열을 추가해 변수를 선언한다는 것을 알려줍니다. 예제를 통해 알아보겠습니다.https://kimalarm.tistory.com/78

- **[ansible-server]**의 my-ansible 디렉터리에 있는 inventory 파일 하단에 [all:vars] 섹션을 선언하고 해당 섹션 아래에 user=ansible이라는 변수와 값을 선언합니다.이렇게 하면 all이라는 그룹에서 user라는 변수를 사용할 수 있습니다. 다음 예제에서 all 그룹에는 web 그룹과 db 그룹이, web 그룹에는 tnode1-ubuntu.local, tnode2-ubuntu.local이 포함되며, db그룹에는 tnode3 호스트가 포함됩니다.
[web] tnode1 ansible_python_interpreter=/usr/bin/python3 tnode2 ansible_python_interpreter=/usr/bin/python3 [db] tnode3 ansible_python_interpreter=/usr/bin/python3 [all:children] web db **[all:vars] user=ansible** - my-ansible/inventory
- 이번에는 create-user.yml 이라는 파일을 생성합니다. 해당 파일은 사용자를 생성하는 태스크를 포함합니다. 앤서블에서 시스템 사용자(account)를 생성하기 위해서는 ansible.builtin.user라는 모듈을 사용합니다. 그리고 인벤토리에서 선언한 user라는 변수를 겹중괄호 사이에 넣어주면, 해당 변수를 플레이북에서 사용할 수 있습니다. 이때 겹 중괄호와 변수명 사이는 항상 한 칸씩 띄워주어야 합니다.
--- - hosts: all tasks: - name: Create User **{{ user }}** ansible.builtin.**user**: name: **"{{ user }}"** state: present - my-ansible/create-user.yml ← 아래 파일은 VSCODE에서 직접 파일 생성 후 코드 내용을 직접 입력해보시길 추천
- 앞에서 생성한 플레이북을 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 사용자 생성 확인합니다.
- # tnode1~3에서 ansible 사용자 생성 확인 *#ssh tnode1 tail -n 3 /etc/passwd #ssh tnode1 ls -l /home* for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **ls -l /home**; echo; done
- 수동으로 tnode1 에 ansible 사용자 삭제 후 다시 플레이북 실행 확인
- # tnode1 에 ansible 사용자 삭제 후 확인 ssh tnode1 userdel -r ansible ssh tnode1 tail -n 2 /etc/passwd # 실행 **ansible-playbook create-user.yml**
- 호스트 변수 : 말 그대로 해당 호스트에서만 사용할 수 있음https://kimalarm.tistory.com/78
- 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언
[web] tnode1 ansible_python_interpreter=/usr/bin/python3 tnode2 ansible_python_interpreter=/usr/bin/python3 [db] tnode3 ansible_python_interpreter=/usr/bin/python3 **user=ansible1** [all:children] web db [all:vars] user=ansible - my-ansible/inventory
- 플레이북 파일 작성 : hosts 를 all → db
--- - hosts: **db** tasks: - name: Create User {{ user }} ansible.builtin.**user**: name: "{{ user }}" state: **present** - my-ansible/create-user1.yml
- 플레이북 실행 확인. user 명 확인 → 호스트 변수와 그룹 변수의 우선순위 확인
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 **ansible-playbook create-user1.yml** ... TASK [Create User **ansible1**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done
- 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언

- 플레이 변수 : 플레이북 내에서 선언되는 변수, 별도 파일 분리
- 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
--- - hosts: **all vars: user: ansible2** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present - my-ansible/create-user2.yml
- 플레이북 실행 확인. 인벤토리에 선언한 그룹 변수 vs 호스트 변수 vs 플레이 변수 우선 순위 확인.
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 인벤토리에 선언한 그룹 변수와 호스트 변수 확인 cat inventory # 실행 **ansible-playbook create-user2.yml** ... TASK [Create User **ansible2**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done
- 플레이 변수를 별도의 파일로 분리하여 정의한 후 이를 플레이북에서 선언하는 방법으로 변수를 사용해보기
my-ansible/create-user3.ymlmkdir vars echo "**user: ansible3**" > vars/users.yml - --- - hosts: **all vars_files: - vars/users.yml** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present
- my-ansible/vars/users.yml
- 플레이북 실행
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 플레이 변수 파일 확인 cat vars/users.yml # 실행 **ansible-playbook create-user3.yml** ... TASK [Create User **ansible3**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 4 /etc/passwd**; echo; done
- 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
- https://kimalarm.tistory.com/78
- 추가 변수 : 외부에서 ansible-playbook를 실행 할 때 함께 파라미터로 넘겨주는 변수를 의미. 앞에 변수 중 우선순위가 가장 높음.
- 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
# (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 **ansible-playbook -e user=ansible4 create-user3.yml** ... TASK [Create User **ansible4**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 5 /etc/passwd**; echo; done - my-ansible/create-user3.yml ← 바로 위 플레이 변수에서 작성한 플레이북임
- 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
- 변수 우선 순위 : 추가변수(실행 시 파라미터) > 플레이 변수 > 호스트 변수 > 그룹 변수변수ansible.builtin.**user** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html
- 그룹 변수 : 인벤토리에 정의된 호스트 그룹에 적용하는 변수
- 그룹 변수는 인벤토리에 정의된 호스트 그룹에 적용하는 변수를 의미합니다. 따라서 인벤토리에 선언해야 하고, 선언하고자 하는 그룹명과 함께 :vars 라는 문자열을 추가해 변수를 선언한다는 것을 알려줍니다. 예제를 통해 알아보겠습니다.https://kimalarm.tistory.com/78

- **[ansible-server]**의 my-ansible 디렉터리에 있는 inventory 파일 하단에 [all:vars] 섹션을 선언하고 해당 섹션 아래에 user=ansible이라는 변수와 값을 선언합니다.이렇게 하면 all이라는 그룹에서 user라는 변수를 사용할 수 있습니다. 다음 예제에서 all 그룹에는 web 그룹과 db 그룹이, web 그룹에는 tnode1-ubuntu.local, tnode2-ubuntu.local이 포함되며, db그룹에는 tnode3 호스트가 포함됩니다.
[web] tnode1 ansible_python_interpreter=/usr/bin/python3 tnode2 ansible_python_interpreter=/usr/bin/python3 [db] tnode3 ansible_python_interpreter=/usr/bin/python3 [all:children] web db **[all:vars] user=ansible** - my-ansible/inventory
- 이번에는 create-user.yml 이라는 파일을 생성합니다. 해당 파일은 사용자를 생성하는 태스크를 포함합니다. 앤서블에서 시스템 사용자(account)를 생성하기 위해서는 ansible.builtin.user라는 모듈을 사용합니다. 그리고 인벤토리에서 선언한 user라는 변수를 겹중괄호 사이에 넣어주면, 해당 변수를 플레이북에서 사용할 수 있습니다. 이때 겹 중괄호와 변수명 사이는 항상 한 칸씩 띄워주어야 합니다.
--- - hosts: all tasks: - name: Create User **{{ user }}** ansible.builtin.**user**: name: **"{{ user }}"** state: present - my-ansible/create-user.yml ← 아래 파일은 VSCODE에서 직접 파일 생성 후 코드 내용을 직접 입력해보시길 추천
- 앞에서 생성한 플레이북을 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 사용자 생성 확인합니다.
- # tnode1~3에서 ansible 사용자 생성 확인 *#ssh tnode1 tail -n 3 /etc/passwd #ssh tnode1 ls -l /home* for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **ls -l /home**; echo; done
- 수동으로 tnode1 에 ansible 사용자 삭제 후 다시 플레이북 실행 확인
- # tnode1 에 ansible 사용자 삭제 후 확인 ssh tnode1 userdel -r ansible ssh tnode1 tail -n 2 /etc/passwd # 실행 **ansible-playbook create-user.yml**
- 호스트 변수 : 말 그대로 해당 호스트에서만 사용할 수 있음https://kimalarm.tistory.com/78
- 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언
[web] tnode1 ansible_python_interpreter=/usr/bin/python3 tnode2 ansible_python_interpreter=/usr/bin/python3 [db] tnode3 ansible_python_interpreter=/usr/bin/python3 **user=ansible1** [all:children] web db [all:vars] user=ansible - my-ansible/inventory
- 플레이북 파일 작성 : hosts 를 all → db
--- - hosts: **db** tasks: - name: Create User {{ user }} ansible.builtin.**user**: name: "{{ user }}" state: **present** - my-ansible/create-user1.yml
- 플레이북 실행 확인. user 명 확인 → 호스트 변수와 그룹 변수의 우선순위 확인
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 **ansible-playbook create-user1.yml** ... TASK [Create User **ansible1**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done
- 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언
- 플레이 변수 : 플레이북 내에서 선언되는 변수, 별도 파일 분리
- 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
--- - hosts: **all vars: user: ansible2** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present - my-ansible/create-user2.yml
- 플레이북 실행 확인. 인벤토리에 선언한 그룹 변수 vs 호스트 변수 vs 플레이 변수 우선 순위 확인.
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 인벤토리에 선언한 그룹 변수와 호스트 변수 확인 cat inventory # 실행 **ansible-playbook create-user2.yml** ... TASK [Create User **ansible2**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done
- 플레이 변수를 별도의 파일로 분리하여 정의한 후 이를 플레이북에서 선언하는 방법으로 변수를 사용해보기
my-ansible/create-user3.ymlmkdir vars echo "**user: ansible3**" > vars/users.yml - --- - hosts: **all vars_files: - vars/users.yml** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present
- my-ansible/vars/users.yml
- 플레이북 실행
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 플레이 변수 파일 확인 cat vars/users.yml # 실행 **ansible-playbook create-user3.yml** ... TASK [Create User **ansible3**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 4 /etc/passwd**; echo; done
- 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
- https://kimalarm.tistory.com/78

- 추가 변수 : 외부에서 ansible-playbook를 실행 할 때 함께 파라미터로 넘겨주는 변수를 의미. 앞에 변수 중 우선순위가 가장 높음.
- 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
# (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 **ansible-playbook -e user=ansible4 create-user3.yml** ... TASK [Create User **ansible4**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 5 /etc/passwd**; echo; done - my-ansible/create-user3.yml ← 바로 위 플레이 변수에서 작성한 플레이북임
- 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
- 변수 우선 순위 : 추가변수(실행 시 파라미터) > 플레이 변수 > 호스트 변수 > 그룹 변수변수ansible.builtin.**user** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html
- 그룹 변수 : 인벤토리에 정의된 호스트 그룹에 적용하는 변수
- 그룹 변수는 인벤토리에 정의된 호스트 그룹에 적용하는 변수를 의미합니다. 따라서 인벤토리에 선언해야 하고, 선언하고자 하는 그룹명과 함께 :vars 라는 문자열을 추가해 변수를 선언한다는 것을 알려줍니다. 예제를 통해 알아보겠습니다.https://kimalarm.tistory.com/78
- **[ansible-server]**의 my-ansible 디렉터리에 있는 inventory 파일 하단에 [all:vars] 섹션을 선언하고 해당 섹션 아래에 user=ansible이라는 변수와 값을 선언합니다.이렇게 하면 all이라는 그룹에서 user라는 변수를 사용할 수 있습니다. 다음 예제에서 all 그룹에는 web 그룹과 db 그룹이, web 그룹에는 tnode1-ubuntu.local, tnode2-ubuntu.local이 포함되며, db그룹에는 tnode3 호스트가 포함됩니다.
[web] tnode1 ansible_python_interpreter=/usr/bin/python3 tnode2 ansible_python_interpreter=/usr/bin/python3 [db] tnode3 ansible_python_interpreter=/usr/bin/python3 [all:children] web db **[all:vars] user=ansible** - my-ansible/inventory
- 이번에는 create-user.yml 이라는 파일을 생성합니다. 해당 파일은 사용자를 생성하는 태스크를 포함합니다. 앤서블에서 시스템 사용자(account)를 생성하기 위해서는 ansible.builtin.user라는 모듈을 사용합니다. 그리고 인벤토리에서 선언한 user라는 변수를 겹중괄호 사이에 넣어주면, 해당 변수를 플레이북에서 사용할 수 있습니다. 이때 겹 중괄호와 변수명 사이는 항상 한 칸씩 띄워주어야 합니다.
--- - hosts: all tasks: - name: Create User **{{ user }}** ansible.builtin.**user**: name: **"{{ user }}"** state: present - my-ansible/create-user.yml ← 아래 파일은 VSCODE에서 직접 파일 생성 후 코드 내용을 직접 입력해보시길 추천
- 앞에서 생성한 플레이북을 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 사용자 생성 확인합니다.
- # tnode1~3에서 ansible 사용자 생성 확인 *#ssh tnode1 tail -n 3 /etc/passwd #ssh tnode1 ls -l /home* for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **ls -l /home**; echo; done
- 수동으로 tnode1 에 ansible 사용자 삭제 후 다시 플레이북 실행 확인
- # tnode1 에 ansible 사용자 삭제 후 확인 ssh tnode1 userdel -r ansible ssh tnode1 tail -n 2 /etc/passwd # 실행 **ansible-playbook create-user.yml**
- 호스트 변수 : 말 그대로 해당 호스트에서만 사용할 수 있음https://kimalarm.tistory.com/78
- 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언
[web] tnode1 ansible_python_interpreter=/usr/bin/python3 tnode2 ansible_python_interpreter=/usr/bin/python3 [db] tnode3 ansible_python_interpreter=/usr/bin/python3 **user=ansible1** [all:children] web db [all:vars] user=ansible - my-ansible/inventory
- 플레이북 파일 작성 : hosts 를 all → db
--- - hosts: **db** tasks: - name: Create User {{ user }} ansible.builtin.**user**: name: "{{ user }}" state: **present** - my-ansible/create-user1.yml
- 플레이북 실행 확인. user 명 확인 → 호스트 변수와 그룹 변수의 우선순위 확인
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 **ansible-playbook create-user1.yml** ... TASK [Create User **ansible1**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done
- 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언

- 플레이 변수 : 플레이북 내에서 선언되는 변수, 별도 파일 분리
- 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
--- - hosts: **all vars: user: ansible2** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present - my-ansible/create-user2.yml
- 플레이북 실행 확인. 인벤토리에 선언한 그룹 변수 vs 호스트 변수 vs 플레이 변수 우선 순위 확인.
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 인벤토리에 선언한 그룹 변수와 호스트 변수 확인 cat inventory # 실행 **ansible-playbook create-user2.yml** ... TASK [Create User **ansible2**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done
- 플레이 변수를 별도의 파일로 분리하여 정의한 후 이를 플레이북에서 선언하는 방법으로 변수를 사용해보기
my-ansible/create-user3.ymlmkdir vars echo "**user: ansible3**" > vars/users.yml - --- - hosts: **all vars_files: - vars/users.yml** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present
- my-ansible/vars/users.yml
- 플레이북 실행
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 플레이 변수 파일 확인 cat vars/users.yml # 실행 **ansible-playbook create-user3.yml** ... TASK [Create User **ansible3**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 4 /etc/passwd**; echo; done
- 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
- https://kimalarm.tistory.com/78

- 추가 변수 : 외부에서 ansible-playbook를 실행 할 때 함께 파라미터로 넘겨주는 변수를 의미. 앞에 변수 중 우선순위가 가장 높음.
- 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
# (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 **ansible-playbook -e user=ansible4 create-user3.yml** ... TASK [Create User **ansible4**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 5 /etc/passwd**; echo; done - my-ansible/create-user3.yml ← 바로 위 플레이 변수에서 작성한 플레이북임
- 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
- 변수 우선 순위 : 추가변수(실행 시 파라미터) > 플레이 변수 > 호스트 변수 > 그룹 변수변수ansible.builtin.**user** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html
- 그룹 변수 : 인벤토리에 정의된 호스트 그룹에 적용하는 변수
- 그룹 변수는 인벤토리에 정의된 호스트 그룹에 적용하는 변수를 의미합니다. 따라서 인벤토리에 선언해야 하고, 선언하고자 하는 그룹명과 함께 :vars 라는 문자열을 추가해 변수를 선언한다는 것을 알려줍니다. 예제를 통해 알아보겠습니다.https://kimalarm.tistory.com/78

- **[ansible-server]**의 my-ansible 디렉터리에 있는 inventory 파일 하단에 [all:vars] 섹션을 선언하고 해당 섹션 아래에 user=ansible이라는 변수와 값을 선언합니다.이렇게 하면 all이라는 그룹에서 user라는 변수를 사용할 수 있습니다. 다음 예제에서 all 그룹에는 web 그룹과 db 그룹이, web 그룹에는 tnode1-ubuntu.local, tnode2-ubuntu.local이 포함되며, db그룹에는 tnode3 호스트가 포함됩니다.
[web] tnode1 ansible_python_interpreter=/usr/bin/python3 tnode2 ansible_python_interpreter=/usr/bin/python3 [db] tnode3 ansible_python_interpreter=/usr/bin/python3 [all:children] web db **[all:vars] user=ansible** - my-ansible/inventory
- 이번에는 create-user.yml 이라는 파일을 생성합니다. 해당 파일은 사용자를 생성하는 태스크를 포함합니다. 앤서블에서 시스템 사용자(account)를 생성하기 위해서는 ansible.builtin.user라는 모듈을 사용합니다. 그리고 인벤토리에서 선언한 user라는 변수를 겹중괄호 사이에 넣어주면, 해당 변수를 플레이북에서 사용할 수 있습니다. 이때 겹 중괄호와 변수명 사이는 항상 한 칸씩 띄워주어야 합니다.
--- - hosts: all tasks: - name: Create User **{{ user }}** ansible.builtin.**user**: name: **"{{ user }}"** state: present - my-ansible/create-user.yml ← 아래 파일은 VSCODE에서 직접 파일 생성 후 코드 내용을 직접 입력해보시길 추천
- 앞에서 생성한 플레이북을 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 사용자 생성 확인합니다.
- # tnode1~3에서 ansible 사용자 생성 확인 *#ssh tnode1 tail -n 3 /etc/passwd #ssh tnode1 ls -l /home* for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **ls -l /home**; echo; done
- 수동으로 tnode1 에 ansible 사용자 삭제 후 다시 플레이북 실행 확인
- # tnode1 에 ansible 사용자 삭제 후 확인 ssh tnode1 userdel -r ansible ssh tnode1 tail -n 2 /etc/passwd # 실행 **ansible-playbook create-user.yml**
- 호스트 변수 : 말 그대로 해당 호스트에서만 사용할 수 있음https://kimalarm.tistory.com/78
- 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언
[web] tnode1 ansible_python_interpreter=/usr/bin/python3 tnode2 ansible_python_interpreter=/usr/bin/python3 [db] tnode3 ansible_python_interpreter=/usr/bin/python3 **user=ansible1** [all:children] web db [all:vars] user=ansible - my-ansible/inventory
- 플레이북 파일 작성 : hosts 를 all → db
--- - hosts: **db** tasks: - name: Create User {{ user }} ansible.builtin.**user**: name: "{{ user }}" state: **present** - my-ansible/create-user1.yml
- 플레이북 실행 확인. user 명 확인 → 호스트 변수와 그룹 변수의 우선순위 확인
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 **ansible-playbook create-user1.yml** ... TASK [Create User **ansible1**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done
- 인벤토리 파일을 열고 db 그룹의 tnode-3 호스트 옆에 변수를 선언

- 플레이 변수 : 플레이북 내에서 선언되는 변수, 별도 파일 분리
- 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
--- - hosts: **all vars: user: ansible2** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present - my-ansible/create-user2.yml
- 플레이북 실행 확인. 인벤토리에 선언한 그룹 변수 vs 호스트 변수 vs 플레이 변수 우선 순위 확인.
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 인벤토리에 선언한 그룹 변수와 호스트 변수 확인 cat inventory # 실행 **ansible-playbook create-user2.yml** ... TASK [Create User **ansible2**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 3 /etc/passwd**; echo; done
- 플레이 변수를 별도의 파일로 분리하여 정의한 후 이를 플레이북에서 선언하는 방법으로 변수를 사용해보기
my-ansible/create-user3.ymlmkdir vars echo "**user: ansible3**" > vars/users.yml - --- - hosts: **all vars_files: - vars/users.yml** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present
- my-ansible/vars/users.yml
- 플레이북 실행
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 플레이 변수 파일 확인 cat vars/users.yml # 실행 **ansible-playbook create-user3.yml** ... TASK [Create User **ansible3**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 4 /etc/passwd**; echo; done
- 플레이북 작성 : hosts 아래에 vars: 를 추가하고 그 아래에 다시 user: ansible2 라는 변수와 값을 추가
- https://kimalarm.tistory.com/78

- 추가 변수 : 외부에서 ansible-playbook를 실행 할 때 함께 파라미터로 넘겨주는 변수를 의미. 앞에 변수 중 우선순위가 가장 높음.
- 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
# (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 **ansible-playbook -e user=ansible4 create-user3.yml** ... TASK [Create User **ansible4**] ********* ... # 확인 for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i **tail -n 5 /etc/passwd**; echo; done - my-ansible/create-user3.yml ← 바로 위 플레이 변수에서 작성한 플레이북임
- 실행 시 -e(extra_vars 약자) 옵션으로 추가 변수 선언
- 변수 우선 순위 : 추가변수(실행 시 파라미터) > 플레이 변수 > 호스트 변수 > 그룹 변수
- 그룹 변수 : 인벤토리에 정의된 호스트 그룹에 적용하는 변수
- 앤서블은 변수를 사용하여 사용자, 설치하고자 하는 패키지, 재시작할 서비스, 생성 또는 삭제할 파일명 등 시스템 작업 시 사용되는 다양한 값을 저장할 수 있습니다. 이런 변수를 활용하면 얼마든지 플레이북을 재사용할 수 있으며, 사용자로부터 받은 값도 쉽게 적용할 수 있습니다. 앤서블에서 사용되는 변수는 그룹 변수, 호스트 변수, 플레이 변수, 추가 변수가 있으며 플레이 결과를 저장하기 위한 작업 변수도 있습니다.
- 그룹 변수 : 인벤토리에 정의된 호스트 그룹에 적용하는 변수
- 앤서블은 변수를 사용하여 사용자, 설치하고자 하는 패키지, 재시작할 서비스, 생성 또는 삭제할 파일명 등 시스템 작업 시 사용되는 다양한 값을 저장할 수 있습니다. 이런 변수를 활용하면 얼마든지 플레이북을 재사용할 수 있으며, 사용자로부터 받은 값도 쉽게 적용할 수 있습니다. 앤서블에서 사용되는 변수는 그룹 변수, 호스트 변수, 플레이 변수, 추가 변수가 있으며 플레이 결과를 저장하기 위한 작업 변수도 있습니다.
- 그룹 변수 : 인벤토리에 정의된 호스트 그룹에 적용하는 변수
- 앤서블은 변수를 사용하여 사용자, 설치하고자 하는 패키지, 재시작할 서비스, 생성 또는 삭제할 파일명 등 시스템 작업 시 사용되는 다양한 값을 저장할 수 있습니다. 이런 변수를 활용하면 얼마든지 플레이북을 재사용할 수 있으며, 사용자로부터 받은 값도 쉽게 적용할 수 있습니다. 앤서블에서 사용되는 변수는 그룹 변수, 호스트 변수, 플레이 변수, 추가 변수가 있으며 플레이 결과를 저장하기 위한 작업 변수도 있습니다.
ansible.builtin.**debug** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/debug_module.html
- 작업 변수 : 플레이북의 수행 결과를 저장. 특정 작업 수행 후 그 결과를 후속 작업에서 사용할 때 주로 사용됨.
- 예를 들어 클라우드 시스템에 VM을 생성한다고 가정해보겠습니다. 이를 위해서는 네트워크나 운영체제 이미지와 같은 가상 자원이 필요합니다.
- 가상 자원을 조회하고, 조회된 결과를 가지고 VM을 생성할 때는 작업 변수를 사용하면 좋습니다.
- 파일 복사 후 수정, Create User 태스트에 register: result 라는 문구를 추가.
- register를 선언하면 태스트를 실행한 결과를 register 다음에 나오는 result라는 변수에 저장하겠다는 의미가 됩니다.
- 그리고 result라는 변수에 저장한 결과를 debug 모듈을 통해 출력합니다.
- --- - hosts: **db** tasks: - name: Create User {{ user }} ansible.builtin.user: name: "{{ user }}" state: present **register: result - ansible.builtin.debug: var: result**
- 추가 변수와 함께 플레이북 실행 확인
- # (터미널2) 모니터링 watch -d "ssh **tnode3** tail -n 3 /etc/passwd" # 실행 : ok=3의 의미는? **ansible-playbook -e user=ansible5 create-user4.yml** PLAY [db] *************************************************************************** **TASK** [Gathering Facts] ************************************************************** ok: [tnode3-ubuntu.local] **TASK** [Create User **ansible5**] ********* changed: [tnode3-ubuntu.local] **TASK** [**ansible.builtin.debug**] ******************************************************** ok: [tnode3-ubuntu.local] => { **"result": { "changed": true, "comment": "", "create_home": true, "failed": false, "group": 1006, "home": "/home/ansible5", "name": "ansible5", "shell": "/bin/sh", "state": "present", "system": false, "uid": 1006** } } PLAY RECAP ************************************************************************** tnode3-ubuntu.local : **ok=3** changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 도전과제1 생성된 user를 ansible.builtin.**user** 모듈을 통해서 제거해보자 - Example
- 도전과제2 관리 대상에 uptime을 ansible.builtin.**debug** 모듈을 통해서 확인해보자 - Example
Facts
팩트 Facts는 앤서블이 관리 호스트에서 자동으로 검색한 변수(자동 예약 변수)입니다. 팩트에는 플레이, 조건문, 반복문 또는 관리 호스트에서 수집한 값에 의존하는 기타 명령문의 일반 변수처럼 사용 가능한 호스트별 정보가 포함되어 있습니다. 관리 호스트에서 수집된 일부 팩트에는 다음 내용들이 포함될 수 있습니다.
- 호스트 이름
- 커널 버전
- 네트워크 인터페이스 이름
- 운영체제 버전
- CPU 개수
- 사용 가능한 메모리
- 스토리지 장치의 크기 및 여유 공간
- 등등…
- kubespary Facts playbook (예시) - Code , Role
Discovering variables: **facts** and magic variables - https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_vars_facts.html
- 팩트 사용하기 : 기본 활성화로, 플레이북을 실행할 때 자동으로 팩트가 수집됨. ansible_facts 변수로 사용.
- 파일 생성
--- - hosts: **db** tasks: - name: Print all facts **ansible.builtin.debug**: **var: ansible_facts** - my-ansible/facts.yml
- 플레이북 실행
- # **ansible-playbook facts.yml** ... TASK [Gathering Facts] *********************************************************************************************************************************************************************** ok: [tnode3] TASK [Print all facts] *********************************************************************************************************************************************************************** ok: [tnode3] => { ... **"hostname": "tnode3"**, ... "**default_ipv4**": { "**address**": "10.10.1.13", ... "**os_family**": "**Debian**", # 참고로 Ubuntu도 os_family는 Debian 으로 출력 - [Link](<https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html#ansible-facts-os-family>) ...
- 팩트를 통해 수집된 변수 중 특정 값만 추출
--- - 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 }}** - my-ansible/facts1.yml
- 플레이북 실행
- # **ansible-playbook facts1.yml**
- ... TASK [Gathering Facts] ************************************************************************** ok: [tnode3] TASK [**Print all facts**] ************************************************************************** ok: [tnode3] => { "**msg**": "**The default IPv4 address of tnode3 is 10.10.1.13**" }
- 파일 생성
- 변수로 사용할 수 있는 앤서블 팩트 : 엔서블 2.* 버전에서는 ansible_facts.* 네임스페이스 표기법을 따름 (권장, ~~구 ansible_ 비권장~~*) - Forum팩트 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_hostname ansible_facts.hostname ansible_fqdn ansible_facts.fqdn ansible_default_ipv4.address ansible_facts.default_ipv4.address ansible_interfaces ansible_facts.interfaces ansible_device.vda.partitions.vda1.size ansible_facts.device.vda.partitions.vda1.size ansible_dns.nameservers ansible_facts.dns.nameservers ansible_kernel ansible_facts.kernel ansible_distribution ansible_facts.distribution - 현재 위 두 개의 표기법 모두 인지. 이는 앤서블 환경 설정 파일인 ansible.cfg [defaults] 섹션에 있는 inject_facts_as_vars 매개 변수 기본 설정 값이 true이기 때문이며, false로 설정하면 ansible_ 표기법을 비활성화* 할 수 있습니다.
- 다만, 대부분의 플레이북에서 이전 표기법인 ansible_* 표기법을 사용하므로 기본 설정 값인 true를 그대로 사용하는 것이 좋습니다.
- 파일 생성
--- - 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** }} - my-ansible/facts2.yml
- 실행
- # **ansible-playbook facts2.yml** ... TASK [Print all facts] ************************************************************************** ok: [tnode3-ubuntu.local] => { "msg": "**The node's host name is tnode3 and the ip is 10.10.1.13**" }
- 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.builtin.**setup** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/setup_module.html
- 팩트 수집 끄기 : 팩트 수집 기능 비활성화 가능
- 팩트 수집을 위해 해당 호스트에 특정 패키지를 설치해야만 하는 경우가 있습니다. 그런데 간혹 특정 이유로 패키지를 설치할 수 없는 경우에는 앤서블도 팩트 수집을 할 수 없게 됩니다. 또는 사용자가 팩트 수집으로 인해 호스트에 부하가 걸리는 것을 원치 않을 수도 있습니다. 이런 경우에는 팩트 수집 기능을 비활성화 할 수 있습니다.
- 팩트 수집 실행 시 관리 호스트에 프로세스 확인
- # (터미널2) tnode3에 SSH 접속 후 아래 모니터링 ssh tnode3 watch -d -n 1 pstree -a # [ansible-server]에서 아래 플레이북 실행 ansible-playbook facts.yml ansible-playbook facts.yml ansible-playbook facts.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 }} - my-ansible/facts3.yml
- 실행
- # 실행 결과 확인 : 팩트를 수집하지 않았는데, 팩트에서 수집해야만 하는 변수를 사용하려고 해서 에러가 발생 ansible-playbook facts3.yml # 파일 복사 cp facts3.yml facts3-2.yml # facts3-2.yml 파일 편집 --- - hosts: db gather_facts: no tasks: **- name: Print message debug: msg: Hello Ansible World** # 실행 : TASK [Print all facts] 가 없다! **ansible-playbook facts3-2.yml** PLAY [db] *************************************************************************** TASK [Print message] **************************************************************** ok: [tnode3] => { "msg": "Hello Ansible World" } ...
- 이번에는 매뉴얼한 방법으로 플레이북에 팩트 수집을 설정해보겠습니다
# 파일 복사 cp facts3.yml facts4.yml # facts4.yml 파일 편집 --- - hosts: **db gather_facts: no** tasks: **- name: Manually gather facts ansible.builtin.setup:** - name: Print all facts ansible.builtin.debug: msg: > The default IPv4 address of {{ ansible_facts.hostname }} is {{ ansible_facts.default_ipv4.address }} - my-ansible/facts4.yml
- 실행
- # **ansible-playbook facts4.yml** ... TASK [**Manually gather facts**] ******************************************************** ok: [tnode3] TASK [Print all facts] ************************************************************** ok: [tnode3] => { "msg": "The default IPv4 address of tnode3 is 10.10.1.13" }
- Gathering Facts 캐싱 - https://docs.ansible.com/ansible/latest/plugins/cache.html
- facts 정보와 inventory 정보는 기본적으로 default 캐시 플러그인인 memory 플러그인을 사용하고 있습니다.
- 캐싱하여 영구 저장을 위해서 파일 혹은 데이터베이스를 사용 할 수 있습니다.
[defaults] inventory = ./inventory remote_user = root ask_pass = false **gathering = smart fact_caching = jsonfile fact_caching_connection = myfacts** [privilege_escalation] become = true become_method = sudo become_user = root become_ask_pass = false - ansible.cfg
- 사용자 지정 팩트 만들기 : 사용자에 의해 정의된 팩트를 이용하여 환경 설정 파일의 일부 항목을 구성하거나 조건부 작업을 진행할 수 있습니다. : Skip
- 사용자 지정 팩트는 관리 호스트의 로컬에 있는 /etc/ansible/facts.d 디렉터리 내에 ‘*.fact’로 저장되어야만 앤서블이 플레이북을 실행할 때 자동으로 팩트를 수집할 수 있습니다.
- ansible-server 에 디렉터리 생성 후 파일 생성
- # mkdir **/etc/ansible/facts.d** # my-custom.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
- 플레이북 파일 생성
- # 파일 복사 cp facts4.yml facts5.yml # facts5.yml 파일 편집 --- - hosts: **localhost** tasks: - name: **Print all facts** ansible.builtin.debug: **var: ansible_local**
- 실행
- # 실행 : 커스텀으로 생성했던 팩트 내용이 출력 **ansible-playbook facts5.yml** PLAY [localhost] ****************************************************************************************************************************************************************** TASK [Gathering Facts] ************************************************************************************************************************************************************ ok: [localhost] TASK [**Print all facts**] ************************************************************************************************************************************************************ ok: [localhost] => { ***"ansible_local": { "my-custom": { "packages": { "db_package": "mariadb-server", "web_package": "httpd" }, "users": { "user1": "ansible", "user2": "gasida" } } } }*** ... # tail -n 5 /etc/passwd
- 실습 완료 후 작성한 yml 파일 삭제
- rm -r *.yml
- 도전과제3 팩트를 사용하여 3개의 서버(노드)의 ‘커널 버전’과 ‘운영체제 종류’를 출력해보자
Ansible **Loops** - https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html
반복문을 사용하면 동일한 모듈을 사용하는 작업을 여러 번 작성하지 않아도 됩니다. 예를 들어 서비스에 필요한 포트를 방화벽에 추가한다고 하면, 포트를 추가하는 작업을 여러 개 작성하는 대신 loop 반복문을 이용해 작업 하나로 여러 개의 포트를 추가할 수 있습니다.
ansible.builtin.**service** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html
- 단순 반복문 : 특정 항목에 대한 작업을 반복 - item 변수, 변수 목록 지정
- loop 키워드를 작업에 추가하면 작업을 반복해야 하는 항목의 목록을 값으로 사용합니다. 그리고 해당하는 값을 사용하려면 item 변수를 이용할 수 있습니다.
- 플레이북 파일 생성 : sshd 와 rsyslog 서비스가 시작되어 있지 않다면 시작 ← 최종 목적 동작
--- - hosts: **all** tasks: - name: Check sshd state on Debian ansible.builtin.service: name: **ssh** state: **started** **when:** ansible_**facts**['os_family'] == '**Debian'** - name: Check sshd state on RedHat ansible.builtin.service: name: **sshd** state: **started** **when**: ansible_**facts**['os_family'] == '**RedHat**' - name: Check rsyslog state **ansible.builtin.service**: name: **rsyslog** state: **started**- state - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html#parameter-state
- started : Start service httpd, if not started
- stooped : Stop service httpd, if started
- restarted : Restart service httpd, in all cases
- reloaded : Reload service httpd, in all cases
- state - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html#parameter-state
- ~/my-ansible/check-services.yml
- 실행
- # 프로세스 동작 확인 ansible -m shell -a "pstree |grep sshd" all ansible -m shell -a "pstree |grep rsyslog" all # systemd로 실행 중인 서비스 목록을 확인 systemctl list-units --type=service # 실행 **ansible-playbook check-services.yml**
- loop 반복문 적용
--- - hosts: **all** tasks: - name: Check sshd and rsyslog state **ansible.builtin.service: name: "{{ item }}" state: started loop: - vboxadd-service** # ssh **- rsyslog** - ~/my-ansible/check-services1.yml
- 실행
- # **ansible-playbook check-services1.yml** *... TASK [Check sshd and rsyslog state] **************************************************** ok: [tnode2] => (item=sshd) ok: [tnode1] => (item=sshd) ok: [tnode3] => (item=sshd) ok: [tnode2] => (item=rsyslog) ok: [tnode1] => (item=rsyslog) ok: [tnode3] => (item=rsyslog) ...*
- loop 문에 사용하는 아이템을 변수에 저장하면 loop 키워드에 해당 변수명을 사용할 수 있습니다.
--- - hosts: **all** **vars: services: - vboxadd-service** # ssh **- rsyslog** tasks: - name: Check sshd and rsyslog state ansible.builtin.service: name: "{{ item }}" state: started **loop**: **"{{ services }}"**- 변수 목록을 loop의 변수로 사용 → 변수 목록을 별도 파일로도 가능!
- ~/my-ansible/check-services2.yml
- 실행
- **ansible-playbook check-services2.yml**
ansible.builtin.**file** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html
- 사전 목록에 의한 반복문 : 여러 개의 아이템을 loop 문에서 사전 목록 dictionary 으로 사용
- 하나의 아이템을 사용할 때도 있지만, 여러 개의 아이템이 필요한 경우가 발생합니다. 예를 들어 여러 개의 사용자 계정을 생성하는 플레이북을 작성한다면 사용자 계정을 생성하기 위해 필요한 이름과 패스워드 등의 여러 항목을 loop 문에서 사전 목록으로 사용할 수 있습니다.
- 플레이북 파일 생성 : loop 문에 추가된 변수를 item[’abc’]로 참조하여 사용
--- - hosts: **all** tasks: - name: Create files ansible.builtin.**file**: path: "**{{ item['log-path'] }}**" mode: "**{{ item['log-mode'] }}**" state: touch **loop**: - log-path: /var/log/test1.log log-mode: '0644' - log-path: /var/log/test2.log log-mode: '0600' - ~/my-ansible/make-file.yml
- 실행
- # (터미널2) 모니터링 watch -d "ssh tnode1 ls -l /var/log/test*.log" # 실행 **ansible-playbook make-file.yml** ... *TASK [Create files] ******************************************************************** changed: [tnode1-ubuntu.local] => (item={'log-path': '/var/log/test1.log', 'log-mode': '0644'}) changed: [tnode3-ubuntu.local] => (item={'log-path': '/var/log/test1.log', 'log-mode': '0644'}) changed: [tnode2-ubuntu.local] => (item={'log-path': '/var/log/test1.log', 'log-mode': '0644'}) changed: [tnode3-ubuntu.local] => (item={'log-path': '/var/log/test2.log', 'log-mode': '0600'}) changed: [tnode1-ubuntu.local] => (item={'log-path': '/var/log/test2.log', 'log-mode': '0600'}) changed: [tnode2-ubuntu.local] => (item={'log-path': '/var/log/test2.log', 'log-mode': '0600'}) ...* # 확인 ansible -m shell -a "ls -l /var/log/test*.log" all
- 이전 앤서블 스타일 반복문 : 앤서블 2.5 버전 이전에는 with_ 접두사 뒤에 여러 개의 반복문 키워드를 제공하는 서로 다른 구문의 반복문 사용 ← 비권장 Skip반복문 키워드 설명
with_items 문자열 목록 또는 사전 목록과 같은 단순한 목록의 경우 loop 키워드와 동일하게 작동함. loop와 달리 목록으로 이루어진 목록이 with_items에 제공되는 경우 단일 수준의 목록으로 병합되며, 반복문 변수 item에는 각 반복 작업 중 사용되는 목록 항목이 있음. with_file 제어 노드의 파일 이름을 목록으로 사용할 경우 사용되며, 반복문 변수 item에는 각 반복 작업 중 파일 목록에 있는 해당 파일의 콘텐츠가 있음. with_sequence 숫자로 된 순서에 따라 값 목록을 생성하는 매개 변수가 필요한 경우 사용되며, 반복문 변수 item에는 각 반복 작업 중 생성된 순서대로 생성된 항목 중 하나의 값이 있음. - 그러나 기존에 작성된 플레이북을 분석해야 하는 경우도 발생하니 with_ 구문으로 시작하는 반복문도 알아두면 플레이북 분석에 도움이 됩니다.
- 플레이북 파일 생성 : 이전 앤서블 스타일 반복문
--- - hosts: **localhost** vars: data: - user0 - user1 - user2 tasks: - name: "with_items" ansible.builtin.debug: msg: "{{ **item** }}" **with_items**: "{{ **data** }}" - my-ansible/old-style-loop.yml
- 실행 : data 변수 값 출력 확인
- # **ansible-playbook old-style-loop.yml ...** *TASK [with_items] ***************************************************************************************************************************************************************************** ok: [localhost] => (item=user0) => { "msg": "user0" } ok: [localhost] => (item=user1) => { "msg": "user1" } ok: [localhost] => (item=user2) => { "msg": "user2" }*
ansible.builtin.**shell** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html
Return Values - https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html
- 반복문과 Register 변수 사용 : Register 변수는 반복 실행되는 작업의 출력을 캡처할 수 있습니다.
- 이를 통해 반복 실행되는 작업들이 모두 잘 수행되었는지 확인할 수 있으며, 이 값을 이용하여 다음 작업을 수행할 수 있습니다.
- 파일 생성
- shell 모듈을 이용하여 “I can speak~”라는 메시지를 출력합니다.
- 이때 loop 키워드를 이용하여 Korean과 English를 할 수 있다고 아이템을 나열합니다.
- 그리고 하단에 register 키워드를 이용하여 실행 결과를 result 변수에 저장합니다.
- 이렇게 저장된 result 변수는 debug 모듈을 통해 해당 내용을 확인합니다.
- --- - hosts: localhost tasks: - name: Loop echo test ansible.builtin.**shell**: "echo 'I can speak {{ item }}'" **loop**: - Korean - English **register**: **result** - name: Show result ansible.builtin.**debug**: **var: result**
- 실행 : register 키워드에 의해 저장된 result 내용에는 대괄호 ([]) 사이에 Key-Value 쌍으로 구성된 결과 값들이 모두 저장됨
- # **ansible-playbook loop_register.yml** ... TASK [Loop echo test] ************************************************************************************************************************************************************************* changed: [localhost] => (item=Korean) changed: [localhost] => (item=English) TASK [Show result] **************************************************************************************************************************************************************************** ok: [localhost] => { "result": { "changed": true, "msg": "All items completed", "results": **[** { "ansible_loop_var": "item", "changed": true, "cmd": "echo 'I can speak Korean'", "delta": "0:00:00.002555", "end": "2023-12-29 05:21:52.898098", "failed": false, "invocation": { "module_args": { "_raw_params": "echo 'I can speak Korean'", "_uses_shell": true, "argv": null, "chdir": null, "creates": null, "executable": null, "removes": null, "stdin": null, "stdin_add_newline": true, "strip_empty_ends": true } }, "item": "**Korean**", "msg": "", "rc": 0, "start": "2023-12-29 05:21:52.895543", "stderr": "", "stderr_lines": [], "stdout": "I can speak Korean", "stdout_lines": [ "I can speak Korean" ] }, { "ansible_loop_var": "item", "changed": true, "cmd": "echo 'I can speak English'", "delta": "0:00:00.003048", "end": "2023-12-29 05:21:53.076240", "failed": false, "invocation": { "module_args": { "_raw_params": "echo 'I can speak English'", "_uses_shell": true, "argv": null, "chdir": null, "creates": null, "executable": null, "removes": null, "stdin": null, "stdin_add_newline": true, "strip_empty_ends": true } }, "item": "**English**", "msg": "", "rc": 0, "start": "2023-12-29 05:21:53.073192", "stderr": "", "stderr_lines": [], "stdout": "I can speak English", "stdout_lines": [ "I can speak English" ] } **],** "skipped": false } }
- 앞서 result 내의 results의 실행 결과는 배열 형식으로 저장된 것을 볼 수 있다. 이때 results의 특정 값을 플레이북에서 사용할 경우 loop문을 이용할 수 있습니다.
- 아래 예제는 debug 모듈에 loop 키워드를 사용하여 result.results를 아이템 변수로 사용한 것입니다.
- 그리고 해당 아이템의 stdout의 값을 출력할 때는 item.stdout이라는 변수로 결과값을 출력합니다.
- stderr : 명령의 표준 에러
- stderr_lines : 표준 에러 출력을 행 단위로 구분한 목록
- stdout : 명령의 표준 출력
- stdout_lines : 표준 출력을 행 단위로 구분한 목록
- rc : ‘return code’ 반환 코드반환 코드 의미
0 성공 1 일반 오류 2 잘못된 인자 126 실행 권한 없음 127 명령 없음 130 Ctrl+C 종료 137 SIGKILL 139 Segmentation fault # 명령 실행 이후 반환 코드(exit status) # 바로 직전 명령의 반환 코드 확인 echo $? # rc = 0 ls -al echo $? # rc = 2 ls abc echo $? # rc = 127 aaa echo $? - msg : 사용자가 전달한 일반 문자열 메시지
- 등등
- --- - hosts: **localhost** tasks: - name: Loop echo test ansible.builtin.**shell**: "echo 'I can speak {{ item }}'" **loop**: - Korean - English **register**: result - name: Show result ansible.builtin.**debug**: **msg**: "Stdout: {{ item.**stdout** }}" **loop**: "{{ result.results }}"
- 실행
- # **ansible-playbook loop_register1.yml** ... *TASK **[Loop echo test]** ************************************************************************************************************************************************************************* changed: [localhost] => (item=Korean) changed: [localhost] => (item=English) TASK **[Show result]** **************************************************************************************************************************************************************************** ok: [localhost] => (item={'changed': True, 'stdout': 'I can speak Korean', 'stderr': '', 'rc': 0, 'cmd': "echo 'I can speak Korean'", 'start': '2023-12-29 05:28:47.378382', 'end': '2023-12-29 05:28:47.381040', 'delta': '0:00:00.002658', 'msg': '', 'invocation': {'module_args': {'_raw_params': "echo 'I can speak Korean'", '_uses_shell': True, 'stdin_add_newline': True, 'strip_empty_ends': True, 'argv': None, 'chdir': None, 'executable': None, 'creates': None, 'removes': None, 'stdin': None}}, 'stdout_lines': ['I can speak Korean'], 'stderr_lines': [], 'failed': False, 'item': 'Korean', 'ansible_loop_var': 'item'}) => { "msg": "Stdout: I can speak Korean" } ok: [localhost] => (item={'changed': True, 'stdout': 'I can speak English', 'stderr': '', 'rc': 0, 'cmd': "echo 'I can speak English'", 'start': '2023-12-29 05:28:47.563545', 'end': '2023-12-29 05:28:47.566676', 'delta': '0:00:00.003131', 'msg': '', 'invocation': {'module_args': {'_raw_params': "echo 'I can speak English'", '_uses_shell': True, 'stdin_add_newline': True, 'strip_empty_ends': True, 'argv': None, 'chdir': None, 'executable': None, 'creates': None, 'removes': None, 'stdin': None}}, 'stdout_lines': ['I can speak English'], 'stderr_lines': [], 'failed': False, 'item': 'English', 'ansible_loop_var': 'item'}) => { "msg": "Stdout: I can speak English" }*
조건문
Conditionals **when -** https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html
앤서블은 조건문을 사용하여 특정 조건이 충족될 때 작업 또는 플레이를 실행할 수 있습니다. 예를 들면 조건문을 사용하여 호스트의 운영체제 버전에 해당하는 서비스를 설치하는 식입니다. 앤서블에서 조건문을 사용할 때는 플레이 변수, 작업 변수, 앤서블 팩트 등을 사용할 수 있습니다.
- 조건 작업 구문 : when 문은 조건부로 작업을 실행할 때 테스트할 조건을 값으로 사용합니다.
- 조건이 충족되면 작업이 실행되고, 조건이 충족되지 않으면 작업을 건너뜁니다.
- when 문을 테스트하는 가장 간단한 조건 중 하나는 Boolean 변수가 true인지 false인지 여부입니다.
- 플레이북 생성 : run_my_task 변수에 true 값, when 문에서 run_my_task를 사용하면 true인 경우에만 작업이 실행됩니다.
--- - hosts: **localhost** vars: run_my_task: **true** tasks: - name: echo message ansible.builtin.**shell**: "echo test" **when: run_my_task** register: result - name: Show result ansible.builtin.**debug**: var: result - ~/my-ansible/when_task.yml
- 실행
- # **ansible-playbook when_task.yml** ... *TASK [**echo message**] *************************************************************************************************************************************************************************** changed: [localhost] ...*
- run_my_task 값을 false 수정 후 실행 확인
- 실행 : 해당 태스트가 수행되지 않고 건너뜀(skipping)
# **ansible-playbook when_task.yml** ... *TASK [**echo message**] *************************************************************************************************************************************************************************** **skipping**: [localhost] ...* - --- - hosts: localhost vars: run_my_task: **false** tasks: - name: echo message ansible.builtin.shell: "echo test" when: run_my_task register: result - name: Show result ansible.builtin.debug: var: result
- 조건 연산자 : when 문에 bool 변수(true, false) 외에도 조건 연산자를 사용할 수 있습니다.
- 예를 들어 when 문에 ansible_facts[’machine’] == “x86_64” 라는 구문을 사용했다면 ansible_facts[’machine’] 값이 x86_64일 때만 해당 태스크를 수행합니다.
ansible_facts[’machine’] == “x86_64” ansible_facts[’machine’] 값이 x86_64와 같으면 true max_memory == 512 max_memory 값이 512와 같다면 true min_memory < 128 min_memory 값이 128보다 작으면 true min_memory > 256 min_memory 값이 256보다 크면 true min_memory <= 256 min_memory 값이 256보다 작거나 같으면 true min_memory >= 512 min_memory 값이 512보다 크거나 같으면 true min_memory != 512 min_memory 값이 512와 같지 않으면 true min_memory is defined min_memory 라는 변수가 있으면 true min_memory is not defined min_memory 라는 변수가 없으면 true memory_available memory 값이 true이며 true, 이때 해당 값이 1이거나 True 또는 yes면 true not memory_available memory 값이 false이며 true, 이때 해당 값이 0이거나 False 또는 no면 true ansible_facts[’distribution’] in supported_distros ansible_facts[’distribution’]의 값이 supported_distros 라는 변수에 있으면 true - != : 값이 같지 않을 때 참 true
- >, >=, <=, < : ‘초과, ‘ 이상’, ‘이하’, ‘미만’ 일 때에 참 true
- not : 조건의 부정
- and, or : ‘그리고’, ‘또는’의 의미로 여러 조건의 조합 가능
- in : 값이 포함된 경우에 참 true. 예를 들어 2 in “1, 2, 3” 은 참 true
- is defined : 변수가 정의된 경우 참 true
- 그럼, OS 종류에 따라 태스크를 수행하는 예제를 통해 조건 연산자 사용법에 대해 알아보겠습니다.
- 플레이북 파일 생성 : vars 키워드로 supported_distros 라는 변수를 사전 타입의 값으로 저장.
- 그리고 태스크의 when 구문에서 ansible_facts[’distribution’] in supported_distros 라는 조건문을 추가합니다
- --- - hosts: all **vars**: supported_distros: - Ubuntu - CentOS tasks: - name: Print supported os ansible.builtin.debug: msg: "This {{ ansible_facts['distribution'] }} need to use **apt**" when: ansible_facts['distribution'] **in** supported_distros
- 실행 : ansible_facts['distribution' 값이 ‘Ubuntu’ 나 ‘CentOS’ 면 출력(태스트 수행)
- # **ansible-playbook check-os.yml** ... *TASK [Print supported os] ********************************************************************************************************************************************************************* ok: [tnode1-ubuntu.local] => { "msg": "This Ubuntu need to use **apt**" } ok: [tnode2-ubuntu.local] => { "msg": "This Ubuntu need to use **apt**" }*
- 복수 조건문 : when 문은 단일 조건문 뿐만 아니라 복수 조건문도 사용할 수 있습니다.
- 예를 들어 CentOS이고 서버 타입이 x86_64일 경우에만 작업이 실행되게 구성할 수 있습니다.
- 그럼 운영체제가 CentOS이거나 우분투일 경우 작업이 수행되는 예제를 통해 복수 조건문 사용 예를 살펴보겠습니다.
- 파일 생성 : when 문에 값에 or 구문 사용
--- - hosts: all tasks: - name: Print os type ansible.builtin.**debug**: msg: "OS Type {{ ansible_facts['distribution'] }}" when: ansible_facts['distribution'] == "**CentOS**" **or** ansible_facts['distribution'] == "**Ubuntu**" - ~/my-ansible/check-os1.yml
- 실행
- # **ansible-playbook check-os1.yml** ... *TASK [**Print os type**] ************************************************************************************************************************************************************************* ...*
- Ubuntu 이고, Version이 24.04 이 경우만 작업 수행 되게 and 연산자 사용
--- - hosts: all tasks: - name: Print os type ansible.builtin.**debug**: msg: >**-** OS Type: {{ ansible_facts['distribution'] }} OS Version: {{ ansible_facts['distribution_version'] }} when: ansible_facts['distribution'] == "**Ubuntu**" **and** ansible_facts['**distribution_version**'] == "**24.04**"- 실행
# **ansible-playbook check-os2.yml** ... *TASK [Print os type] ************************************************************************************************************************************************************************* ok: [tnode1-ubuntu.local] => { "msg": "OS Type: Ubuntu OS Version: 24.04\\n" } ok: [tnode2-ubuntu.local] => { "msg": "OS Type: Ubuntu OS Version: 24.04\\n" }* - ~/my-ansible/check-os2.yml
- and 연산자는 조건문에서 바로 사용하거나 아래 플레이북처럼 사전 형태의 목록으로 표현하는 방법 두 가지가 있습니다.
--- - hosts: all tasks: - name: Print os type ansible.builtin.debug: msg: >**-** OS Type: {{ ansible_facts['distribution'] }} OS Version: {{ ansible_facts['distribution_version'] }} **when: - ansible_facts['distribution'] == "Ubuntu" - ansible_facts['distribution_version'] == "24.04"**- 실행 : 바로 위와 동일한 결과 확인
# **ansible-playbook check-os3.yml** ... - ~/my-ansible/check-os3.yml
- and 연산자와 or 연산자를 함께 사용할 수도 있습니다.
- 다음 플레이북은 두 연산자를 함께 사용한 예제로, CentOS이면서 8 이거나, Ubuntu이면서 24.04 인 경우를 표현합니다.
- 실행
# ansible **tnode1** -m **ansible.builtin.setup** | grep -iE 'os_family|ansible_distribution|fqdn' "ansible_distribution": "**Ubuntu**", ... "ansible_distribution_version": "24.04", "ansible_os_family": "**Debian**", ansible **tnode3** -m **ansible.builtin.setup** | grep -iE 'os_family|ansible_distribution|fqdn' "ansible_distribution": "**Rocky**", ... "ansible_distribution_version": "9.6", "ansible_os_family": "**RedHat**", # **ansible-playbook check-os4.yml** ... - --- - hosts: all tasks: - name: Print os type ansible.builtin.debug: msg: >**-** OS Type: {{ ansible_facts['distribution'] }} OS Version: {{ ansible_facts['distribution_version'] }} when: > ( ansible_facts['distribution'] == "Rocky" **and** ansible_facts['distribution_version'] == "9.6" ) **or** ( ansible_facts['distribution'] == "Ubuntu" **and** ansible_facts['distribution_version'] == "24.04" )
- 도전과제6 Ubuntu OS이면서 fqdn으로 tnode1 인 경우, debug 모듈을 사용하여 OS 정보와 fqdn 정보를 출력해보자
ansible.builtin.**command** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html
- 반복문과 조건문 사용 : 반복문과 조건문 함께 사용
- 플레이북 파일 생성 : when 문의 item[’mount’]은 loop문에서 선언한 ansible_facts의 mounts 중 mount 값과 size_available 값을 사용해 구현.
--- - hosts: db tasks: - name: Print Root Directory Size ansible.builtin.debug: **msg**: "Directory {{ **item.mount** }} size is {{ **item.size_available** }}" **loop**: "{{ ansible_facts['**mounts**'] }}" **when**: item['mount'] == "/" and item['size_available'] > 300000000 - ~/my-ansible/check-mount.yml
- 실행 : 앤서블 팩트에서 mounts라는 사전 타입의 변수값을 반복하면서 mount가 ‘/’ 이고 size_available 값이 ‘300000000’(300메가)보다 큰 경우에만 메시지를 출력하고, 그렇지 않을 경우에는 작업을 건너뜁니다.
- # 모니터링 **watch -d -n 1 ls -l ~/my-ansible/myfacts** # **ansible-playbook check-mount.yml --flush-cache** ... *TASK [**Print Root Directory Size**] ************************************************************************************************************************************************* ok: [tnode3-ubuntu.local] => (item={'mount': '/', 'device': '/dev/sda5', 'fstype': 'ext4', 'options': 'rw,relatime', 'size_total': 66258055168, 'size_available': 54189862912, 'block_size': 4096, 'block_total': 16176283, 'block_available': 13229947, 'block_used': 2946336, 'inode_total': 4128768, 'inode_available': 4008926, 'inode_used': 119842, 'uuid': 'b684e7f8-3875-4c99-bbca-5690776d49e1'}) => { "msg": "**Directory / size is 54189862912**" } **skipping**: [tnode3-ubuntu.local] => (item={'mount': '/snap/core20/2015', 'device': '/dev/loop1', 'fstype': 'squashfs', 'options': 'ro,nodev,relatime,errors=continue', 'size_total': 66584576, 'size_available': 0, 'block_size': 131072, 'block_total': 508, 'block_available': 0, 'block_used': 508, 'inode_total': 11991, 'inode_available': 0, 'inode_used': 11991, 'uuid': 'N/A'}) **skipping**: [tnode3-ubuntu.local] => (item={'mount': '/snap/lxd/22753', 'device': '/dev/loop2', 'fstype': 'squashfs', 'options': 'ro,nodev,relatime,errors=continue', 'size_total': 71172096, 'size_available': 0, 'block_size': 131072, 'block_total': 543, 'block_available': 0, 'block_used': 543, 'inode_total': 802, 'inode_available': 0, 'inode_used': 802, 'uuid': 'N/A'}) **skipping**: [tnode3-ubuntu.local] => (item={'mount': '/snap/lxd/24061', 'device': '/dev/loop3', 'fstype': 'squashfs', 'options': 'ro,nodev,relatime,errors=continue', 'size_total': 96337920, 'size_available': 0, 'block_size': 131072, 'block_total': 735, 'block_available': 0, 'block_used': 735, 'inode_total': 815, 'inode_available': 0, 'inode_used': 815, 'uuid': 'N/A'}) **skipping**: [tnode3-ubuntu.local] => (item={'mount': '/snap/snapd/20092', 'device': '/dev/loop5', 'fstype': 'squashfs', 'options': 'ro,nodev,relatime,errors=continue', 'size_total': 42860544, 'size_available': 0, 'block_size': 131072, 'block_total': 327, 'block_available': 0, 'block_used': 327, 'inode_total': 658, 'inode_available': 0, 'inode_used': 658, 'uuid': 'N/A'}) **skipping**: [tnode3-ubuntu.local] => (item={'mount': '/boot', 'device': '/dev/sda2', 'fstype': 'ext4', 'options': 'rw,relatime', 'size_total': 1020702720, 'size_available': 687181824, 'block_size': 4096, 'block_total': 249195, 'block_available': 167769, 'block_used': 81426, 'inode_total': 65536, 'inode_available': 65220, 'inode_used': 316, 'uuid': '6ad800db-3eed-463f-994d-75acc8733af2'}) **skipping**: [tnode3-ubuntu.local] => (item={'mount': '/tmp', 'device': '/dev/sda4', 'fstype': 'ext4', 'options': 'rw,relatime', 'size_total': 8350298112, 'size_available': 7903719424, 'block_size': 4096, 'block_total': 2038647, 'block_available': 1929619, 'block_used': 109028, 'inode_total': 524288, 'inode_available': 524258, 'inode_used': 30, 'uuid': '2a7a4c11-fd2d-4c38-a159-6786929495c3'}) **skipping**: [tnode3-ubuntu.local] => (item={'mount': '/snap/snapd/20290', 'device': '/dev/loop6', 'fstype': 'squashfs', 'options': 'ro,nodev,relatime,errors=continue', 'size_total': 42860544, 'size_available': 0, 'block_size': 131072, 'block_total': 327, 'block_available': 0, 'block_used': 327, 'inode_total': 658, 'inode_available': 0, 'inode_used': 658, 'uuid': 'N/A'}) **skipping**: [tnode3-ubuntu.local] => (item={'mount': '/snap/core20/2105', 'device': '/dev/loop4', 'fstype': 'squashfs', 'options': 'ro,nodev,relatime,errors=continue', 'size_total': 67108864, 'size_available': 0, 'block_size': 131072, 'block_total': 512, 'block_available': 0, 'block_used': 512, 'inode_total': 12041, 'inode_available': 0, 'inode_used': 12041, 'uuid': 'N/A'})*
- 조건문을 사용할 때는 반복문뿐만 아니라 register 키워드로 작업 변수도 사용할 수 있습니다.
- 아래 예제는 systemctl 명령어로 rsyslog가 active인지를 체크하여 해당 결과를 result 변수에 저장하고, Print rsyslog status 태스크에서 result.stdout 값이 active 일 경우에만 해당 값을 출력합니다.
- 실행 : 각 호스트의 rsyslog 상태를 확인하고 해당 결과를 출력
# **ansible-playbook register-when.yml** ... *TASK [**Get rsyslog service status**] ************************************************************************************************************************************************************ changed: [tnode1-ubuntu.local] changed: [tnode2-ubuntu.local] changed: [tnode3-ubuntu.local] TASK [**Print rsyslog status**] ****************************************************************************************************************************************************************** ok: [**tnode1**-ubuntu.local] => { "msg": "Rsyslog status is **active**" } ok: [**tnode2**-ubuntu.local] => { "msg": "Rsyslog status is **active**" } ok: [**tnode3**-ubuntu.local] => { "msg": "Rsyslog status is **active**" }* - --- - hosts: all tasks: - name: Get rsyslog service status ansible.builtin.**command**: **systemctl** **is-active rsyslog** **register: result** - name: **Print rsyslog status** ansible.builtin.**debug**: msg: "Rsyslog status is {{ result.stdout }}" **when**: result.stdout == "**active**"
- 플레이북 파일 생성 : when 문의 item[’mount’]은 loop문에서 선언한 ansible_facts의 mounts 중 mount 값과 size_available 값을 사용해 구현.
핸들러 및 작업 실패 처리
앤서블 모듈은 멱등(idempotent)이 가능하도록 설계되어 있습니다. 즉 플레이북을 여러 번 실행해도 결과는 항상 동일합니다. 또한 플레이 및 해당 작업은 여러 번 실행할 수 있지만, 해당 호스트는 원하는 상태로 만드는 데 필요한 경우에만 변경됩니다.
하지만 한 작업에서 시스템을 변경해야 하는 경우 추가 작업을 실행해야 할 수도 있습니다. 예를 들어 서비스의 구성 파일을 변경하려면 변경 내용이 적용되도록 서비스를 다시 로드해야 합니다. 이때 핸들러는 다른 작업에서 트리거한 알림에 응답하는 작업이며, 해당 호스트에서 작업이 변경될 때만 핸들러에 통지합니다.
Handlers: running operations on change - https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html
- 앤서블 핸들러 - Link
- 앤서블에서 핸들러를 사용하려면 notify 문을 사용하여 명시적으로 호출된 경우에만 사용할 수 있습니다. 또한 핸들러를 정의할 때는 같은 이름으로 여러 개의 핸드러를 정의하기보다는 각각의 고유한 이름을 사용하여 정의하는 것이 좋습니다.
- 플레이북 생성 : rsyslog 재시작 태스크가 실행되면 notify 키워드를 통해 print msg라는 핸들러를 호출합니다. 핸들러는 handlers 키워드로 시작함.
--- - hosts: **tnode2** **tasks**: - name: restart rsyslog ansible.builtin.**service**: name: "rsyslog" state: **restarted** **notify**: - **print msg** **handlers**: - name: **print msg** ansible.builtin.**debug**: msg: "rsyslog is restarted" - ~/my-ansible/handler-sample.yml
- 실행 : tnode2 노드에 rsyslog 서비스를 재시작하고, print msg라는 핸들러를 호출해 “rsyslog..” 메시지를 출력
- # **ansible-playbook handler-sample.yml** ... *TASK [restart rsyslog] ********************************************************************************************************************************************************************** changed: [tnode2-ubuntu.local] RUNNING HANDLER [print msg] ***************************************************************************************************************************************************************** ok: [tnode2-ubuntu.local] => { "msg": "rsyslog is restarted" }* # 한번 더 실행 해보기 **ansible-playbook handler-sample.yml**
- 도전과제8 apache2 패키지를 apt 모듈을 통해서 설치 시, 핸들러를 호출하여 service 모듈로 apache2를 재시작 해보자
ansible.builtin.**apt** 모듈 - ****https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html
ansible.builtin.**dnf** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/dnf_module.html
**Error handling** in playbooks - https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_error_handling.html
- 작업 실패 무시
- 앤서블은 플레이 시 각 작업의 반환 코드를 평가하여 작업의 성공 여부를 판단합니다. 일반적으로 작업이 실패하면 앤서블은 이후의 모든 작업을 건너뜁니다.
- 하지만 작업이 실패해도 플레이를 계속 실행할 수 있습니다. 이는 **ignore_errors**라는 키워드로 구현할 수 있습니다.
- 플레이북 생성 : apache3 패키지를 설치하는 작업을 추가하고 비교해보자
~/my-ansible/ignore-example-2.yml--- - hosts : **tnode1** tasks: - name: Install apache3 ansible.builtin.**apt**: name: **apache3** state: latest - name: Print msg ansible.builtin.**debug**: msg: "Before task is ignored" - --- - hosts : **tnode1** tasks: - name: Install apache3 ansible.builtin.**apt**: name: **apache3** state: latest **ignore_errors: yes** - name: Print msg ansible.builtin.**debug**: msg: "Before task is ignored"
- ~/my-ansible/ignore-example-1.yml
- 실행
- # **ansible-playbook ignore-example-1.yml** ... # 결과 출력 내용을 비교해보자 **ansible-playbook ignore-example-2.yml ...**
- 작업 실패 후 핸들러 실행
- 앤서블은 일반적으로 작업이 실패하고 해당 호스트에서 플레이가 중단되면 이전 작업에서 알림을 받은 모든 핸들러가 실행되지 않습니다.
- 하지만 플레이북에 force_handlers: yes 키워드를 설정하면 이후 작업이 실패하여 플레이가 중단되어도 알림을 받은 핸들러가 호출됩니다.
- 플레이북 생성 : hosts 아래 force_handlers: yes ****를 추가하고, install apache2 태스크를 추가합니다
my-ansible/force-handler-2.yml--- - hosts: tnode2 **** **tasks**: - name: restart rsyslog ansible.builtin.service: name: "rsyslog" state: restarted notify: - print msg - name: **install apache3** ansible.builtin.apt: name: "apache3" state: latest **handlers**: - name: print msg ansible.builtin.debug: msg: "rsyslog is restarted" - --- - hosts: tnode2 **force_handlers: yes** **tasks**: - name: restart rsyslog ansible.builtin.service: name: "rsyslog" state: restarted notify: - print msg - name: **install apache3** ansible.builtin.apt: name: "apache3" state: latest **handlers**: - name: print msg ansible.builtin.debug: msg: "rsyslog is restarted"
- ~/my-ansible/force-handler-1.yml
- 실행
- # **ansible-playbook force-handler-1.yml** ... # 결과 출력 내용을 비교해보자 **ansible-playbook force-handler-2.yml ...**
**Error handling** in playbooks - https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_error_handling.html#defining-failure
ansible.builtin.**fail** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/fail_module.html
- 작업 실패 조건 지정 : 셸 스크립트 보다는 모듈 사용 하자!
- command 계열 모듈 사용 시
- 앤서블에서 셸 스크립트를 실행한 뒤 결과로 실패 또는 에러 메시지를 출력해도, 앤서블에서는 작업이 성공했다고 간주합니다.
- 어떤 명령이라도 실행된 경우에는 태스크 실행 상태를 항상 changed 로 한다.
명령을 실행한 경우에 반환 코드가 0이 아니면 failed로 처리한다.- 이런 경우 failed_when 키워드를 사용하여 작업이 실패했음을 나타내는 조건을 지정할 수 있습니다.
- 사용자 추가하는 스크립트 파일 확인
# 사용자 추가하는 스크립트 파일 내용 확인 wget <https://raw.githubusercontent.com/naleeJang/Easy-Ansible/refs/heads/main/chapter_07.3/adduser-script.sh> chmod +x adduser-script.sh ls -l adduser-script.sh # 해당 스크립트로 user1 생성해보기 ## "passwd: unrecognized option '--stdin'" 에러는 암호 적용 부분에서 발생 ./adduser-script.sh **./adduser-script.sh "user1" "qwe123"** tail -n 3 /etc/passwd sudo **userdel** -rf **user1** tail -n 3 /etc/passwd - ~/my-ansible/adduser-script.sh
- 사용자 추가하는 스크립트 파일을 tnode1에 복사 후 확인
- # 사용자 추가하는 스크립트 파일을 tnode1에 복사 **ansible** -m **copy** -a '**src**=/root/my-ansible/adduser-script.sh **dest**=/root/adduser-script.sh' **tnode1** # 복사 확인 **ssh tnode1 ls -l** /root *-rw-r--r-- 1 root root 846 Jan 13 22:09 adduser-script.sh* # 스크립트 실행 확인 ssh tnode1 --------------- chmod +x adduser-script.sh ./adduser-script.sh exit ---------------
- 플레이북 생성 : sh 실행을 위해서 shell 모듈 사용 태스크를 사용
~/my-ansible/failed-when-2.yml--- - hosts: **tnode1** **tasks**: - name: Run user add script ansible.builtin.**shell**: **/root/adduser-script.sh** **register**: command_result - name: Print msg ansible.builtin.**debug**: msg: "{{ command_result.stdout }}"- failed_when 조건식 : command_result.stdout 변수에 “Please…”라는 문자열이 있으면 **작업을 실패(fail)**로 처리하겠다는 의미
--- - hosts: **tnode1** tasks: - name: Run user add script ansible.builtin.shell: **/root/adduser-script.sh** register: command_result **failed_when**: "'Please input user id and password' **in** command_result.**stdout**" - name: Print msg ansible.builtin.debug: msg: "{{ command_result.stdout }}" - ~/my-ansible/failed-when-1.yml
- 실행
- # 실행 **ansible-playbook failed-when-1.yml** ... # 실행 후 user 가 추가되었는지 확인 ansible -m shell -a "tail -n 3 /etc/passwd" tnode1 # 실행 : 바로 위 실행 결과와 다른 점은 무엇인가? **ansible-playbook failed-when-2.yml** ... ***TASK** [Run user add script] ****************************************************************************************************************************************************************** fatal: [tnode1-ubuntu.local]: **FAILED**! => {"changed": true, "cmd": "/root/adduser-script.sh", "delta": "0:00:00.003903", "end": "2024-01-03 14:33:04.634716", "failed_when_result": true, "msg": "", "rc": 0, "start": "2024-01-03 14:33:04.630813", "stderr": "", "stderr_lines": [], "stdout": "Please input user id and password.\\nUsage: adduser-script.sh \\"user01 user02\\" \\"pw01 pw02\\"", "stdout_lines": ["Please input user id and password.", "Usage: adduser-script.sh \\"user01 user02\\" \\"pw01 pw02\\""]} ...* # 실행 후 user 가 추가되었는지 확인 ansible -m shell -a "tail -n 3 /etc/passwd" tnode1
- fail 시 사용자 정의 메시지를 출력할 수 있습니다. 다만 실습에 출력 내용이 거의 동일하게 되어 있긴 합니다
--- - hosts: tnode1 tasks: - name: Run user add script ansible.builtin.shell: **/root/adduser-script.sh** register: command_result **ignore_errors: yes** - name: Report script failure ansible.builtin.**fail**: **msg**: "{{ command_result.stdout }}" **when**: "'Please input user id and password' **in** command_result.**stdout**"- 실행
# 실행 **ansible-playbook failed-when-custom.yml** *... **TASK** [Run user add script] ****************************************************************************************************************************************************************** changed: [tnode1-ubuntu.local] **TASK** [Report script failure] **************************************************************************************************************************************************************** fatal: [tnode1-ubuntu.local]: **FAILED**! => {"changed": false, "msg": "Please input user id and password.\\nUsage: adduser-script.sh \\"user01 user02\\" \\"pw01 pw02\\""} ...* - ~/my-ansible/failed-when-custom.yml
- command 계열 모듈 사용 시
- </aside>
Blocks - https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_blocks.html
ansible.builtin.**find** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/find_module.html
- 앤서블 블록 및 오류처리
- 앤서블은 블록 block 이라는 오류를 제어하는 문법을 제공합니다. 블록은 작업을 논리적으로 그룹화하는 절이며, 작업 실행 방법을 제어하는 데 사용할 수 있습니다. 또한 블록을 통해 rescue 문과 always 문을 함께 사용함으로써 오류를 처리할 수 있습니다.
- block : 실행할 기본 작업을 정의함
- rescure : block 절에 정의된 작업이 실패할 경우 실행할 작업을 정의함
- always : block 및 rescue 절에 정의된 작업의 성공 또는 실패 여부와 관계 없이 항상 실행되는 작업을 정의함
- 플레이북 생성
- block 구문에서 failed_when 구문을 사용하여 result.msg 변수에 “Not..” 메시지 발견되면 실패 처리함
- rescue 구문은 block 정의 작업이 실패 시 실행되며, 해당 디렉터리가 없는 경우 생성함
- always 구문은 항상 실행되며, 여기서는 로그 파일을 생성함
--- - hosts: **tnode2** **vars**: **logdir**: /var/log/daily_log **logfile**: todays.log **tasks**: - name: Configure Log Env **block**: - name: Find Directory ansible.builtin.**find**: paths: "{{ logdir }}" register: result **failed_when**: "'Not all paths' in result.msg" **rescue**: - name: Make Directory when Not found Directory ansible.builtin.**file**: path: "{{ logdir }}" state: directory mode: '0755' **always**: - name: Create File ansible.builtin.**file**: path: "{{ logdir }}/{{ logfile }}" state: touch mode: '0644' - ~/my-ansible/block-example.yml
- 실행
- 다시 한번 더 실행
# ansible-playbook **block-example.yml ...** *TASK [Find Directory] *********************************************************************************************************************************************************************** ok: [tnode2-ubuntu.local] TASK [Create File] ************************************************************************************************************************************************************************** changed: [tnode2-ubuntu.local] PLAY RECAP ********************************************************************************************************************************************************************************** tnode2-ubuntu.local : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0* ****# tnode2에서 확인 : 디렉터리와 로그 파일 생성 확인 ansible -m shell -a "**ls -l /var/log/daily_log/**" **tnode2** *-rw-r--r-- 1 root root 0 Jan 3 **15:05** todays.log* - # ansible-playbook **block-example.yml ... *TASK** [Find Directory] *********************************************************************************************************************************************************************** [WARNING]: **Skipped** '/var/log/daily_log' path due to this access issue: '/var/log/daily_log' is not a directory fatal: [tnode2-ubuntu.local]: FAILED! => {"changed": false, "examined": 0, "failed_when_result": true, "files": [], "matched": 0, "msg": "Not all paths examined, check warnings for details", "skipped_paths": {"/var/log/daily_log": "'/var/log/daily_log' is not a directory"}} **TASK** [Make Directory when Not found Directory] ********************************************************************************************************************************************** **changed**: [tnode2-ubuntu.local] **TASK** [Create File] ************************************************************************************************************************************************************************** **changed**: [tnode2-ubuntu.local] PLAY RECAP ********************************************************************************************************************************************************************************** tnode2-ubuntu.local : ok=2 **changed=2** unreachable=0 failed=0 skipped=0 **rescued=1** ignored=0* # tnode2에서 확인 : 디렉터리와 로그 파일 생성 확인 ansible -m shell -a "**ls -l /var/log/daily_log/**" **tnode2** *-rw-r--r-- 1 root root 0 Jan 3 **15:00** todays.log*
- 앤서블은 블록 block 이라는 오류를 제어하는 문법을 제공합니다. 블록은 작업을 논리적으로 그룹화하는 절이며, 작업 실행 방법을 제어하는 데 사용할 수 있습니다. 또한 블록을 통해 rescue 문과 always 문을 함께 사용함으로써 오류를 처리할 수 있습니다.
롤 구조 소개 및 사용법
Roles - https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html
롤은 “플레이북 내용을 기능 단위로 나누어 공통 부품으로 관리/재사용하기 위한 구조”
- 플레이북에서 전달된 변수를 사용할 수 있습니다. 변수 미설정 시 기본값을 롤의 해당 변수에 설정하기도 합니다.
- 콘텐츠를 그룹화하여 코드를 다른 사용자와 쉽게 공유할 수 있습니다.
- 웹 서버, 데이터베이스 서버 또는 깃(Git) 리포지터리와 같은 시스템 유형의 필수 요소를 정의할 수 있습니다.
- 대규모 프로젝트를 쉽게 관리할 수 있습니다.
- 다른 사용자와 동시에 개발할 수 있습니다.
- 잘 작성한 롤은 앤서블 갤럭시를 통해 공유하거나 다른 사람이 공유한 롤을 가져올 수도 있습니다.
앤서블 롤 구조 : 롤은 하위 디렉터리 및 파일의 표준화된 구조에 의해 정의됩니다.
- 최상위 디렉터리는 롤 자체의 이름을 의미하고, 그 안은 tasks 및 handlers 등 롤에서 목적에 따라 정의된 하위 디렉터리로 구성됩니다.
- 아래 표는 롤의 최상의 디렉터리 아래에 있는 하위 디렉터리의 이름과 기능을 설명한 것 입니다.
하위 디렉터리 기능
| defaults | 이 디렉터리의 main.yml 파일에는 롤이 사용될 때 덮어쓸 수 있는 롤 변수의 기본값이 포함되어 있습니다. 이러한 변수는 우선순위가 낮으며 플레이에서 변경할 수 있습니다. |
| files | 이 디렉터리에는 롤 작업에서 참조한 정적 파일이 있습니다. |
| handlers | 이 디렉터리의 main.yml 파일에는 롤의 핸들러 정의가 포함되어 있습니다. |
| meta | 이 디렉터리의 main.yml 파일에는 작성자, 라이센스, 플랫폼 및 옵션, 롤 종속성을 포함한 롤에 대한 정보가 들어 있습니다. |
| tasks | 이 디렉터리의 main.yml 파일에는 롤의 작업 정의가 포함되어 있습니다. |
| templates | 이 디렉터리에는 롤 작업에서 참조할 Jinja2 템플릿이 있습니다. |
| tests | 이 디렉터리에는 롤을 테스트하는 데 사용할 수 있는 인벤토리와 test.yml 플레이북이 포함될 수 있습니다. |
| vars | 이 디렉터리의 main.yml 파일은 롤의 변수 값을 정의합니다. 종종 이러한 변수는 롤 내에서 내부 목적으로 사용됩니다. 또한 우선순위가 높으며, 플레이북에서 사용될 때 변경되지 않습니다. |
- 롤 생성
- 롤 생성 명령어 확인
- *# (옵션) 이전 실습 yml 파일 삭제 rm -r *.yml* # 서브 명령어 확인 : init 롤 생성 서브 명령어 **ansible-galaxy role -h** usage: ansible-galaxy role [-h] ROLE_ACTION ... positional arguments: ROLE_ACTION **init Initialize new role with the base structure of a role.** remove Delete roles from roles_path. delete Removes the role from Galaxy. It does not remove or alter the actual GitHub repository. list Show the name and version of each role installed in the roles_path. search Search the Galaxy database by tags, platforms, author and multiple keywords. import Import a role into a galaxy server setup Manage the integration between Galaxy and the given source. info View more details about a specific role. install Install role(s) from file(s), URL(s) or Ansible Galaxy options: -h, --help show this help message and exit
- 롤 생성 및 디렉터리 구조 확인
# 롤 생성 **ansible-galaxy role init my-role** - Role my-role was created successfully # **tree ./my-role/** my-role/ ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml 8 directories, 8 files - ~/my-ansible/my-role/…
- 롤을 이용한 플레이북 개발 : 간단한 롤 플레이북을 개발해보자
- 프로세스 → 각 구조에 맞게 태스크를 작성 하자
- 롤이 호출되면 현재 호스트의 운영체제 버전이 지원 운영체제 목록에 포함되는지 확인한다.
- 운영체제가 CentOS나 레드햇이면 httpd 관련 패키지를 dnf 모듈을 이용해 설치한다.
- 설치가 끝나면 제어 노드의 files 디렉터리 안에 있는 index.html 파일을 관리 노드의 /var/www/html 디렉터리에 복사한다.
- 파일 복사가 끝나면 httpd 서비스를 재시작한다.
- 롤 구조
- 롤 이름 : my-role
- tasks (메인 태스크)
- install service : httpd 관련 패키지 설치
- copy html file : index.html 파일 복사
- files (정적 파일)
- index.html
- handlers (핸들러)
- restart service : httpd 서비스 재시작
- defaults (가변 변수) : 메인 태스크에서 사용된 변수 선언
- service_title
- vars (불변 변수) : 메인 태스크와 핸들러에서 사용된 변수 선언
- service_name : 서비스명
- src_file_path : 복사할 파일 경로
- dest_file_path : 파일이 복사될 디렉터리 경로
- httpd_packages : httpd 관련 패키지 목록
- supported_distros : 지원 OS 목록
- 메인 태스크 작성
- 첫 번째 태스크인 install service에는 플레이북에서 변수로 정의한 서비스명을 함께 출력합니다. 그리고 ansible.builtin.apt 모듈을 이용하여 httpd 관련 패키지를 설치합니다. 이때 관련 패키지는 여러 개이며 loop 문을 사용합니다.
- 서비스 설치가 끝나면 ansible.builtin.copy 모듈을 이용하여 파일을 복사하고, 복사가 끝나면 restart servie라는 핸들러를 호출합니다.
- --- # tasks file for my-role - name: install service {{ service_title }} ansible.builtin.**apt**: name: "{{ item }}" state: latest **loop**: "{{ httpd_packages }}" **when**: ansible_facts.distribution in supported_distros - name: copy conf file ansible.builtin.**copy**: src: "{{ src_file_path }}" dest: "{{ dest_file_path }}" **notify**: - restart service
- cd ~/my-ansible/my-role
- index.html 정적 파일 생성
echo "Hello! Ansible" > files/index.html - ~/my-ansible/my-role/files/index.html
- 핸들러 작성 : 특정 태스크가 끝나고 그 다음에 수행해야 하는 태스크, service 모듈을 이용하여 서비스를 재시작
--- # handlers file for my-role - name: restart service ansible.builtin.**service**: name: "{{ service_name }}" state: **restarted** - ~/my-ansible/my-role/handlers/main.yml
- defaults (가변 변수) 작성 : 외부로부터 재정의 될 수 있는 가변 변수, service_title을 외부에서 받아 수정 가능하도록 함
echo '**service_title**: "Apache Web Server"' >> defaults/main.yml - ~/my-ansible/my-role/defaults/main.yml
- vars (불변 변수) 작성 : 한번 정의되면 외부로부터 변수 값을 수정 할 수 없음. 롤 내의 플레이북에서만 사용되는 변수로 정의하는 것이 좋음
--- # vars file for my-role service_name: **apache2** src_file_path: **../files/index.html** dest_file_path: **/var/www/html** httpd_packages: - **apache2** - **apache2-doc** supported_distros: - **Ubuntu** - my-ansible/my-role/vars/main.yml
- 프로세스 → 각 구조에 맞게 태스크를 작성 하자
ansible.builtin.**import_role** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/import_role_module.html
ansible.builtin.**include_role** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_role_module.html
ansible.posix.**firewalld** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/posix/firewalld_module.html
- 플레이북에 롤 추가하기 : 롤 실행을 위해 롤을 호출해주는 플레이북 필요
- 플레이북에 롤을 추가하려면 ansible.builtin.**import_role** 와 ansible.builtin.**include_role** 모듈 2가지 방법이 있습니다.
- ansible.builtin.**import_role**은 롤을 정적으로 추가하며, ansible.builtin.**include_role**는 롤을 동적으로 추가합니다.
- 정적으로 롤을 추가한다는 건 고정된 롤을 추가하겠다는 의미이며, 동적으로 추가한다는 건 반복문이나 조건문에 의해 롤이 변경될 수 있다는 의미입니다.
- 플레이북 파일 생성 : import_role 모듈을 이용하여 my-role 롤을 추가~/my-ansible/role-example.yml
- --- - hosts: **tnode1** **tasks**: - name: Print start play ansible.builtin.**debug**: msg: "Let's start role play" - name: Install Service by role ansible.builtin.**import_role**: name: **my-role**
- cd .. pwd
- 실행 : Print 태스트 후 my-role 내의 각 태스트와 핸들러가 순차적으로 수행
- # **ansible-playbook role-example.yml** ... ***TASK** [Print start play] ***************************************************************************************************************** ok: [tnode1-ubuntu.local] => { "msg": "Let's start role play" } **TASK** [**my-role** : install service **Apache Web Server**] ************************************************************************************** changed: [tnode1-ubuntu.local] => (item=**apache2**) changed: [tnode1-ubuntu.local] => (item=**apache2-doc**) TASK [**my-role** : **copy** conf file] ********************************************************************************************************* changed: [tnode1-ubuntu.local] RUNNING **HANDLER** **[my-role** : restart service] ********************************************************************************************* changed: [tnode1-ubuntu.local] ...* # 확인 **curl tnode1** Hello! Ansible
- default/main.yml 파일에 정의된 가변 변수인 service_title을 롤을 호출하는 곳에서 재정의하는 플레이북으로 수정 후 확인
--- - hosts: **tnode1** **tasks**: - name: Print start play ansible.builtin.**debug**: msg: "Let's start role play" - name: Install Service by role ansible.builtin.**import_role**: name: **my-role vars: service_title: Httpd**- 실행
# **ansible-playbook role-example.yml** ... *TASK [my-role : install service **Httpd**] ************************************************************************************************** ok: [tnode1-ubuntu.local] => (item=apache2) ok: [tnode1-ubuntu.local] => (item=apache2-doc) ...* # 확인 **curl tnode1** Hello! Ansible - ~/my-ansible/role-example.yml
- index.html 정적 파일 변경 적용 후 실행해보기
- # echo "Hello! CloudNet@" > my-role/files/index.html **ansible-playbook role-example.yml** # 확인 **curl tnode1**
- hosts 를 tnode2 로 변경 후 실행 → curl tnode2 호출 확인
- 플레이북에서 Roles 섹션 사용하기 : 롤 추가하는 또 다른 방법은 roles 섹션에 롤을 나열
- roles 섹션은 tasks 섹션과 매우 유사하나 작업 목록이 아닌 롤 목록으로 구성되어 있습니다.
- 실습을 위해서 tnode1에 firewalld 설치 후 기본 설정tnode1 에 TCP 80(http) 접속 확인
- ping -c 1 tnode1 **curl tnode1** *curl: (7) Failed to connect to 10.10.13.147 port 80 after 46 ms: Couldn't connect to server*
- # tnode1 진입 **ssh tnode1** ----------------------- # firewalld 설치 apt install firewalld -y systemctl status firewalld # 기본 정책 확인 firewall-cmd --list-all ... ***services**: dhcpv6-client **ssh*** ... # 영구적으로 public zone에서 TCP 8080 포트 추가 설정 firewall-cmd --permanent --zone=public --add-port=8080/tcp # firewalld에 rule 적용 : 아래 명령 실행 전까지 추가한 rule은 적용되지 않음 firewall-cmd --list-all firewall-cmd --**reload** firewall-cmd --list-all ***public** target: default icmp-block-inversion: no interfaces: sources: **services**: dhcpv6-client **ssh** **ports: 8080/tcp** protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:* # 로컬에서 apache2 web 접속 확인 curl localhost # tnode1 빠져나오기 exit -----------------------
- my-role2 롤 생성
# 롤 생성 **ansible-galaxy role init my-role2** # 디렉터리 구조 확인 tree my-role2 - my-ansible/my-role2/…
- 메인 태스크 작성 : firewalld 방화벽 서비스에 http 서비스를 추가하는 태스크와 reload 태스크를 추가
--- # tasks file for my-role2 - name: Config firewalld ansible.posix.**firewalld**: service: "{{ **item** }}" permanent: true state: enabled **loop**: "{{ **service_port** }}" - name: Reload firewalld ansible.builtin.**service**: name: **firewalld** state: **reloaded** - my-ansible/my-role2/tasks/main.yml
- vars (불변 변수) 작성 : http 포트와 https 포트를 정의
--- # defaults file for my-role2 **service_port**: - http - https - my-ansible/my-role2/vars/main.yml
- 플레이북 작성
--- - hosts: **tnode1** **roles**: - **my-role** - **my-role2** **tasks**: - name: Print finish role play ansible.builtin.**debug**: msg: "Finish role play" - my-ansible/role-example2.yml
- 실행
- # --check 옵션 사용 시 실제 수행되기 전에 어떻게 플레이 될지 미리 시뮬레이션 해볼 수 있음 **ansible-playbook --check role-example2.yml** *... TASK [my-role2 : Config firewalld] *********************************************************************************************************************************** changed: [tnode1-ubuntu.local] => (item=http) changed: [tnode1-ubuntu.local] => (item=https) TASK [my-role2 : Reload firewalld] *********************************************************************************************************************************** changed: [tnode1-ubuntu.local] ...* # 실행 **ansible-playbook role-example2.yml** # 확인 **curl tnode1** # firewalld 정책 확인 ansible -m shell -a "**firewall-cmd --list-all**" tnode1 *public target: default icmp-block-inversion: no interfaces: sources: services: dhcpv6-client **http https** ssh ports: 22/tcp protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:*
- 가변 변수 전달 확인
--- - hosts: tnode1 roles: **- role: my-role service_title: "Httpd Web" - role: my-role2** tasks: - name: Print finish role play ansible.builtin.debug: msg: "Finish role play"- 실행
# 실행 **ansible-playbook role-example3.yml** ... *TASK [my-role : install service **Httpd Web**] *************************************************************************************************************************** ok: [tnode1-ubuntu.local] => (item=apache2) ok: [tnode1-ubuntu.local] => (item=apache2-doc)* ... - my-ansible/role-example3.yml
ansible.builtin.**uri** 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/uri_module.html
- 특수 작업 섹션 : roles 섹션과 함께 자주 사용 - pre_tasks , post_tasks
- pre_tasks 섹션은 tasks와 유사한 작업 목록이지만 roles 섹션의 롤보다 먼저 실행됩니다. 또한 pre-tasks 섹션은 작업을 핸들러에 알리면 해당 핸들러 작업이 롤 또는 일반 태스크 전에 실행됩니다.
- post_tasks 섹션은 tasks 및 tasks에서 알림을 받은 핸들러 다음에 실행됩니다.
- 플레이북 작성 : 특수 작업 섹션인 pre_tasks, post_tasks 포함되며 roles 섹션과 tasks 섹션(→ 호출한 handlers 섹션) 포함
--- - hosts: **tnode1** **pre_tasks**: - name: Print Start role ansible.builtin.debug: msg: "Let's start role play" **roles**: - role: my-role - role: my-role2 **tasks**: - name: Curl test ansible.builtin.**uri**: url: http://**tnode1** **return_content**: true register: curl_result **notify**: Print result **changed_when**: true **post_tasks**: - name: Print Finish role ansible.builtin.debug: msg: "Finish role play" **handlers**: - name: Print result ansible.builtin.debug: msg: "{{ curl_result.content }}"- uri return_content 가 true 경우 응답 본문 있으면 성공, 없을 경우 실패 - Link
- ~/my-ansible/special_role.yml
- 실행 : 어떤 순서로 태스크와 롤이 실행되는지 확인
- pre_tasks 섹션에 태스크 → my-role → my-role2 → tasks(curl test) ⇒ notify 구문에 의해 handlers 태스크 실행 → 마지막 post_tasks 실행
# **ansible-playbook special_role.yml** ***PLAY** [tnode1-ubuntu.local] ******************************************************************************************************************************************* **TASK** [Gathering Facts] *********************************************************************************************************************************************** ok: [tnode1-ubuntu.local] **TASK** [**Print Start role**] ********************************************************************************************************************************************** ok: [tnode1-ubuntu.local] => { "msg": "Let's start role play" } **TASK** [my-role : install service Apache Web Server] ******************************************************************************************************************* ok: [tnode1-ubuntu.local] => (item=apache2) ok: [tnode1-ubuntu.local] => (item=apache2-doc) **TASK** [my-role : copy conf file] ************************************************************************************************************************************** ok: [tnode1-ubuntu.local] **TASK** [my-role2 : Config firewalld] *********************************************************************************************************************************** ok: [tnode1-ubuntu.local] => (item=http) ok: [tnode1-ubuntu.local] => (item=https) **TASK** [my-role2 : Reload firewalld] *********************************************************************************************************************************** changed: [tnode1-ubuntu.local] **TASK** [Curl test] ***************************************************************************************************************************************************** changed: [tnode1-ubuntu.local] RUNNING **HANDLER** [Print result] *************************************************************************************************************************************** ok: [tnode1-ubuntu.local] => { "msg": "Hello! CloudNet@\\n" } **TASK** [Print Finish role] ********************************************************************************************************************************************* ok: [tnode1-ubuntu.local] => { "msg": "Finish role play" }* - tnode1 에 firewalld 삭제
- ansible -m shell -a "systemctl stop firewalld" tnode1 ansible -m shell -a "apt remove firewalld -y" tnode1
- (심화) changed_when vs failed_when 이해 - Link
--- - hosts: **webnode** **vars**: web_url: http://**10.10.1.100** roles: - role: myrole.httpd post_tasks: - name: Check http service ansible.builtin.**uri**: url: "{{ web_url }}" **return_content**: true register: check_result **failed_when**: check_result.status != **200** - name: Print result ansible.builtin.**debug**: var: check_result.status - failed_when 활용 예시 : 웹 서버 체크 후 200응답이 아닐 경우 작업 실패
Tags (업데이트)
- Tags 소개 : 태그를 사용하여 선택한 작업을 실행하거나 건너뛰게 설정 - Docs
- 플레이북이 큰 경우 전체 플레이북을 실행하는 대신 특정 부분만 실행하는 것이 유용할 수 있습니다.
- Ansible 태그를 사용하면 이를 수행할 수 있습니다. 태그를 사용하여 선택한 작업을 실행하거나 건너뛰는 과정은 두 단계로 이루어집니다.
- 작업에 태그를 추가할 수 있습니다. 태그는 개별적으로 추가하거나 블록, 플레이, 역할 또는 가져오기에서 태그를 상속받아 추가할 수 있습니다.
- 플레이북을 실행할 때 태그를 선택하거나 건너뛸 수 있습니다.
- 해당 tags키워드는 플레이북의 '사전 처리 pre processing' 단계에 포함되며, 실행 가능한 작업을 결정할 때 높은 우선순위를 갖습니다.
- Adding tags with the tags keyword 태그 사용
- 단일 작업 또는 포함 항목에 태그를 추가할 수 있습니다.
- 또한 블록 block, 플레이 play, 역할 role 또는 가져오기 import 수준에서 태그를 정의하여 여러 작업에 태그를 추가할 수도 있습니다.
- tags 키워드는 항상 태그를 정의하고 작업에 추가하며, 실행할 작업을 선택하거나 건너뛰지는 않습니다.
- 플레이북을 실행할 때 명령줄에서만 태그를 기반으로 작업을 선택하거나 건너뛸 수 있습니다.
- 가장 기본적인 수준에서, 개별 작업에 하나 이상의 태그를 적용할 수 있습니다. playbooks, task files 또는 role 내의 작업에 태그를 추가할 수 있습니다.
- 다음은 두 작업에 서로 다른 태그를 지정하는 예입니다.
- **tasks**: **- name: Install the servers** ansible.builtin.yum: name: - httpd - memcached state: present **tags: - packages - webservers** **- name: Configure the service** ansible.builtin.template: src: templates/src.j2 dest: /etc/foo.conf **tags: - configuration**
- 여러 작업에 동일한 태그를 적용할 수 있습니다. 이 예시에서는 여러 작업에 "ntp"라는 동일한 태그를 지정합니다.
- 만약 플레이북에서 --tags ntp 작업을 실행한다면 , Ansible은 태그가 지정된 세 가지 작업은 실행 하고 태그가 없는 한 가지 작업은 건너뜁니다.
- --- # file: roles/common/tasks/main.yml - name: Install ntp ansible.builtin.yum: name: ntp state: present **tags: ntp** - name: Configure ntp ansible.builtin.template: src: ntp.conf.j2 dest: /etc/ntp.conf notify: - restart ntpd **tags: ntp** - name: Enable and run ntpd ansible.builtin.service: name: ntpd state: started enabled: true **tags: ntp** - name: Install NFS utils ansible.builtin.yum: name: - nfs-utils - nfs-util-lib state: present **tags: filesharing**
- 핸들러 handlers 에 태그 추가
- 핸들러는 알림을 받았을 때만 실행되는 특수한 작업 유형으로, 모든 태그를 무시하며 선택 대상이 될 수 없습니다.
- 블록 blocks 에 태그 추가
- 플레이의 모든 작업에 태그를 적용하는 것이 아니라 일부 작업에만 태그를 적용하려면 블록을 사용 하고 블록 수준에서 태그를 정의하세요.
- 예를 들어, 위에 표시된 NTP 예제를 블록을 사용하도록 수정할 수 있습니다.
# myrole/tasks/main.yml **- name: ntp tasks** **tags: ntp** **block**: - name: Install ntp ansible.builtin.yum: name: ntp state: present - name: Configure ntp ansible.builtin.template: src: ntp.conf.j2 dest: /etc/ntp.conf notify: - restart ntpd - name: Enable and run ntpd ansible.builtin.service: name: ntpd state: started enabled: true - name: Install NFS utils ansible.builtin.yum: name: - nfs-utils - nfs-util-lib state: present tags: filesharing- tag선택 사항이 block 오류 처리를 포함한 다른 대부분의 논리보다 우선한다는 점에 유의하십시오.
- block 의 작업에 태그를 설정하지만 rescue 섹션이나 always 섹션에 태그를 설정하지 않으면 해당 섹션의 작업을 포함하지 않는 태그가 트리거되는 것을 방지할 수 있습니다.
- **block**: - debug: msg=run with tag, but always fail failed_when: true **tags: example** rescue: - debug: msg=I always run because the block always fails, except if you select to only run 'example' tag always: - debug: msg=I always run, except if you select to only run 'example' tag- 이 예제는 지정 없이 호출하면 3개의 작업을 모두 실행하지만, --tags example을 지정하여 실행하면 첫 번째 작업만 실행합니다 .
- plays 에 태그 추가
- 플레이에 포함된 모든 작업에 동일한 태그를 지정해야 하는 경우, 플레이 수준에서 태그를 추가할 수 있습니다.
- 예를 들어, NTP 작업만 포함된 플레이가 있다면 전체 플레이에 태그를 지정할 수 있습니다.
- hosts: all **tags: ntp** tasks: - name: Install ntp ansible.builtin.yum: name: ntp state: present - name: Configure ntp ansible.builtin.template: src: ntp.conf.j2 dest: /etc/ntp.conf notify: - restart ntpd - name: Enable and run ntpd ansible.builtin.service: name: ntpd state: started enabled: true - hosts: fileservers **tags: filesharing** tasks: # ... - roles 에 태그 추가 (3가지 방법)
- 역할 아래에 태그를 설정하여 역할의 모든 작업에 동일한 태그 또는 태그를 추가합니다.
- 역할 키워드와 함께 플레이북에 역할을 정적으로 통합하면 Ansible은 해당 역할의 모든 작업에 정의한 태그를 추가합니다. 예를 들어:
- 역할 수준에서 태그를 추가하면 모든 작업에 태그가 지정될 뿐만 아니라 해당 역할의 종속 작업에도 태그가 지정됩니다.
roles: - role: webserver vars: port: 5000 **tags: [ web, foo ] or:** --- - hosts: webservers roles: - role: foo **tags: - bar - baz** # using YAML shorthand, this is equivalent to: # - { role: foo, tags: ["bar", "baz"] } - 플레이북의 static import_role 에 태그를 설정하여 역할의 모든 작업에 동일한 태그 또는 태그를 추가합니다.
- 정적 import_role 및 import_tasks 문에서 가져온 모든 작업에 태그 또는 태그를 적용할 수도 있습니다:
--- - hosts: webservers tasks: - name: Import the foo role import_role: name: foo **tags: - bar - baz** - name: Import tasks from foo.yml import_tasks: foo.yml tags: [ web, foo ] - role 자체 내의 개별 task이나 block에 태그 또는 태그를 추가합니다. 이 접근 방식은 역할 내의 일부 작업을 선택하거나 건너뛸 수 있는 유일한 방법입니다.
- 역할 내의 작업을 선택하거나 건너뛸 수 있도록 하려면 개별 작업이나 블록에 태그를 설정하고 플레이북의 동적 include_rolole을 사용한 다음 동일한 태그 또는 태그를 포함 항목에 추가해야 합니다.
- 이 접근 방식을 사용한 다음 --tags foo로 플레이북을 실행하면 Ansible이 포함 항목 자체와 태그 foo가 있는 역할 내의 모든 작업을 실행합니다.
- 아래 includes 에 태그 추가 예시 참고.
- 역할 아래에 태그를 설정하여 역할의 모든 작업에 동일한 태그 또는 태그를 추가합니다.
- includes 에 태그 추가
- 플레이북의 dynamic includes 항목에 태그를 적용할 수 있습니다. You can apply tags to dynamic includes in a playbook
- 개별 작업의 태그와 마찬가지로, include_* 작업의 태그는 include 항목 자체에만 적용되며 포함된 파일이나 역할 내의 작업에는 적용되지 않습니다.
- dynamic includes 항목에 내 태그를 추가한 다음 --tags mytags로 해당 플레이북을 실행하면 Ansible은 include 항목 자체를 실행하고, 포함된 파일이나 역할 내의 모든 작업을 내 태그로 지정한 후, 해당 태그 없이 포함된 파일이나 역할 내의 모든 작업을 건너뛸 수 있습니다.
- See Selectively running tagged tasks in reusable files for more details.
- 다른 작업에 태그를 추가하는 것과 동일한 방식으로 태그를 추가합니다:
--- # file: roles/common/tasks/main.yml - name: Dynamic reuse of database tasks **include_tasks: db.yml tags: db**- 태그는 role의 dynamic includes에만 추가할 수 있습니다. 이 예에서는 foo 태그가 bar role 내부의 작업에는 적용되지 않습니다:
--- - hosts: webservers tasks: - name: Include the bar role include_role: name: bar tags: - foo - includes 에 대한 태그 상속 inheritance : blocks 및 apply 키워드
- 기본적으로 Ansible은 include_rolole과 include_tasks를 사용하는 dynamic reuse 에 태그 상속을 적용하지 않습니다.
- include 항목에 태그를 추가하면 include 항목 자체에만 적용되며 포함된 파일이나 역할의 어떤 작업에도 적용되지 않습니다.
- 이를 통해 role 또는 작업 파일 내에서 선택한 작업을 실행할 수 있습니다. 태그 상속을 원한다면 imports 를 사용하는 것이 좋습니다.
- 그러나 하나의 플레이북에 포함된 항목과 가져오기 항목을 모두 사용하면 진단하기 어려운 버그가 발생할 수 있습니다.
- 이러한 이유로 플레이북에서 역할이나 작업을 재사용하기 위해 include_*를 사용하고 하나의 포함 항목에 태그 상속이 필요한 경우 Ansible은 두 가지 해결 방법을 제공합니다. apply 키워드를 사용할 수 있습니다:
- - name: Apply the db tag to the include and to all tasks in db.yml **include_tasks**: file: db.yml # adds 'db' tag to tasks within db.yml **apply**: tags: db # adds 'db' tag to this 'include_tasks' itself tags: db
- 혹은 block 를 사용할 수 있습니다.
- - **block**: - name: Include tasks from db.yml **include_tasks**: db.yml tags: db
- Special tags
- Ansible은 특별한 동작을 위해 always, never, tagged, untagged, all 등 여러 태그 이름을 예약합니다.
- always 과 never 모두 작업 자체를 태그하는 데 주로 사용되며, 나머지 세 가지는 실행하거나 건너뛸 태그를 선택할 때 사용됩니다.
- Always 과 Never
- Ansible은 특별한 동작을 위해 여러 태그 이름을 예약합니다. 그 중 두 개는 always 태그와 never 태그입니다.
- always 태그를 작업이나 플레이에 할당하면, Ansible은 특정 작업을 건너뛰거나(--skip-tags always) 해당 작업에 정의된 다른 태그를 제외하고는 항상 해당 작업을 실행하거나 플레이합니다.
tasks: - name: Print a message ansible.builtin.debug: msg: "Always runs" **tags: - always** - name: Print a message ansible.builtin.debug: msg: "runs when you use specify tag1, all(default) or tagged" **tags: - tag1** - name: Print a message ansible.builtin.debug: msg: "always runs unless you explicitly skip, like if you use ``--skip-tags tag2``" **tags: - always - tag2**- 내부 사실 수집 작업은 기본적으로 '항상' 태그가 지정되어 있습니다. The internal fact gathering task is tagged with ‘always’ by default.
- 하지만 태그를 플레이에 적용하고 직접 건너뛸 경우(--태그 생략) 또는 태그를 사용할 때 간접적으로 건너뛸 수 있습니다.
- 작업이나 플레이에 never 태그를 할당하는 경우, Ansible은 특별히 요청하지 않는 한(--tags never) 또는 해당 작업에 정의된 다른 태그를 제외하고 해당 작업이나 플레이를 건너뛸 수 있습니다.
tasks: - name: Run the rarely-used debug task, either with ``--tags debug`` or ``--tags never`` ansible.builtin.debug: msg: '{{ showmevar }}' **tags: [ never, debug ]** - 플레이북을 실행할 때 태그 선택 또는 건너뛰기 Selecting or skipping tags when you run a playbook
- 작업에 태그를 추가하고, 포함, 차단, 재생, 역할 및 가져오기를 완료한 후, Ansible-PlayBook을 실행할 때 태그를 기반으로 작업을 선택적으로 실행하거나 건너뛸 수 있습니다.
- Ansible은 명령줄에서 전달하는 태그와 일치하는 태그로 모든 작업을 실행하거나 건너뛸 수 있습니다.
- 블록 또는 플레이 수준, 역할, 가져오기에서 태그를 추가한 경우 해당 태그는 블록 내의 모든 작업, 재생, 역할 또는 가져오기에서 적용됩니다.
- 여러 태그가 있는 역할이 있고 다른 시간에 역할의 하위 집합을 호출하고 싶다면 동적 포함과 함께 사용하거나 역할을 여러 역할로 나누세요.
- Ansible-playbook은 다섯 가지 태그 관련 명령줄 옵션을 제공합니다:
- 태그가 지정된 모든 작업을 실행하지만, 태그가 지정되지 않은 경우는 예외입니다(기본 동작)
- --tags all - run all tasks, tagged and untagged except if never (default behavior).
- tag1 또는 tag2 (always 태그된 작업도 포함) 작업만 실행합니다.
- --tags tag1,tag2 - run only tasks with either the tag tag1 or the tag tag2 (also those tagged always).
# For example, to run only tasks and blocks tagged either configuration or packages in a very long playbook: ansible-playbook example.yml --tags "configuration,packages" - tag3 또는 tag4 또는 never 태그가 있는 작업을 제외한 모든 작업을 실행합니다.
- --skip-tags tag3,tag4 - run all tasks except those with either the tag tag3 or the tag tag4 or never.
# To run all tasks except those tagged packages: ansible-playbook example.yml --skip-tags "packages" - 태그가 하나 이상 있는 작업만 실행합니다. (never 태그를 덮어쓰지 않음)
- --tags tagged - run only tasks with at least one tag (never overrides).
- 태그가 없는 작업만 실행합니다.(always 를 덮어씀)
- --tags untagged - run only tasks with no tags (always overrides).
- 태그가 지정된 모든 작업을 실행하지만, 태그가 지정되지 않은 경우는 예외입니다(기본 동작)
- 모든 태스크 실행 : To run all tasks, even those excluded because are tagged never
- ansible-playbook example.yml --tags "all,never"
- tag1,tag3 은 실행하고 tag4는 건너뜀 : Run tasks with tag1 or tag3 but skip tasks that also have tag4:
- ansible-playbook example.yml --tags "tag1,tag3" --skip-tags "tag4"
- 태그 우선순위 Tag precedence
- **건너뛰기(--skip-tags)**는 항상 명시적인 태그보다 우선합니다. Skipping always takes precedence over explicit tags
- 예를 들어 --tags와 --skip-tags를 모두 지정하면 후자가 우선합니다.
- 예를 들어 --tags tag1, tag3, tag4 --skip-tags tag3는 tag1 또는 tag4로 태그된 작업만 실행하지만, 작업에 다른 작업 중 하나가 있더라도 tag3에서는 실행되지 않습니다
- 태그 사용 결과 미리보기 Previewing the results of using tags
- 역할이나 플레이북을 실행할 때 어떤 작업에 어떤 태그가 있는지, 어떤 태그가 있는지 또는 어떤 태그가 존재하는지 모르거나 기억하지 못할 수 있습니다.
- Ansible은 태그된 플레이북을 관리하는 데 도움이 되는 두 가지 명령줄 플래그를 제공합니다:
- --list-tags : 사용 가능한 태그 목록 생성
- --list-tasks : --tags tagname 또는 --skip-tags tagname과 함께 사용할 경우 태그가 지정된 작업의 미리보기를 생성합니다.
- 예를 들어, 구성 작업의 태그가 플레이북, 역할 또는 작업 파일에서 구성인지 conf인지 모르는 경우, 작업을 실행하지 않고도 사용 가능한 모든 태그를 표시할 수 있습니다:
- ansible-playbook example.yml **--list-tags**
- 태그 구성 및 패키지가 있는 작업을 모르는 경우 태그를 전달하고 --list-tasks를 추가할 수 있습니다.
- Ansible은 작업을 나열하지만 실행하지 않습니다.
- ansible-playbook example.yml **--tags "configuration,packages" --list-tasks**
- 이러한 명령줄 플래그에는 한 가지 제한 사항이 있습니다: 동적으로 포함된 파일이나 역할 내에서 태그나 작업을 표시할 수 없습니다.
- 재사용 가능한 파일에서 태그가 지정된 작업을 선택적으로 실행하기 Selectively running tagged tasks in reusable files
- task 또는 block 수준에서 태그가 정의된 role이나 task 파일이 있는 경우, static import 대신 dynamic include을 사용하는 경우 플레이북에서 태그가 지정된 작업을 선택적으로 실행하거나 건너뛸 수 있습니다.
- You must use the same tag on the included tasks and on the include statement itself.
- 예를 들어, 태그가 지정된 작업과 태그가 지정되지 않은 작업이 있는 파일을 만들 수 있습니다:
# mixed.yml **tasks:** - name: Run the task with no tags ansible.builtin.debug: msg: this task has no tags - name: Run the tagged task ansible.builtin.debug: msg: this task is tagged with mytag **tags: mytag** **- block:** - name: Run the first block task with mytag # ... - name: Run the second block task with mytag # ... **tags: - mytag**- 그리고 위의 작업 파일을 플레이북에 포함시킬 수도 있습니다:
# myplaybook.yml - hosts: all tasks: - name: Run tasks from mixed.yml **include_tasks: name: mixed.yml tags: mytag**- Ansible-playbook -i host myplaybook.yml --tags "mytags"로 플레이북을 실행하면 Ansible은 태그 없이 작업을 건너뛰고 태그된 개별 작업을 실행하며 블록 내 두 작업을 실행합니다.
- 또한 항상 태그된 상태로 팩트 수집(암시적 작업)을 실행할 수도 있습니다.
- 태그 상속: 여러 작업에 태그 추가 Tag inheritance: adding tags to multiple tasks
- 모든 작업에 태그 줄을 추가하지 않고 여러 작업에 동일한 태그 또는 태그를 적용하려면 재생 또는 차단 수준에서 태그를 정의하거나 역할을 추가하거나 파일을 가져올 때 태그를 정의할 수 있습니다. Ansible은 모든 하위 작업에 종속성 체인을 따라 태그를 적용합니다. 역할과 가져오기를 통해 Ansible은 역할 섹션 또는 가져오기에서 설정한 태그를 역할 또는 파일 내의 개별 작업 또는 블록에 설정된 모든 태그에 추가합니다. 이를 태그 상속이라고 합니다. 태그 상속은 모든 작업에 태그를 지정할 필요가 없기 때문에 편리합니다. 그러나 태그는 여전히 개별 작업에 적용됩니다.
- 재생, 블록, 역할 키워드 및 정적 가져오기를 통해 Ansible은 태그 상속을 적용하여 정의한 태그를 재생, 블록, 역할 또는 가져온 파일 내의 모든 작업에 추가합니다. 그러나 태그 상속은 include_rolole 및 include_tasks를 사용한 동적 재사용에는 적용되지 않습니다. 동적 재사용(포함)에서는 정의한 태그가 포함 자체에만 적용됩니다. 태그 상속이 필요한 경우 정적 가져오기를 사용하세요. 플레이북의 나머지 사용 항목에 포함된 항목이 포함되어 있어 중요한 항목을 사용할 수 없는 경우, 해당 항목에 대한 태그 상속을 참조하여 이 동작을 해결하는 방법을 확인하세요: 블록 및 적용 키워드를 참조하세요.
- 플레이북의 동적 포함 항목에 태그를 적용할 수 있습니다. 개별 작업의 태그와 마찬가지로, 포함_* 작업의 태그는 포함 항목 자체에만 적용되며 포함된 파일이나 역할 내의 작업에는 적용되지 않습니다. 동적 포함 항목에 내 태그를 추가한 다음 --tags mytags로 해당 플레이북을 실행하면 Ansible은 포함 항목 자체를 실행하고, 포함된 파일이나 역할 내의 모든 작업을 내 태그로 지정한 후, 해당 태그 없이 포함된 파일이나 역할 내의 모든 작업을 건너뛸 수 있습니다. 자세한 내용은 재사용 가능한 파일에서 태그된 작업을 선택적으로 실행하는 것을 참조하십시오.
- Tags 실습
- 두 작업에 서로 다른 태그를 지정하고 플레이북 실행 시 선택 혹은 건너뛰어 보기
- # cat << EOF > tags1.yml --- - hosts: web tasks: - name: Install the servers ansible.builtin.apt: name: - htop state: present tags: - packages - name: Restart the service ansible.builtin.service: name: rsyslog state: restarted tags: - service EOF # ansible-playbook **tags1.yml --list-tags** *playbook: tags1.yml play #1 (web): web TAGS: [] TASK TAGS: [packages, service]* # ansible-playbook **tags1.yml --tags "packages" --list-tasks** *playbook: tags1.yml play #1 (web): web TAGS: [] tasks: Install the servers TAGS: [packages]* # packages 태그가 포함된 task 만 실행 확인 ansible-playbook **tags1.yml --tags "packages"** *... TASK [Install the servers] ********************************************************************** ok: [tnode1] ok: [tnode2] ...* # packages 태그가 포함된 task 만 제외하고 실행 확인 : --skip-tags ansible-playbook **tags1.yml --skip-tags "packages"** *... TASK [Restart the service] ********************************************************************** changed: [tnode2] changed: [tnode1] ...* # 태그가 하나 이상 있는 작업 실행 : --tags tagged ansible-playbook **tags1.yml --tags tagged** *... TASK [Install the servers] ********************************************************************** ok: [tnode1] ok: [tnode2] TASK [Restart the service] ********************************************************************** changed: [tnode2] changed: [tnode1] ...*
앤서블 갤럭시
롤을 생성할 때 사용했던 앤서블 갤럭시 ansible-galaxy 에 대해 알아보자
ansible-galaxy - https://docs.ansible.com/ansible/latest/cli/ansible-galaxy.html
- 앤서블 갤럭시 소개 : 롤 공유, 다만 롤은 검증되지 않은 것이 대부분이기 때문에 사용 시 주의해야 합니다
- Roles : 키워드 ‘postgres’ 검색 + 분류 ‘Download count‘
- 검색될 롤 확인 - Link
- 롤 설치 방법, 커밋 commit 한 날짜, 다른 유저가 다운로드한 횟수, 설치 가능한 운영체제, 지원 가능한 버전 등 내용 확인할 수 있다

- Installs and configures PostgreSQL server on RHEL/CentOS or Debian/Ubuntu servers.
- Ansible Galaxy
- 명령어를 이용한 앤서블 갤럭시 활용 : 앤서블 갤럭시로부터 롤 가져오기
- 롤 서브 명령어 확인
- **ansible-galaxy role -h** usage: ansible-galaxy role [-h] ROLE_ACTION ... positional arguments: ROLE_ACTION init Initialize new role with the base structure of a role. **remove** Delete roles from roles_path. delete Removes the role from Galaxy. It does not remove or alter the actual GitHub repository. **list** Show the name and version of each role installed in the roles_path. **search** Search the Galaxy database by tags, platforms, author and multiple keywords. import Import a role into a galaxy server setup Manage the integration between Galaxy and the given source. **info** View more details about a specific role. **install** Install role(s) from file(s), URL(s) or Ansible Galaxy options: -h, --help show this help message and exit
- 롤 검색
- **ansible-galaxy role search postgresql --platforms Ubuntu** *Found 270 roles matching your search: Name Description ---- ----------- aaronpederson.postgresql PostgreSQL is a powerful, open source object-relational database system. It has more than 15 years of active> alainvanhoof.alpine_postgresql PostgreSQL for Alpine Linux alikins.postgresql PostgreSQL server for Linux. ...*
- 롤 상세 정보 확인
- **ansible-galaxy role info geerlingguy.postgresql** *Role: geerlingguy.postgresql **description**: PostgreSQL server for Linux. commit: a7723eb017c618611da37531e5961632d9ae03b0 **commit_message**: Fedora support time for 37 and 38. created: 2023-05-08T20:49:59.794667Z **download_count**: 2454875 github_branch: master github_repo: ansible-role-postgresql github_user: geerlingguy id: 10986 imported: 2023-06-15T23:23:15.275804-04:00 modified: 2023-10-29T18:44:43.644380Z **path**: ('/root/.ansible/roles', '/usr/share/ansible/roles', '/etc/ansible/roles') upstream_id: 12427 username: geerlingguy*
- 롤 가져오기
# -p 옵션으로 롤이 설치될 디렉터리 경로 지정 **ansible-galaxy role install -p roles geerlingguy.postgresql** # 확인 **tree roles** *roles └── geerlingguy.postgresql ├── defaults │ └── main.yml ├── handlers │ └── main.yml ...* **ansible-galaxy role list -p roles** *# /root/my-ansible/roles - geerlingguy.postgresql, 3.5.0 # /etc/ansible/roles [WARNING]: - the configured path /root/.ansible/roles does not exist. [WARNING]: - the configured path /usr/share/ansible/roles does not exist.* # (옵션) 앤서블 환경 설정에 롤 디렉터리 설정 ## my-ansible/ansible.cfg 파일 편집 [defaults] inventory = ./inventory remote_user = root ask_pass = false **roles_path = ./roles** ... **~~inject_facts_as_vars = false~~** <- **실습 사용 롤이 예전 facts 를 사용하니 이 옵션은 제거하자** # 확인 **ansible-galaxy role list** **ansible-galaxy role list -p roles**- VSCODE에서 메인 태스크 등 확인 : my-ansible/roles/tasks/main.yml , my-ansible/roles/vars/Ubuntu-22.yml
--- # Variable configuration. - include_tasks: variables.yml # Setup/install tasks. - include_tasks: setup-Archlinux.yml when: ansible_os_family == 'Archlinux' - include_tasks: setup-Debian.yml when: ansible_os_family == 'Debian' - include_tasks: setup-RedHat.yml when: ansible_os_family == 'RedHat' - include_tasks: initialize.yml - include_tasks: configure.yml - name: Ensure PostgreSQL is started and enabled on boot. service: name: "{{ postgresql_daemon }}" state: "{{ postgresql_service_state }}" enabled: "{{ postgresql_service_enabled }}" # Configure PostgreSQL. - import_tasks: users.yml - import_tasks: databases.yml - import_tasks: users_props.yml--- __postgresql_version: "14" __postgresql_data_dir: "/var/lib/postgresql/{{ __postgresql_version }}/main" __postgresql_bin_path: "/usr/lib/postgresql/{{ __postgresql_version }}/bin" __postgresql_config_path: "/etc/postgresql/{{ __postgresql_version }}/main" __postgresql_daemon: postgresql __postgresql_packages: - postgresql - postgresql-contrib - libpq-dev postgresql_python_library: python3-psycopg2 - my-ansible/roles/…
- 가져온 롤을 이용하여 설치 : 설치 중 root 권한 필요(become: yes)
--- - hosts: **tnode1** **roles**: - **geerlingguy.postgresql**- 설치 실행
**ansible-playbook role-galaxy.yml** *PLAY [tnode1-ubuntu.local] **************************************************************************************************************************************** TASK [Gathering Facts] ******************************************************************************************************************************************** ok: [tnode1-ubuntu.local] TASK [geerlingguy.postgresql : include_tasks] ********************************************************************************************************************* included: /root/my-ansible/roles/geerlingguy.postgresql/tasks/variables.yml for tnode1-ubuntu.local **TASK** [geerlingguy.postgresql : Include OS-specific variables (**Debian**).] ******************************************************************************************* ok: [tnode1-ubuntu.local] ...*- 설치 확인
ssh tnode1 **systemctl status postgresql** - my-ansible/role-galaxy.yml
- 가져온 롤 삭제
- ansible-galaxy role **remove** geerlingguy.postgresql ansible-galaxy role list rm -r roles
- 도전과제7 앤서블 갤럭시에서 관심 있는 롤을 검색하여 해당 롤을 사용하는 플레이북을 만들어서 롤을 통한 애플리케이션을 배포해보자
콘텐츠 컬렉션
앤서블이 처음 개발되었을 때는 사용되는 모듈이 모두 핵심 소프트웨어 패키지의 일부로 포함되었습니다. 그런데 모듈 수가 늘어나면서 업스트림 프로젝트에서 모듈을 관리하기가 더 어려워졌습니다. 모든 모듈에는 고유한 이름이 필요하고, 모듈 업데이트를 핵심 앤서블 코드에 대한 업데이트와 동기화해야 했습니다.
그래서 개발한 것이 바로 앤서블 콘텐츠 컬렉션입니다. 앤서블 콘텐츠 컬렉션을 사용하면 핵심 앤서블 코드 업데이트와 모듈 및 플러그인에 대한 업데이트가 분리됩니다. 그리고 플레이북에서 사용할 수 있는 일련의 관련 모듈, 역할, 기타 플러그인을 제공합니다. 그렇기 때문에 벤더와 개발자는 앤서블 릴리스와 독립적으로 컬렉션을 자신의 속도에 맞게 유지, 관리하고 배포할 수 있습니다.
앤서블 콘텐츠 컬렉션을 사용하면 유연성도 향상됩니다. 지원되는 모듈을 모두 설치하는 대신 필요한 콘텐츠만 설치할 수 있습니다. 특정 버전(이전 버전 또는 이후 버전)의 컬렉션을 선택하거나 레드햇 또는 벤더가 지원하는 컬렉션 버전 또는 커뮤니티에서 제공하는 버전 중에서 선택할 수도 있습니다.
Ansible 2.9 이상은 콘텐츠 컬렉션을 지원합니다. 업스트림 앤서블은 Ansible Base 2.10 및 Ansible Core 2.11의 코어 Ansible 코드에서 대부분의 모듈을 번들 해제하고 컬렉션에 배치했습니다. 레드햇 앤서블 오토메이션 플랫폼 2.2는 자동화 실행 기능을 상속하는 Ansible Core 2.13 기반의 자동화 실행 환경을 제공합니다.
- 명령어를 이용한 앤서블 콘텐츠 컬렉션
- 명령어 확인
-
ansible-galaxy collection -h usage: ansible-galaxy collection [-h] COLLECTION_ACTION ... positional arguments: COLLECTION_ACTION download Download collections and their dependencies as a tarball for an offline install. init Initialize new collection with the base structure of a collection. build Build an Ansible collection artifact that can be published to Ansible Galaxy. publish Publish a collection artifact to Ansible Galaxy. install Install collection(s) from file(s), URL(s) or Ansible Galaxy list Show the name and version of each collection installed in the collections_path. verify Compare checksums with the collection(s) found on the server and the installed copy. This does not verify dependencies. options: -h, --help show this help message and exit -
# 특정 버전으로 설치 **ansible-galaxy collection install openstack.cloud:2.1.0** # 설치 확인 ansible-galaxy collection list **ansible-galaxy collection list openstack.cloud** # /root/.ansible/collections/ansible_collections Collection Version --------------- ------- openstack.cloud 2.1.0 **tree /home/ubuntu/.ansible/collections/ansible_collections -L 3** ... - 앤서블이 설치된 프로젝트 환경에 설치된 컬렉션 확인
-
ansible-galaxy collection list # /usr/lib/python3/dist-packages/ansible_collections Collection Version ----------------------------- ------- amazon.aws 6.5.0 ansible.netcommon 5.3.0 ansible.posix 1.5.4 ansible.utils 2.12.0 ansible.windows 1.14.0 arista.eos 6.2.2 awx.awx 22.7.0 azure.azcollection 1.19.0 ... tree /usr/lib/python3/dist-packages/ansible_collections -L 1 /usr/lib/python3/dist-packages/ansible_collections ├── amazon ├── ansible ├── ansible_community.py ├── ansible_release.py ├── arista ├── awx ├── azure ├── check_point ├── chocolatey ... - 컬렉션 삭제 및 설치
-
# ansible-galaxy collection list openstack.cloud # /usr/lib/python3/dist-packages/ansible_collections Collection Version --------------- ------- openstack.cloud 2.2.0 tree /usr/lib/python3/dist-packages/ansible_collections/openstack -L 3 ... # 삭제 sudo rm -rf /usr/lib/python3/dist-packages/ansible_collections/openstack* # 확인 ansible-galaxy collection list openstack.cloud ansible-galaxy collection list - 설치
-
# 특정 버전으로 설치 ansible-galaxy collection install openstack.cloud:2.1.0 # 설치 확인 ansible-galaxy collection list ansible-galaxy collection list openstack.cloud # /root/.ansible/collections/ansible_collections Collection Version --------------- ------- openstack.cloud 2.1.0 tree /home/ubuntu/.ansible/collections/ansible_collections -L 3 ... - 오프라인 환경 지원을 위해서, 컬렉션을 tar 파일 형태로 다운로드 가능
-
# -p 디렉터리 지정 ansible-galaxy collection download -p ./collection openstack.cloud # 확인 tree collection/ collection/ ├── openstack-cloud-2.2.0.tar.gz └── requirements.yml tar tvf collection/openstack-cloud-2.2.0.tar.gz ... cat collection/requirements.yml collections: - name: openstack-cloud-2.2.0.tar.gz version: 2.2.0 ansible-galaxy collection list ... ansible-galaxy collection list openstack.cloud ...
- tar 파일로 컬렉션 설치
# tar 파일로 컬렉션 설치 **ansible-galaxy collection install ./collection/openstack-cloud-2.2.0.tar.gz** # 확인 **ansible-galaxy collection list** *# /root/.ansible/collections/ansible_collections Collection Version ----------------------------- ------- **openstack.cloud 2.2.**0 # /usr/lib/python3/dist-packages/ansible_collections Collection Version ----------------------------- ------- amazon.aws 6.5.0 ansible.netcommon 5.3.0 ...* **ansible-galaxy collection list openstack.cloud**
도전 해보세요![To_be_next_challanged]
- 도전과제1 생성된 user를 ansible.builtin.**user** 모듈을 통해서 제거해보자 - Example
- 도전과제2 관리 대상에 uptime을 ansible.builtin.**debug** 모듈을 통해서 확인해보자 - Example
- 도전과제3 팩트를 사용하여 3개의 VM의 ‘커널 버전’과 ‘운영체제 종류’를 출력해보자
- 도전과제4 linux user1~10(10명) 를 반복문을 통해서 생성 후 확인 후 삭제를 해보자
- 도전과제5 loop 반복문 중 sequence 를 이용하여 /var/log/test1 ~ /var/log/test100 100개 파일(file 모듈)을 생성 확인 후 삭제를 해보자 - Link1 Link2
- 도전과제6 Ubuntu OS이면서 fqdn으로 tnode1 인 경우, debug 모듈을 사용하여 OS 정보와 fqdn 정보를 출력해보자
- 도전과제7 반복문+조건문을 함께 사용해보자 - Link
- 도전과제8 apache2 패키지를 apt 모듈을 통해서 설치 시, 핸들러를 호출하여 service 모듈로 apache2를 재시작해보자
- 도전과제9 block rescure always 키워드를 사용한 플레이북을 작성하여 테스트 해보자 - Link
- 도전과제10 앤서블 갤럭시에서 관심 있는 롤을 검색하여 해당 롤을 사용하는 플레이북을 만들어서 롤을 통한 애플리케이션을 배포해보자