10년 전, 이런 질문이 있었습니다.많은 서버에서 SSH를 통해 명령 실행 자동화.
기본적으로 동일한 작업이 있지만 (아마도 다를 수 있는) 매개변수를 사용하여 명령/스크립트를 실행해야 하고 장기 실행 작업을 중지해야 합니다. 또한 어떤 스크립트가 실행 중이거나 완료되고 결과가 무엇인지 모니터링할 수 있도록 최신 모니터(적어도 웹 UI 또는 탄력적 출력과 같은)를 선호합니다. 궁극적으로 줄을 서거나 시간 제한을 두는 것이 좋습니다. 또한 모든 컴퓨터에 내 공개 키를 추가할 수는 없지만 그곳에 일부 소프트웨어를 설치하도록 할 수는 있습니다.
이는 주로 AI 훈련 과정에 사용되지만, 프레임워크를 업그레이드하고 궁극적으로 새로운 스크립트와 데이터를 전송(다운로드)하는 데에도 사용됩니다.
위 링크에서 다들 Ansible 사용을 제안하셨는데요, 저는 자동화 방식이 현대적인 방식이라고 생각하는데 다른 방법은 없을까요?
친구도 CI/CD(gitlab 작업)를 제안했는데 그건 좀 과한 것 같아서 코드 테스트 같은 다른 용도로 사용했습니다. AutoML에 대한 힌트도 얻었지만 이는 완전한 AI 프레임워크이고 다양한 매개변수를 사용하여 여러 명령/스크립트를 실행해야 하기 때문에 필요하지 않습니다.
답변1
매개변수를 사전에 넣습니다.
- 예를 들어 기본값부터 시작하겠습니다.
shell> cat group_vars/all/scripts.yml
scripts:
default:
script: /root/bin/default.sh
params: p1 p2 p3
timeout: 30
retries: 10
delay: 3
log: /tmp/ansible_script.log
특정 컨트롤러의 스크립트
shell> tree files
files
├── default.sh
├── script_A.sh
├── script_B.sh
└── script_C.sh
shell> cat files/default.sh
#!/bin/sh
echo $1 $2 $3
echo finished > /tmp/ansible_script.log
exit 0
아래 스크립트
shell> cat pb.yml
- hosts: all
vars:
my_script: "{{ scripts[inventory_hostname]|d(scripts['default']) }}"
_script: "{{ my_script.script|d(scripts.default.script) }}"
_params: "{{ my_script.params|d(scripts.default.params) }}"
_timeout: "{{ my_script.timeout|d(scripts.default.timeout) }}"
_retries: "{{ my_script.retries|d(scripts.default.retries) }}"
_delay: "{{ my_script.delay|d(scripts.default.delay) }}"
_log: "{{ my_script.log|d(scripts.default.log) }}"
tasks:
- debug:
msg: |-
_script: {{ _script }}
_params: {{ _params }}
_timeout: {{ _timeout }}
_retries: {{ _retries }}
_delay: {{ _delay }}
_log: {{ _log }}
when: debug|d(false)|bool
- name: Copy script
block:
- file:
state: directory
path: "{{ _script|dirname }}"
mode: 0750
- copy:
src: "{{ _script|basename }}"
dest: "{{ _script }}"
mode: 0550
when: copy_script|d(false)|bool
- name: Run script
block:
- command:
cmd: "{{ _script }} {{ _params }}"
async: "{{ _timeout }}"
poll: 0
register: cmd_async
- debug:
var: cmd_async.ansible_job_id
when: debug|d(false)|bool
- name: Read log until finished
block:
- command:
cmd: "cat {{ _log }}"
register: cmd_log
until: cmd_log.stdout == 'finished'
retries: "{{ _retries }}"
delay: "{{ _delay }}"
- debug:
var: cmd_log.stdout
when: debug|d(false)|bool
when: read_log_fin|d(false)|bool
- name: Check async script
block:
- async_status:
jid: "{{ cmd_async.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: "{{ _retries }}"
delay: "{{ _delay }}"
- debug:
msg: >-
{{ job_result.start }}
{{ job_result.end }}
rc: {{ job_result.rc}}
when: debug|d(false)|bool
주어진
shell> ansible-playbook pb.yml -e debug=true -e copy_script=true -e read_log_fin=true
PLAY [all] ***********************************************************************************
TASK [debug] *********************************************************************************
ok: [test_11] =>
msg: |-
_script: /root/bin/default.sh
_params: p1 p2 p3
_timeout: 30
_retries: 10
_delay: 3
_log: /tmp/ansible_script.log
ok: [test_12] =>
msg: |-
_script: /root/bin/default.sh
_params: p1 p2 p3
_timeout: 30
_retries: 10
_delay: 3
_log: /tmp/ansible_script.log
ok: [test_13] =>
msg: |-
_script: /root/bin/default.sh
_params: p1 p2 p3
_timeout: 30
_retries: 10
_delay: 3
_log: /tmp/ansible_script.log
TASK [file] **********************************************************************************
ok: [test_13]
ok: [test_12]
ok: [test_11]
TASK [copy] **********************************************************************************
ok: [test_12]
ok: [test_11]
ok: [test_13]
TASK [command] *******************************************************************************
changed: [test_12]
changed: [test_11]
changed: [test_13]
TASK [debug] *********************************************************************************
ok: [test_11] =>
cmd_async.ansible_job_id: '754707567219.90860'
ok: [test_12] =>
cmd_async.ansible_job_id: '148176661548.90862'
ok: [test_13] =>
cmd_async.ansible_job_id: '688240445475.90861'
TASK [command] *******************************************************************************
changed: [test_13]
changed: [test_11]
changed: [test_12]
TASK [debug] *********************************************************************************
ok: [test_11] =>
cmd_log.stdout: finished
ok: [test_12] =>
cmd_log.stdout: finished
ok: [test_13] =>
cmd_log.stdout: finished
TASK [async_status] **************************************************************************
changed: [test_12]
changed: [test_13]
changed: [test_11]
TASK [debug] *********************************************************************************
ok: [test_11] =>
msg: '2022-08-01 16:02:50.287027 2022-08-01 16:02:50.320177 rc: 0'
ok: [test_12] =>
msg: '2022-08-01 16:02:49.770331 2022-08-01 16:02:49.801347 rc: 0'
ok: [test_13] =>
msg: '2022-08-01 16:02:50.189800 2022-08-01 16:02:50.343773 rc: 0'
PLAY RECAP ***********************************************************************************
test_11: ok=9 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_12: ok=9 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_13: ok=9 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 반복 중에는 중간 로그를 표시할 수 없습니다. 콜백 플러그인은 반복 후 모든 결과를 함께 표시합니다. 중간 로그를 관찰하려면 Ansible에서 나가야 합니다. 예를 들어 로그 파일을 가져옵니다.
- name: Fetch log until finished
fetch:
dest: /tmp/ansible/
src: "{{ _log }}"
until: lookup('file', my_logfile) == 'finished'
retries: "{{ _retries }}"
delay: "{{ _delay }}"
vars:
my_logfile: "/tmp/ansible/{{ inventory_hostname}}/tmp/ansible_script.log"
when: fetch_log_fin|d(false)|bool
이렇게 하면 컨트롤러에 정기적으로 업데이트되는 파일이 생성됩니다.
shell> tree /tmp/ansible/
/tmp/ansible/
├── test_11
│ └── tmp
│ └── ansible_script.log
├── test_12
│ └── tmp
│ └── ansible_script.log
└── test_13
└── tmp
└── ansible_script.log
컨트롤러에 파일을 표시합니다. 예를 들어보다
shell> watch cat /tmp/ansible/test_11/tmp/ansible_script.log
이를 테스트하기 위해 다음 스크립트는 $2 간격으로 로그에 $1번 기록합니다.
shell> cat files/script_A.sh
#!/bin/sh
for i in $(seq 1 $1); do
echo step $i > /tmp/ansible_script.log
sleep $2
done
echo finished > /tmp/ansible_script.log
exit 0
포스터를 볼 수 있도록 사전을 업데이트하세요.테스트_11스크립트 실행
shell> cat group_vars/all/scripts.yml
scripts:
default:
script: /root/bin/default.sh
params: p1 p2 p3
timeout: 30
retries: 10
delay: 3
log: /tmp/ansible_script.log
test_11:
script: /root/bin/script_A.sh
params: 7 3
스크립트에는 요약이 포함되어 있습니다. (플레이북을 다시 실행하기 전에 가져온 파일을 삭제하세요. 그렇지 않으면 마지막 파일에서 작업을 건너뜁니다.)
shell> ansible-playbook pb.yml -e debug=true -e fetch_log_fin=true
...
TASK [Fetch log until finished] **************************************************************
ok: [test_12]
FAILED - RETRYING: [test_11]: Fetch log until finished (10 retries left).
ok: [test_13]
FAILED - RETRYING: [test_11]: Fetch log until finished (9 retries left).
FAILED - RETRYING: [test_11]: Fetch log until finished (8 retries left).
FAILED - RETRYING: [test_11]: Fetch log until finished (7 retries left).
FAILED - RETRYING: [test_11]: Fetch log until finished (6 retries left).
changed: [test_11]
TASK [async_status] **************************************************************************
changed: [test_13]
changed: [test_12]
changed: [test_11]
TASK [debug] *********************************************************************************
ok: [test_11] =>
msg: '2022-08-01 18:00:13.304133 2022-08-01 18:00:34.768385 rc: 0'
ok: [test_12] =>
msg: '2022-08-01 18:00:13.413492 2022-08-01 18:00:13.480142 rc: 0'
ok: [test_13] =>
msg: '2022-08-01 18:00:13.537767 2022-08-01 18:00:13.731926 rc: 0'
PLAY RECAP ***********************************************************************************
test_11: ok=6 changed=3 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
test_12: ok=6 changed=2 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
test_13: ok=6 changed=2 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
로그를 읽으면 출력이 거의 동일합니다.
shell> ansible-playbook pb.yml -e debug=true -e read_log_fin=true
...
TASK [Read log until finished] ***************************************************************
FAILED - RETRYING: [test_11]: Read log until finished (10 retries left).
changed: [test_12]
changed: [test_13]
FAILED - RETRYING: [test_11]: Read log until finished (9 retries left).
FAILED - RETRYING: [test_11]: Read log until finished (8 retries left).
FAILED - RETRYING: [test_11]: Read log until finished (7 retries left).
FAILED - RETRYING: [test_11]: Read log until finished (6 retries left).
changed: [test_11]
TASK [debug] *********************************************************************************
ok: [test_11] =>
cmd_log.stdout: finished
ok: [test_12] =>
cmd_log.stdout: finished
ok: [test_13] =>
cmd_log.stdout: finished
답변2
귀하의 질문은 두 부분으로 구성된 것 같습니다.
- (대규모) 서버 목록에서 실행 중인 스크립트/프로세스를 중지/시작/관리하는 방법은 무엇입니까?
- 동일한 서버 목록에서 장기 실행 스크립트/프로세스의 상태를 어떻게 추적하거나 모니터링할 수 있습니까?
Ansible 및 기타 구성 관리 소프트웨어(Puppet, Chef, Saltstack 등)는 질문 1에 대한 좋은 후보일 수 있지만 특히 진행 그래프 또는 경고 스크립트를 구상하는 경우 시작/중지하는 프로세스에 대한 추적/모니터링을 제공하지 않습니다. 문제가 발생했습니다. (IMO) 모니터링 시스템은 이러한 상태 모니터링 및 보고 기능을 더 잘 제공할 것입니다.
질문 1로 돌아가서, Ansible은 사전 구성된 서버이든 명령줄에서 즉시 입력하는 "임시" 명령/스크립트이든 상관없이 여러 서버에서 명령/스크립트를 실행하는 기능으로 잘 알려져 있습니다. Saltstack은 유사한 기능을 가지고 있지만 Ansible만큼 복잡한 임시 명령을 처리하지 못할 수도 있습니다. 다른 구성 관리 팩은 대상 서버에서 명령을 실행하는 직접적인 방법이 적고 여기에 설명된 문제를 해결하기 위해 쉽게 구성되지 않을 수 있습니다.
질문 #2의 경우, 서버 기본(CPU, 메모리, 디스크)에 대한 모니터링 시스템이 이미 존재하는지 여부, 스크립트/프로세스 추적을 위해 얼마나 쉽게 확장할 수 있는지 등 모니터링 시스템을 선택할 때 고려해야 할 요소가 많습니다. 또한 이러한 서버가 스크립트/프로세스 실행 전용이거나 다른 작업도 실행하는 경우입니다. 이는 모니터링하려는 항목, 상태를 확인하는 방법 및 원하는 알림 유형에 대한 세부 정보가 포함된 자체 질문을 받을 만큼 충분히 큰 주제입니다.
답변3
꼭두각시 볼트상대적으로 쉽게 설명하는 작업을 수행합니다. 우리는 제가 설명한 복잡한 워크플로에 이를 사용했고, 짧은 시간 내에 terraform(구성) 및 serviceNow(CR 유효성 검사)와 같은 다른 도구에 연결했습니다. 귀하의 사용 사례에는 통합이 필요하지 않을 수도 있습니다. 그러나 이러한 요구 사항이 어떻게 변경되는지 알고 있는 것이 좋습니다.
OP는 대상 노드에 공개 키를 넣지 않는다고 언급했습니다... 완전히 이해했는지는 모르겠지만 액면 그대로 받아들이면 사용자 이름과 비밀번호를 사용하여 Bolt로 인증하는 것이 가능합니다.
동료가 제안한 것과 같은 CI 도구는 웹을 통해 모든 것을 볼 수 있는 우아한 방법입니다.