Ansible Study -3

LEE EUI JOO·2024년 2월 1일
0

Ansible & Vagrant

목록 보기
6/7


시스템 구축 자동화

사용자 계정 생성하기

목적

  • 사용자 계정과 패스워드는 Vault를 이용해 암호화 처리합니다.
  • 사용자 계정 생성은 ansible.builtin.user 모듈을 이용합니다.

플레이북 설계

  • 파일 이름, 태스크 명, 사용할 모듈과 변수 정의, 변수명과 변수를 선언할 위치 등

플레이북 개발

  • 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
ubuntu@server:~/my-ansible$ mkdir ~/my-ansible/chapter_09.1
cd ~/my-ansible/chapter_09.1

ubuntu@server:~/my-ansible/chapter_09.1$ cat <<EOT > ansible.cfg
[defaults]= ./inventory
inventory = ./inventory
remote_user = ubuntu
ask_pass = false
[privilege_escalation]
[privilege_escalation]
become = true = sudo
become_method = sudo
become_user = rootfalse
become_ask_pass = false
EOT

cat <<EOT> inventory
tnode1
tnode2
tnode3
EOT
  • 사용자 계정 정보가 정의된 변수 파일을 생성
# 패스워드 지정
ubuntu@server:~/my-ansible/chapter_09.1$ ansible-vault create vars/secret.yml
New Vault password: 
Confirm New Vault password: 
# 입력후 wq 저장
----
user_info:
  - userid: "ansible"
    userpw: "ansiblePw1"
  - userid: "stack"
    userpw: "stackPw1"
----

[WARNING]: vars does not exist, creating...
ubuntu@server:~/my-ansible/chapter_09.1$ ls -l vars/secret.yml
-rw------- 1 ubuntu ubuntu 743 Feb  1 20:26 vars/secret.yml
ubuntu@server:~/my-ansible/chapter_09.1$ cat vars/secret.yml
$ANSIBLE_VAULT;1.1;AES256
35623435363363613734316432653637343138633333363833646261386438343739376362366636
6165663331303134336630333166626363346335623732360a343034663834373264616533623963
36396664376137643964386136616432383031393037656633323366623031333338303762376536
3135626538663462360a333638303734316631343866643238343661373166633832346134643965
38653736623634393130396365346366616431383162646464616563633030363862333739346665
31313739393264613232363339343231633632393431303362366133623435633439356234643163
66343834363663326533306238633866616166623435363031306435383666653563623639616531
35613234633762393539303065303037656134616230623063666632343131393162383464633538
33323865393539626230303731666630336538616236316137663836353761636265
  • 사용자 계정을 생성하는 플레이북을 작성 : 모든 호스트에 동일하게 생성하며 vault로 작성된 변수 파일을 읽어 사용함
# 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/bash
    loop: "{{ user_info }}
  • 플레이북 실행
ubuntu@server:~/my-ansible/chapter_09.1$ ansible-playbook --ask-vault-pass create_user.yml
Vault password: 

PLAY [all] ********************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode3]
ok: [tnode1]
ok: [tnode2]

TASK [Create user] ************************************************************************************************************************************************************************************************************
[DEPRECATION WARNING]: Encryption using the Python crypt module is deprecated. The Python crypt module is deprecated and will be removed from Python 3.13. Install the passlib library for continued encryption functionality.
 This feature will be removed in version 2.17. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
[DEPRECATION WARNING]: Encryption using the Python crypt module is deprecated. The Python crypt module is deprecated and will be removed from Python 3.13. Install the passlib library for continued encryption functionality.
 This feature will be removed in version 2.17. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
[DEPRECATION WARNING]: Encryption using the Python crypt module is deprecated. The Python crypt module is deprecated and will be removed from Python 3.13. Install the passlib library for continued encryption functionality.
 This feature will be removed in version 2.17. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
changed: [tnode3] => (item={'userid': 'ansible', 'userpw': 'ansiblePw1'})
changed: [tnode2] => (item={'userid': 'ansible', 'userpw': 'ansiblePw1'})
changed: [tnode1] => (item={'userid': 'ansible', 'userpw': 'ansiblePw1'})
changed: [tnode2] => (item={'userid': 'stack', 'userpw': 'stackPw1'})
changed: [tnode3] => (item={'userid': 'stack', 'userpw': 'stackPw1'})
changed: [tnode1] => (item={'userid': 'stack', 'userpw': 'stackPw1'})

PLAY RECAP ********************************************************************************************************************************************************************************************************************
tnode1                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode2                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode3                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 확인
ansible -m shell -a "tail -n 3 /etc/passwd" all

tnode3 | CHANGED | rc=0 >>
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
ansible:x:1001:1001::/home/ansible:/bin/bash
stack:x:1002:1002::/home/stack:/bin/bash
tnode1 | CHANGED | rc=0 >>
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
ansible:x:1001:1001::/home/ansible:/bin/bash
stack:x:1002:1002::/home/stack:/bin/bash
tnode2 | CHANGED | rc=0 >>
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
ansible:x:1001:1001::/home/ansible:/bin/bash
stack:x:1002:1002::/home/stack:/bin/bash

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(현재 ansble 서버)에서 실행하고, ‘Copy SSH Pub Key’ 태스크는 tnode에서 실행합니다.

  • 인벤토리에는 다음과 같이 tnode라는 그룹을 만든 다음 모든 관리 노드를 tnode 그룹으로 정의합니다.

ansible.posix.authorized_key 모듈 https://docs.ansible.com/ansible/latest/collections/ansible/posix/authorized_key_module.html

Lookups 플러그인 https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_lookups.html

플레이북 개발

  • 프로젝트 dir 생성 및 인벤토리 파일 작성
ubuntu@server:~/my-ansible/chapter_09.1$ mkdir ~/my-ansible/chapter_09.2
cd ~/my-ansible/chapter_09.2

ubuntu@server:~/my-ansible/chapter_09.2$ cp ~/my-ansible/ansible.cfg ./
ubuntu@server:~/my-ansible/chapter_09.2$ cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT

### lookup 플러그인
ubuntu@server:~/my-ansible/chapter_09.2$ ansible-doc -l -t lookup
[WARNING]: While constructing a mapping from /usr/lib/python3/dist-packages/ansible_collections/wti/remote/plugins/lookup/cpm_snmp_config.py, line 58, column 9, found a duplicate dict key (type). Using last defined value
only.
amazon.aws.aws_account_attribute                  Look up AWS account attributes                                                                                                                                          
amazon.aws.aws_collection_constants               expose various collection related constants                                                                                                                             
amazon.aws.aws_service_ip_ranges                  Look up the IP ranges for services provided in AWS such as EC2 and S3                                                                                                   
amazon.aws.secretsmanager_secret                  Look up secrets stored in AWS Secrets Manager                                                                                                                           
amazon.aws.ssm_parameter                          gets the value for a SSM parameter or all parameters under a path                                                                                                       
ansible.builtin.config                            Lookup current Ansible configuration values                                                                                                                             
ansible.builtin.csvfile                           read data from a TSV or CSV file                                                                                                                                        
ansible.builtin.dict                              returns key/value pair items from dictionaries                                                                                                                          
ansible.builtin.env                               Read the value of environment variables                                                                                                                                 
ansible.builtin.file                              read file contents                                                                                                                                                      
ansible.builtin.fileglob                          list files matching a pattern                                                                                                                                           
ansible.builtin.first_found                       return first file found from list                                                                                                                                       
ansible.builtin.indexed_items                     rewrites lists to return 'indexed items'                                                                                                                                
ansible.builtin.ini                               read data from an ini file                                                                                                                                              
ansible.builtin.inventory_hostnames               list of inventory hosts matching a host pattern                                                                                                                         
ansible.builtin.items                             list of items   
  • SSH 키 생성하고 복사하는 플레이북을 작성 : 여기서는 태스크가 실행될 호스트별로 태스크 작성

    • localhost인 ansible-server에서 생성된 SSH 공개 키는 ansible.posix.authorized_key 모듈을 이용하여 인벤토리의 tnode 호스트 그룹의 각 서버로 복사됩니다.

    • 이때 키를 등록하기 위해 lookup 함수가 사용 : 외부 소스(파일, DB, key/value stores, APIs 등)ㅌ으로 부터 데이터를 검색 합니다.

