-
[Ansible] WinSVR 업데이트 Playbook 고도화 (V2)오픈소스 2022. 7. 18. 13:26
개요
마지막 포스팅 이후로 색다른 내용이 없었기에 새로운 포스팅이 많이 늦어졌다. 이번 포스팅은 기존에 사용하던 WinSVR 업데이트 자동화의 Playbook을 좀 더 효율적으로 사용할 수 있는 개선 방안에 대한 포스팅이다. 전체적인 동작 방식에는 차이가 없으나 사용함에 있어서 보다 효율적일 수 있도록 계층 구조를 적용하여 작성하였다.
구조 변경
사실 처음에 작성할 때는 번잡하게 왜 여러 파일로 작성을 해야 할까, 오히려 배포할 때 파일이 많아져서 트러블 슈팅에 더 많은 시간이 소요되지는 않을까하는 걱정에 하나의 파일로 작성하였다. 그러나, 기능별로 분리하여 파일을 작성하고 보니 배포의 단점보다는 장점이 더 많았는데 크게 3가지가 있었다.
각 단계별 기능 수정의 편리함
계층 구조 적용에 따라 문제점에 대한 빠른 파악 가능
불필요한 결과값 출력이 간소화되어, 가독성이 향상됨
필자는 아래와 같은 구조로 개선하였는데, OS 버전별로 공통적으로 사용하는 YAML파일을 호출하고 이어서 각 버전에 맞는 YAML을 추가로 호출하는 구조이다. 각 YMAL파일에 대한 세부 설명은 아래에서 순차 기술하도록 하겠다.
Etc#0 gater_facts / vars_files
기존에는 gather_facts를 사용하지 않았었는데, 불필요한 정보를 모두 긁어오고 이는 곧 서버에 부하로 이어질 수 있다는 판단에서였다. 그래서 wmic 명령어를 통하여 OS 버전 정보를 확인하였는데 filter 기능을 통하여 필요한 내역만 가져올 수 있는 것으로 확인하여 gather_facts를 통하여 가져오는 것으로 대체하였다. vars_files은 고도화하면서 변수가 점차 많아지게 되었고 이를 한 파일안에서 모두 관리할 수 있도록 하였다.
gather_facts: True pre_tasks: - setup: filter: ansible_facts.distribution vars_files: vars.yml
그리고 아래는 vars.yml 파일의 내용이다. 원래는 패치 수행하는 YAML파일에 포함시켜두었었는데 별도로 빼온 것일 뿐. 기능상의 차이나 문법의 차이는 없고, 오히려 가독성이 더 좋아진 느낌이다.
#### Common Variables #### Ansible_MasterDir: "/etc/ansible/work/" Ansible_ClientDir: "C:\\AnsiblePM" #### WinSVR Patch Variables #### SVR2012_Stack: KB5014025.msu SVR2012_Rollup: KB5014738.msu SVR2016_Stack: KB5014026.msu SVR2016_Rollup: KB5014702.msu SVR2019_Patch_Total: KB5014692.msu
00_main.yml
모든 Hosts가 공통으로 호출하는 YAML파일이다. 패치 수행하기 위한 변수/OS정보 등을 수집하며 각 단계에 맞는 YAML파일을 호출할 수 있도록 구현하였다. when 구문 포함 여부에 따라 공통적으로 수행하느냐, 해당 Hosts만 수행하느냐가 나눠지며 모든 파일은 동일 경로상에 위치하고 있어야 정상적으로 호출됨에 주의하자.
- name: Start Main YAML hosts: strategy: free gather_facts: True pre_tasks: - setup: filter: ansible_facts.distribution vars_files: vars.yml tasks: - name: Call in Common Process Playbook import_tasks: 01_common.yml - name: Call in WinSVR 2012 Patch Playbook import_tasks: 02_01_WinSVR_2012.yml when: '"2012" in ansible_facts.distribution' - name: Call in WinSVR 2016 Patch Playbook import_tasks: 02_02_WinSVR_2016.yml when: '"2016" in ansible_facts.distribution' - name: Call in WinSVR 2019 Patch Playbook import_tasks: 02_03_WinSVR_2019.yml when: '"2019" in ansible_facts.distribution' - name: Call in Last CleanUp Playbook import_tasks: 03_cleanup.yml - name: Call in CheckPatch Result Playbook import_tasks: 04_CheckPatch.yml
01_common.yml
호출되는 Playbook이 공통적으로 가지는 특성이 있는데, 기존에 수행하던 Hosts 등의 정보를 기재하지 않는다. 가장 상위에서 호출하는 Playbook의 정보를 상속받아서 사용하기 때문이며 이를 무시하고 기재하게 되면 중복 값이 존재한다는 오류와 함께 더 이상 진행되지 않는다. 이에 따라 각 Task도 들여쓰기를 하지 않고 가장 앞에서부터 작성하게 됨에 주의하자.
--- - name: Make Working Folder win_file: path: "{{ Ansible_ClientDir }}" state: directory ignore_errors: yes - name: Starting Before Config Backup import_tasks: extra_ConfigBak.yml - name: PM First Reboot (Menual) win_reboot: - name: Wait for First Reboot (Default 300's) wait_for_connection: - name: Enable Windows Update win_shell: | cmd /C "sc config wuauserv start= delayed-auto" cmd /C "net start wuauserv" ignore_errors: yes
1행의 "---"는 YAML파일임을 선언하는 구문으로, 필수로 사용하지 않아도 된다. 그 외는 패치를 위한 사전 작업을 수행하는부분으로 큰 차이는 없으나, 사전 Config 백업하는 YAML 파일을 별도로 호출한다. 향후 더 좋은 방식으로 변경될 요지가 있기에 해당 방식으로 사용하였으며, 이 부분이 앞서 애기했던 장점 중에 하나인 각 단계별 기능 수정의 편리함이다.
02_01_WinSVR_2012.yml / 02_02_WinSVR_2016.yml / 02_03_WinSVR_2019.yml
gather_facts로 OS버전을 수집하고, when 구문을 통하여 각 버전에 상응하는 Playbook을 호출한다.
- name: Copy PatchFile to Client win_copy: src: "{{ Ansible_MasterDir }}/2012/" dest: "{{ Ansible_ClientDir }}" - name: Execute 2012 PatchFile#1 win_hotfix: source: "{{ Ansible_ClientDir }}\\{{ SVR2012_Stack }}" state: present - name: Execute 2012 PatchFile#2 win_hotfix: source: "{{ Ansible_ClientDir }}\\{{ SVR2012_Rollup }}" state: present - name: Wait for Second Reboot (Default 300's) wait_for_connection:
- name: Copy PatchFile to Client win_copy: src: "{{ Ansible_MasterDir }}/2016/" dest: "{{ Ansible_ClientDir }}" - name: Execute 2016 PatchFile#1 win_hotfix: source: "{{ Ansible_ClientDir }}\\{{ SVR2016_Stack }}" state: present - name: Execute 2016 PatchFile#2 win_hotfix: source: "{{ Ansible_ClientDir }}\\{{ SVR2016_Rollup }}" state: present - name: Wait for Second Reboot (Default 300's) wait_for_connection:
- name: Copy PatchFile to Client win_copy: src: "{{ Ansible_MasterDir }}/2019/" dest: "{{ Ansible_ClientDir }}" - name: Expand 2019 PatchFile win_shell: | cmd /C "Expand -F:* {{ Ansible_ClientDir }}\\{{ SVR2019_Patch_Total }} {{ Ansible_ClientDir }}" - name: Execute 2019 Patch(SSU + Rollup) win_shell: | cmd /C "FOR /F %a in ('dir /B {{ Ansible_ClientDir }} ^| findstr cab ^| findstr SSU') do (C:\Windows\System32\Dism.exe /Online /Add-Package /PackagePath:{{ Ansible_ClientDir }}\%a)" cmd /C "FOR /F %b in ('dir /B {{ Ansible_ClientDir }} ^| findstr cab ^| findstr {{ SVR2019_Patch_Total.split('.').0 }}') do (C:\Windows\System32\Dism.exe /Online /Add-Package /NoRestart /PackagePath:{{ Ansible_ClientDir }}\%b)" ignore_errors: yes - name: PM Second Reboot (Menual) win_reboot: - name: Wait for Second Reboot (Default 300's) wait_for_connection:
위에서부터 순서대로 WinSVR 2012_R2 / 2016 / 2019에 대한 패치 Playbook이다. 이후 버전이 추가되면 신규 Playbook만 추가하면 되도록 작성하였으며, 각 버전별로 패치 방식과 변수에 대한 차이점이 있는데 유독 2019부터는 내용이 많이 다른데 최근 MS에서 배포되는 패치 파일의 구조가 변화되었기 때문이며, 세부 내용은 [Ansible] Windows Server 2019 업데이트 자동화 포스팅을 참고하면 된다.
03_cleanup.yml
--- - name: Disable Windows Update win_shell: | cmd /C "net stop wuauserv" cmd /C "sc config wuauserv start= disabled" cmd /C "del /Q {{ Ansible_ClientDir }}\*" ignore_errors: yes - name: PM Third Reboot (Menual) win_reboot: - name: Wait for Third Reboot (Default 300's) wait_for_connection:
패치 완료 이후, 01_common.yml 단계와 같이 모든 서버가 진행하는 단계로, 사용했던 패치 파일을 지우거나 관련 서비스를 비활성화시키는 동작을 수행한다.
04_CheckPatch.yml
기존에는 패치하는 Playbook, 그리고 패치 적용 여부를 점검하는 Playbook을 2개로 나누어 작성하였었다. 이번에는 고도화하면서 점검 기능까지 하나로 만들어보았는데, 작업이 정상적으로 끝나면 패치까지 모두 완료된 것으로 볼 수 있어서 하나의 Playbook으로 더욱 편하게 사용할 수 있었다. 마찬가지로 기존 구문과의 차이점은 없다.
--- - name: Patch Applied Check (2012) win_shell: | cmd /C "wmic qfe list | findstr {{ SVR2012_Stack.split('.').0 }}" cmd /C "wmic qfe list | findstr {{ SVR2012_Rollup.split('.').0 }}" when: '"2012" in ansible_facts.distribution' - name: Patch Applied Check (2016) win_shell: | cmd /C "wmic qfe list | findstr {{ SVR2016_Stack.split('.').0 }}" cmd /C "wmic qfe list | findstr {{ SVR2016_Rollup.split('.').0 }}" when: '"2016" in ansible_facts.distribution' - name: Patch Applied Check (2019) win_shell: | cmd /C "wmic qfe list | findstr {{ SVR2019_Patch_Total.split('.').0 }}" when: '"2019" in ansible_facts.distribution'
최종 Playbook
기존의 하나의 파일이 아닌, 기능별로 분류하여 하나의 Playbook으로 만든 WinSVR 업데이트 자동화 V2 전체 Playbook이다.
마무리
금일 작성한 포스팅은 기존에 포스팅했던 내용을 기능별로 분류했다가 하나로 합친 것과 다름이 없다. 간단한 작업이었음에도 불구하고 더 효율적으로 바꿀 수 있었다는 것이 오픈소스의 또 다른 매력이 아닌가 싶다. 오픈소스라는 것이 자유도가 높은 것이 특징인 만큼 많은 의견들이 있어야 보다 효율적으로 사용할 수 있는 것 같다. 포스팅을 읽은 많은 사람들이 오픈소스를 사용함에 있어서 리스크보다 효율성을 더 중요시 할 수 있게 되었으면 하는 바람이다.
궁금하신 내용은 댓글로 남겨주시고, 많은 블로그 방문은 저에게 큰 힘이 됩니다. ・ᴥ・
'오픈소스' 카테고리의 다른 글
[Docker] 파이썬(Python3.8) 개발 환경 구축하기 (0) 2022.08.29 [Ansible] WinSVR 업데이트 Playbook 고도화 (V3) (0) 2022.08.04 [Ansible] Window Server 2019 업데이트 자동화 (5) 2022.03.29 [Ansible] VMware 프로비저닝 (VMtools 설치 및 초기 설정) (0) 2021.07.22 [Ansible] VMware 프로비저닝 자동화 (0) 2021.03.31