DC 환경 배포 -> KVM -> instance를 배포하면 VM 들이 배포된다.
문제는 DC에 너무 많은 compute node들이 존재한다. 이들이 관리가 안된다. 그래서 우리가 필요하다고 느끼는 노드에 가서 하이퍼 바이저를 이용하여 VM을 생성하라고 요청을 받으면 하이퍼바이저가 위쪽에 vResource가 할당되고 그 위에 VM이 생성된다.
그래서 전체를 클러스터로 묶고, 전체를 오케스트레이션 하기 위한 도구가 필요해지는데 이 도구를 우리는 controller라고 부른다.
보통 DC에는 노드들이 위치하게 되는데 하나는 compute 노드(HV 노드 : 인스턴스, vNetwork 만듬), Controller를 이용한 오케스트레이션을 한다, 관리자는 controller에 작업지시를 해서 인스턴스에 작업을 수행한다.
이때의 controller 노드에도 오케스트레이션, 인증 도구, 사용자 UI들이 들어가게 된다.
* 사용자 UI 의 경우 외부에서 서비스를 사용하려고 하는 일반 사용자가 들어올 수도 있다. 이들을 위한 웹페이지 같은 거다
스토리지 노드, 인스턴스 생성시 볼륨을 제공할 수 있어야 한다. 그 볼륨의 디스크를 물리자원의 일부를 잘라서 제공하는 방식이다. 이 디스크는 로컬 디스크가 된다. 이때에 또 중요한 기술이 마이그레이션이다. XML 언어로 작성된 VM은 로컬 디스크가 아닌 원격 디스크에 연결되어 저장소를 공급받을 수 있어야 한다. 스토리지는 인스턴스에게 영구볼륨을 제공(NFS, iSCSI, Ceph, GlusterFS, aws ebs, aws efs)
전체 클러스터를 오버레이 네트워크로 만들고 외부 사용자의 접근을 적절한 인스턴스로 연결하기 위한것, 인스턴스간의 소통을 위한 것, 인스턴스들을 하나의 tennant, project에 포함시킬 네트워크 노드가 필요하다. 이걸 위해 터널링, DHCP, NAT(fip, eip), OpenSwitch(linux bridge)
정리하면 클라우드형 DC 구축시에는 compute, controller, storage, network가 필수요소이다.
---
그럼 앞서 말했던것과 같이 CentOS가 있고 이 내부 커널에 KVM 을 설치해주자. KVM 위쪽에 인스턴스들을 배포해주자. 그래서 이 인스턴스를 포함한 환경을 관리할 수 있는 도구가 필요하다. 이때 쓰는것이 Vagrant이다. Vagrant를 이용해서 환경 명세서를 전달해주는 것이다. 그러면 vagrant는 명세서를 보고 환경을 구성해주는데 이 환경을 위해 libvirt나 ESXi, Virtual Box, aws CloudFormation(템플릿, yaml) -> ec2 이용해서 instance 생성 -> EKS를 불러와서 인스턴스들 묶기. Openstack의 HEAT로도 가능. 환경이 구성되면 이것들을 관리할 필요가 있어진다.
그런데 인스턴스가 정말 많으면 이것들을 관리하기 위한 도구로 어떤것을 이용할 것인가? 각각의 노드들에 똑같은 명령을 전달하는 방법으로 SSH가 있을 수도 있지만 Ansible을 이용해서 멱등성과 관리의 수월성등을 도모할 수 있다.
추가적으로 배포한 서버들에 대해서 전체서버관리도구(Ansible)와 개발자 컴퓨터를 연결해 놓는다. 트리거를 걸어놓아서 새로운 commit이 발생했다면 이걸 ansible에게 전달하고 ansible은 새로운 commit을 가져와서 해당 코드를 서버에 배포하라는 것을 구성할 수도 있다.
ansible이 새로운 commit을 긁어와서 업데이트가 필요한 노드에 새로운 코드로 업데이트 하라고 던져주는 것이다. 그러면 노드 내의 인스턴스들은 새로운 버전으로 업데이트가 되는 CI/CD 연계도 해줄 수 있다.
결국 이걸 위해서는 CI/CD 도구도 필요해진다. 이때의 CI/CD 도구는 gitlab, github, jenkins를 이용해주자
```
uname -nr
```
로 현재 사용하는 OS의 커널 버전을 확인가능하다.
```
yum install -y wget curl vim git
systemctl stop firewalld ; systemctl disable firewalld
systemctl stop NetworkManager ; systemctl disable NetworkManager
echo "1" > /proc/sys/net/ipv4/ip_forward
```
인스턴스에 볼륨을 저장하기 위한 저장소로 기본 저장소를 사용하는 것이 아니라, 별도로 지정한 디렉토리를 사용하기 위해서는 SELinux가 중지되어 있어야 한다.
```
setenforce 0
vi /etc/selinux/config
```
볼륨을 저장하기 위한 저장소 디렉토리 생성
KVM -> 인스턴스생성(ansible-server, ansible-node)
```
mkdir /shared
chmod 777 /shared
yum -y install epel-release
yum -y install qemu-kvm libvirt virt-install openssh-askpass libguestfs-tools libguestfs-xfs virt-top htop
vi /etc/libvirt/qemu.conf # KVM 데몬을 root로 동작시키기 위한 설정
```
442, 446에 있는 "#"를 제거
```
systemctl start libvirtd ; systemctl enable libvirtd
```
이렇게하면 kvm이 정상 작동하게 된다.
---
가상환경을 웹을 통해 확인하고 싶다면 kimchi(wokd)를 설치한다.
https://atl.kr/dokuwiki/doku.php/kvm_-_wok_kimchi_manager
https로 접속해 보니 정상 화면 뜨는 것을 확인할 수 있다.
---
session 유지를 위한 설정, 토큰의 유효기간이 따로 설정되어 있다.
```
vi /etc/wok/wok.conf
systemctl restart wokd
```
여기까지 했다면 스냅샷을 한번 찍어주자
---
[ 리눅스 브릿지를 이용한 가상 네트워크 구성 ]
kvm에서 이용하는 default 네트워크와 리눅스 브릿지가 있을때
default network는 virbr0 브릿지를 이용하게 된다. 별도의 리눅스 브릿지를 사용하게 된다면 virbr1를 사용하게 된다. virbr0는 host 위쪽에 배치가 된다. eth0와 virbr0가 연결되고 나머지 가상머신들이 eth0와 연결된 구조이다.
그러면 virbr0의 네트워크가 구분된 구조가 된다. 이렇게 된다면 1 인터페이스 = 1 네트워크 = 1 Broadcast Domain이 된다. 인스턴스가 나가기 위해서는 NAT를 타야하는데 virbr0는 결국 NAT의 역활을 하게 되는 것이다. 이러한 방식을 Routed Port라고 부른다.
이와 다르게 우리는 linux bridge에서 virbr1에 eth0를 집어넣을 것이다. 스위치에 들어가는 한개의 포트는 L2가 된다. 그래서 이 부분에 ip는 안들어가고 관리용으로 사용하게 된다. 이때 vlan1을 사용해서 관리하게 된다.
이때의 각 포트는 동일 vlan의 동일 ip 대역인 L2 포트가 된다. 즉 동일네트워크이니 BroadCast Domain이 된다. 이것은 Bridge를 쓰는 방법이라고 부른다.
---
wok에 가보면 가상 사설 네트워크가 있는 것을 볼 수 있다. 가상머신을 설치하면 자동으로 연결되는 네트워크이다. 얘는 외부와 소통이 안되기 때문에 반드시 NAT를 거치어서 ip를 변화된 상태로 외부로 빠져나가야만 한다.
우리는 별도의 bridge 네트워크를 만들고 virbr1이라는 독립된 스위치를 만들어주자. 그리고 이 안에 물리 인터페이스를 만들고 가상머신을 만들면 여기에 연결되도록 해주자.
---
1. VM에 할당되는 IP주소는 211.183.3.0/24 대역내에서 할당을 받게 된다.
이때 DHCP로 받은 ip 주소가 쉽게 받기지 않도록 VMware Workstation에서 조정해주자.
2. br0(linux bridge)만들고 기존 물리 인터페이스를 br0에 포함시켜보자. 단, 현재 인터페이스 이름이 ens32와 같은 이름이므로 이를 eth0으로 수정 한뒤, br0에 포함시킨다.
2.1 ens32 -> eth0
eth0의 이름도 수정해주고 필요없는 부분도 없애주자
2.2 vi /etc/default/grub
```
vi /etc/default/grub
```
GRUB_CMDLINE_LINUX 끝에 net.ifnames=0 biosdevname=0를 추가해주자 이렇게 해야만 인터페이스 이름이 바뀐다. 안해주면 위에서 해주었던 eth0의 이름이 안 바뀐다.
그리고 이걸 부팅 파일에 적용해주어야 한다.
```
grub2-mkconfig -o /boot/grub2/grub.cfg
```
하고 재부팅하여 `ip a` 했을 때, eth0에 211.183.3.77이 등록되어 있고 ping이 가능해야 한다.
3. br0 생성하고 eth0을 br0의 포트로 등록 시키기
```
cd /etc/sysconfig/network-scripts/
cp ifcfg-eth0 ifcfg-br0
vi ifcfg-br0
```
마지막으로 ifcfg-eth0의 내용을 바꾸어 주기만 하면 된다.
```
systemctl enable network ; systemctl restart network
```
그 결과 eth0에는 ip가 없고 br0에는 ip가 있으면 된다.
```
brctl show
```
를 했을때 br0가 보이면 된다.
---
볼륨을 준비해보자, 인스턴스 만들기
KVM에서 VM 생성하기
1. iso를 통한 설치 -> 사용의 요구에 맞는 상세한 설정이 가능하지만, 시간이 오래걸린다. 다수의 인스턴스, VM을 운영해야하고 사용자가 요구하는 즉시 서비스를 제공해 주어야 하는 클라우드 환경에서는 적절한 방법이 아니다.
2. cloud img를 이용한 방법
qcow2 이미지를 이용하여 이를 배포하는 방법. 그냥 배포하면 디스크 사이즈가 684 MB가 되므로 이를 확장해야 한다. virt-resize를 이용하여 디스크를 확장시켜 사용해야 한다.
3. virt-builder 를 이용하는 방법
저장소에 있는 클라우드용 이미지 템플릿을 다운로드 하면서 디스크 사이즈 지정, 루트 패스워드 지정, 파일 복사 | 수정, 명령 실행, 인스턴스 내에서 처음 부팅될 때 실행할 명령어등의 지정이 가능한 방법.
먼저 스냅샷을 찍어놓자
```
virt-builder -l
```
을 이용해서 사용할 수 있는 이미지들을 확인해보자
이중에서도 우리는 7.0을 가지고 테스트해보자
```
virt-builder centos-7.0 --format qcow2 --size 20G -o /shared/centos7img.qcow2 --root-password password:test123 --install httpd --run-command 'systemctl enable httpd' --selinux-relabel
```
마지막에 selinux 를 활성화 해주어야 접근이 가능해진다.
```
cd /shared/
cp centos7img.qcow2 centos01.qcow2
cp centos01.qcow2 centos02.qcow2
mkdir /template
mv centos7img.qcow2 /template/
virt-install --name CENTOS701 --vcpus 1 --ram 1024 --network bridge=br0,model=virtio --disk /shared/centos01.qcow2 --import --graphics none &
```
생성 확인차 직접 들어가 보고
wok에 있는것도 확인해보자
가성머신에서 3점대의 ip를 할당받은 것을 확인해볼 수 있다.
방화벽 해제시에 ip를 통해 웹페이지 접속도 되는 것을 확인해볼 수 있다.
이제 이 방법으로 인스턴스를 하나더 만들어보자
```
virt-install --name CENTOS702 --vcpus 1 --ram 1024 --network bridge=br0,model=virtio --disk /shared/centos02.qcow2 --import --graphics none &
```
CENTOS701 -> 3.129
CENTOS702 -> 3.130
에 만들어진것을 확인해볼 수 있었다.
지금까지 우리가 설정한 내역은 Linux OS 안에 kernel이 들어가 있을 것이다. 그리고 커널안에 KVM이 존재하는데 이건 Host based(Bare Metal 로 작동하는)이다. 그리고 이 위쪽에 가상머신이 커널에 전달한 내용을 실재 커널에 전달하고 또 kvm의 명령을 가상머신에게 전달해준다. 그래서 Qemu가 이 전달자 역활을 한다.
????
결국 Ansible은 SSH로 연락하게 된다. 또 Ansible에는 멱등성이 존재하게 된다.
????
root라는 계정은 정확하지만 비밀번호라는 대칭 키를 사용해서 접속하기 때문에 안전한 방법이 될 수 없다.
dictionary key attack이라는 것이 존재하기 때문에 끊임없이 패스워드를 입력해서 공격하는 경우가 존재한다. 그래서 이를 막기 위해 접속 시도 횟수를 계산할 수도 있다.
결론은 좋은 방법이 아니다.
또 .ssh 폴더를 지워버리면 fingerprint를 또 물어볼거기 때문에 좋지 못하다.
---
SSH 연결
1. 서버인증
접속하고자 하는 서버가 정상적인 서버인지 여부를 검증하기 위한 절차이며
접속 요청을 받은 서버는 클라이언트에게 자신의 공개키를 전송하게 된다. 만약 첫번째 접속이었다면 해당 공개키를 저장할 것인지 여부를 묻게되고 클라리언트는 yes를 타이프하면 공개키가 .ssh/known_hosts에 등록된다.
이후 재 접속을 시도하면 해당 공개키가 있는 것을 확인할 수 있으므로 서버에 대한 인증 절차를 거칠 수 있다.
2. 클라이언트 인증
일반적으로 두가지 방식이 있다.
- 패스워드 인증 : test123 -> ansible 에서는 -k 옵션 사용한다.
- 안전한 클라이언트 인증을 위해 key-pair를 사용한다.
1) 클라이언트는 key-pair를 만든다. (id_rsa[개인키], id_rsa.pub[공개키])
2) 퍼블릭키를 서버의 .ssh/authorized_keys에 등록시킨다.
3) 클라이언트는 서버에 접속하기 위해 사용할 key pair 의 ID를 서버로 전송한다.
4) 서버는 ID와 매칭되는 키가 authorized_keys에 등록되어 있는지 여부를 확인한다.
5) 만약 해당 키가 등록되어 있다면 난수(임의의 문자열)를 생성하고 이를 서버가 가지고 있는 퍼블릭키를 이용하여 암호화 시키고 이를 클라이언트에게 전달한다.
6) 클라이언트는 자신이 가지고 있는 개인키를 이용하여 이를 복호화 한다. 정상적으로 처리되면 난수가 보일것이다.
7) 이 난수를 hash 한다. 임의의 문자열이 나온다. 이를 다시 서버에게 전달한다.
8) 서버는 자신이 가지고 있던 난수를 동일한 hash function에 넣고 임의의 문자열을 확인한다. 이를 클라이언트로부터 받은 해시코드와 비교한다.
만약 동일하다면 내가 가지고 있는 퍼블릭키의 주인이라는 것을 증명한 것이다.
9) 클라이언트가 증명되었으므로 정상적인 데이터 송수신이 가능해 진다.
우리는 key를 이용한 방법을 쓰자
현재 환경에서의 문제점
1. 서버는 앤서블로부터 명령을 받아서 처리하는 CentOS VM이다.
2. 이 서버들은 현재 패스워드 인증이 지원된다. -> 서버에서 패스워드 인증을 disable 시켜야 한다.
3. 클라이언트는 접속할때 기본으로 자신의 키를 이용하여 접속하도록 설정한다.
4. 다수의 서버의 초기 접속시 퍼블릭키를 클라이언트의 known_hosts에 어떻게 등록할 것인가? 만약 없다면 접속하고자 하는 서버의 숫자만큼 'yes'를 타이프해야한다.
이를 해결하기 위해, StrictHostKeyChecking=no 옵션을 이용하면 해당 서버가 등록되어 있지 않더라도 접속이 되도록 할 수 있다. 하지만 이는 보안상 절대 추천하지 않는 방법이다.
ssh-keyscan을 통해 서버의 퍼블릭 키를 가져와야 한다.
5. 키를 생성할 때 생성하는 사람에게 무엇인가를 물어보는 단계는 모두 생략되어야 한다. 즉, ssh-keygen에서 옵션을 이용하여 key-pair를 즉시 요청 생성해야 한다.
* 우리같은 관리자들은 유저가 우리에게 물어보는 단계가 모두 생략될 수 있어야 함
---
[ 해결 ]
1. ansible을 설치한다.
```
yum -y install epel-release
yum -y install ansible
vi /etc/ansible/hosts #인벤토리 파일
```
인벤토리 파일은 내가 관리하고자 하는 서버가 등록되어 있는 파일이다.
2. 관리하고자 하는 서버들의 IP 주소를 /etc/ansible/hosts에 등록한다. 제일 아래쪽에 등록해주자.
```
ansible all -m ping
```
하면 등록되어 있는 서버들 모두에 ping을 보내는 방식이다. 문제는 이렇게하면 fingerpring 인증하라는게 돌아온다. 그래서 이건 좋은 방법이 아니다.
패스워드를 쓰는 것도 좋은 방법이 아니다.
바로 응답이 나올 수 있도록 만들어야 한다.
3. 관리하고자 하는 ssh 서버에서 사용자 인증을 패스워드로 하지 않도록 설정
wok에 들어가서 한개의 인스턴스의 Serial을 실행시키고
```
cat /etc/ssh/sshd_config | grep PasswordAuth
```
에서 이거 관련된 부분들을 no로 바꾸어주자
```
sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
```
로 내용을 수정해주자.
이제부터는 공용/개인키로만 접속해야 한다.
4. 클라이언트쪽(KVM) 에서 key-pair를 생성하고 public key를 각 서버의 .ssh/authorized_keys에 등록해야 한다.
```
ssh-keygen -q -f ~/.ssh/id_rsa -N ''
```
파일이 생성된다. 그리고 id_rsa_pub도 만들어진다.
결과는
이렇게 키 두개가 생기게 된다.
id_rsa.pub를 각 서버에 붙여넣기 (authorized_keys) 한다. 이와 유사하게 생성된 인스턴스들에도 이 명령어를 넣어주자.
이 상황인데 이제 id_rsa.pub을 인스턴스들의 .ssh/authorized_keys로 붙여넣어주자.
그렇다보니 처음 이미지 만들때 이거 다 집어넣으면 편하다는 것이다.
3. kvm의 .ssh 아래에 있는 id_rsa.pub를 복사하여 각 서버의 .ssh 아래에 authorized_keys 파일에 붙여넣기 한다.
직접 인스턴스에 들어가서 ~/.ssh/authorized_keys에 host os의 id_rsa.pub을 복사해서 붙여넣어주자
그리고 권한 부여도 해주자
```
chmod 600 ~/.ssh/authorized_keys
```
모든 인스턴스에 반복해주자
4. 접속하고자 하는 서버의 public key를 끌고와서 .ssh/known_hosts 등록시킨다.
```
ssh-keyscan 211.183.3.129 >> ~/.ssh/known_hosts
ssh-keyscan 211.183.3.130 >> ~/.ssh/known_hosts
```
키들이 보인다.
```
ansible centos -m ping
```
요렇게 초록색이 나오면 성공이다. 안되면 처음부터 다시해야 한다.
```
ansible centos -m shell -a 'ip a'
```
shell로 ip a 라는 명령어를 보내서 ip들을 확인해볼 수 있다.
만약 .ssh 아래에 id_rsa 파일이 아닌 별도의 장소에 보관되어 있거나 기본 이름이 아닌경우라면 인증이 되지 않는다. 이 경우에는 다음과같은 방법을 사용할 수 있다.
예를들어 키 이름이 chulsoo.pem -- chulsoo.pem.pub
vi /etc/ssh/ssh_config
파일 가장 아래쪽으로 가서 위와같이 pem 파일 위치를 등록할 수도 있다. 모든 계정을 root로 인증을 하되 파일은 지정해놓은것이다.
이때 앤서블 본체는 앤서블 소프트웨어 그 자체이기 때문에 서버/클라이언트 구성과 같은 형태를 취하지 않는다.
앤서블의 인벤토리
- 서버관리를 위한 목록
- 기본적으로 /etc/ansible/hosts를 이용한다.
- 관리의 편의 또는 구분의 편의, 효율적(hosts에만 쓰면 너무 길어짐) 인 사용을 위하여 여러 인벤토리 파일을 별도로 만들어 사용할 수 있다.
예를들어서 위와같이 -i 옵션으로 인벤토리들을 불러오고 그 중에서도 production이라는 list-host를 불러올 수 있다.
모듈 = 함수
앤서블에서 실행된 하나하나의 명령과 같은 것
- 리눅스에서 사용하는 각각의 명령어를 별도의 모듈로 지정해 둔것으로
- 일반 shell을 이용하면 지원되지 않는 "멱등성" 을 제공하는 경우가 많다.
* 멱등성이란 어떤 특정 조건을 갖추어야 하는 상태를 만드는 것. 예를 들어 a라는 파일에 a=b라는 값을 넣었다고 가정해 보자. 만약 shell을 이용하여 동일 값을 추가한다면 추가된다. 즉 한번 했을때 결과가 이미 만족했다면 더 이상 안한다.
start -> started, stop -> stopped
shell 모듈은 좋지 않다. 보통 체크용도로만 쓰자. 실재로는 체크 모듈이 정말 많다.
All modules — Ansible Documentation
```
ansible all -m shell -a "systemctl stop firewalld"
```
그래서 m은 모듈이다.
요런식으로 작동하게 된다.
[플레이북](작업 명세서)
앤서블에서 명령이라고 하면 스크립트(코드)아며 앤서블을 사용할 때 필요한 작업은 플레이북의 구현과 실행이라고 할 수 있다. 이를 간단히 yaml 작성할 경우 다수의 명령을 한꺼번에 실행할 수 있게 된다. yaml 파일로 작성되며 재사용 역시 가능하다.
---
실습
예를들어 인벤토리는 위와같이 만들어준다. lst로 끝나기만 하면 되나보다
먼저 파일 두개를 만들자
seoul.lst 안에는 위와같이 ip를 적어주자 ip는 내가 만든 가상머신 ip이다.
그리고 seoul.lst내용을 busan.lst에 넣어놓자
실재로 ping 모듈로 해보니 이렇게 된다.
삼성만 하려면 이렇게 하면된다.
설치도 되기는 하지만 이렇게 쓰면 멱등성에 문제가 생김으로 가급적 다른 모듈을 써주자
user 모듈
사용자를 생성, 삭제, 수정할 수 이는 모듈
```
ansible all -m user -a "name=newuser1"
```
이 모듈은 생성시 state:present를 유지해 달라는 의미이다. 만약에 빈자리이다면? 없는 상태로 유지해달라고 해보자
```
ansible all -m user -a "name=user2 state=absent"
```
state=absent는 이거 말고도 yum이라는 모듈에서도 사용이 가능하다.
```
ansible all -m yum -a "name=httpd state=absent"
```
만약에 한번더 입력하더라도 멱등성 유지를 위해 상태변화가 생기지 않는다.
```
ansible all -m yum -a "name=httpd state=present"
```
다시 설치하고자 한다면 present로 state를 변경해주면 된다.
copy 모듈
- copy는 로컬에서 작성한 파일을 노드에 복사할 수 있는 모듈이다. 예를들어 httpd가 설치된 각 노드에 로컬서버에서 작성한 index.html 파일을 복사해보자
```
curl https://www.naver.com > index.html
ansible all -m copy -a "src=index.html dest=/var/www/html/index.html"
ansible all -m service -a "name=firewalld state=stopped"
ansible all -m service -a "name=httpd state=started"
```
사이트가 변경된것을 확인할 수 있다.
---
vagrant
```
yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
yum -y install libvirt-daemon-kvm libvirt-client vagrant gcc-c++ make libstdc++-devel libvirt-devel
systemctl restart libvirtd
vagrant plugin install vagrant-libvirt
vagrant -v
```
libvirtd 환경에서 테스트로 인스턴스를 하나 생성해보기
Discover Vagrant Boxes - Vagrant Cloud (vagrantup.com)
위의 링크로 가보면 다양한 vagrant의 프로비저닝 된 이미지들을 확인해볼 수 있다.
```
vagrant init centos/7
```
자동으로 프로비저닝 된 파일을 확인해볼 수 있다.
```
vagrant up
```
하고나면 위와같이 .vagrant 파일이 보인다.
```
vagrant box list
```
하면 우리가 설치했던 파일이 보인다.
```
virsh list
```
하면 우리가 vagrant init 때 요청했던 vm이 돌아가는 것을 볼 수 있다.
```
vagrant ssh
```
하면 해당 vm에 접속할 수 있다. vagrant vm이 많으면 직접 이름을 지칭해야겠지만 지금은 한개뿐이기 떄문에 이것만으로도 접속이 가능해진다.
vagrant vm의 ip는 DHCP로 자동 할당받으며 virbr1의 주소인 192.168.122.1을 통해 외부와 통신할 수 있는 NAT 브릿지로 연결된다.
```
exit # vagrant에서 빠져나오기
vagrant halt
vagrant destroy
```
default 가상머신을 없앨 수 있다.
vagrant 파일안에 있는 35번쨰 줄의 주석을 제거해보자. 그러면 별도로 네트워크가 지정되어 가상머신에는 추가적인 인터페이스가 생성되며 지정된 IP를 할당 받게 된다. 사설 주소이므로 기존의 인터페이스와 별도의 인터페이스를 갖게 된다.
생성후 ip는 192.168.33.10에 할당되었으며 사설 주소이므로 기존의 인터페이스와 별도의 인터페이스를 갖게 된다.
이제 Vagrantfile 내부를 모두 지우고 이렇게 작성해주자
# -*- mode: ruby -*-
# # vi: set ft=ruby :
###### ANSIBLE SERVER CONFIG #######
Vagrant.configure("2") do |config|
config.vm.define "ansible-server" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-server"
cfg.vm.network "private_network", ip: "172.16.1.10"
cfg.vm.network "forwarded_port", guest: 22, host: 60010, auto_correct: true, id: 'ssh'
end
end
위와같이 Vagrantfile을 작성해주자
그러면 배포시 ip와 포트번호가 설정된 상태로 배포되는 것을 확인해볼 수 있을 것이다.
```
vagrant up
```
하면 생성된거 확인할 수 있으니 다시 내려주고
---
- name: test configuration
hosts: localhost
gather_facts: no
tasks:
- name: install git
yum:
name: git
state: present
- name: install httpd
yum:
name: httpd
state: present
- name: start httpd
service:
name: httpd
state: started
- name: stop firewalld
service:
name: firewalld
state: stopped
이 상황에서 test.yml 파일과 Vagrantfile의 내용도 test.yml을 사용할 수 있도록 살짝 수정해보자
# -*- mode: ruby -*-
# # vi: set ft=ruby :
###### ANSIBLE SERVER CONFIG #######
Vagrant.configure("2") do |config|
config.vm.define "ansible-server" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-server"
cfg.vm.network "private_network", ip: "172.16.1.10"
cfg.vm.network "forwarded_port", guest: 22, host: 60010, auto_correct: true, id: 'ssh'
cfg.vm.provision "shell", inline: "yum -y install epel-release"
cfg.vm.provision "shell", inline: "yum -y install ansible"
cfg.vm.provision "file", source: "test.yml", destination: "test.yml"
cfg.vm.provision "shell", inline: "ansible-playbook test.yml"
end
end
playbook와 vagrantfile에는 큰 차이가 없다. 그리고 test.yaml 파일만 수정한 상태이다. 이럴때 vagrantfile을 provision 하려고 하는데 기존과 변경사항이 없다. 하지만 test.yaml 의 변경사항까지 점검해서 그걸 감지하고 프로비저닝하겠다는 의미이다.
github도 이와 유사하게 index.html 파일안에 변경점이 발견되면 이를 감지하는 vcs인 .git이 존재한다.
예를 들어 vagrant도 위와같이 .vagrant 라는 vcs가 생긴것을 볼 수 있다.
이 상황에서
```
vagrant provision
```
해주면 프로비저닝된다.
배포된 인스턴스의 정보를 긁어와보자
제대로 배포된 것을 확인할 수 있다.
그럼 지금 상황을 파악해보면 아래쪽에 192.168.122.x 의 주소가 있고 스위치 주소로(192.168.122.1)의 자체 주소가 있다.
위쪽에는 가상의 스위치가 만들어져서 172.16.1.x(스위치 주소는 172.16.1.1)의 주소를 가지고 있다.
그리고 인스턴스는 이 둘과 연결되어 .10의 주소를 가지고 있는 상태이다.
이걸확인하기 위해 `virsh net-list` 명령어를 사용해보면 위와같이 구성되어 있는데
```
virsh net-dumpxml default
virsh net-dumpxml vagrant0
```
를 보면
위와같이 작성되어 있다. 그래서 172.16.1.1에 연결도 가능하다.
나중에 가상머신을 추가로 연결한다면 virsh 스위치에 연결시키면 내부적으로 관리도 가능해질것이다.
이제 서버는 준비가 되었다.
그러니 추가 노드를 만들어보자
# -*- mode: ruby -*-
# # vi: set ft=ruby :
###### ANSIBLE NODE 1~3 ######
Vagrant.configure("2") do |config|
config.vm.define "ansible-node1" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-node1"
cfg.vm.network "private_network", ip: "172.16.1.11"
cfg.vm.network "forwarded_port", guest: 22, host: 60011, auto_correct: true, id: "ssh"
end
config.vm.define "ansible-node2" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-node2"
cfg.vm.network "private_network", ip: "172.16.1.12"
cfg.vm.network "forwarded_port", guest: 22, host: 60012, auto_correct: true, id: "ssh"
end
config.vm.define "ansible-node3" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-node3"
cfg.vm.network "private_network", ip: "172.16.1.13"
cfg.vm.network "forwarded_port", guest: 22, host: 60013, auto_correct: true, id: "ssh"
end
end
###### ANSIBLE SERVER CONFIG #######
Vagrant.configure("2") do |config|
config.vm.define "ansible-server" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-server"
cfg.vm.network "private_network", ip: "172.16.1.10"
cfg.vm.network "forwarded_port", guest: 22, host: 60010, auto_correct: true, id: 'ssh'
cfg.vm.provision "shell", inline: "yum -y install epel-release"
cfg.vm.provision "shell", inline: "yum -y install ansible"
cfg.vm.provision "file", source: "test.yml", destination: "test.yml"
cfg.vm.provision "shell", inline: "ansible-playbook test.yml"
end
end
```
vagrant up
ping -c 3 172.16.1.10 ; ping -c 3 172.16.1.11 ; ping -c 3 172.16.1.12 ; ping -c 3 172.16.1.13
```
그런데 지금 노드들에는 패스워드가 없다. 그래서 접근시 아무렇게나 들어올 수 있다는 단점이 있다.
먼저 ansible-server로 접속해보자
```
vi /etc/ansible/hosts
```
하고 나갈려고 하면 안된다.
그래서
```
sudo vi /etc/ansible/hosts
```
하면 된다... 오잉? 중요한 부분이다.
PasswordAuthentication no
ansible은 sudo의 권한은 있다. 그래서 /etc/ansible/hosts는 root의 권한을 불러와서 사용해야 하는데 vagrant는 sudo에 포함되어 있다. 그럼 서버가 명령을 전달할때 vagrant로 전달하더라도 상대도 vagrant로 받게 된다.
내가 playbook을 만들때 playbook은 노드들에게 명령을 전달하는 것인데 노드들이 실행할 수 있는 권한도 없는데 당연히 실행이 안된다. 그래서 노드들에게 루트 권한을 잠시 빌려와서 sudo로 실행하라고 할 수 있다.
예시로 위와같이
```
ansible all -m ping -k
# 패스워드 : vagrant
```
하면 fail이 뜬다.
그래서 서버의 authorized_keys를 확인해보면 `vagrant`키 값이 암호화되어 저장된 것을 볼 수 있다.
현재상태
server --- node1 ~ node3
server가 노드들에 접속을 시도했는데 이전에 접속한적이 없으니 known_hosts가 없다. 그러니 처음 접속시 public key를 서버에 저장할 것인지를 물어봤어야 했는데 이번에는 그러지 않았다.
어떤 문제가 있는 것일까?
```
vi /etc/ssh/sshd_config
```
이 안에서 PasswordAuthentication을 yes로 바꾸어주자.
그런데 모든 node들에서 이것을 허용해주어야 한다. Vagrant 파일에서 이를 해결하기 위한 내용을 추가해서 이 문제를 해결해보자. vagrant server에서는 할 필요 없다.
---
현재 server에서 node로의 접속은 불가능한 상태이다. 그러니 다음을 해보자
Vagrantfile에서 a.sh를 각 노드에 붙여넣기.
a.sh 파일은 /etc/ssh/sshd_config 파일의 내용중 PasswordAuthentication no를 PasswordAuthentication yes로 변경하고 ssh를 재실행하는 것을 포함해야한다.
또한, 서버에서는 각 노드들의 서버인증을 위해 keyscan 해야 한다.
이후 서버에서 노드로 ansible all -m ping -k를 하면 Password: vagrant를 통해 ping:pong이 확인 되어야 한다.
```
vi auth.sh
```
를 확인해보면 위와같이 나오는 것을 볼 수 있다. 이걸 Vagrantfile안에 넣고 실행시키자
위와같이 2줄을 추가해주었다.
# -*- mode: ruby -*-
# # vi: set ft=ruby :
###### ANSIBLE NODE 1~3 ######
Vagrant.configure("2") do |config|
config.vm.define "ansible-node1" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-node1"
cfg.vm.network "private_network", ip: "172.16.1.11"
cfg.vm.network "forwarded_port", guest: 22, host: 60011, auto_correct: true, id: "ssh"
cfg.vm.provision "file", source: "auth.sh", destination: "auth.sh"
cfg.vm.provision "shell", inline: "/bin/bash auth.sh", privileged: true
end
config.vm.define "ansible-node2" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-node2"
cfg.vm.network "private_network", ip: "172.16.1.12"
cfg.vm.network "forwarded_port", guest: 22, host: 60012, auto_correct: true, id: "ssh"
cfg.vm.provision "file", source: "auth.sh", destination: "auth.sh"
cfg.vm.provision "shell", inline: "/bin/bash auth.sh", privileged: true
end
config.vm.define "ansible-node3" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-node3"
cfg.vm.network "private_network", ip: "172.16.1.13"
cfg.vm.network "forwarded_port", guest: 22, host: 60013, auto_correct: true, id: "ssh"
cfg.vm.provision "file", source: "auth.sh", destination: "auth.sh"
cfg.vm.provision "shell", inline: "/bin/bash auth.sh", privileged: true
end
end
###### ANSIBLE SERVER CONFIG #######
Vagrant.configure("2") do |config|
config.vm.define "ansible-server" do |cfg|
cfg.vm.box = "centos/7"
cfg.vm.host_name = "ansible-server"
cfg.vm.network "private_network", ip: "172.16.1.10"
cfg.vm.network "forwarded_port", guest: 22, host: 60010, auto_correct: true, id: 'ssh'
cfg.vm.provision "shell", inline: "yum -y install epel-release"
cfg.vm.provision "shell", inline: "yum -y install ansible"
cfg.vm.provision "file", source: "test.yml", destination: "test.yml"
cfg.vm.provision "shell", inline: "ansible-playbook test.yml"
cfg.vm.provider :libvirt do |resource|
resource.memory = 2048
resource.cpus = 2
end
end
end
하는김에 libvirt로 만드는 서버에 메모리와 cpu 갯수를 올려주었다. 즉시 반영은 안되고 재부팅을 해야한다.
```
vagrant provision
vagrant ssh ansible-server
ssh-keyscan 172.16.1.11 >> ~/.ssh/known_hosts
ssh-keyscan 172.16.1.12 >> ~/.ssh/known_hosts
ssh-keyscan 172.16.1.13 >> ~/.ssh/known_hosts
ansible all -m ping -k
```
이제 서버는 모든 노드를 관리할 수 있는 상태가 되었다.
단, vagrant 계정으로 관리할 수 있는 상태이다.
만약 root로 관리하고 싶다면 vagrant에서 플레이북을 실행할 때 root의 권한을 일시적으로 빌려와서 쓰는 방법(become: true)
두번째, root 계정에서 key 만들고 퍼블릭키를 배포하여 사용하는 방법
플레이북
플레이북은 yaml 형식으로 작성된 시스템 정의서 같은 것
위와같은 구조로 작성해주면 된다.
--- : yaml 형식의 파일임을 알려주는 선언
name: 로그에 표시되는 이름
hosts: 배포대상
tasks: 실제 작업
배포에 걸리는 시간을 줄이는데 gather_facts를 false 또는 no라고 해놓자.
gather_facts는 각각의 노드 정보를 수집하는데 수집해서 무언가를 하겠다는 의미이지만 no로 하면 수집안하겠다. 즉 네 os 환경에 상과없이 처리하라는 의미이자. 내가 대상의 정보를 아니 그냥 처리하겠다는 것이다.
수집되는 정보는 도대체 무엇이 있을까?
```
ansible all -m setup -k >gatherfacts.txt
```
하면 위와같이 엄청 많은 정보들이 불러와진다.
이 중에서도 우리에게 필요한 정보를 긁어와보자
```
cat gatherfacts.txt | grep SSH_CONNECTION
```
하면 위와같이 연결정보들을 모두 확인할 수 있다.
```
cat gatherfacts.txt | grep ansible_eth0
cat gatherfacts.txt | grep ansible_eth1
cat gatherfacts.txt | grep ansible_pkg_mgr # 패키지 매니저
cat gatherfacts.txt | grep ansible_distribution
```
보면 ansible_distribution으로 OS 정보가 뜬다. 이걸 이용해서 OS 별로 조건을 걸수도 있다.
그런데 이런정보까지 다 필요없이 그냥 해달라 그래서 gather_facts no라고 해놓는것이다.
물론 우리가 쓰는 OS가 centos이면 플레이북의 yum은 오류가 나지만... 이것도 조건을 걸어주어서 해결할 수 있다.
플레이 내에서 태스크 구현과 엔진엑스의 배포
1. 관리자 권한으로 실행
이거 실행할때만 관리자 권한을 쓰라고 할 수 있다.
2. SELinux 설정
SELinux를 파이썬에서 사용할 수 있도록 libselinux-python을 yum으로 설치하자.
=을 쓰는 방법으로도 가능하다. 하지만 잘 안쓴다.
3. EPEL 저장소 설치
일반적으로 nginx는 yum으로 설치되지 않는다. epel-release 설치가 된 후에 설치가능해진다.
```
# 반드시 ansible-server에서 실행하고 만들자
vi httpdinstall.yaml
```
---
- name: httpd installation
hosts: all
gather_facts: no
tasks:
- name: DIRECTORY CREATION
file:
path: /home/vagrant/testdir
state: directory
- name: libselinux-python install
become: yes
yum:
name: libselinux-python
state: present
- name: httpd install
become: yes
yum:
name: httpd
state: present
- name: start httpd
become: yes
service:
name: httpd
state: started
enabled: true
- name: stop firewalld
become: yes
service:
name: firewalld
state: stopped
enabled: false
```
ansible-playbook httpdinstall.yaml -k
```
성공한것을 확인할 수 있다.
curl로 ip를 따보니 httpd 의 정보가 보인다.
quiz. get_url을 이용하여 https://www.nginx.com 의 페이지를 각 노드의 /var/www/html에 붙여 넣기 하세요.
---
- name: httpd installation
hosts: all
gather_facts: no
tasks:
- name: DIRECTORY CREATION
file:
path: /home/vagrant/testdir
state: directory
- name: libselinux-python install
become: yes
yum:
name: libselinux-python
state: present
- name: httpd install
become: yes
yum:
name: httpd
state: present
# 이 부분이 추가되었다.
- name: index creation
become: yes
get_url: url=https://www.nginx.com dest=/var/www/html/index.html
- name: start httpd
become: yes
service:
name: httpd
state: started
enabled: true
- name: stop firewalld
become: yes
service:
name: firewalld
state: stopped
enabled: false
```
ansible-playbook httpdinstall.yaml -k
```
해주면 nginx.com 홉페이지가 curl로 긁어와진다.
---
- name: using sed
hosts: localhost
become: yes
gather_facts: no
tasks:
- name: change selinux
replace:
path: /etc/selinux/config
regexp: 'SELINUX=enforcing'
replace: 'SELINUX=disabled'
```
vi sed.yaml
ansible-playbook sed.yaml -k
```
파일을 위와같이 작성하여 모든 노드의 selinux=disabled 로 바꾸어주자.
---
- name: httpd installation
hosts: all
gather_facts: no
tasks:
- name: SELINUX disabled
become: yes
replace:
path: /etc/selinux/config
regexp: 'SELINUX=enforcing'
replace: 'SELINUX=disabled'
- name: DIRECTORY CREATION
file:
path: /home/vagrant/testdir
state: directory
- name: libselinux-python install
become: yes
yum:
name: libselinux-python
state: present
- name: httpd install
become: yes
yum:
name: httpd
state: present
- name: index.html creation
become: yes
get_url: url=https://www.nginx.com dest=/var/www/html/index.htm
- name: start httpd
become: yes
service:
name: httpd
state: started
enabled: true
- name: stop firewalld
become: yes
service:
name: firewalld
state: stopped
enabled: false
```
ansible-playbook httpdinstall.yaml -k
```
---
이번에는
```
cp sed.yaml file.yaml
vi file.yaml
```
---
- name: using sed
hosts: localhost
become: yes
gather_facts: no
tasks:
- name: line in file
lineinfile:
path: /etc/ansible/hosts
line: 172.16.1.14
위와 같이 내용을 넣고 실행해보자
그러면 가장 아래쪽에 ip가 추가 등록되어 있는 것을 확인할 수 있다.
참고로 멱등성이 적용되므로 한번더 실행한다고 같은게 또 등록되지는 않는다.
---
- name: using sed
hosts: localhost
become: yes
gather_facts: no
tasks:
- name: line in file
lineinfile:
path: /etc/ansible/hosts
line: "{{ item }}"
with_items:
- "172.16.1.15"
- "172.16.1.16"
file.yaml 을 한번더 수정해보자
위와같이 된다.
---
block 단위로 입력
여러줄을 입력할 수도 있고 블럭 형태로 그대로 도장찍듯이. 띄어쓰기 등도 그대로 옮겨진다.
---
- name: using sed
hosts: localhost
become: yes
gather_facts: no
tasks:
- name: line in file
blockinfile:
path: /etc/ansible/hosts
block: |
[centos]
172.16.1.11
172.16.1.12
172.16.1.13
요런식으로 들어오게 된다.
파이프를 쓰게 되면 마지막 라인을 비우지 않는다.
그리고 # BEGIN ANSIBLE MANAGED BLOCK 부분이 BLOCK임을 알려준다.
```
ansible centos -m ping -k --list-hosts
```
---
nfs ansible playbook 만들기
---
- name: nfs-server
hosts: localhost
gather_facts: no
tasks:
- name: DIR creation
file:
path: /home/vagrant/shared
state: directory
mode: 0777
- name: installation nfs server
become: yes
yum:
name: nfs-utils
state: present
- name: configuring /etc/exports
become: yes
lineinfile:
path: /etc/exports
line: /home/vagrant/shared 172.16.1.0/24(rw,sync)
- name: start nfs server
become: yes
service:
name: nfs-server
state: restarted
#- name: nfs-client
# hosts: centos
# gather_facts: no
# tasks:
nfsconfiguration.yaml 을 만들어서 배포해보자
```
ansible-playbook nfsconfiguration.yaml -k
```
'Development(Web, Server, Cloud) > 22) LINUX - Cloud' 카테고리의 다른 글
클라우드 72일차 (0) | 2022.05.09 |
---|---|
클라우드 71일차 (0) | 2022.05.09 |
클라우드 69일차(aws-정리중, ansible, ????) (0) | 2022.05.02 |
클라우드 68일차 (0) | 2022.04.29 |
클라우드 67일차(PV,PVC,jenkins,gcp-정리중) (0) | 2022.04.28 |