### create_sshkey.yml
---

- hosts: localhost
  tasks:
  - name : Create ssh key
    ansible.builtin.user:
      name: "{{ userid }}"
      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') }}"
  • 플레이북 실행 -> 에러가 발생하여 root로 계정 전환
## ansible.cfg 파일 수정

[defaults]
inventory = ./inventory
remote_user = root
inject_facts_as_vars = false
---

ubuntu@server:~/my-ansible/chapter_09.2$ sudo ansible-playbook -e userid=ansible create_sshkey.yml --ask-pass
SSH password: 

PLAY [localhost] **************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Create ssh key] *********************************************************************************************************************************************************************************************************
ok: [localhost]

PLAY [tnode] ******************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode2]
ok: [tnode3]
ok: [tnode1]

TASK [Copy SSH Pub key] *******************************************************************************************************************************************************************************************************
changed: [tnode3]
changed: [tnode1]
changed: [tnode2]

PLAY RECAP ********************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode1                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode2                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode3                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 공개 키 복사 및 접속 확인
# ansible 계정 전환
ubuntu@server:~/my-ansible/chapter_09.2$ sudo su - ansible
ansible@server:~$ echo $SHELL
/bin/bash
ansible@server:~$ whoami
ansible
ansible@server:~$ ls -al
total 24
drwxr-x--- 3 ansible ansible 4096 Feb  1 20:50 .
drwxr-xr-x 4 root    root    4096 Feb  1 20:50 ..
-rw-r--r-- 1 ansible ansible  220 Jan  7  2022 .bash_logout
-rw-r--r-- 1 ansible ansible 3771 Jan  7  2022 .bashrc
-rw-r--r-- 1 ansible ansible  807 Jan  7  2022 .profile
drwx------ 2 ansible ansible 4096 Feb  1 20:50 .ssh
ansible@server:~$ ls -l .ssh/
total 8
-rw------- 1 ansible ansible 1831 Feb  1 20:50 id_rsa
-rw-r--r-- 1 ansible ansible  409 Feb  1 20:50 id_rsa.pub

## tnode ssh 접속 테스트

for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i hostname; echo; done

## # 대상 노드에 정보 확인
ansible@server:~$ for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i tree /home/ansible/.ssh; echo; done
>> tnode1 <<
/home/ansible/.ssh
└── authorized_keys

0 directories, 1 file

>> tnode2 <<
/home/ansible/.ssh
└── authorized_keys

0 directories, 1 file

>> tnode3 <<
/home/ansible/.ssh
└── authorized_keys

0 directories, 1 file

ansible@server:~$ for i in {1..3}; do echo ">> tnode$i <<"; ssh tnode$i cat /home/ansible/.ssh/authorized_keys; echo; done
>> tnode1 <<
ssh-rsa ... ansible-generated on server

>> tnode2 <<
ssh-rsa ... ansible-generated on server

>> tnode3 <<
ssh-rsa ... ansible-generated on server

## ubuntu 유저로 복귀
exit
  • tnode 관리 노드에 ansible 계정에 패스워드 입력 없이 sudo 권한 줄 수 있게 설정 ->root 계정 권한으로 진행
## sudo-ansible.yml
---
- 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
  • 플레이북 실행
ubuntu@server:~/my-ansible/chapter_09.2$ sudo ansible-playbook sudo-ansible.yml --ask-pass
SSH password: 

PLAY [all] ********************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode2]
ok: [tnode3]
ok: [tnode1]

TASK [Create file] ************************************************************************************************************************************************************************************************************
changed: [tnode2]
changed: [tnode1]
changed: [tnode3]

TASK [Edit file] **************************************************************************************************************************************************************************************************************
changed: [tnode2]
changed: [tnode3]
changed: [tnode1]

PLAY RECAP ********************************************************************************************************************************************************************************************************************
tnode1                     : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode2                     : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode3                     : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • 확인
    • ansible 계정 전환 후 tnode1 접속 후 확인
ubuntu@server:~/my-ansible/chapter_09.2$ sudo su - ansible
ansible@server:~$ ssh tnode1
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 6.2.0-1018-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

  System information as of Thu Feb  1 21:08:05 KST 2024

  System load:  0.0205078125      Processes:             104
  Usage of /:   6.1% of 28.89GB   Users logged in:       0
  Memory usage: 6%                IPv4 address for ens5: 10.10.1.11
  Swap usage:   0%


Expanded Security Maintenance for Applications is not enabled.

2 updates can be applied immediately.
2 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


ansible@tnode1:~$ whoami
ansible
ansible@tnode1:~$ sudo cat /etc/sudoers.d/ansible
ansible ALL=(root) NOPASSWD:ALL

NTP 서버 설치 및 설정

목적

  • NTP 서버 주소는 메인 플레이북에서 정의합니다.

  • 운영체제가 Ubuntuapt 모듈을 사용하여 chrony를 설치합니다.

  • 운영체제가 CentOS/레드햇이면 dnf 모듈을 사용하여 chrony를 설치합니다.

  • Jinja2 템플릿 방식의 chrony.conf 파일을 대상 호스트로 복사합니다.

  • 설정 파일이 복사되면 chrony 서비스를 재시작합니다.

  • 다음에도 사용할 수 있도록 롤을 이용하여 설계하고 작성해보겠습니다.

플레이북 설계

  • 이번 예제에서는 chrony를 서로 다른 운영체제에서 각각의 모듈을 이용하여 설치할 것이므로 롤을 생성하고 호출하는 방식으로 작성해보겠습니다.

  • 롤 구성에 필요한 플레이북

    • 대략적인 설계가 끝나면 롤에 대한 상세 설계를 하는데, chrony 서비스 설치를 위한 롤에서는 변수를 정의하는 vars, 환경 설정 템플릿을 위한 templates, 태스크를 정의한 tasks, 환경 설정 후 chrony 서비스를 재시작하기 위한 handlers(후속조치)를 사용할 것 입니다.

또한, 원활한 실습 진행을 위해 root 계정으로 실습을 진행하도록 하겠습니다.

  • .ssh/config 파일을 수정하여 user 를 root 로 수정해줍니다.
## ansible 계정의 실습 디렉토리 생성
root@server:~# su - ansible -c 'mkdir -p ~/ansible-project/chapter_09.3'
root@server:~# ls -l /home/ansible/
total 4
drwxrwxr-x 3 ansible ansible 4096 Feb  1 21:23 ansible-project
root@server:~# ls -l /home/ansible/
total 4
drwxrwxr-x 3 ansible ansible 4096 Feb  1 21:23 ansible-project
  • VSCODE에서 작업 영역에 폴더 추가 : /home/ansible/ansible-project
  • ansible 계정으로 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
  • ansible.cfg 파일 생성(remote_user 는 ansible 로 설정)
  • inventory 파일과 롤 생성
