📌 Ansible이란?
🔹 Ansible(앤서블)은 자동화(Automation) 도구
🔹 주로 서버 관리, 애플리케이션 배포, 네트워크 구성 자동화 등에 사용
🔹 복잡한 IT 인프라를 쉽고 빠르게 설정하고 운영할 수 있
📌 IaC (Infrastructure as Code)
🔹 "인프라를 코드로 관리"
🔹 서버, 네트워크, 데이터베이스 등의 IT 인프라를 코드로 작성하여 자동화하는 방식
🔹 사람이 직접 서버를 설정하는 게 아니라, 코드(YAML, JSON, Terraform 등)를 사용해 서버를 구성하고 배포
DevOps = IaC + CI/CD
IaC가 뭐냐?
"인프라를 코드로 정의하는 것을 말함"
- 이때 중요한 건 인프라를 코드로 정의하는 것 중에 하나로, ansible이랑 terraform을 사용한다는 것.
- 장점: 인프라를 On-demand로 빠르게 띄울 수 있음. 휴먼 에러를 줄일 수 있음, 그리고 동일한 환경을 재현 가능함 ( = immutable, 불변)
- 특징: 멱등성 성립 - 여러 번 수행해도 같은 결과가 나옴
-> 멱등성? 첫 번째 수행을 한 뒤 여러 차례 적용해도 결과를 변경시키지 않는 작업 또는 기능의 속성을 의미함. 즉, 명등한 작업의 결과는 한 번 수행하든 여러 번 수행하든 같음
ex) httpd 데몬이 설치되어 있으면 좋겠음 = Desired
-> 설치가 안되어 있다면 설치, 이미 설치가 되어있다면 설치를 안 할 것
1. ansible은 '이미 구축된' 인프라를 '관리'하는 특화
ex) virt-builder를 통해 kvm이미지를 커스터마이징 한 후, 100개의 서버를 생성한 후에 이 서버들을 한꺼번에 관리
물론 얘도 생성을 할 수 있지만 관리하는 것에 더 초점이 맞춰져 있음
2. terraform - '클라우드 인프라 구축'에 특화
ex) InfoGrab
실습) 앞으로는 계속 복사해서 사용할 예정임. VM 템플릿을 하나 만들어보자.

2 core 2GB 20GB, 미니멀. IP : 211.183.3.100/24
selinux , firewalld , NetworkManager 끄고 비활성화 + 레포 추가 + update
초기 설정
sed -i s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config
init 6
systemctl stop firewalld
systemctl disable firewalld
cat <<EOF> /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-$releasever - Base
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
baseurl=https://vault.centos.org/7.9.2009/os/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#released updates
[updates]
name=CentOS-$releasever - Updates
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra
baseurl=https://vault.centos.org/7.9.2009/updates/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra
baseurl=https://vault.centos.org/7.9.2009/extras/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra
baseurl=https://vault.centos.org/7.9.2009/centosplus/x86_64/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=contrib&infra=$infra
baseurl=https://vault.centos.org/7.9.2009/contrib/x86_64/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[root@cent-tem ~]# systemctl stop NetworkManager
[root@cent-tem ~]# systemctl disable NetworkManager
[root@cent-tem ~]# yum -y update

- Shut Down 하고


- 나머지는 넘기고 create a full clone만 선택하면 됨

- 이름은 m1으로 해주기
- 위에랑 비슷하게 m2도 만들어주기

- 그리고 추가로 m1, m2 노드에 명령을 내려 관리할 예정
- 앤서블은 server-client 구조는 아니임. 역할군이 딱 정해져 있는 게 아니라, managed node들에게 ssh로 앤서블 명령만 전달할 수 있으면 어디가 됐던 control node가 될 수 있음. 이 의미를 잘 이해하시면 좋을 것 같음.
ansible 노드 구성

