네트워크 IP 설정하기
OS가 우분투일 경우에는 netplan 파일을 이용하여 IP를 설정한다
- netplan은 파일이므로 사전에 netplan 파일 구조를 확인하고 jinja2 템플릿으로 작성한다.
OS가 CentOS/레드햇일 경우에는 nmcli 모듈을 사용하여 IP를 설정한다.
- community.general.nmcli 모듈 - https://docs.ansible.com/ansible/latest/collections/community/general/nmcli_module.html
예제에서는 ethernet 타입의 네트워크 IP를 설정한다.
IP 설정 관련 정보는 메인 플레이북에서 변수로 정의한다.
변수로 정의한 네트워크 인터페이스가 실제 호스트에 존재하는지 앤서블 팩트를 통해 확인한다.
플레이북 설계
우분투 일 경우 netplan을 사용하는 롤과 CentOS/레드햇 일 경우 nmcli 모듈을 사용하는 롤로 구성합니다.
그리고 OS의 종류에 따라 해당 롤을 호출하는 방식으로 메인 플레이북을 설계하였습니다.
ansible.builtin.template 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html
플레이북 개발
1. 플레이북 개발 및 실행 : nic2를 추가하기 번거로워서 동작 적용은 하지 않음
- 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
#
mkdir ~/ansible-project/chapter_10.1
cd ~/ansible-project/chapter_10.1
# ansible.cfg, inventory 파일 작성
cat <<EOT> ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ansible
ask_pass = false
inject_facts_as_vars = false
roles_path = ./roles
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT
2. 롤 생성
#
ansible-galaxy role init --init-path ./roles myrole.nmcli
ansible-galaxy role init --init-path ./roles myrole.netplan
# 확인
ansible-galaxy role list
tree roles -L 2
3. myrole.nmcli 에 태스크 파일 작성
#~/chapter_10.1/roles/myrole.nmcli/tasks/main.yml
---
# 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
- nmcli 모듈을 사용하여 외부로부터 받은 변수로 네트워크 IP를 설정.
- 이때 변수는 배열 방식으로 받은 변수이므로 loop를 이용하였고, when 키워드를 사용하여 외부로부터 받은 인터페이스가 앤서블 팩트에 존재하는 확인
4. myrole.netplan 에 Jinna2 템플릿(파이썬 웹 프로그래밍에 주로 쓰이는 템플릿 파일) 파일 작성
touch ~/ansible-project/chapter_10.1/roles/myrole.netplan/templates/01-netplan-ansible.yaml.j2
#~/chapter_10.1/roles/myrole.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 %}
- Jinja2 템플릿을 이용하여 외부로부터 받은 배열형 변수를 for 문으로 하나씩 꺼내 사용할 수 있습니다.
- Jinja2 템플릿에서 제어문이나 반복문을 사용할 때는 다음과 같이 {% ~ %}를 이용합니다.
Jinja(진자)2 소개
- 앤서블에서 변수 확장에는 파이썬으로 작성된 Jinja2 템플릿 엔진을 사용.
- 원래 플라스크 Flask라는 파이썬의 웹 애플리케이션 프로임워크로 HTML에 동적인 값을 설정할 때 사용되는 템플릿 엔진.
- 진자의 ‘템플릿의 변수 정보를 확장하고 출력한다’ 일반적인 동작을 앤서블에서는 템플릿 모듈을 사용해 파일을 확장하는 것은 물론이고,
플레이북에 있는 변수 정보를 확장할 때도 진자2를 사용합니다.
https://cumulus.tistory.com/75
5. myrole.netplan 에 태스크 파일 작성
#~/chapter_10.1/roles/myrole.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
- template 모듈을 이용하여 앞에서 생성한 템플릿 파일을 대상 호스트에 복사합니다.
- 이때 when 구문을 이용하여 외부로부터 받은 인터페이스가 앤서블 팩트에 존재하는지 확인합니다.
- 템플릿 복사가 잘 되면 notify 키워드를 사용하여 핸들러를 호출합니다.
6. myrole.netplan 에 핸들러 파일 작성 : 핸들러는 command 모듈을 이용하여 netplan apply 명령어를 수행
#~/chapter_10.1/roles/myrole.netplan/handlers/main.yml
---
# handlers file for myrole.netplan
- name: Netplan apply
ansible.builtin.command: netplan apply
7. 마지막으로 롤을 호출할 메인 플레이북을 작성
- 메인 플레이북에는 롤에 전달할 변수들을 vars 섹션에 선언하고 tasks 섹센에 롤을 추가합니다.
- 이때 ansible.builtin.include_role 모듈을 이용하여 롤을 호출하면 when 구문을 함께 사용할 수 있습니다.
- 이렇게 앤서블 팩트에서 수집한 OS 버전에 따라 해당 롤을 호출할 수 있습니다.
cd ~/ansible-project/chapter_10.1
touch set_ip.yml
#~/chapter_10.1/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"
8. 실행
실행 전 확인
# 실행 전 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
# 플레이북 실행 : 우분투 OS로 롤 호출 되지만, tnode2는 enp7 NIC가 없어서 Setup nic ip 태스크가 실행되지는 않는다
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
결과
호스트명 설정하기
앤서블로 접근하기 위한 대상 서버(tnode1~3)들은 이미 제어 노드(server)의 인벤토리에 등록되어 있다.
호스트명 설정을 하기 위해 ansible.builtin.hostname 모듈을 사용한다.
/etc/hosts 에 tnode 정보들을 등록하기 위해 필요한 정보들을 변수로 정의한다.
호스트명을 hosts 파일에 추가할 때는 ansible.builtin.lineinfile 모듈을 사용한다.
ansible.builtin.hostname 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/hostname_module.html
ansible.builtin.lineinfile 모듈 - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html
1. 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
#
mkdir ~/ansible-project/chapter_10.2
cd ~/ansible-project/chapter_10.2
# ansible.cfg, inventory 파일 작성
cat <<EOT> ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ansible
ask_pass = false
inject_facts_as_vars = false
roles_path = ./roles
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT
2. 변수 정의 파일 생성 : hosts 파일에 추가할 정보를 사전형 변수로 정의하여 반복문에서 사용할 수 있게
touch ~/ansible-project/chapter_10.2/vars_hosts_info.yml
####chapter_10.2/vars_hosts_info.yml
tnodes:
- hostname: tnode1
fqdn: tnode1.local
net_ip: 10.10.1.11
- hostname: tnode2
fqdn: tnode2.local
net_ip: 10.10.1.12
- hostname: tnode3
fqdn: tnode3.local
net_ip: 10.10.1.13
3. 메인 플레이북 작성 : hostname은 inventory 정보를 통해서 설정하고, /etc/hosts 파일은 내용 추가는 변수 정의 파일에서 반복문을 통해 가져온다.
- regexp 는 /etc/hosts 에서 해당 값(여기서는 ip)가 있을 경우 대체(기본값 수정, state=present)하거나 혹은 삭제(state=absent).
- 매칭되는 것이 없다면 line(내용)을 추가합니다
touch ~/ansible-project/chapter_10.2/set_hostname.yml
chapter_10.2/set_hostname.yml
---
- hosts: tnode
tasks:
- name: Set hostname from inventory
ansible.builtin.hostname:
name: "{{ inventory_hostname }}"
- hosts: all
vars_files: vars_hosts_info.yml
tasks:
- name: Add host ip to hosts
ansible.builtin.lineinfile:
path: /etc/hosts
line: "{{ item.net_ip }} {{ item.hostname }} {{ item.fqdn }}"
regexp: "^{{ item.net_ip }}"
loop: "{{ tnodes }}"
4. 플레이북 실행
- 실행 전 확인
ansible -m shell -a "cat /etc/hosts" tnode
실행 후 확인
# 문법 체크
ansible-playbook --syntax-check set_hostname.yml
# 플레이북 실행
ansible-playbook set_hostname.yml
...
# 확인
ansible -m shell -a "hostname" tnode
ansible -m shell -a "cat /etc/hosts | grep tnode" tnode
# tnode1에서 다른 노드 통신 확인
ssh tnode1 ping -c 1 tnode2
ssh tnode1 ping -c 1 tnode3.local
확인
NFS 서버 설치 및 NFS 스토리지
실습 환경에서는 NFS 서버를 CentOS에 구성한다
- NFS 서버가 구성되면 나머지 두 노드에는 NFS 스토리지를 마운트한다
- 플레이북 재사용을 위한 NFS 서버 및 클라이언트는 롤로 구성한다
NFS 서버 설치를 위한 myrole.nfs_server 롤과 NFS 스토리지 마운트를 위한 myrole.nfs_client 롤이 있습니다
롤 설계 : NFS 패키지를 OS에 맞게 설치하고 설치가 끝난 후 마운트할 디텍터리를 생성하고 설치한 NFS 서버의 공유 디렉터리로 마운트합니다
1. 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
#chapter_10.3/..
#
mkdir ~/ansible-project/chapter_10.3
cd ~/ansible-project/chapter_10.3
# ansible.cfg, inventory 파일 작성
cat <<EOT> ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ansible
ask_pass = false
inject_facts_as_vars = false
roles_path = ./roles
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
[nfs_server]
tnode1
[nfs_client]
tnode2
tnode3
EOT
2. 롤 생성 : myrole.nfs_server, myrole.nfs_client
#
ansible-galaxy role init --init-path ./roles myrole.nfs_server
ansible-galaxy role init --init-path ./roles myrole.nfs_client
# 확인
ansible-galaxy role list
tree roles -L 2
3. myrole.nfs_server 에 변수 파일 작성 : 설치할 NFS 서버 관련 패키지
#chapter_10.3/roles/myrole.nfs_server/vars/main.yml
---
# vars file for myrole.nfs-server
nfs_packages:
- nfs-kernel-server
4. myrole.nfs_server 에 태스크 파일 작성
chapter_10.3/roles/myrole.nfs_server/tasks/main.yml
---
# tasks file for myrole.nfs_server
- name: Install NFS packages
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop: "{{ nfs_packages }}"
- name: Create NFS export directory
ansible.builtin.file:
path: "{{ share_path }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Configure NFS exports
ansible.builtin.lineinfile:
path: "/etc/exports"
line: "{{ share_path }} *(rw,sync)"
regexp: "^{{ share_path }}"
state: present
create: true
notify: Restart NFS Service
5. myrole.nfs_server 에 핸들러 파일 작성
chapter_10.3/roles/myrole.nfs_server/handlers/main.yml
---
# handlers file for myrole.nfs_server
- name: Restart NFS Service
ansible.builtin.service:
name: nfs-server
state: restarted
6. myrole.nfs_client 에 변수 파일 작성 : 설치할 NFS 패키지
chapter_10.3/roles/myrole.nfs_client/vars/main.yml
---
# vars file for myrole.nfs_client
apt_nfs_packages:
- nfs-common
dnf_nfs_packages:
- nfs-utils
7. myrole.nfs_client 에 태스크 파일 작성
chapter_10.3/roles/myrole.nfs_client/tasks/main.yml
---
# tasks file for myrole.nfs-client
- name: Install NFS Packages on Ubuntu
ansible.builtin.apt:
name: "{{ item }}"
update_cache: true
state: present
loop: "{{ apt_nfs_packages }}"
when: ansible_facts.distribution == "Ubuntu"
- name: Install NFS Packages on Rhel
ansible.builtin.dnf:
name: "{{ item }}"
state: present
loop: "{{ dnf_nfs_packages }}"
when: ansible_facts.distribution == "RedHat"
- name: Create Mount Directory
ansible.builtin.file:
path: "{{ mount_path }}"
state: directory
- name: Mount NFS
ansible.posix.mount:
src: "{{ share_server }}:{{ share_path }}"
path: "{{ mount_path }}"
opts: rw,sync
state: mounted
fstype: nfs
8. 메인 플레이북에서 사용할 변수를 정의 → 롤에 포함하지 않은 이유는 각각의 롤이 동일한 값의 변수를 사용하기 위함
touch ~/ansible-project/chapter_10.3/vars_share_path.yml
chapter_10.3/vars_share_path.yml
---
share_server: tnode1
share_path: /mnt/nfs_shares
mount_path: /mnt/nfs_data
9. 메인 플레이북 작성
touch ~/ansible-project/chapter_10.3/set_nfs_storage.yml
chapter_10.3/set_nfs_storage.yml
---
- hosts: nfs_server
vars_files: vars_share_path.yml
roles:
- role: myrole.nfs_server
- hosts: nfs_client
vars_files: vars_share_path.yml
roles:
- role: myrole.nfs_client
10. 플레이북 실행 및 nfs 동작 확인
# 실행 전 tnod2, tnode3 NFS 스토리지 마운트 확인
ssh tnode2 df -h --type nfs4
ssh tnode3 df -h --type ext4
# 문법 체크
ansible-playbook --syntax-check set_nfs_storage.yml
# 실행
ansible-playbook set_nfs_storage.yml
...
# 실행 후 tnod2, tnode3 NFS 스토리지 마운트 확인
ssh tnode2 df -h --type nfs4
ssh tnode3 df -h --type nfs4
# tnode1에 nfs-server 확인
ssh tnode1 systemctl status nfs-server
ssh tnode1 sudo exportfs -s
# (모니터링) 신규 터미널
sudo su - ubuntu
ssh tnode2 ls /mnt/nfs_data
watch -d "ssh tnode2 ls -l /mnt/nfs_data"
# tnode1 접속 후 /mnt/nfs_shares에 파일 10개 생성
ssh tnode1
for i in {1..10}; do sudo touch /mnt/nfs_shares/deleteme.$i; done;
exit
DB 애플리케이션 설치하기
앤서블 갤럭시에서 MySQL 설치하는 롤을 찾아보고, 해당 롤을 이용하여 테스트 진행 - Link geerlingguy → GitHub 방문
https://github.com/geerlingguy/ansible-role-mysql
- MySQL을 tnode2에 설치한다
앤서블 갤럭시에서 우분투에 설치할 수 있는 MySQL 롤을 검색하여 해당 롤을 이용한다
1. 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
#
mkdir ~/ansible-project/chapter_10.4
cd ~/ansible-project/chapter_10.4
# ansible.cfg, inventory 파일 작성
cat <<EOT> ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ansible
ask_pass = false
roles_path = ./roles
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
[db]
tnode2
[tnode]
tnode1
tnode2
tnode3
EOT
2. 검색한 mysql role 설치
#
ansible-galaxy role install -p ./roles geerlingguy.mysql
# 확인
ansible-galaxy role list
tree roles -L 3
3. 롤 태스트 정보 확인 : 오래된 Facts 표기법 사용하니, ansible.cfg 확인
chapter_10.4/roles/geerlingguy.mysql/tasks/main.yml
---
# Variable configuration.
- ansible.builtin.include_tasks: variables.yml
# Setup/install tasks.
- ansible.builtin.include_tasks: setup-RedHat.yml
when: ansible_os_family == 'RedHat'
- ansible.builtin.include_tasks: setup-Debian.yml
when: ansible_os_family == 'Debian'
- ansible.builtin.include_tasks: setup-Archlinux.yml
when: ansible_os_family == 'Archlinux'
- name: Check if MySQL packages were installed.
ansible.builtin.set_fact:
mysql_install_packages: "{{ (rh_mysql_install_packages is defined and rh_mysql_install_packages.changed)
or (deb_mysql_install_packages is defined and deb_mysql_install_packages.changed)
or (arch_mysql_install_packages is defined and arch_mysql_install_packages.changed) }}"
# Configure MySQL.
- ansible.builtin.include_tasks: configure.yml
- ansible.builtin.include_tasks: secure-installation.yml
- ansible.builtin.include_tasks: databases.yml
- ansible.builtin.include_tasks: users.yml
- ansible.builtin.include_tasks: replication.yml
os_family 에 따라 mysql 설치 후 환경 설정 태스크들을 차례대로 호출 ⇒ 나머지 yml 파일들도 한번 내용 확인해보시기 바랍니다.
- (참고) os_family 는 간단하게 분류 : Debian에 Ubuntu도 속함 - Link
4. 플레이북 작성
touch ~/ansible-project/chapter_10.4/install_mysql.yml
chapter_10.4/install_mysql.yml
---
- hosts: db
roles:
- role: geerlingguy.mysql
5. 실행
# 문법 체크
ansible-playbook --syntax-check install_mysql.yml
# 시뮬레이션 : Ensure MySQL is stopped after initial install 는 설치가 안되서 발생하는 거니 문제 없음
ansible-playbook --check install_mysql.yml
# 실행
ansible-playbook install_mysql.yml
# 확인
ssh tnode2 systemctl status mysql
#
ssh tnode2
sudo mysql -u root -e "show databases;"
sudo mysql -u root mysql
status
exit
exit
'study > Ansible101 1기' 카테고리의 다른 글
Ansible Semaphore (0) | 2024.02.09 |
---|---|
Ansible101 1기 4주차 첫번째 (0) | 2024.02.04 |
Ansible101 1기 3주차 첫번째 (0) | 2024.01.28 |
Ansible101 1기 2주차 두번째 (0) | 2024.01.14 |
Ansible101 1기 2주차 첫번째 (0) | 2024.01.14 |