root@server:/home/ansible/ansible-project# su - ansible
ansible@server:~$ whoami
ansible
ansible@server:~$ pwd
/home/ansible
ansible@server:~$ cd ~/ansible-project/chapter_09.3/
ansible@server:~/ansible-project/chapter_09.3$ 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
ansible@server:~/ansible-project/chapter_09.3$ cat <<EOT > inventory
[tnode]
tnode1
tnode2
tnode3
EOT
ansible@server:~/ansible-project/chapter_09.3$ ll
total 16
drwxrwxr-x 2 ansible ansible 4096 Feb  1 21:26 ./
drwxrwxr-x 3 ansible ansible 4096 Feb  1 21:23 ../
-rw-rw-r-- 1 ansible ansible  197 Feb  1 21:26 ansible.cfg
-rw-rw-r-- 1 ansible ansible   29 Feb  1 21:26 inventory
ansible@server:~/ansible-project/chapter_09.3$ ansible-galaxy role init --init-path ./roles myrole.chrony
- Role myrole.chrony was created successfully
ansible@server:~/ansible-project/chapter_09.3$ tree roles
roles
└── myrole.chrony
    ├── README.md
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml

9 directories, 8 files
  • 롤 디렉터리에 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
  • chrony.conf.j2 파일을 생성 : 외부로부터 입력받은 ntp_server 변수를 사용
    • 롤 디렉터리에 templates/chrony.conf.j2 파일 선택 후 아래 내용 추가
    • chrony.conf 파일의 내용은 이미 chrony 서비스가 설치되어 있는 서버의 chrony.conf 파일 내용을 참조하여 작성합니다.
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
--------

ansible@server:~/ansible-project/chapter_09.3/roles/myrole.chrony/vars$ cat ~/ansible-project/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
  • 핸들러에는 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

------
ansible@server:~/ansible-project/chapter_09.3/roles/myrole.chrony/handlers$ cat main.yml 
---
# handlers file for myrole.chrony

- name: Restart chrony
  ansible.builtin.service:
    name: "{{ service_name }}"
    state: restarted---
# handlers file for myrole.chrony
  • 메인 태스크 작성 : chapter_09.3/roles/myrole.chrony/tasks/main.yml
    • ansible_facts.distribution 팩트 변수를 이용하여 다른 파일에서 태스크를 포함 시킴
    • 운영체제에 맞는 chrony 환경 설정 파일 설정 복사 → 복사 후 notify로 ‘Restart chrony’ 핸들러 호출
---
# 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
------------
ansible@server:~/ansible-project/chapter_09.3/roles/myrole.chrony/tasks$ cat 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
  • 메인 태스크에서 호출된 운영체제별 플레이북을 하나씩 작성
touch ~/ansible-project/chapter_09.3/roles/myrole.chrony/tasks/RedHat.yml
---
---

- name: Install chrony using dnf
  ansible.builtin.dnf:
    name: "{{ package_name }}"
    state: latest
---
touch ~/ansible-project/chapter_09.3/roles/myrole.chrony/tasks/CentOS.yml
---
---

- name: Install chrony using dnf
  ansible.builtin.dnf:
    name: "{{ package_name }}"
    state: latest
---
touch ~/ansible-project/chapter_09.3/roles/myrole.chrony/tasks/Ubuntu.yml
---
---

- name: Install chrony using apt
  ansible.builtin.apt:
    name: "{{ package_name }}"
    state: latest
---
  • 메인 플레이북인 install_ntp.yml 파일을 작성 : 롤 추가 후 ntp_server 변수를 함께 선언
touch ~/ansible-project/chapter_09.3/install_ntp.yml
---
ansible@server:~/ansible-project/chapter_09.3$ cat install_ntp.yml 
---

- hosts: tnode
  roles:
    - role: myrole.chrony
      ntp_server: 0.kr.pool.ntp.org
  • 플레이북 실행 (문법 체크 후 실행)
ansible@server:~/ansible-project/chapter_09.3$ ansible-playbook --syntax-check install_ntp.yml

playbook: install_ntp.yml
ansible@server:~/ansible-project/chapter_09.3$ ansible-playbook install_ntp.yml

PLAY [tnode] *************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [tnode3]
ok: [tnode1]
ok: [tnode2]

TASK [myrole.chrony : Import playbook] ***********************************************************************
included: /home/ansible/ansible-project/chapter_09.3/roles/myrole.chrony/tasks/Ubuntu.yml for tnode1, tnode2, tnode3

TASK [myrole.chrony : Install chrony using apt] **************************************************************
ok: [tnode3]
ok: [tnode1]
ok: [tnode2]

TASK [myrole.chrony : Copy chrony config file when Ubuntu] ***************************************************
changed: [tnode2]
changed: [tnode3]
changed: [tnode1]

TASK [myrole.chrony : Copy chrony config file when Other OS] *************************************************
skipping: [tnode1]
skipping: [tnode2]
skipping: [tnode3]

RUNNING HANDLER [myrole.chrony : Restart chrony] *************************************************************
changed: [tnode2]
changed: [tnode1]
changed: [tnode3]

PLAY RECAP ***************************************************************************************************
tnode1                     : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
tnode2                     : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
tnode3                     : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
  • 확인
ansible@server:~/ansible-project/chapter_09.3$ ansible -m shell -a "cat /etc/chrony/chrony.conf" tnode1
tnode1 | CHANGED | rc=0 >>
pool 0.kr.pool.ntp.org
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
ansible@server:~/ansible-project/chapter_09.3$ ansible -m shell -a "systemctl status chrony" tnode1
tnode1 | CHANGED | rc=0 >>
● chrony.service - chrony, an NTP client/server
     Loaded: loaded (/lib/systemd/system/chrony.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2024-02-01 21:42:30 KST; 2min 25s ago
       Docs: man:chronyd(8)
             man:chronyc(1)
             man:chrony.conf(5)
    Process: 3554 ExecStart=/usr/lib/systemd/scripts/chronyd-starter.sh $DAEMON_OPTS (code=exited, status=0/SUCCESS)
   Main PID: 3565 (chronyd)
      Tasks: 2 (limit: 4598)
     Memory: 1.2M
        CPU: 50ms
     CGroup: /system.slice/chrony.service
             ├─3565 /usr/sbin/chronyd -F 1
             └─3566 /usr/sbin/chronyd -F 1

Feb 01 21:42:30 tnode1 systemd[1]: Starting chrony, an NTP client/server...
Feb 01 21:42:30 tnode1 chronyd[3565]: chronyd version 4.2 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +NTS +SECHASH +IPV6 -DEBUG)
Feb 01 21:42:30 tnode1 chronyd[3565]: Could not open keyfile /etc/chrony.keys
Feb 01 21:42:30 tnode1 chronyd[3565]: Initial frequency -6.115 ppm
Feb 01 21:42:30 tnode1 chronyd[3565]: Using right/UTC timezone to obtain leap second data
Feb 01 21:42:30 tnode1 chronyd[3565]: Loaded seccomp filter (level 1)
Feb 01 21:42:30 tnode1 systemd[1]: Started chrony, an NTP client/server.
Feb 01 21:44:40 tnode1 chronyd[3565]: Selected source 121.162.54.1 (0.kr.pool.ntp.org)
Feb 01 21:44:40 tnode1 chronyd[3565]: System clock TAI offset set to 37 seconds

환경 설정 자동화

네트워크 IP 설정하기

목적

  • OS가 우분투일 경우에는 netplan 파일을 이용하여 IP를 설정합니다.
    • netplan은 파일이므로 사전에 netplan 파일 구조를 확인하고 jinja2 템플릿으로 작성합니다.
  • OS가 CentOS/레드햇일 경우에는 nmcli 모듈을 사용하여 IP를 설정합니다.
  • 예제에서는 ethernet 타입의 네트워크 IP를 설정합니다.
  • IP 설정 관련 정보는 메인 플레이북에서 변수로 정의합니다.
  • 변수로 정의한 네트워크 인터페이스가 실제 호스트에 존재하는지 앤서블 팩트를 통해 확인하겠습니다.

