앤서블 롤(Roles)
롤은 관리/재사용의 목적으로 "플레이북 내용을 기능 단위로 나눈 모듈 단위를 말합니다.
앤서블 갤럭시를 통해 롤을 공유하고 사용자들이 만든 잘 짜인 롤을 가져올 수도 있습니다.
롤 생성하기
ansible-galaxy
명령어로 롤을 생성하고 확인할 수 있습니다.
# 롤 생성
# : ansible-galaxy role init --init-path <생성할 롤 경로> <롤 이름>
mkdir roles
ansible-galaxy role init --init-path ./roles myrol
# 롤 생성 확인
role list --roles-path roles
- myrole, (unknown version)
tree roles
앤서블 롤의 구조는 다음과 같은 구성요소로 구성되어 있습니다.
앤서블 롤은 용도에 맞게 디렉토리로 구분되어 있기 때문에 관리가 용이할 뿐만아니라,
다른 사람들과의 쉽게 협업할 수 있습니다.
그러면, 앤서블 롤을 활용하여 인프라 환경구성 자동화 실습을 해보도록 하겠습니다.
인프라 구성 자동화 실습
앤서블 사전 설정 및 문법(반복문, 조건문, 핸들러 등) 설명은 이전 포스팅을 참고 부탁드립니다.
Case 1 : NTP 서버 설치 및 설정하기
- facts변수를 이용해서 운영체제의 맞는 설치 패키지를 분기 처리 합니다.
- jinja2 템플릿을 이용하여 설정 파일(chrony.conf )을 작성하고 대상 호스트로 복사합니다.
- 재사용을 위해 롤을 이용하여 설계하고 작성합니다.
먼저, roles 디렉터리 하위에 인벤토리와 chrony 이름의 롤을 생성합니다.
# 인벤토리 생성
cat <<EOT > inventory
[tnode]
tnode1
tnode2
tnode3
EOT
# 롤 생성
root@server:~/roles# ansible-galaxy role init chrony
- Role chrony was created successfully
root@server:~/roles# ls
chrony inventory
root@server:~/roles# tree chrony
chrony
├── README.md
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
롤 디렉터리 vars/main.yml파일을 열어 변수를 정의합니다.
vars/main.yml
---
# vars file for myrole.chrony
package_name : chrony
service_name : chronyd
fedora_os:
- RedHat
- CentOS
chrony.conf.j2 파일을 생성합니다. 외부로부터 입력받은 {{ ntp_server }}
변수를 사용해서 동적으로 파일을 활용할 수 있습니다. (jinja 템플릿 문법으로 동작, 파일 확장자 =. j2 )
chrony/templates/chrony.conf.j2
# 파일 내용 작성
root@server:~/roles# cat << EOF > chrony/templates/chrony.conf.j2
> pool {{ ntp_server }}
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
allow 10.10.0.0/16
local stratum 10
keyfile /etc/chrony.keys
leapsectz right/UTC
logdir /var/log/chrony
> EOF
핸들러에는 chrony 서비스를 재시작하는 태스크를 작성합니다.
- 설정파일이 세팅이 되면 chrony 서비스를 재시작되도록 설계
chrony/handlers/main.yml
# 핸들러 작성
---
# handlers file for chrony
- name: Restart chrony
ansible.builtin.service:
name: "{{ service_name }}"
state: restarted
메인 태스크 작성
ansible_facts.distribution
팩트 변수를 이용해서 운영체제에 맞게 분기처리합니다.- 운영체제에 맞게 작성한 태스크를 가져오도록 합니다.
- 다른 파일에서 태스크를 가져오는
include
모듈을 사용합니다.
- 다른 파일에서 태스크를 가져오는
chrony/tasks/main.yml
# 메인 테스크 작성
---
# tasks file for chrony
- name: Import playbook
ansible.builtin.include_tasks:
file: "{{ ansible_facts.distribution }}.yml"
- name: Copy chrony config file when Ubuntu
ansible.builtin.template:
src: chrony.conf.j2
dest: /etc/chrony/chrony.conf
notify: "Restart chrony"
when: ansible_facts.distribution == "Ubuntu"
- name: Copy chrony config file when Other OS
ansible.builtin.template:
src: chrony.conf.j2
dest: /etc/chrony.conf
notify: "Restart chrony"
when: ansible_facts.distribution in fedora_os
root@server:~/roles#
메인 태스크에서 호출하는 운영체제별 태스크를 작성합니다.
- Ubuntu는
apt
설치 패키지 매니저 사용 - CentOS/RHEL은
dnf
설치 패키지 매니저 사용
chrony/tasks/RedHat.yml
---
- name: Install chrony using dnf
ansible.builtin.dnf:
name: "{{ package_name }}"
state: latest
chrony/tasks/CentOS.yml
---
- name: Install chrony using dnf
ansible.builtin.dnf:
name: "{{ package_name }}"
state: latest
chrony/tasks/Ubuntu.yml
---
- name: Install chrony using apt
ansible.builtin.apt:
name: "{{ package_name }}"
state: latest
마지막으로, 메인 플레이북인 install_ntp.yml 파일을 작성합니다.
- chrony 롤 추가
- ntp_server 변수 선언
install_ntp.yml
# roles 디렉토리와 같은 뎁스에 위치.
---
- hosts: tnode
roles:
- role: myrole.chrony
ntp_server: 0.kr.pool.ntp.org
플레이북을 실행합니다.
# 문법체크
ansible-playbook --syntax-check install_ntp.yml
# 플레이북 실행 : when문을 통해 해당 운영체제에 따라 특정 태스크만 실행됨
ansible-playbook -i inventory install_ntp.yml
ansible-adhoc을 이용하여 chrony 설정이 잘 되었는지 확인합니다.
ansible -m shell -a "cat /etc/chrony/chrony.conf" tnode1
ansible -m shell -a "systemctl status chrony" tnode1
이제, 실습을 통해 설정 파일을 작성하고 서비스를 재시작하는 nginx, apache와 같은 서비스들도 자동화할 수 있습니다.
Case 2 : 네트워크 IP 설정하기
- OS가 Ubuntu일 경우, netplan, CentOS/RHEL일 경우, nmcli 모듈을 사용합니다.
- 두 가지 타입의 롤을 만들어서 사용합니다.
- ethernet 타입의 네트워크 IP를 설정합니다.
- 앤서블 팩트를 통해 실제 호스트에 존재하는 네트워크 인터페이스를 확인합니다.
netplan
nmcli
모듈을 분리하여 두 가지 타입의 롤을 생성합니다.
# 롤 생성
ansible-galaxy role init nmcli
ansible-galaxy role init netplan
# 롤 확인
ansible-galaxy role list --roles-path roles/
# /root/ansible/roles
- nmcli, (unknown version)
- netplan, (unknown version)
nmcli 롤의 태스크 파일 작성합니다.
ansible_facts.interfaces
앤서블 팩트 변수를 사용하여 호스트에 네트워크 인터페이스를 확인할 수 있습니다.- 추가할 네트워크 관련 정보는
{{ net_info }}
외부 변수를 통해 주입받습니다.
nmcli/tasks/main.yml
# 팩트 변수 확인
ansible tnode -m setup | grep -i interface
# nmcli 태스크 작성
---
# tasks file for myrole.nmcli
- name: Setup nic ip
community.general.nmcli:
type: ethernet
conn_name: "{{ item.con_name }}"
ip4: "{{ item.ip_addr }}"
gw4: "{{ item.ip_gw }}"
dns4: "{{ item.ip_dns }}"
state: present
loop: "{{ net_info }}"
when: net_info[0].con_name in ansible_facts.interfaces
netpaln은 설정 파일을 통해 네트워크를 구성합니다.
따라서, Jinja2 템플릿을 이용해서 설정 파일을 작성합니다.
netplan/templates/01-netplan-ansible.yaml.j2
# This is the network config written by 'ansible'
network:
version: 2
ethernets:
{% for item in net_info %}
{{ item.con_name }}:
dhcp4: no
dhcp6: no
addresses: [{{ item.ip_addr }}]
gateway4: {{ item.ip_gw }}
nameservers:
addresses: [{{ item.ip_dns }}]
{% endfor %}
netplan에 태스크 파일 및 핸들러 파일 작성
notify
키워드를 통해서 설정파일이 정상적으로 복사되면 핸들러를 호출합니다.netplan apply
명령어가 수행되어야 네트워크 설정이 적용됨.
netplan/tasks/main.yml
---
# tasks file for myrole.netplan
- name: Copy netplan file
ansible.builtin.template:
src: 01-netplan-ansible.yaml.j2
dest: /etc/netplan/01-netplan-ansible.yaml
when: net_info[0].con_name in ansible_facts.interfaces
notify: Netplan apply
netplan/handlers/main.yml
---
# handlers file for myrole.netplan
- name: Netplan apply
ansible.builtin.command: netplan apply
마지막으로, 롤을 호출할 메인 플레이북 작성합니다
- 롤에 전달할 변수들을 vars 섹션에 선언
ansible.builtin.include_role
모듈을 이용하여 OS 맞게 태스크 파일을 분기처리
set_ip.yml
---
- hosts: tnode1
vars:
fedora_os:
- CentOS
- RedHat
net_info:
- con_name: ens5
ip_addr: 10.10.1.11/24
ip_gw: 10.10.1.1
ip_dns: 127.0.0.53
tasks:
- name: Include role in CentOS and RedHat
ansible.builtin.include_role:
name: myrole.nmcli
when: ansible_facts.distribution in fedora_os
- name: Include role in Ubuntu
ansible.builtin.include_role:
name: myrole.netplan
when: ansible_facts.distribution == "Ubuntu"
- hosts: tnode2
vars:
fedora_os:
- CentOS
- RedHat
net_info:
- con_name: ens7
ip_addr: 10.10.1.12/24
ip_gw: 10.10.1.1
ip_dns: 127.0.0.53
tasks:
- name: Include role in CentOS and RedHat
ansible.builtin.include_role:
name: myrole.nmcli
when: ansible_facts.distribution in fedora_os
- name: Include role in Ubuntu
ansible.builtin.include_role:
name: myrole.netplan
when: ansible_facts.distribution == "Ubuntu"
먼저 실행 전 네트워크 정보를 확인합니다.
# 실행 전 tnode1 정보 확인
ssh tnode1 ls /etc/netplan
ssh tnode1 cat /etc/netplan/50-cloud-init.yaml
ssh tnode1 ip -br -c addr
ssh tnode1 ip -c route
ssh tnode1 nslookup blog.cloudneta.net
#
ansible -m shell -a "cat /var/log/syslog | grep -i dhcp" tnode1
ssh tnode1 sudo dhclient -v ens5
플레이북을 실행합니다.
ansible-playbook --syntax-check set_ip.yml
# 문법 체크
ansible-playbook --syntax-check set_ip.yml
# 플레이북 실행
ansible-playbook set_ip.yml
...
# 실행 후 tnode1 정보 확인
ssh tnode1 ls /etc/netplan
ssh tnode1 cat /etc/netplan/01-netplan-ansible.yaml
ssh tnode1 ip -br -c addr
ssh tnode1 ip -c route
ssh tnode1 nslookup blog.cloudneta.net
Case 3 : 쿠버네티스 애드온 구성하기
종종 쿠버네티스 클러스터를 새로 구성하였을 때, 쿠버네티스 애드온 도구들을 매번 수동으로 설치하곤 했었는데,
앤서블을 통해 자동화 해보도록 합니다.
- 쿠버네티스 관련 도구(k9s, krew, helm)를 구성합니다.
- 확장성을 고려해 두고 플레이북을 설계합니다.
- 추후에 태스크를 언제든지 분리하고 확장할 수 있도록 작성합니다.
- 이번 실습은 대상 호스트의 OS가 Ubuntu이고 Bash 쉘을 사용하여야 합니다.
먼저, 롤을 생성합니다.
# 롤 생성
ansible-galaxy role init k8s_addon
# 롤 확인
ansible-galaxy role list --roles-path roles/
# /root/ansible/roles
- k8s_addon, (unknown version)
Addon의 종류별로 태스크 파일을 나누어 작성합니다.
k8s_addon/tasks/k9s.yml
# # k9s 다운로드 및 설치
- name: 작업 디렉토리 생성
ansible.builtin.file:
path: "/tmp/k9s"
state: directory
- name: k9s tar.gz 파일 다운로드
get_url:
url: "https://github.com/derailed/k9s/releases/download/v0.30.6/k9s_Linux_amd64.tar.gz"
dest: "/tmp/k9s/k9s.tar.gz"
- name: k9s tar.gz 파일 압축 해제
ansible.builtin.unarchive:
src: "/tmp/k9s/k9s.tar.gz"
dest: "/tmp/k9s"
- name: k9s를 /usr/local/bin으로 이동
ansible.builtin.command:
cmd: "mv /tmp/k9s/k9s /usr/local/bin/"
- name: k9s 실행 권한 설정
ansible.builtin.command:
cmd: "chmod +x /usr/local/bin/k9s"
- name: 작업 디렉토리 삭제
ansible.builtin.file:
path: "/tmp/k9s"
state: absent
k8s_addon/tasks/helm.yml
# Helm 플러그인 설치
- name: Helm 설치스크립트 다운로드
get_url:
url: "https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3"
dest: "/tmp/get_helm.sh"
mode: "0700"
- name: 설치 스크립트 실행
command: "/tmp/get_helm.sh"
- name: 설치 스크립트 삭제
ansible.builtin.file:
path: "/tmp/get_helm.sh"
state: absent
ansible에서는 쉘 실행 시, /bin/sh
를 사용하기 때문에 source 명령어 시 오류가 발생한다.
따라서, executable을 이용해 /bin/bash를 사용하도록 직접 지정해 주면 해결된다.
k8s_addon/tasks/krew.yml
---
# krew 플러그인 설치
- name: 작업 디렉토리 생성
ansible.builtin.file:
path: "/tmp/krew"
state: directory
- name: 설치 스크립트 생성
ansible.builtin.copy:
content: |
#!/bin/bash
set -x
cd "$(mktemp -d)" || exit 1
OS="$(uname | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')"
KREW="krew-${OS}_${ARCH}"
wget "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" || exit 1
tar zxvf "${KREW}.tar.gz" || exit 1
./"${KREW}" install krew || exit 1
dest: "/tmp/krew/install_krew.sh"
mode: "0755"
- name: 설치 스크립트 실행
ansible.builtin.shell: "/tmp/krew/install_krew.sh"
- name: PATH 추가
ansible.builtin.lineinfile:
path: "~/.bashrc"
line: 'export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"'
create: yes
- name: Source .bashrc
ansible.builtin.shell: "source ~/.bashrc"
args:
executable: /bin/bash
- name: Krew 플러그인 설치
ansible.builtin.command: "kubectl krew install {{ item }}"
loop: "{{ krew_plugins }}"
register: result
- name: Print command result
ansible.builtin.debug:
var: result.stdout_lines
- name: 작업 디렉토리 삭제
ansible.builtin.file:
path: "/tmp/k9s"
state: absent
이제, 메인 태스크 yml을 작성합니다.
k8s_addon/tasks/main.yml
---
- name: Install addon
ansible.builtin.include_tasks:
file: "{{ item.name }}.yml"
loop: "{{ k8s_addons }}"
when: item.enabled == true
vars 파일에는 설치할 플러그인 종류와 릴리즈 정보들을 작성합니다.
k8s_addon/vars/main.yml
---
# vars file for k8s addon
# k9s 릴리즈 버전
k9s_release: v0.30.6
# 설치할 krew 플러그인
krew_plugins:
- ctx
- df-pv
- doctor
- example
- get-all
- images
- neat
- ns
- podevents
- resource-capacity
- rolesum
- sick-pods
- stern
마지막으로, 롤을 호출할 메인 플레이북 작성합니다.
- 설치할 addon을
k8s_addons.enabled
플래그 변수를 통해 쉽게 선택할 수 있습니다.- enabled: true => 설치, k8s_addons: false => 미설치
install_k8s_addon.yml
---
- hosts: controlplane
roles:
- role: k8s_addon
k8s_addons:
- name: helm
enabled: true
- name: k9s
enabled: true
- name: krew
enabled: true
플레이북을 실행하고 결과를 확인합니다.
ansible-playbook install_k8s_addon.yml -vv
# k9s 확인
k9s version
# helm 확인
helm version
# krew 플러그인 확인
kubectl krew list
Reference
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html
'Automation > Ansible' 카테고리의 다른 글
앤서블(Ansible) 세마포어(Semaphore UI) - 4주차_2 (3) | 2024.02.08 |
---|---|
앤서블(Ansible) 보안설정 및 모니터링 자동화 - 4주차 (0) | 2024.02.08 |
앤서블(Ansible) 반복문, 조건문, 핸들러 및 작업 실패 처리 - 2주차 (0) | 2024.01.21 |
앤서블(Ansible) 개념 및 기본 사용 - 1주차 (0) | 2024.01.12 |