- 그림에 나오는 ip로 변경해 주고 호스트 명을 밑에 명령어를 활용해서 수정해 주기
- control-node에서 각 각 명령을 내리면 ssh로 명령을 전달하면 managed node들이 m1과 m2를 관리함
- 제어를 '할' 노드
- 제어를 '당할' 노드
control_node
[root@cent-tem ~]# hostnamectl set-hostname control_node
[root@cent-tem ~]# su
m1 - 호스트네임
[root@cent-tem ~]# hostnamectl set-hostname m1
[root@cent-tem ~]# su
m2 - 호스트네임
[root@cent-tem ~]#hostnamectl set-hostname m2
[root@cent-tem ~]# su

- 컨트롤노드에서 m1, m2에 통신이 되는 것을 확인할 수 있음
- 컨트롤 노드에 ansible 설치
[root@control_node ~]# yum install -y epel-release
[root@control_node ~]# yum install -y ansible
[root@control_node ~]# ansible --version

[root@control_node ~]# vi /etc/ansible/hosts

- 두대의 관리당할 서버를 적어줌.
- 위의 인벤토리에 속한 두대의 서버(m1, m2)에 ansible 명령을 전달해 보자


- 우리는 두 대를 만들었으니까 yes를 두 번 해야 됨.

- ssh 접속이 성립 안 하고 있음. 왜냐하면 키페어를 나눠갖거나, 암호를 통해 인증하지 않음.
control_node = ssh client(프라이빗키)
m1, m2 = ssh server(퍼블릭키)

[root@control_node ~]# ansible all -m ping -k
# -k : --ask-pass, 암호로 인증을 하겠다는 옵션

# 연결성을 테스트하는 모듈 : 우리가 흔히 아는 icmp 패킷을 보내는 프로토콜이 아니라 ping이라는 요청에 대해 pong을 반환하는 모듈임
yum 모듈
control_node
[root@control_node ~]# vi /etc/ansible/hosts


- 내가 사용할 수 있는 명령어들을 알려줌
[root@control_node ~]# ansible m1 -m yum -a "name=httpd state=present" -k
- 설치가 된 상태면 안 해줘도 됨, 근데 설치가 안된 상태면 설치해 줘라~
[root@control_node ~]# ansible m1 -m yum -a "name=httpd state=present"
기본 인벤토리의 [m1] 서버
-a 인자 전달
패키지 이름은 httpd이고
state는 원하는 상태 = present는 존재하는 상태를 의미함
absent : 존재 x (removed와 같은 의미)
installed : 설치됐으면
latest : 최신버전이었으면
present : 존재했으면
removed : 제거됐으면

- 변화가 생긴 상태
- changed가 true라고 나타난 거 보니, 변경된 게 잘 반영된 걸 알 수 있음
- 내가 원하는 상태는 state가 present 된 상태
m1으로 가서 확인
- httpd가 잘 설치된 상태인 걸 확인할 수 있음

control_node로 가서 확인
- 변화가 안된 상태에서는 초록색 결과창이 나타난 걸 확인할 수 있음

- 한 번 더 입력했을 때 changed에서 변화가 안 일어난 걸 볼 수 있음. 이것을 멱등성이라고 함

- 나의 desired 부분을 입력하고 그 명령어가 어떤 프로그램을 설치한다고 했을 때, 설치가 된 프로그램이라면 설치가 안되고, 설치가 안 된 프로그램이라면 설치가 됨
- 현재 상태 확인과 바람을 대조해서 일치하지 않으면 수행을 하고, 일치하면 수행함
[root@control_node ~]# ansible 211.183.3.210 -m service -a "name=httpd state=started"
ansible 211.183.3.210 -m service -a "name=httpd state=started"
systemctl = service


- 한번 더 입력하면 상태가 변경된 것을 확인할 수 있음
m1으로 가서 확인