설계

  • 플레이북
    • 우분투 일 경우 netplan을 사용하는 롤과 CentOS/레드햇 일 경우 nmcli 모듈을 사용하는 롤로 구성합니다.
    • 그리고 OS의 종류에 따라 해당 롤을 호출하는 방식으로 메인 플레이북을 설계합니다.

플레이북 개발 및 실행

  • nic2를 추가하기 번거로워서 동작 적용은 하지 않았습니다.

  • 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성

ansible@server:~/ansible-project/chapter_09.3$ mkdir ~/ansible-project/chapter_10.1
cd ~/ansible-project/chapter_10.1
ansible@server:~/ansible-project/chapter_10.1$ 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
ansible@server:~/ansible-project/chapter_10.1$ cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT
  • 롤 생성
    • myrole.nmcli, myrole.netplan
ansible@server:~/ansible-project/chapter_10.1$ ansible-galaxy role init --init-path ./roles myrole.nmcli
- Role myrole.nmcli was created successfully
ansible@server:~/ansible-project/chapter_10.1$ ansible-galaxy role init --init-path ./roles myrole.netplan
- Role myrole.netplan was created successfully
ansible@server:~/ansible-project/chapter_10.1$ ansible-galaxy role list
# /home/ansible/ansible-project/chapter_10.1/roles
- myrole.nmcli, (unknown version)
- myrole.netplan, (unknown version)
  • myrole.nmcli 에 태스크 파일 작성 : ~/chapter_10.1/roles/myrole.nmcli/tasks/main.yml
    • nmcli 모듈을 사용하여 외부로부터 받은 변수로 네트워크 IP를 설정합니다.
    • 이때, 변수는 배열 방식으로 받은 변수이므로 loop를 이용, when 키워드를 사용하여 외부로부터 받은 인터페이스가 앤서블 팩트에 존재하는 확인합니다.
ansible@server:~/ansible-project/chapter_10.1/roles/myrole.nmcli/tasks$ cat 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
  • myrole.netplan 에 Jinna2 템플릿(파이썬 웹 프로그래밍에 주로 쓰이는 템플릿 파일) 파일 작성 : ~/chapter_10.1/roles/myrole.netplan/templates/01-netplan-ansible.yaml.j2
ansible@server:~/ansible-project/chapter_10.1/roles/myrole.nmcli/tasks$ cat ~/ansible-project/chapter_10.1/rol
es/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를 사용합니다.


  • myrole.netplan 에 태스크 파일 작성 : ~/chapter_10.1/roles/myrole.netplan/tasks/main.yml
ansible@server:~/ansible-project/chapter_10.1/roles/myrole.netplan/tasks$ cat 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
  • emplate 모듈을 이용하여 앞에서 생성한 템플릿 파일을 대상 호스트에 복사합니다.

  • 이때 when 구문을 이용하여 외부로부터 받은 인터페이스가 앤서블 팩트에 존재하는지 확인합니다.

  • 템플릿 복사가 잘 되면 notify 키워드를 사용하여 핸들러를 호출합니다.

    1. myrole.netplan 에 핸들러 파일 작성 : 핸들러는 command 모듈을 이용하여 netplan apply 명령어를 수행 : ~/chapter_10.1/roles/myrole.netplan/handlers/main.yml
ansible@server:~/ansible-project/chapter_10.1/roles/myrole.netplan/handlers$ cat main.yml 
---
# handlers file for myrole.netplan

- name: Netplan apply
  ansible.builtin.command: netplan apply
  • 마지막으로 호출메인 플레이북을 작성

    • 메인 플레이북에는 롤에 전달할 변수들을 vars 섹션에 선언하고 tasks 섹센에 롤을 추가합니다.

    • 이때 ansible.builtin.include_role 모듈을 이용하여 롤을 호출하면 when 구문을 함께 사용할 수 있습니다.

    • 이렇게 앤서블 팩트에서 수집한 OS 버전에 따라 해당 롤을 호출할 수 있습니다.

ansible@server:~/ansible-project/chapter_10.1/roles/myrole.netplan/handlers$ cd ~/ansible-project/chapter_10.1 
touch set_ip.yml
ansible@server:~/ansible-project/chapter_10.1$ vi set_ip.yml 
ansible@server:~/ansible-project/chapter_10.1$ cat 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 네트워크 정보를 확인해봅시다.
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 ls /etc/netplan
50-cloud-init.yaml
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 cat /etc/netplan/50-cloud-init.yaml
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        ens5:
            dhcp4: true
            dhcp6: false
            match:
                macaddress: 02:dd:05:9b:2c:26
            set-name: ens5
    version: 2
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 ip -br -c addr
lo               UNKNOWN        127.0.0.1/8 ::1/128 
ens5             UP             10.10.1.11/24 metric 100 fe80::dd:5ff:fe9b:2c26/64 
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 ip -c route
default via 10.10.1.1 dev ens5 proto dhcp src 10.10.1.11 metric 100 
10.10.0.2 via 10.10.1.1 dev ens5 proto dhcp src 10.10.1.11 metric 100 
10.10.1.0/24 dev ens5 proto kernel scope link src 10.10.1.11 metric 100 
10.10.1.1 dev ens5 proto dhcp scope link src 10.10.1.11 metric 100 
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 nslookup blog.cloudneta.net
Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
Name:   blog.cloudneta.net
Address: 52.219.60.116
Name:   blog.cloudneta.net
Address: 52.219.60.129
Name:   blog.cloudneta.net
Address: 52.219.206.40
Name:   blog.cloudneta.net
Address: 52.219.60.92
Name:   blog.cloudneta.net
Address: 52.219.60.21
Name:   blog.cloudneta.net
Address: 52.219.206.64
Name:   blog.cloudneta.net
Address: 52.219.56.9
Name:   blog.cloudneta.net
Address: 52.219.146.13

ansible@server:~/ansible-project/chapter_10.1$ ansible -m shell -a "cat /var/log/syslog | grep -i dhcp" tnode1
tnode1 | CHANGED | rc=0 >>
Feb  1 11:00:16 ip-10-10-1-11 dhclient[295]: Internet Systems Consortium DHCP Client 4.4.1
Feb  1 11:00:16 ip-10-10-1-11 dhclient[295]: For info, please visit https://www.isc.org/software/dhcp/
Feb  1 11:00:16 ip-10-10-1-11 dhclient[295]: DHCPDISCOVER on ens5 to 255.255.255.255 port 67 interval 3 (xid=0xbf46a67d)
Feb  1 11:00:16 ip-10-10-1-11 dhclient[295]: DHCPOFFER of 10.10.1.11 from 10.10.1.1
Feb  1 11:00:16 ip-10-10-1-11 dhclient[295]: DHCPREQUEST for 10.10.1.11 on ens5 to 255.255.255.255 port 67 (xid=0x7da646bf)
Feb  1 11:00:16 ip-10-10-1-11 dhclient[295]: DHCPACK of 10.10.1.11 from 10.10.1.1 (xid=0xbf46a67d)
Feb  1 11:00:16 ip-10-10-1-11 systemd-networkd[332]: ens5: DHCPv4 address 10.10.1.11/24 via 10.10.1.1
Feb  1 11:00:16 ip-10-10-1-11 kernel: [    6.076597] audit: type=1400 audit(1706785209.340:8): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/NetworkManager/nm-dhcp-client.action" pid=257 comm="apparmor_parser"
Feb  1 11:00:16 ip-10-10-1-11 kernel: [    6.078154] audit: type=1400 audit(1706785209.344:9): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/NetworkManager/nm-dhcp-helper" pid=257 comm="apparmor_parser"
Feb  1 13:13:38 ip-10-10-1-11 python3[4012]: ansible-ansible.legacy.command Invoked with _raw_params=cat /var/log/syslog | grep -i dhcp _uses_shell=True stdin_add_newline=True strip_empty_ends=True argv=None chdir=None executable=None creates=None removes=None stdin=None
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 sudo dhclient -v ens5
Internet Systems Consortium DHCP Client 4.4.1
Copyright 2004-2018 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/ens5/02:dd:05:9b:2c:26
Sending on   LPF/ens5/02:dd:05:9b:2c:26
Sending on   Socket/fallback
DHCPDISCOVER on ens5 to 255.255.255.255 port 67 interval 3 (xid=0x1dcce82b)
DHCPDISCOVER on ens5 to 255.255.255.255 port 67 interval 5 (xid=0x1dcce82b)
DHCPOFFER of 10.10.1.11 from 10.10.1.1
DHCPREQUEST for 10.10.1.11 on ens5 to 255.255.255.255 port 67 (xid=0x2be8cc1d)
DHCPACK of 10.10.1.11 from 10.10.1.1 (xid=0x1dcce82b)
RTNETLINK answers: File exists
bound to 10.10.1.11 -- renewal in 1565 seconds.
  • 실행
    • 우분투 OS로 롤 호출 되지만, tnode2는 enp7 NIC가 없어서 Setup nic ip 태스크가 실행되지는 않습니다.
