티스토리 뷰
CloudNet@의 가시다님 Ansible 1기 스터디에 참여하게 되어 배운 내용과 책의 내용을 함께 정리합니다.
📚 앤서블로 시작하는 인프라 자동화
1. 사용자 계정 생성
플레이북을 안전하고 효율적으로 사용하기 위해서는 플레이북에 필요한 모듈을 먼저 생각하고 이를 사용하는 플레이북을 미리 설계하여 작성하는 습관을 가져야 합니다.
사전 분석
- 사용자 계정과 패스워드는 Vault를 이용해 암호화 처리합니다.
- 사용자 계정 생성은 ansible.builtin.user 모듈을 이용합니다.
플레이북 설계
플레이북을 하나의 디렉토리 단위로 구분하면 디렉토리 안에 있는 ansible.cfg 파일과 inventory 파일을 플레이북마다 별도로 관리할 수 있어 보다 효율적입니다. 디렉토리를 기준으로 파일 이름, 태스크명, 사용할 모듈과 변수들의 정의, 변수명과 변수를 선언할 위치 등을 미리 설계해봅니다.
플레이북 개발
1. 프로젝트 디렉토리를 생성하고 ansible.cfg 파일과 inventory 파일을 작성합니다.
~/my-ansible/chapter_09.1
#
mkdir ~/my-ansible/chapter_09.1
cd ~/my-ansible/chapter_09.1
# ansible.cfg, inventory 파일 작성
cat <<EOT > ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ubuntu
ask_pass = false
[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
EOT
cat <<EOT> inventory
tnode1
tnode2
tnode3
EOT
2. 사용자 계정 정보가 정의된 변수 파일을 생성합니다.
~/my-ansible/chapter_09.1/vars/secret.yml
# vault 암호는 편하게 입력
ansible-vault create vars/secret.yml
New Vault password: qwe123
Confirm New Vault password: qwe123
## 에디터 창으로 전환 : (아래 내용 복붙) user_info 변수에 userid와 userpw가 같이 있는 사전형 변수를 정의
---
user_info:
- userid: "ansible"
userpw: "ansiblePw1"
- userid: "stack"
userpw: "stackPw1"
~
~
:wq
# 변수 파일 확인
ls -l vars/secret.yml
cat vars/secret.yml
생성된 secret 파일이 암호화된 것을 확인할 수 있습니다.
3. 사용자 계정을 생성하는 플레이북을 작성합니다. (모든 호스트에 동일하게 생성하며 vault로 작성된 변수 파일을 읽어 사용합니다.)
~/my-ansible/chapter_09.1/create_user.yml
---
- hosts: all
# vault로 사용자 계정 관련 변수가 정의된 파일을 임포트하여 사용
vars_files:
- vars/secret.yml
tasks:
# loop 문을 사용하여 user_info의 userid와 userpw 사용
- name: Create user
ansible.builtin.user:
name: "{{ item.userid }}"
password: "{{ item.userpw | password_hash('sha512', 'mysecret') }}"
state: present
# 기본 shell은 /bin/sh이므로 변경 권장
shell: /bin/bash
loop: "{{ user_info }}"
4. 플레이북을 실행하기 전에 플레이북의 문법을 체크합니다.
# 에러 메시지 없이 플레이북 이름만 출력되면 문법 정상!
ansible-playbook --syntax-check create_user.yml
...
# 실패! > 다시 실행
ansible-playbook --ask-vault-pass --syntax-check create_user.yml
사용자 계정 정보가 정의된 변수를 생성할 때 secret 파일을 통해 생성했기 때문에 --ask-vault-pass 옵션을 함께 사용해주어야 합니다.
5. 플레이북에 --ask-vault-pass 옵션을 주어 실행합니다.
ansible-playbook --ask-vault-pass create_user.yml
6. 계정이 생성되었는지 확인합니다.
# 계정 생성 확인
ansible -m shell -a "tail -n 3 /etc/passwd" all
도전과제1
- 9.1 실습 시 vault에 AWS SecretManager를 활용해보세요
2. SSH 키 생성 및 복사
사전 분석
- 사용자 아이디는 외부 변수로 받습니다.
- ansible-server에서 ansible 계정을 만들고 SSH 키를 생성합니다.
- ansible-server에 생성된 SSH 공개 키를 각 tnode에 복사합니다.
- 계정을 생성할 때는 ansible.builtin.user 모듈을, SSH 공개 키를 복사할 때는 ansible.posix.authorized_key 모듈을 이용합니다.
플레이북 설계
- 앤서블 공식 문서의 콘텐츠 컬렉션에서 플레이북 개발에 필요한 SSH 키 생성 모듈과 SSH 키 복사 모듈을 찾았다면, 해당 모듈의 예제와 파라미터 정보를 이용해 플레이북을 설계합니다.
- 해당 플레이북명은 create_sshkey.yml 로 설정하고, Create ssh key 태스크와 Copy SSH Pub Key 라는 2개의 태스크를 갖습니다.
- Create ssh key 태스크는 localhost에서 실행하고, Copy SSH Pub Key 태스크는 tnode에서 실행합니다.
- 인벤토리에는 tnode라는 그룹을 만든 다음 모든 관리 노드를 tnode 그룹으로 정의합니다.
플레이북 개발
1. 프로젝트 디렉토리를 생성하고 inventory 파일을 작성합니다.
#
mkdir ~/my-ansible/chapter_09.2
cd ~/my-ansible/chapter_09.2
# ansible.cfg, inventory 파일 작성
cp ~/my-ansible/ansible.cfg ./
# inventory 파일 수정
cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT
# lookup 플러그인
ansible-doc -l -t lookup
2. SSH키를 생성하고 복사하는 플레이북을 작성합니다. (태스크가 실행될 호스트별로 태스크를 작성합니다.)
- localhost인 ansible-server에서 생성된 SSH 공개 키는 ansible.posix.authorized_key 모듈을 이용하여 인벤토리의 tnode 호스트 그룹의 각 서버로 복사됩니다.
- 이때 키를 등록하기 위해 lookup 함수가 사용됩니다. 외부 소스(파일, DB, key/value stores, APIs 등)으로부터 데이터를 검색
~/my-ansible/chapter_09.2/create_sshkey.yml
---
- hosts: localhost
tasks:
- name : Create ssh key
ansible.builtin.user:
name: "{{ userid }}"
# 해당 파라미터를 사용하면 userid에 대해 자동으로 ssh 키 생성
generate_ssh_key: true
ssh_key_bits: 2048
ssh_key_file: /home/{{ userid }}/.ssh/id_rsa
shell: /bin/bash
- hosts: tnode
tasks:
- name: Copy SSH Pub key
ansible.posix.authorized_key:
user: "{{ userid }}"
state: present
key: "{{ lookup('file', '/home/{{ userid }}/.ssh/id_rsa.pub') }}"
3. 플레이북을 실행합니다.
- 실행 시 외부 변수(-e) 로 사용하기 위해, 사용자 계정을 플레이북이나 별도의 파일에 정의하지 않았습니다.
# 문법 체크
ansible-playbook --syntax-check create_sshkey.yml
# 실행 : 외부 변수(-e)로 userid 정의하고 전달 실행 >> 실패!
ansible-playbook -e userid=ansible create_sshkey.yml
ansible-playbook -e userid=ansible create_sshkey.yml -vvvvv
#
ls -l /home/ansible/.ssh/id_rsa.pub
sudo ls -l /home/ansible/.ssh/id_rsa.pub
4. ubuntu계정에는 SSH Key Copy 권한이 없기 때문에 root 계정으로 플레이북을 실행하기 위해 ansible.cfg 파일을 수정합니다.
[defaults]
inventory = ./inventory
remote_user = root
inject_facts_as_vars = false
5. 각 노드에서 root 계정으로 실행되는 플레이북을 SSH Key 접근권한 때문에 localhost에서도 root 계정으로 실행해야 합니다.
6. tnode 그룹에만 있던 ansible계정이 localhost에서도 ansible계정이 생긴 것을 확인할 수 있습니다.
---
- hosts: all
tasks:
- name: Create file
ansible.builtin.file:
path: /etc/sudoers.d/ansible
mode: '0600'
state: touch
- name: Edit file
ansible.builtin.lineinfile:
path: /etc/sudoers.d/ansible
line: ansible ALL=(root) NOPASSWD:ALL
8. ubuntu 계정에서 플레이북을 실행하면 패스워드 입력없이 sudo 권한을 가질 수 있습니다.
도전과제2
- Lookups 플러그인을 활용한 playbook를 직접 작성해서 실습해보세요.
3. NTP 서버 설치 및 설정
사전 분석
- NTP 서버 주소는 메인 플레이북에서 정의합니다.
- 운영체제가 Ubuntu면 apt 모듈을 사용하여 chrony를 설치합니다.
- 운영체제가 CentOS/레드햇이면 dnf 모듈을 사용하여 chrony를 설치합니다.
- Jinja2 템플릿 방식의 chrony.conf 파일을 대상 호스트로 복사합니다.
- 설정 파일이 복사되면 chrony 서비스를 재시작합니다.
- 다음에도 사용할 수 있도록 롤을 이용하여 설계하고 작성합니다.
플레이북 설계
- 이번 예제에서는 chrony를 서로 다른 운영체제에서 각각의 모듈을 이용하여 설치할 것이므로 롤을 생성하고 호출하는 방식으로 작성합니다.
롤 구성에 필요한 플레이북 설계
- 대략적인 설계가 끝나면 롤에 대한 상세 설계를 합니다. chrony 서비스 설치를 위한 롤에서는 변수를 정의하는 vars, 환경 설정 템플릿을 위한 templates, 태스크를 정의한 tasks, 환경 설정 후 chrony 서비스를 재시작하기 위한 handlers를 사용합니다.
플레이북 개발
실습 편리를 위해 VSCODE에서 remote SSH 접속 시 root 계정으로 로그인하도록 설정을 변경합니다.
- 커맨드창(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 50.1.1.1 <- 각자 자신의 ansible-server 의 유동 공인 IP
User root
1. ansible 계정의 실습 디렉토리를 생성합니다.
su - ansible -c 'mkdir -p ~/ansible-project/chapter_09.3'
ls -l /home/ansible/
2. ansible 계정으로 전환하고 프로젝트 디렉토리로 이동합니다.
chapter_09.3/
# ansible 계정 전환
su - ansible
whoami
cd
pwd
# 프로젝트 디렉터리로 이동
cd ~/ansible-project/chapter_09.3
pwd
/home/ansible/ansible-project/chapter_09.3
3. ansible.cfg 파일과 inventory 파일을 생성합니다. (remote_user는 ansible로 설정합니다.)
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
[tnode]
tnode1
tnode2
tnode3
EOT
4. 롤을 생성합니다.
# --init-path 옵션으로 롤 생성 경로를 ./roles로 설정
ansible-galaxy role init --init-path ./roles myrole.chrony
# 확인
tree roles
5. 롤 디렉토리에서 vars/main.yml 파일을 선택한 후 아래 내용을 추가합니다.
chapter_09.3/roles/myrole.chrony/vars/main.yml
---
# vars file for myrole.chrony
package_name : chrony
service_name : chronyd
fedora_os:
- RedHat
- CentOS
6. chrony.conf.j2 파일을 생성합니다. (외부로부터 입력받은 ntp_server 변수를 사용합니다.)
touch ~/ansible-project/chapter_09.3/roles/myrole.chrony/templates/chrony.conf.j2
7. 롤 디렉토리에서 templates/chrony.conf.j2 파일을 선택한 후 아래 내용을 추가합니다.
- chrony.conf 파일의 내용은 이미 chrony 서비스가 설치되어 있는 서버의 chrony.conf 파일 내용을 참조하여 작성합니다.
chapter_09.3/roles/myrole.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
8. 핸들러에는 chrony 서비스를 재시작하는 태스크가 포함됩니다.
chapter_09.3/roles/myrole.chrony/handlers/main.yml
---
# handlers file for myrole.chrony
- name: Restart chrony
ansible.builtin.service:
name: "{{ service_name }}"
state: restarted
9. 메인 태스크를 작성합니다.
- ansible_facts.distribution 팩트 변수를 이용하여 다른 파일에서 태스크를 포함시킵니다.
- 운영체제에 맞는 chrony 환경 설정 파일의 설정을 복사하고 notify로 Restart chrony 핸들러를 호출합니다.
chapter_09.3/roles/myrole.chrony/tasks/main.yml
---
# tasks file for myrole.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
10. 메인 태스크에서 호출된 운영체제별 플레이북을 하나씩 작성합니다.
chapter_09.3/roles/myrole.chrony/tasks/RedHat.yml
---
- name: Install chrony using dnf
ansible.builtin.dnf:
name: "{{ package_name }}"
state: latest
chapter_09.3/roles/myrole.chrony/tasks/CentOS.yml
---
- name: Install chrony using dnf
ansible.builtin.dnf:
name: "{{ package_name }}"
state: latest
chapter_09.3/roles/myrole.chrony/tasks/Ubuntu.yml
---
- name: Install chrony using apt
ansible.builtin.apt:
name: "{{ package_name }}"
state: latest
11. 메인 플레이북인 install_ntp.yml 파일을 작성합니다. 롤 추가 후 ntp_server 변수를 함께 선언합니다.
chapter_09.3/install_ntp.yml
---
- hosts: tnode
roles:
- role: myrole.chrony
ntp_server: 0.kr.pool.ntp.org
12. 플레이북을 실행합니다.
ansible-playbook --syntax-check install_ntp.yml
'DevOps > Ansible' 카테고리의 다른 글
[A101] Ansible - 모니터링 자동화 (1) | 2024.02.06 |
---|---|
[A101] Ansible - 보안설정 자동화 (0) | 2024.02.05 |
[A101] Ansible - 앤서블 갤럭시와 콘텐츠 컬렉션 (0) | 2024.01.28 |
[A101] Ansible - 핸들러와 롤 (0) | 2024.01.20 |
[A101] Ansible - 반복문과 조건문 (0) | 2024.01.15 |