느린 Ansible 플레이북의 병목 현상 식별 및 해결
성능 병목 현상을 식별하고 제거하여 Ansible 배포 속도를 획기적으로 높이세요. 이 가이드는 느린 플레이북 프로파일링, 팩트 수집 최적화, 연결 관리, 작업 실행 튜닝을 위한 실용적인 단계, 구성 예제 및 모범 사례를 제공합니다. 효율적이고 신속한 인프라 자동화를 위해 Ansible의 기능을 활용하는 방법을 알아보세요.
느린 Ansible 플레이북의 병목 현상 식별 및 해결
느린 Ansible 플레이북은 지연이 한 곳에 명확하게 나타나지 않기 때문에 실망스럽습니다. 실행 중 몇 초는 팩트를 수집하고, 몇 초 더 SSH 연결을 연 다음, 한 번에 한 호스트씩 파일을 복사하는 데 몇 분이 소요될 수 있습니다. 추측만 한다면 보통 잘못된 부분을 튜닝하게 됩니다.
시간이 어디에 소요되는지 측정하는 것부터 시작하세요. 그런 다음 가장 큰 지연 원인을 먼저 수정하세요. 소규모 환경에서는 매번 패키지 관리자를 실행하는 단일 셸 작업일 수 있습니다. 대규모 환경에서는 연결 설정, 팩트 수집, 낮은 forks, 또는 의도한 것보다 더 많이 작업을 직렬화하는 플레이북인 경우가 많습니다.
Ansible 성능 메트릭 이해
특정 최적화 기술을 살펴보기 전에 Ansible의 성능을 측정하고 해석하는 방법을 이해하는 것이 중요합니다. Ansible은 진단에 매우 유용한 내장 타이밍 정보를 제공합니다.
상세 로그보다 타이밍 출력 사용
매우 상세한 출력은 연결 문제를 해결하는 데 도움이 될 수 있지만, 성능 작업에는 잡음이 많습니다. 더 깔끔한 첫 번째 방법은 실행 종료 시 작업 기간을 보여주는 profile_tasks 콜백입니다.
ansible.cfg에서:
[defaults]
callbacks_enabled = profile_tasks
그런 다음 플레이북을 정상적으로 실행합니다:
ansible-playbook my_playbook.yml
가장 느린 작업을 먼저 확인하세요. 하나의 작업이 실행의 대부분을 차지한다면, 아침 내내 forks에 대해 논쟁하지 마세요.
출력 상세도 제어
SSH 세부 정보, 모듈 전송 동작, 재시도 또는 인터프리터 검색을 확인해야 할 때 -vvv를 사용하세요. 일상적인 타이밍의 경우 로그 출력 페이지 아래에 신호가 가려질 수 있습니다.
일반적인 병목 현상 및 최적화 전략
여러 요인이 느린 Ansible 플레이북에 기여할 수 있습니다. 여기서는 일반적인 병목 현상을 살펴보고 해결 가능한 전략을 제공합니다.
1. 과도한 팩트 수집
기본적으로 Ansible은 각 플레이 시작 시 관리 호스트에서 팩트(시스템 정보)를 수집합니다. 유용하지만, 특히 많은 수의 호스트나 느린 네트워크에서는 시간이 많이 소요될 수 있습니다. 플레이북에 수집된 모든 팩트가 필요하지 않은 경우 팩트 수집을 비활성화하거나 제한할 수 있습니다.
팩트 수집 비활성화
플레이에 대해 팩트 수집을 완전히 비활성화하려면 gather_facts: no 지시문을 사용하세요:
- name: My Playbook
hosts: webservers
gather_facts: no
tasks:
- name: Ensure Apache is installed
apt: name=apache2 state=present
팩트 수집 제한
일부 팩트만 필요하지만 전부는 아닌 경우 gather_subset을 사용하여 수집할 팩트를 지정할 수 있습니다.
- name: My Playbook
hosts: webservers
gather_facts: yes
gather_subset:
- '!all'
- '!any'
- hardware
- network
tasks:
- name: Use network facts
debug: var=ansible_default_ipv4.address
팩트 캐싱
팩트가 자주 변경되지 않는 환경에서는 팩트를 캐싱하면 후속 플레이북 실행 속도를 크게 높일 수 있습니다. Ansible은 여러 팩트 캐싱 플러그인(예: jsonfile, redis, memcached)을 지원합니다.
팩트 캐싱을 활성화하려면 ansible.cfg 파일에서 구성하세요:
[defaults]
fact_caching = jsonfile
fact_caching_connection = /path/to/ansible/facts_cache
fact_caching_timeout = 86400 # 24시간 동안 캐시
그러면 플레이북은 사용 가능한 경우 자동으로 캐시된 팩트를 사용합니다.
2. 비효율적인 작업 실행
일부 작업은 본질적으로 느리거나 비효율적인 방식으로 실행될 수 있습니다.
병렬 실행 (Forking)
Ansible의 기본 동작은 플레이 내에서 호스트에서 순차적으로 작업을 실행하는 것입니다. Ansible이 동시에 호스트를 관리하는 데 사용하는 병렬 프로세스(forks) 수를 늘릴 수 있습니다. 이는 ansible.cfg의 forks 설정 또는 -f 명령줄 옵션을 통해 제어됩니다.
ansible.cfg:
[defaults]
forks = 10
명령줄:
ansible-playbook my_playbook.yml -f 10
팁: 적당한 수의 포크로 시작하고 제어 노드, 네트워크 및 대상 서비스를 관찰하면서 점차적으로 늘리세요. 더 많은 포크는 배포를 더 빠르게 만들 수 있지만 패키지 저장소, 로드 밸런서 또는 데이터베이스 마이그레이션 단계를 압도할 수도 있습니다.
멱등성 및 상태 관리
작업이 멱등성을 가지도록 하세요. 즉, 작업을 여러 번 실행하는 것이 한 번 실행하는 것과 동일한 효과를 가져야 합니다. Ansible 모듈은 일반적으로 멱등성을 갖도록 설계되었지만 사용자 정의 스크립트나 명령은 그렇지 않을 수 있습니다. 작업 내의 비효율적인 검사도 오버헤드를 추가할 수 있습니다.
예를 들어, 서비스가 실행 중인지 확인한 다음 시작하는 명령을 실행하는 대신 전용 service 모듈을 사용하세요:
비효율적:
- name: Start service (inefficient check)
command: systemctl start my_service.service || true
when: "'inactive' in service_status.stdout"
register: service_status
changed_when: false # 이 작업은 상태를 변경하지 않음
효율적 (service 모듈 사용):
- name: Ensure my_service is running
service:
name: my_service
state: started
장기 실행 작업에 async 및 poll 사용
완료하는 데 오래 걸릴 수 있는 작업(예: 패키지 업그레이드, 데이터베이스 마이그레이션)의 경우 Ansible의 async 및 poll 지시문을 사용하면 플레이북이 중단되는 것을 방지할 수 있습니다.
async: 작업이 백그라운드에서 실행되어야 하는 최대 시간을 지정합니다.poll: Ansible이 비동기 작업의 상태를 확인해야 하는 빈도를 지정합니다.
- name: Perform a long-running operation
command: /usr/local/bin/long_script.sh
async: 3600 # 최대 1시간 동안 실행
poll: 60 # 60초마다 상태 확인
3. 연결 최적화
Ansible이 관리 노드에 연결하는 방식은 성능에 중요한 역할을 합니다.
SSH 연결 멀티플렉싱
SSH 멀티플렉싱(ControlMaster)을 사용하면 여러 SSH 세션이 단일 네트워크 연결을 공유할 수 있습니다. 이는 동일한 호스트에 대한 후속 연결 속도를 크게 높일 수 있습니다.
ansible.cfg에서 활성화:
[ssh_connection]
control_master = auto
control_path = ~/.ansible/cp/ansible-%%r@%%h:%%p
control_persist = 600 # 제어 연결을 10분 동안 유지
SSH 재시도 및 시간 초과
SSH 연결 매개변수를 조정하면 호스트를 일시적으로 사용할 수 없을 때 불필요한 지연을 방지할 수 있습니다.
[ssh_connection]
sf_retries = 3
sf_delay = 1
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ConnectionAttempts=5 -o ConnectTimeout=10
pipelining 사용
파이프라이닝을 사용하면 Ansible이 각 명령에 대해 새 SSH 세션을 만들지 않고 원격 호스트에서 직접 명령을 실행할 수 있습니다. 이는 많은 작업에 대한 오버헤드를 크게 줄일 수 있습니다.
ansible.cfg에서 활성화:
[ssh_connection]
pipelining = True
경고: 파이프라이닝은 일부 권한 상승 설정, 특히 이전 배포판에서 sudo에 requiretty가 활성화된 경우 충돌할 수 있습니다. 프로덕션 플레이북에서 사용하는 것과 동일한 become 경로로 테스트하세요.
4. 플레이북 구조 및 로직 최적화
때로는 플레이북이 작성된 방식 자체가 느린 원인이 될 수 있습니다.
delegate_to 및 run_once 사용
작업이 하나의 호스트에서만 수행되어야 하지만 다른 여러 호스트에 영향을 미치는 경우(예: 로드 밸런서 다시 시작) delegate_to 및 run_once를 사용하여 효율적으로 실행하세요.
- name: Restart load balancer
service: name=haproxy state=restarted
delegate_to: lb_server_1
run_once: true
역할 및 포함의 전략적 사용
역할과 포함은 구성을 체계화하는 데 도움이 되지만, 깊게 중첩되거나 비효율적으로 구조화된 포함은 약간의 오버헤드를 추가할 수 있습니다. 역할 종속성 및 포함 로직이 깔끔한지 확인하세요.
serial 키워드
serial 키워드는 플레이 내에서 동시에 작업을 수행할 수 있는 호스트 수를 제한합니다. 제어된 롤아웃에 자주 사용되지만 원하는 성능에 비해 너무 낮게 설정된 경우 병목 현상이 될 수도 있습니다.
- name: Deploy application to a subset of servers
hosts: appservers
serial: 2 # 한 번에 2개의 호스트에서만 실행
tasks:
- name: Update application code
copy: src=app/ dest=/opt/app/
의도적으로 병렬 처리를 제한하지 않는 경우 serial이 설정되지 않았거나 충분히 높은 숫자로 설정되었는지 확인하세요.
느린 전송뿐만 아니라 느린 작업 수정
연결 튜닝은 플레이북에 많은 짧은 작업이 있을 때 도움이 됩니다. 매번 너무 많은 작업을 수행하는 작업을 수정하지는 않습니다.
일반적인 예는 shell을 사용하여 패키지 명령을 실행하는 것입니다:
- name: Install nginx with shell
shell: apt-get update && apt-get install -y nginx
Ansible이 해당 작업을 추론하기 어렵습니다. 매번 변경된 것으로 보고할 수 있고, 매 실행마다 패키지 메타데이터를 업데이트할 수 있으며, 구조화된 실패 정보를 덜 제공합니다. 상태를 이해하는 모듈을 선호하세요:
- name: Refresh apt cache when needed
apt:
update_cache: true
cache_valid_time: 3600
- name: Install nginx
apt:
name: nginx
state: present
파일 배포에도 동일한 아이디어가 적용됩니다. 수백 개의 작은 파일이 있는 대용량 디렉토리를 copy 모듈을 통해 복사하는 것은 Ansible이 파일별로 확인하고 전송하기 때문에 느릴 수 있습니다. 애플리케이션 릴리스의 경우 아티팩트를 한 번 빌드하고 아카이브를 업로드한 다음 대상에서 압축을 푸는 것이 더 빠를 수 있습니다:
- name: Upload release artifact
copy:
src: dist/app.tar.gz
dest: /tmp/app.tar.gz
- name: Unpack release
unarchive:
src: /tmp/app.tar.gz
dest: /opt/app
remote_src: true
항상 올바른 설계는 아니지만 올바른 질문입니다: 하나의 아티팩트가 더 명확할 때 수천 개의 작은 결정을 동기화하도록 Ansible에 요청하고 있습니까?
인벤토리 및 변수 작업 확인
동적 인벤토리는 또 다른 숨겨진 지연이 될 수 있습니다. 모든 플레이북 실행이 클라우드 API를 호출하고, 페이지 매김을 기다리고, 전체 호스트 목록을 다시 빌드하는 경우 플레이북은 첫 번째 작업이 시작되기 전에 느리게 느껴질 수 있습니다. 플러그인이 지원하는 경우 인벤토리 데이터를 캐시하고 호스트 패턴을 좁게 유지하세요. all에 대해 웹 배포를 실행한 다음 when 조건으로 대부분의 호스트를 건너뛰는 것은 시간을 낭비합니다.
변수 로딩도 지저분해질 수 있습니다. 큰 group_vars/all.yml 파일, 비용이 많이 드는 조회, 반복되는 템플릿 렌더링이 누적될 수 있습니다. 조회가 시크릿 관리자나 HTTP 엔드포인트에 도달하는 경우 많은 작업에서 호출하는 대신 플레이당 한 번 변수에 결과를 저장하세요.
프로파일링 도구 및 기술
Ansible 자체의 상세 출력 외에도 전용 프로파일링은 더 깊은 통찰력을 제공할 수 있습니다.
ansible-playbook --syntax-check
이 명령은 플레이북의 구문 오류를 확인하지만 실행하지는 않습니다. 전체 실행 전에 플레이북 구조를 빠르게 검증하는 방법입니다.
Ansible 이벤트 로깅
Ansible은 실행 이벤트를 파일에 기록할 수 있으며, 이를 분석할 수 있습니다. 이는 장기 실행 플레이북이나 감사에 특히 유용합니다.
ansible.cfg에서 이벤트 로깅 구성:
[defaults]
log_path = /var/log/ansible.log
사용자 정의 콜백 플러그인
고급 프로파일링을 위해 사용자 정의 콜백 플러그인을 작성하여 특정 메트릭을 캡처하거나 플레이북 실행에 대한 사용자 정의 보고서를 만들 수 있습니다.
모든 것에 대해 Async를 사용하지 말고 대기에 사용
일부 플레이북 시간은 실제 대기입니다: 서비스 재시작, 패키지 빌드, 클라우드 인스턴스 준비, 또는 합법적으로 몇 분이 걸리는 데이터베이스 마이그레이션. 이러한 작업이 모든 호스트를 동시에 차단할 필요가 없는 경우 Ansible의 async 및 poll이 도움이 될 수 있습니다.
- name: Start long-running report generation
command: /opt/tools/build-report
async: 1800
poll: 0
register: report_job
- name: Check report job
async_status:
jid: "{{ report_job.ansible_job_id }}"
register: report_status
until: report_status.finished
retries: 60
delay: 10
주의해서 사용하세요. Async는 안전하지 않은 작업을 병렬로 만들기 위한 지름길이 아닙니다. 10개의 호스트가 모두 동시에 데이터베이스 마이그레이션을 시작하면 플레이북이 더 빨리 완료되고 여전히 환경을 손상시킬 수 있습니다. Async는 대상이 Ansible이 나중에 다시 확인하는 동안 안전하게 계속할 수 있는 독립적인 작업에 가장 적합합니다.
사용자 관점에서 측정
플레이북이 기술적으로 더 빠를 수 있지만 운영자가 유용한 피드백을 보기 전에 너무 오래 기다리면 여전히 느리게 느껴질 수 있습니다. 대규모 배포를 명확한 작업 이름이 있는 단계로 분할하세요: 사전 점검, 아티팩트 업로드, 서비스 업데이트, 상태 확인, 정리. 단계가 느리면 프로필 출력과 터미널을 읽는 사람 모두 시간이 어디에 소요되었는지 이해합니다.
이는 롤백 결정에도 도움이 됩니다. 플레이북이 첫 번째 상태 확인 전에 12분을 소비한다면 실패를 너무 늦게 발견할 수 있습니다. 디스크 공간, 패키지 저장소 액세스 및 서비스 자격 증명을 확인하는 작은 사전 점검 작업은 SSH 설정에서 1초를 줄이는 것보다 훨씬 더 많은 시간을 절약할 수 있습니다.
최고의 Ansible 성능 작업은 좋은 의미에서 지루합니다: 작업 타이밍을 활성화하고, 가장 느린 단계를 찾고, 한 가지를 변경하고, 다시 측정하세요. 필요하지 않을 때만 팩트를 비활성화하세요. 대상과 종속성이 병렬 처리를 처리할 수 있을 때만 forks를 늘리세요. 시끄러운 셸 명령을 상태 인식 모듈로 교체하세요. 연결 오버헤드가 실제로 문제의 일부인지 확인한 후 SSH 멀티플렉싱 및 파이프라이닝을 사용하세요.
이러한 규율은 플레이북을 더 빠르게 만들면서도 읽기 쉽게 유지합니다. 빠르게 완료되지만 아무도 이해하지 못하는 배포는 단지 더 짧은 진행 표시줄이 있는 내일의 장애일 뿐입니다.