ansible@server:~/ansible-project/chapter_10.1$ ansible-playbook --syntax-check set_ip.yml

playbook: set_ip.yml
ansible@server:~/ansible-project/chapter_10.1$ ansible-playbook set_ip.yml

PLAY [tnode1] *****************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode1]

TASK [Include role in CentOS and RedHat] **************************************************************************************************************************************************************************************
skipping: [tnode1]

TASK [Include role in Ubuntu] *************************************************************************************************************************************************************************************************

TASK [myrole.netplan : Copy netplan file] *************************************************************************************************************************************************************************************
changed: [tnode1]

RUNNING HANDLER [myrole.netplan : Netplan apply] ******************************************************************************************************************************************************************************
changed: [tnode1]

PLAY [tnode2] *****************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode2]

TASK [Include role in CentOS and RedHat] **************************************************************************************************************************************************************************************
skipping: [tnode2]

TASK [Include role in Ubuntu] *************************************************************************************************************************************************************************************************

TASK [myrole.netplan : Copy netplan file] *************************************************************************************************************************************************************************************
skipping: [tnode2]

PLAY RECAP ********************************************************************************************************************************************************************************************************************
tnode1                     : ok=3    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
tnode2                     : ok=1    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0   
  • 확인
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 ls /etc/netplan
01-netplan-ansible.yaml
50-cloud-init.yaml
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 cat /etc/netplan/01-netplan-ansible.yaml
# This is the network config written by 'ansible'
network:
  version: 2
  ethernets:
    ens5:
      dhcp4: no
      dhcp6: no
      addresses: [10.10.1.11/24]
      gateway4: 10.10.1.1
      nameservers:
        addresses: [127.0.0.53]

ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 ip -br -c addr
lo               UNKNOWN        127.0.0.1/8 ::1/128 
ens5             UP             10.10.1.11/24 fe80::dd:5ff:fe9b:2c26/64 
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 ip -c route
default via 10.10.1.1 dev ens5 proto static 
default via 10.10.1.1 dev ens5 proto dhcp src 10.10.1.11 metric 100 
10.10.0.2 via 10.10.1.1 dev ens5 proto dhcp src 10.10.1.11 metric 100 
10.10.1.0/24 dev ens5 proto kernel scope link src 10.10.1.11 
10.10.1.1 dev ens5 proto dhcp scope link src 10.10.1.11 metric 100 
ansible@server:~/ansible-project/chapter_10.1$ ssh tnode1 nslookup blog.cloudneta.net
Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
Name:   blog.cloudneta.net
Address: 52.219.146.68
Name:   blog.cloudneta.net
Address: 52.219.60.72
Name:   blog.cloudneta.net
Address: 52.219.146.25
Name:   blog.cloudneta.net
Address: 52.219.202.24
Name:   blog.cloudneta.net
Address: 52.219.146.60
Name:   blog.cloudneta.net
Address: 52.219.146.13
Name:   blog.cloudneta.net
Address: 52.219.204.60
Name:   blog.cloudneta.net
Address: 52.219.58.153

호스트명 설정하기

목적

  • 앤서블로 접근하기 위한 대상 서버(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

플레이북 개발 및 실행

  • 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
ansible@server:~/ansible-project/chapter_10.1$ mkdir ~/ansible-project/chapter_10.2
cd ~/ansible-project/chapter_10.2
ansible@server:~/ansible-project/chapter_10.2$ 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
ansible@server:~/ansible-project/chapter_10.2$ cat <<EOT> inventory
[tnode]
tnode1
tnode2
tnode3
EOT
  • 변수 정의 파일 생성 : hosts 파일에 추가할 정보를 사전형 변수로 정의하여 반복문에서 사용할 수 있게 합니다.
ansible@server:~/ansible-project/chapter_10.2$ touch ~/ansible-project/chapter_10.2/vars_hosts_info.yml
ansible@server:~/ansible-project/chapter_10.2$ ll
total 16
drwxrwxr-x 2 ansible ansible 4096 Feb  1 22:29 ./
drwxrwxr-x 5 ansible ansible 4096 Feb  1 22:28 ../
-rw-rw-r-- 1 ansible ansible  226 Feb  1 22:28 ansible.cfg
-rw-rw-r-- 1 ansible ansible   29 Feb  1 22:28 inventory
-rw-rw-r-- 1 ansible ansible    0 Feb  1 22:29 vars_hosts_info.yml

ansible@server:~/ansible-project/chapter_10.2$ cat 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
  • 메인 플레이북 작성 : hostname은 inventory 정보를 통해서 설정하고, /etc/hosts 파일은 내용 추가는 변수 정의 파일에서 반복문을 통해 가져온다.
    • regexp 는 /etc/hosts 에서 해당 값(여기서는 ip)가 있을 경우 대체(기본값 수정, state=present)하거나 혹은 삭제(state=absent)하며, 매칭되는 것이 없다면 line(내용)을 추가합니다.
ansible@server:~/ansible-project/chapter_10.2$ touch ~/ansible-project/chapter_10.2/set_hostname.yml
ansible@server:~/ansible-project/chapter_10.2$ cat 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 }}"
  • 플레이북 실행하기 전 확인
ansible@server:~/ansible-project/chapter_10.2$ ansible -m shell -a "cat /etc/hosts" tnode
tnode1 | CHANGED | rc=0 >>
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
tnode3 | CHANGED | rc=0 >>
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
tnode2 | CHANGED | rc=0 >>
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
  • 플레이북 실행 후 확인
ansible@server:~/ansible-project/chapter_10.2$ ansible-playbook --syntax-check set_hostname.yml

playbook: set_hostname.yml
ansible@server:~/ansible-project/chapter_10.2$ ansible-playbook set_hostname.yml

PLAY [tnode] ******************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode3]
ok: [tnode1]
ok: [tnode2]

TASK [Set hostname from inventory] ********************************************************************************************************************************************************************************************
ok: [tnode1]
ok: [tnode2]
ok: [tnode3]

PLAY [all] ********************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode1]
ok: [tnode2]
ok: [tnode3]