- m1의 상태가 active 된 걸 확인할 수 있음
미니 실습) m2에 httpd라는 데몬이 잘 동작하고, 재부팅 후에도 동작할 수 있도록 ansible 명령을 수행해 보세요.
control_node
[root@control_node ~]# ansible m2 -m yum -a "name=httpd state=present" -k
[root@control_node ~]# ansible m2 -m service -a "name=httpd state=started" -k
[root@control_node ~]# ansible m2 -m service -a "name=httpd enabled=true" -k
m2

Ansinle collections

# 다양한 모듈들의 사용법을 알 수 있는 공식 문서


https://docs.ansible.com/ansible/latest/collections/index_module.html

# 여기에 나와있는 모듈들 중에서도 특정한 모듈만 잘 이해하면 좋음
실습 2) 앤서블로 m2의 방화벽을 켜보세요.
[root@control_node ~]# ansible m2 -m service -a "name=firewalld state=started" -k

user 모듈
- 사용자가 관리하는 모듈
[root@control_node ~]# ansible m1 -m user -a "name=newuser1" -k

m1
[root@m1 ~]# cat /etc/passwd | grep newuser1
- m1서버에서 newuser1이라는 사용자 생성

- m1서버에서 확인해 보면 생성이 잘 된 걸 확인할 수 있음
실습) m3 서버를 한대 추가(. 230)해서 m1, m2는 seoul 서버로 묶고 m3서버는 busan 서버로 묶어보세요.
- m3 서버를 한대 추가하고

# 인벤토리의 서버목록은 얼마든지 중복돼도 괜찮음
[root@control_node ~]# vi myinven
# 이런 식으로 따로 인벤토리 파일을 생성해도 괜찮음

# 내가 임의로 만든 myinven이라는 인벤토리를 사용하고 싶다면 -i 옵션으로 해당 인벤토리 파일을 지정하면 됨.
[root@control_node ~]# ansible busan -i myinven service -a "name=firewalld state=started"

[root@control_node ~]# ansible busan -i myinven service -a "name=firewalld state=started" -k
- 다시 -k 붙이고 명령 수행

[root@control_node ~]# ansible busan -i myinven -m service -a "name=firewalld state=started" -k
# -k 붙이고 다시 명령 수행

계속 암호를 치는 게 불편하니까, ssh 인증을 암호가 아닌 키페어를 사용(public-key 방식)해서 해보자.
키페어 생성
[root@control_node ~]# ssh-keygen -b 2048 -t rsa -f ~/. ssh/id_rsa -q -N ""
- 사실상 ssh-keygen 한 것과 크게 다른 게 없음, 다만 굳이 엔터를 연속으로 치지 않고 한 번만 쳐도 키페어가 생성됨.
- ssh-keygen -b 2048 -t rsa -f ~/.ssh/id_rsa -q -N ""
-> 비트
-> 암호화 타입
-> 파일 위치
-> 메시지 x
-> passphrase = 프라이빗 키 암호 x

- managed 노드들에 심어줄 예정

- password: test123
- 대상 서버에 authorized_keys에 내 퍼블릭키를 등록
m1
[root@m1 ~]# vi ~/.ssh/authorized_keys
- m1로 가서 authorized_keys를 확인해 보자