TASK [Add host ip to hosts] ***************************************************************************************************************************************************************************************************
changed: [tnode1] => (item={'hostname': 'tnode1', 'fqdn': 'tnode1.local', 'net_ip': '10.10.1.11'})
changed: [tnode3] => (item={'hostname': 'tnode1', 'fqdn': 'tnode1.local', 'net_ip': '10.10.1.11'})
changed: [tnode2] => (item={'hostname': 'tnode1', 'fqdn': 'tnode1.local', 'net_ip': '10.10.1.11'})
changed: [tnode1] => (item={'hostname': 'tnode2', 'fqdn': 'tnode2.local', 'net_ip': '10.10.1.12'})
changed: [tnode3] => (item={'hostname': 'tnode2', 'fqdn': 'tnode2.local', 'net_ip': '10.10.1.12'})
changed: [tnode2] => (item={'hostname': 'tnode2', 'fqdn': 'tnode2.local', 'net_ip': '10.10.1.12'})
changed: [tnode1] => (item={'hostname': 'tnode3', 'fqdn': 'tnode3.local', 'net_ip': '10.10.1.13'})
changed: [tnode3] => (item={'hostname': 'tnode3', 'fqdn': 'tnode3.local', 'net_ip': '10.10.1.13'})
changed: [tnode2] => (item={'hostname': 'tnode3', 'fqdn': 'tnode3.local', 'net_ip': '10.10.1.13'})

PLAY RECAP ********************************************************************************************************************************************************************************************************************
tnode1                     : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode2                     : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode3                     : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansible@server:~/ansible-project/chapter_10.2$ ansible -m shell -a "hostname" tnode
tnode3 | CHANGED | rc=0 >>
tnode3
tnode1 | CHANGED | rc=0 >>
tnode1
tnode2 | CHANGED | rc=0 >>
tnode2
ansible@server:~/ansible-project/chapter_10.2$ ansible -m shell -a "cat /etc/hosts | grep tnode" tnode
tnode3 | CHANGED | rc=0 >>
10.10.1.11  tnode1 tnode1.local
10.10.1.12  tnode2 tnode2.local
10.10.1.13  tnode3 tnode3.local
tnode1 | CHANGED | rc=0 >>
10.10.1.11  tnode1 tnode1.local
10.10.1.12  tnode2 tnode2.local
10.10.1.13  tnode3 tnode3.local
tnode2 | CHANGED | rc=0 >>
10.10.1.11  tnode1 tnode1.local
10.10.1.12  tnode2 tnode2.local
10.10.1.13  tnode3 tnode3.local
ansible@server:~/ansible-project/chapter_10.2$ ssh tnode1 ping -c 1 tnode2
PING tnode2 (10.10.1.12) 56(84) bytes of data.
64 bytes from tnode2 (10.10.1.12): icmp_seq=1 ttl=64 time=1.04 ms

--- tnode2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.042/1.042/1.042/0.000 ms
ansible@server:~/ansible-project/chapter_10.2$ ssh tnode1 ping -c 1 tnode3.local
PING tnode3 (10.10.1.13) 56(84) bytes of data.
64 bytes from tnode3 (10.10.1.13): icmp_seq=1 ttl=64 time=0.843 ms

--- tnode3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.843/0.843/0.843/0.000 ms

NFS 서버 설치 및 NFS 스토리지 설정

목적

  • 실습 환경에서는 NFS 서버를 CentOS에 구성합니다.
  • NFS 서버가 구성되면 나머지 두 노드에는 NFS 스토리지를 마운트합니다.
  • 플레이북 재사용을 위한 NFS 서버 및 클라이언트는 롤로 구성합니다.

플레이북 설계

  • NFS 서버 설치를 위한 myrole.nfs_server 롤과 NFS 스토리지 마운트를 위한 myrole.nfs_client 롤이 있습니다

롤 설계

  • NFS 패키지를 OS에 맞게 설치하고 설치가 끝난 후 마운트할 디텍터리를 생성하고 설치한 NFS 서버의 공유 디렉터리로 마운트합니다

플레이북 개발 및 실행

  • 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
ansible@server:~/ansible-project/chapter_10.2$ mkdir ~/ansible-project/chapter_10.3
cd ~/ansible-project/chapter_10.3
ansible@server:~/ansible-project/chapter_10.3$ 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
ansible@server:~/ansible-project/chapter_10.3$ cat <<EOT> inventory
[nfs_server]
tnode1

[nfs_client]
tnode2
tnode3
EOT
  • 롤 생성 : myrole.nfs_server, myrole.nfs_client
ansible@server:~/ansible-project/chapter_10.3$ ansible-galaxy role init --init-path ./roles myrole.nfs_server
- Role myrole.nfs_server was created successfully
ansible@server:~/ansible-project/chapter_10.3$ ansible-galaxy role init --init-path ./roles myrole.nfs_client
- Role myrole.nfs_client was created successfully
ansible@server:~/ansible-project/chapter_10.3$ ansible-galaxy role list
# /home/ansible/ansible-project/chapter_10.3/roles
- myrole.nfs_server, (unknown version)
- myrole.nfs_client, (unknown version)
  • myrole.nfs_server 에 변수 파일 작성 - 설치할 NFS 서버 관련 패키지 : chapter_10.3/roles/myrole.nfs_server/vars/main.yml
ansible@server:~/ansible-project/chapter_10.3/roles/myrole.nfs_server/vars$ cat main.yml 
---
# vars file for myrole.nfs-server

nfs_packages: 
  - nfs-kernel-server
  • myrole.nfs_server 에 태스크 파일 작성 : chapter_10.3/roles/myrole.nfs_server/tasks/main.yml
ansible@server:~/ansible-project/chapter_10.3/roles/myrole.nfs_server/tasks$ cat 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
  • myrole.nfs_server 에 핸들러 파일 작성 : chapter_10.3/roles/myrole.nfs_server/handlers/main.yml
ansible@server:~/ansible-project/chapter_10.3/roles/myrole.nfs_server/handlers$ cat main.yml 
---
# handlers file for myrole.nfs_server

- name: Restart NFS Service
  ansible.builtin.service:
    name: nfs-server
    state: restarted
  • myrole.nfs_client 에 변수 파일 작성 - 설치할 NFS 패키지 : chapter_10.3/roles/myrole.nfs_client/vars/main.yml
ansible@server:~/ansible-project/chapter_10.3/roles/myrole.nfs_client/vars$ cat main.yml 
---
# vars file for myrole.nfs_client

apt_nfs_packages:
  - nfs-common
dnf_nfs_packages:
  - nfs-utils
  • myrole.nfs_client 에 태스크 파일 작성 : chapter_10.3/roles/myrole.nfs_client/tasks/main.yml
ansible@server:~/ansible-project/chapter_10.3/roles/myrole.nfs_client/tasks$ cat 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
  • 메인 플레이북에서 사용할 변수를 정의하는데, 롤에 포함하지 않은 이유는 각각의 롤이 동일한 값의 변수를 사용하기 위함입니다.
ansible@server:~/ansible-project/chapter_10.3/roles/myrole.nfs_client/tasks$ touch ~/ansible-project/chapter_10.3/vars_share_path.yml
ansible@server:~/ansible-project/chapter_10.3$ cat vars_share_path.yml 
---

share_server: tnode1
share_path: /mnt/nfs_shares
mount_path: /mnt/nfs_data
  • 메인 플레이북 작성
ansible@server:~/ansible-project/chapter_10.3$ touch ~/ansible-project/chapter_10.3/set_nfs_storage.yml
ansible@server:~/ansible-project/chapter_10.3$ vi set_nfs_storage.yml 
ansible@server:~/ansible-project/chapter_10.3$ cat 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
  • 플레이북 실행 전 확인
ansible@server:~/ansible-project/chapter_10.3$ ssh tnode2 df -h --type nfs4
df: no file systems processed
ansible@server:~/ansible-project/chapter_10.3$ ssh tnode3 df -h --type ext4
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        29G  1.8G   28G   7% /
  • 플레이북 실행
ansible@server:~/ansible-project/chapter_10.3$ ansible-playbook --syntax-check set_nfs_storage.yml

playbook: set_nfs_storage.yml
ansible@server:~/ansible-project/chapter_10.3$ ansible-playbook set_nfs_storage.yml

PLAY [nfs_server] *************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode1]

TASK [myrole.nfs_server : Install NFS packages] *******************************************************************************************************************************************************************************
changed: [tnode1] => (item=nfs-kernel-server)

TASK [myrole.nfs_server : Create NFS export directory] ************************************************************************************************************************************************************************
changed: [tnode1]

TASK [myrole.nfs_server : Configure NFS exports] ******************************************************************************************************************************************************************************
changed: [tnode1]

RUNNING HANDLER [myrole.nfs_server : Restart NFS Service] *********************************************************************************************************************************************************************
changed: [tnode1]

PLAY [nfs_client] *************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode3]
ok: [tnode2]

TASK [myrole.nfs_client : Install NFS Packages on Ubuntu] *********************************************************************************************************************************************************************
changed: [tnode3] => (item=nfs-common)
changed: [tnode2] => (item=nfs-common)

TASK [myrole.nfs_client : Install NFS Packages on Rhel] ***********************************************************************************************************************************************************************
skipping: [tnode2] => (item=nfs-utils) 
skipping: [tnode2]
skipping: [tnode3] => (item=nfs-utils) 
skipping: [tnode3]

TASK [myrole.nfs_client : Create Mount Directory] *****************************************************************************************************************************************************************************
changed: [tnode2]
changed: [tnode3]

TASK [myrole.nfs_client : Mount NFS] ******************************************************************************************************************************************************************************************
changed: [tnode2]
changed: [tnode3]

PLAY RECAP ********************************************************************************************************************************************************************************************************************
tnode1                     : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
tnode2                     : ok=4    changed=3    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
tnode3                     : ok=4    changed=3    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
  • 확인
# 실행 후 tnod2, tnode3 NFS 스토리지 마운트 확인
ansible@server:~/ansible-project/chapter_10.3$ ssh tnode2 df -h --type nfs4
Filesystem              Size  Used Avail Use% Mounted on
tnode1:/mnt/nfs_shares   29G  1.8G   28G   7% /mnt/nfs_data
ansible@server:~/ansible-project/chapter_10.3$ ssh tnode3 df -h --type ext4
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        29G  1.8G   28G   7% /
ansible@server:~/ansible-project/chapter_10.3$ ssh tnode3 df -h --type nfs4
Filesystem              Size  Used Avail Use% Mounted on
tnode1:/mnt/nfs_shares   29G  1.8G   28G   7% /mnt/nfs_data

# tnode1에 nfs-server 확인

ansible@server:~/ansible-project/chapter_10.3$ ssh tnode1 systemctl status nfs-server
● nfs-server.service - NFS server and services
     Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; vendor preset: enabled)
     Active: active (exited) since Thu 2024-02-01 22:48:14 KST; 1min 53s ago
    Process: 6764 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
    Process: 6765 ExecStart=/usr/sbin/rpc.nfsd (code=exited, status=0/SUCCESS)
   Main PID: 6765 (code=exited, status=0/SUCCESS)
        CPU: 6ms
ansible@server:~/ansible-project/chapter_10.3$ ssh tnode1 sudo exportfs -s
/mnt/nfs_shares  *(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,root_squash,no_all_squash)
  • 모니터링
    • 새로운 Terminal 열어서 테스트
root@server:/home/ansible/ansible-project# sudo su - ubuntu
ubuntu@server:~$ ssh tnode2 ls /mnt/nfs_data
ubuntu@server:~$ watch -d "ssh tnode2 ls -l /mnt/nfs_data"
-----
### 기존 터미널
ansible@server:~/ansible-project/chapter_10.3$ ssh tnode1
ansible@tnode1:~$ for i in {1..10}; do sudo touch /mnt/nfs_shares/deleteme.$i; done;
exit


DB 애플리케이션 설치하기

앤서블 갤럭시 사용

  • 앤서블 갤럭시에서 MySQL 설치하는 롤을 찾아보고, 해당 롤을 이용하여 테스트 진행

이동 : https://galaxy.ansible.com/ui/standalone/roles/geerlingguy/mysql/

이동 : https://github.com/geerlingguy/ansible-role-mysql

목적

  • MySQL을 tnode2에 설치합니다.
    • 앤서블 갤럭시에서 우분투에 설치할 수 있는 MySQL 롤을 검색하여 해당 롤을 이용합니다.

플레이북 설계

  • 롤은 앤서블 갤럭시에서 캐옵니다.

플레이북 개발 및 실행

  • 프로젝트 디렉터리 생성 및 ansible.cfg, inventory 파일 작성
ansible@server:~/ansible-project/chapter_10.3$ mkdir ~/ansible-project/chapter_10.4
cd ~/ansible-project/chapter_10.4
ansible@server:~/ansible-project/chapter_10.4$ 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
ansible@server:~/ansible-project/chapter_10.4$ cat <<EOT> inventory
[db]
tnode2

[tnode]
tnode1
tnode2
tnode3
EOT
  • 검색한 mysql role 을 설치해줍니다.
ansible@server:~/ansible-project/chapter_10.4$ ansible-galaxy role install -p ./roles geerlingguy.mysql
Starting galaxy role install process
- downloading role 'mysql', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-mysql/archive/4.3.4.tar.gz
- extracting geerlingguy.mysql to /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql
- geerlingguy.mysql (4.3.4) was installed successfully
ansible@server:~/ansible-project/chapter_10.4$ ansible-galaxy role list
# /home/ansible/ansible-project/chapter_10.4/roles
- geerlingguy.mysql, 4.3.4
  • 롤의 태스크 정보를 확인합니다. : chapter_10.4/roles/geerlingguy.mysql/tasks/main.yml
    • 다운받은 롤은 오래된 Facts 표기법을 사용하니 ansible.cfg 를 확인합니다.
ansible@server:~/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks$ cat 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 설치 후에 환경 설정 태스크들을 차례대로 호출합니다.
    • os_family 는 간단하게 분류되며 Debian 에 Ubuntu 가 속해있습니다.
AIX
Alpine
Altlinux
Archlinux
Darwin
Debian  -----> Ubuntu 속해있습니다!
FreeBSD
Gentoo
HP-UX
Mandrake
RedHat
SMGL
Slackware
Solaris
Suse
Windows
  • 플레이북 작성
ansible@server:~/ansible-project/chapter_10.4$ cat install_mysql.yml 
---
- hosts: db
  roles:
    - role: geerlingguy.mysql
  • 플레이북 실행
    • 시뮬레이션 시에 Ensure MySQL is stopped after initial install 오류는 설치 안되어 있기 때문에 그렇습니다.
ansible@server:~/ansible-project/chapter_10.4$ ansible-playbook --syntax-check install_mysql.yml

## 시뮬레이션
ansible@server:~/ansible-project/chapter_10.4$ ansible-playbook --check install_mysql.yml

PLAY [db] *********************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/variables.yml for tnode2

TASK [geerlingguy.mysql : Include OS-specific variables.] *********************************************************************************************************************************************************************
ok: [tnode2] => (item=/home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/vars/Debian.yml)