- 퍼블릭키가 잘 등록되어 있는지 확인
[root@control_node ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@211.183.3.220
[root@control_node ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@211.183.3.230
- 나머지 두대도 퍼블릭키를 심어주자.
[root@control_node ~]# ansible all -i myinven -m ping

- 퍼블릭키를 심어준 다음에는 따로 암호로 인증하지 않아도 명령이 잘 전달된 걸 볼 수 있음
플레이북
= 태스크를 모아놓은 명세표(문서)
모듈: 도구
태스크: 작업
인벤토리: Managed node들의 목록
-> 모듈은 도구이고 태스크는 작업을 말함
모듈 = 장도리(= 망치)
태스크: 못 박기, 못 뽑기
1. 내가 수행하고자 하는 작업(task) = httpd라는 패키지가 설치가 됐으면 좋겠다.
=> yum이라는 도구를 사용해서 state를 present로 만들면 됨
2. 내가 수행하고자 하는 작업(task) = httpd라는 패키지가 없었으면 좋겠음
=> yum이라는 도구를 사용하여 state를 absent로 만들면 됨
yaml 파일
- 확장자를 일반적으로 yaml, yml로 사용
- JSON파일과 호환되는 <key>:<value> 형탤로 구성된 파일
- 파이썬의 자료형 중 리스트와 딕셔너리를 통해 구성되어 있음
예) state: started
state = key값
started = valud값
리스트
동물 = ["고양이", "강아지"]
딕셔너리
서버 ={"cpu": 2, "ram": 2048}
[root@control_node ans]# vi playbook.yml

# 플레이북은 결국 다양한 태스크들을 모아놓은 파일인데, 수행할 task가 없는 플레이북을 한번 만들어보자.
[root@control_node ans]# ansible-playbook playbook.yml
- 기본 인벤토리의 모든 서버한테 playbook.yml이라는 플레이북 파일을 수행

[root@control_node ans]# cp ~/myinven.
- 아까 /root 경로에 만든 인벤토리 파일을 /ans로 복사
[root@control_node ans]# ansible-playbook playbook.yml -i myinven
- myinven라는 인벤토리를 대상으로 playbook.yml 수행
[root@control_node ans]# vi playbook.yml
- 플레이북에 httpd라는 패키지를 설치하는 태스크를 추가해 보자

- 2칸 들여 쓰기를 해서 표현.
[root@control_node ans]# ansible-playbook playbook.yml -i myinven

- m1, m2는 이미 설치가 되어있었기 때문에 설치 안 됐고 m3만 설치.
실습) nginx.yml이라는 플레이북을 만들어서 busan 서버에 nginx를 설치하고 동작시켜서 접속이 잘 되는 것까지 확인을 해보세요.
[root@control_node ans]# vi nginx.yml

✅ 기존 nginx.yml에 저장소 업데이트 추가
✅ Nginx 설치
✅ Nginx 시작 및 부팅 시 자동 실행 설정
[root@control_node ans]# ansible busan -i myinven -m service -a "name=firewalld state=stopped"
[root@control_node ans]# ansible busan -i myinven -m service -a "name=firewalld enabled=no"
[root@control_node ans]# ansible-playbook nginx.yml


또 다른 풀이
- m3에 가서 일단 nginx를 설치해 보자

# 패키지가 없다.
[root@m3 ~]# yum install -y epel-release
[root@m3 ~]# yum install -y nginx
[root@m3 ~]# systemctl restart nginx


[root@m3 ~]# yum remove httpd -y

# httpd를 제거하고 nginx를 재시작하면 잘 동작함.
플레이북
httpd의 status를 absent로 하는 태스크(필요모듈=yum)
firewalld 끄는 태스크(service모듈)
epel-release 설치하는 태스크
nginx 동작시키는 태스크
# 이런 형태로 플레이북을 구성하면 될 것 같음. (대상 = busan 서버)
[root@control_node ans]# cat nginx.yml
- name: nginx-pb
hosts: busan
tasks:
- name: remove_httpd
yum:
name: httpd
state: removed
- name: firewalld_stopped
service:
name: firewalld
state: stopped
enabled: false # systemctl disable firewalld
- name: install_epel
yum:
name: epel-release
state: present
- name: install_nginx
yum:
name: nginx
state: present
- name: start_nginx
service:
name: nginx
state: started
enabled: true
[root@control_node ans]# ansible-playbook nginx.yml -i myinven
- 접속이 잘 되는 걸 확인할 수 있음.

여러 개의 패키지를 설치하는 플레이북
[root@control_node ans]# vi multi.yml

[root@control_node ans]# ansible-playbook multi.yml -i myinven