TASK [geerlingguy.mysql : Define mysql_packages.] *****************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_daemon.] *******************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_slow_query_log_file.] ******************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_log_error.] ****************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_syslog_tag.] ***************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_pid_file.] *****************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_config_file.] **************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_config_include_dir.] *******************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_socket.] *******************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_supports_innodb_large_prefix.] *********************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/setup-Debian.yml for tnode2

TASK [geerlingguy.mysql : Check if MySQL is already installed.] ***************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Update apt cache if MySQL is not yet installed.] ****************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Ensure MySQL Python libraries are installed.] *******************************************************************************************************************************************************
changed: [tnode2]

TASK [geerlingguy.mysql : Ensure MySQL packages are installed.] ***************************************************************************************************************************************************************
changed: [tnode2]

TASK [geerlingguy.mysql : Ensure MySQL is stopped after initial install.] *****************************************************************************************************************************************************
fatal: [tnode2]: FAILED! => {"changed": false, "msg": "Could not find the requested service mysql: host"}

PLAY RECAP ********************************************************************************************************************************************************************************************************************
tnode2                     : ok=18   changed=2    unreachable=0    failed=1    skipped=1    rescued=0    ignored=0   

-----------------
ansible@server:~/ansible-project/chapter_10.4$ ansible-playbook install_mysql.yml

PLAY [db] *********************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/variables.yml for tnode2

TASK [geerlingguy.mysql : Include OS-specific variables.] *********************************************************************************************************************************************************************
ok: [tnode2] => (item=/home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/vars/Debian.yml)

TASK [geerlingguy.mysql : Define mysql_packages.] *****************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_daemon.] *******************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_slow_query_log_file.] ******************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_log_error.] ****************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_syslog_tag.] ***************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_pid_file.] *****************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_config_file.] **************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_config_include_dir.] *******************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_socket.] *******************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Define mysql_supports_innodb_large_prefix.] *********************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/setup-Debian.yml for tnode2

TASK [geerlingguy.mysql : Check if MySQL is already installed.] ***************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Update apt cache if MySQL is not yet installed.] ****************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Ensure MySQL Python libraries are installed.] *******************************************************************************************************************************************************
changed: [tnode2]

TASK [geerlingguy.mysql : Ensure MySQL packages are installed.] ***************************************************************************************************************************************************************
changed: [tnode2]

TASK [geerlingguy.mysql : Ensure MySQL is stopped after initial install.] *****************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Delete innodb log files created by apt package after initial install.] ******************************************************************************************************************************
skipping: [tnode2] => (item=ib_logfile0) 
skipping: [tnode2] => (item=ib_logfile1) 
skipping: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Check if MySQL packages were installed.] ************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/configure.yml for tnode2

TASK [geerlingguy.mysql : Get MySQL version.] *********************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Copy my.cnf global MySQL configuration.] ************************************************************************************************************************************************************
changed: [tnode2]

TASK [geerlingguy.mysql : Verify mysql include directory exists.] *************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Copy my.cnf override files into include directory.] *************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Create slow query log file (if configured).] ********************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Create datadir if it does not exist] ****************************************************************************************************************************************************************
changed: [tnode2]

TASK [geerlingguy.mysql : Set ownership on slow query log file (if configured).] **********************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Create error log file (if configured).] *************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Set ownership on error log file (if configured).] ***************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Ensure MySQL is started and enabled on boot.] *******************************************************************************************************************************************************
changed: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/secure-installation.yml for tnode2

TASK [geerlingguy.mysql : Ensure default user is present.] ********************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Copy user-my.cnf file with password credentials.] ***************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Disallow root login remotely] ***********************************************************************************************************************************************************************
ok: [tnode2] => (item=DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'))

TASK [geerlingguy.mysql : Get list of hosts for the root user.] ***************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Update MySQL root password for localhost root account (5.7.x).] *************************************************************************************************************************************
changed: [tnode2] => (item=localhost)

TASK [geerlingguy.mysql : Update MySQL root password for localhost root account (< 5.7.x).] ***********************************************************************************************************************************
skipping: [tnode2] => (item=localhost) 
skipping: [tnode2]

TASK [geerlingguy.mysql : Copy .my.cnf file with root password credentials.] **************************************************************************************************************************************************
changed: [tnode2]

TASK [geerlingguy.mysql : Get list of hosts for the anonymous user.] **********************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : Remove anonymous MySQL users.] **********************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Remove MySQL test database.] ************************************************************************************************************************************************************************
ok: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/databases.yml for tnode2

TASK [geerlingguy.mysql : Ensure MySQL databases are present.] ****************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/users.yml for tnode2

TASK [geerlingguy.mysql : Ensure MySQL users are present.] ********************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : ansible.builtin.include_tasks] **********************************************************************************************************************************************************************
included: /home/ansible/ansible-project/chapter_10.4/roles/geerlingguy.mysql/tasks/replication.yml for tnode2

TASK [geerlingguy.mysql : Ensure replication user exists on master.] **********************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Check slave replication status.] ********************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Check master replication status.] *******************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Configure replication on the slave.] ****************************************************************************************************************************************************************
skipping: [tnode2]

TASK [geerlingguy.mysql : Start replication.] *********************************************************************************************************************************************************************************
skipping: [tnode2]

RUNNING HANDLER [geerlingguy.mysql : restart mysql] ***************************************************************************************************************************************************************************
[WARNING]: Ignoring "sleep" as it is not used in "systemd"
changed: [tnode2]

PLAY RECAP ********************************************************************************************************************************************************************************************************************
tnode2                     : ok=36   changed=8    unreachable=0    failed=0    skipped=20   rescued=0    ignored=0   
  • 확인
ansible@server:~/ansible-project/chapter_10.4$ ssh tnode2 systemctl status mysql
● mysql.service - MySQL Community Server
     Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2024-02-01 23:08:10 KST; 1min 12s ago
    Process: 8871 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
   Main PID: 8879 (mysqld)
     Status: "Server is operational"
      Tasks: 36 (limit: 4598)
     Memory: 345.2M
        CPU: 1.479s
     CGroup: /system.slice/mysql.service
             └─8879 /usr/sbin/mysqld
ansible@server:~/ansible-project/chapter_10.4$ ssh tnode2
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 6.2.0-1018-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

  System information as of Thu Feb  1 23:09:22 KST 2024

  System load:  0.2724609375      Processes:             111
  Usage of /:   8.1% of 28.89GB   Users logged in:       0
  Memory usage: 15%               IPv4 address for ens5: 10.10.1.12
  Swap usage:   0%

 * Ubuntu Pro delivers the most comprehensive open source security and
   compliance features.

   https://ubuntu.com/aws/pro

Expanded Security Maintenance for Applications is not enabled.

2 updates can be applied immediately.
2 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


Last login: Thu Feb  1 23:08:08 2024 from 10.10.1.10
ansible@tnode2:~$ sudo mysql -u root -e "show databases;"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
ansible@tnode2:~$ sudo mysql -u root mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.36-0ubuntu0.22.04.1 (Ubuntu)

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
--------------
mysql  Ver 8.0.36-0ubuntu0.22.04.1 for Linux on x86_64 ((Ubuntu))

Connection id:          8
Current database:       mysql
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         8.0.36-0ubuntu0.22.04.1 (Ubuntu)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8mb4
Db     characterset:    utf8mb4
Client characterset:    utf8mb4
Conn.  characterset:    utf8mb4
UNIX socket:            /var/run/mysqld/mysqld.sock
Binary data as:         Hexadecimal
Uptime:                 1 min 47 sec

Threads: 1  Questions: 47  Slow queries: 0  Opens: 1389  Flush tables: 3  Open tables: 49  Queries per second avg: 0.439
--------------

mysql> exit
Bye
ansible@tnode2:~$ exit
logout
Connection to tnode2 closed.
profile
무럭무럭 자라볼까

0개의 댓글