- 경고가 뜨긴 했지만 m3서버에 (busan)에 ifconfig명령이 존재하는 걸 보면, net-tools은 잘 설치된 것으로 보임
copy 모듈
- 컨트롤 노드에 존재하는 파일을 매니지드 서버에 복사하자.
- 물론 매니지드-매니지드 복사 가능(remote_src)
- 내가 원하는 상태 = 웹서버를 설치 및 동작시키고, index.html 복사.
[root@control_node ans]# echo test_copy > index.html
# 넣어줄 index.html 파일 생성

# m1서버에 아까 httpd를 제거하고, nginx를 설치했기 때문에 /var/www/html 경로가 삭제됨.
centos7에 nginx를 설치하면 웹루트디렉터리가/usr/share/nginx/html
[root@control_node ans]# vi copy.yml
- name: copy_index_pb
hosts: seoul
tasks:
- name: copy_file_task
copy:
src: /ans/index.html
dest: /var/www/html/index.html
[root@control_node ans]# ansible-playbook copy.yml -i myinven


- index.html파일이 잘 복사된 걸 확인할 수 있음.
lineinfile 모듈
[root@control_node ans]# vi lineinfile.yml
- name: lineinfile_pb
hosts: busan
tasks:
- name: lineinfile
lineinfile:
path: /usr/share/nginx/html/index.html
line: "line in file test"
[root@control_node ans]# ansible-playbook lineinfile.yml -i myinven

[root@m3 ~]# rm /usr/share/nginx/html/index.html
# index.html 파일을 삭제 후 create 옵션으로 파일을 생성 후 내용추가해 보자.



- 파일 생성 후 내용 추가
file 모듈
- 파일 생성 및 권한 부여
[root@control_node ans]# vi file.yml
- name: make_file_pb
hosts: busan
tasks:
- name: make_file_task
file:
path: /touch-test.txt
state: touch
mode: '0777' # 777앞의 0은 8진수를 의미
[root@control_node ans]# ansible-playbook file.yml -i myinven

m3

- 최상위 디렉터리에 파일 생성 및 권한부여가 잘 된 걸 확인할 수 있음.
실습) rapa.inven이라는 인벤토리파일을 하나 만든 후 [web] 목록을 하나 만든다, [web]에 속하는 서버는 IP가 211.183.3.150,211.183.3.160 인 서버이며 여기에 간단한 index.html 파일을 넣어서 배포하고자 하는데 배포할 파일은 웹상의 https://www.w3.org/TR/PNG/iso_8859-1.txt 이 파일을 index.html로 다운로드하여서 배포하면 된다. wget 같은 모듈을 찾아서 한번 해보세요. 노드에 따로 파일을 다운받아서 넣지 말라는 뜻.
1. 이때 IP가 211.183.3.150, 211.183.3.160 인 서버

web1 - 211.183.3.150


web2 - 211.183.3.160


2.rapa.inven이라는 인벤토리파일에 [web] 목록 생성

3. 키 설정해 주기
ssh-copy-id -i ~/.ssh/id_rsa.pub root@211.183.3.150
ssh-copy-id -i ~/.ssh/id_rsa.pub root@211.183.3.160
4. 여기에 간단한 index.html 파일을 넣어주고, 웹 상의https://www.w3.org/TR/PNG/iso_8859-1.txt이 파일을 받아오기.
- name: deploy_index_pb
hosts: web
tasks:
- name: firewalld_stopped
service:
name: firewalld
state: stopped
enabled: false # systemctl disable firewalld
- name: install_epel
yum:
name: epel-release
state: present
- name: install_nginx
yum:
name: nginx
state: present
- name: start_nginx
service:
name: nginx
state: started
enabled: true
- name: download_index_task
get_url:
url: https://www.w3.org/TR/PNG/iso_8859-1.txt
dest: /usr/share/nginx/html/index.html
force: true #파일이 존재하면 덮어쓰기


잘 뜨는 걸 확인할 수 있음.
shell 모듈
- 명령을 수행하는 shell 모듈의 경우, 단순히 명령을 수행하기 때문에 멱등성이 보장되지 않는다.
[root@control_node ans]# vi shell.yml
- name: shell_test_pb
hosts: web
tasks:
- name: shell_test_task
shell: "{{ item }}"
with_items:
- "mkdir /shelltest"
- "cp /root/anaconda-ks.cfg /shelltest"
- "ls -al /shelltest"
[root@control_node ans]# ansible-playbook shell.yml -i rapa.inven
# 플레이북 수행 후

- 이미 파일이 있으니까... 이 명령어를 수행하,,,,결론 shell이란 모듈은 사용 안 하는 게 좋음

- 만약에 파일이 shelltest에 생성이 되지 않는다면, 한 번 지우고 다시 ansible을 실행시키면 됨
실습 1) 인벤토리의 [web] 서버들을 대상으로 하여 프리템플릿을 배포해 보세요.
플레이북을 만들어 실행시키기 전에 이 과정이 수동으로 어떤 식으로 실행되는 건지 해본다면?
[root@control_node ans]# yum install -y wget
[root@control_node ans]# wget https://www.free-css.com/assets/files/free-css-templates/download/page293/dgital.zip





플레이북을 사용해서 구현한다면?
[root@control_node ans]# vi html.yml
- name: Deploy DGital Web Template
hosts: web
become: true
tasks:
- name: Install required packages (Nginx, Unzip)
yum:
name:
- nginx
- unzip
state: present
- name: Download DGital template zip file
get_url:
url: "https://www.free-css.com/assets/files/free-css-templates/download/page293/dgital.zip"
dest: "/tmp/dgital.zip"
mode: '0644'
- name: Extract template to Nginx web directory
unarchive:
src: "/tmp/dgital.zip"
dest: "/usr/share/nginx/html/" #여기 뒤에 unzip한 상태로 오기 때문에 http://211.183.3.150/digital-agency-html-template/ 이 루트를 입력해줘야 웹페이지가 정상적으로 보임
remote_src: yes
- name: Ensure Nginx is running
service:
name: nginx
state: started
enabled: true
[root@control_node ans]# ansible-playbook html.yml -i rapa.inven
실습 2) 앤서블 플레이북을 통해 m3는 nfs-server로, m1은 nfs-client로 구성해 보세요.
[root@control_node ans]# vi nfs.yml
- name: setup NFS
hosts: busan
tasks:
- name: install_nfs
yum:
name: nfs-utils
state: present
- name: start_nfs
service:
name: nfs-server
state: started
- name: create_dir
file:
path: /shared
state: directory
mode: '0777'
- name: create_file
lineinfile:
path: /etc/exports
line: "/shared 211.183.3.*(rw)"
create: true
- name: exportfs
shell: exportfs -r
become: true
- name: restart_nfs_server
service:
name: nfs-server
state: restarted
enabled: yes
- name: setup NFS_client
hosts: 211.183.3.210
tasks:
- name: yum_nfs_client
yum:
name: nfs-utils
state: present
- name: create_dir_clinet
file:
path: /remote
state: directory
mode: '0777'
- name: mount
mount:
path: /remote
src: "211.183.3.230:/shared"
fstype: nfs
opts: defaults
state: mounted
[root@control_node ans]# ansible-playbook nfs.yml -i myinven

m1

m3

마운트가 잘 된 걸 확인할 수 있음.
'AWS Cloud School 8기 > 서버가상화_클라우드 이미지' 카테고리의 다른 글
Ubuntu/ debug/ when/ register (0) | 2025.03.09 |
---|---|
서버 모니터링/ ggdG - 전부 삭제 (0) | 2025.03.07 |
Open vSwitch/ openvswitch 실행 안될 때 (2) | 2025.03.06 |
KVM(CLI) (2) | 2025.03.05 |
KVM(Kernel-Based Virtual Machine)/ kvmnet (5) | 2025.02.20 |