<p data-ke-size="size16">2024년 첫 스터디이면서 믿고 참여하는 가시다님의 Ansible 스터디가 시작됐다. 1주차라서 기본 이론과 간단한 실습을 진행했고, 몇가지 도전 과제들을 기록해보려고 한다.</p>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">먼저 Ansible을 사용하기 위해서는 대상 서버들에 SSH로 접속이 가능해야하고 Python 설치가 되어 있어야 한다. 이 대상 서버들은 Inventory라는 이름으로 사전에 등록해놓고 활용하게 되는데 SSH 접속 시 인증으로 Key 파일을 사용하거나 Password를 사용할 수 있다. </p>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">테라폼처럼 Ansible에도 모듈의 개념이 있는데 미리 구현되어 있는 기능들을 자유롭게 참조해서 사용할 수 있다는 면에서 유사한 것 같다. 예를들어 서비스 모듈은 서버에 실행되고 있는 서비스를 Start/Stop/Restart/Reload 할 수 있다. 모듈은 너무나 많기 때문에 각 설정들을 외우는 것은 비효율적이고, 필요한 모듈이 있을 때 레퍼런스를 참조해서 사용하면 된다.</p>
<p data-ke-size="size16"> </p>
<h4 data-ke-size="size20">Ansible 모듈 내용 확인</h4>
<p data-ke-size="size16">서비스 모듈을 예제로 간단히 모듈에 대한 설명을 보는 방법을 살펴본다. </p>
<p data-ke-size="size16">1. 구글에서 상세한 내용을 보고 싶은 모듈을 입력한다. ex) ansible service module</p>
<p data-ke-size="size16">2. 레퍼런스는 Synopsis, Parameters, Attributes, Notes, See Also, Examples로 구성되는데 개인적으로 Examples를 먼저 보는 것이 이해가 빠른 듯 하다. Linux에서 실행되는 명령들은 대부분 익숙하기 때문에 예제만 보더라도 쉽게 이해가된다.</p>
<p><figure class="imageblock alignCenter" data-ke-mobileStyle="widthOrigin" data-origin-width="1322" data-origin-height="744"><span data-url="https://blog.kakaocdn.net/dn/7Upyt/btsDpx7xORx/PXIItaFWei4xmQaaZJsKtk/img.png" data-lightbox="lightbox"><img src="https://blog.kakaocdn.net/dn/7Upyt/btsDpx7xORx/PXIItaFWei4xmQaaZJsKtk/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7Upyt%2FbtsDpx7xORx%2FPXIItaFWei4xmQaaZJsKtk%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" width="652" height="367" data-origin-width="1322" data-origin-height="744"/></span></figure>
</p>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">3. Examples에서 모든 옵션들이 표현되지는 않기 때문에 원하는 설정이 없을 경우에는 상세한 파라미터를 확인해야한다.</p>
<p><figure class="imageblock alignCenter" data-ke-mobileStyle="widthOrigin" data-origin-width="1323" data-origin-height="854"><span data-url="https://blog.kakaocdn.net/dn/ys2qY/btsDqNPg14g/2VCWjeT0zAUMf0XymEb5s1/img.png" data-lightbox="lightbox"><img src="https://blog.kakaocdn.net/dn/ys2qY/btsDqNPg14g/2VCWjeT0zAUMf0XymEb5s1/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fys2qY%2FbtsDqNPg14g%2F2VCWjeT0zAUMf0XymEb5s1%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" width="632" height="408" data-origin-width="1323" data-origin-height="854"/></span></figure>
</p>
<p data-ke-size="size16">4. Playbook을 작성하고 나면 잘못된 부분은 없는지 아래 명령으로 문법 체크를 한다.</p>
<pre id="code_1705145873967" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>ansible-playbook --syntax-check playbook.yml</code></pre>
<p data-ke-size="size16">5. 이상이 없다면 Playbook을 실행하여 인벤토리에 등록되어 있는 대상 서버들로 명령을 전달한다.</p>
<p data-ke-size="size16"> </p>
<h4 data-ke-size="size20">실습1 - Playbook으로 user 삭제하기</h4>
<p data-ke-size="size16">위 내용을 숙지하고 먼저 Linux user를 생성하고, Playbook으로 삭제하는 과정을 진행해본다.</p>
<p data-ke-size="size16">1. Ansible 레퍼런스로 user 모듈에 대해 살펴본다. 별다른 설명을 안읽어보고 예제만 보더라도 어떻게 하면 될지 알 수 있다.</p>
<p><figure class="imageblock alignCenter" data-ke-mobileStyle="widthOrigin" data-origin-width="1169" data-origin-height="333"><span data-url="https://blog.kakaocdn.net/dn/FRbrX/btsDpu33Wuo/1b49LMvROGc9MxMuR65aK1/img.png" data-lightbox="lightbox"><img src="https://blog.kakaocdn.net/dn/FRbrX/btsDpu33Wuo/1b49LMvROGc9MxMuR65aK1/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFRbrX%2FbtsDpu33Wuo%2F1b49LMvROGc9MxMuR65aK1%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" width="635" height="181" data-origin-width="1169" data-origin-height="333"/></span></figure>
</p>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">2. 사전에 ansible이라는 이름의 user를 추가해놓았기 때문에 아래와 같이 Playbook을 작성했다.</p>
<pre id="code_1705147727859" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>---
- hosts: all
tasks:
- name: Remove user ansible
ansible.builtin.user:
name: ansible
state: absent
remove: yes</code></pre>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">3. 문법 오류가 없는지 아래 명령으로 확인한다.</p>
<pre id="code_1705147701570" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>$ ansible-playbook -i ./inventory --syntax-check user-remove.yml
# 오류 없이 아래와 같은 결과가 반환되면 정상
playbook: user-remove.yml</code></pre>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">4. Playbook 명령을 실행하여 대상 서버에 적용한다.</p>
<pre id="code_1705147846529" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>$ ansible-playbook -i ./inventory user-remove.yml
PLAY [all] ****************************************************************************
TASK [Gathering Facts] ****************************************************************
ok: [tnode1]
TASK [Remove user ansible] ************************************************************
changed: [tnode1]
PLAY RECAP ****************************************************************************
tnode1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0</code></pre>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">5. 대상 서버에 접속해서 ansible user가 삭제되었는지 확인해보니 정상적으로 삭제되었다.</p>
<pre id="code_1705148007123" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>tail -n 3 /etc/passwd
# ansible user가 표시되지 않음
_chrony:x:114:121:Chrony daemon,,,:/var/lib/chrony:/usr/sbin/nologin
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false</code></pre>
<p data-ke-size="size16"> </p>
<h4 data-ke-size="size20">실습2 - 관리 대상 서버에 uptime 정보를 debug 모듈로 확인하기</h4>
<p data-ke-size="size16">1. Ansible의 uptime 모듈이 있는지 확인해보니 존재하지 않아서 shell 모듈을 사용하기로 했다. cmd 파라미터를 사용하면 간단하게 명령어를 실행할 수 있다.</p>
<p><figure class="imageblock alignCenter" data-ke-mobileStyle="widthOrigin" data-origin-width="1225" data-origin-height="328"><span data-url="https://blog.kakaocdn.net/dn/d5GgmT/btsDnaLZmhj/BgoI3IQWqRFz9FWGUI79DK/img.png" data-lightbox="lightbox"><img src="https://blog.kakaocdn.net/dn/d5GgmT/btsDnaLZmhj/BgoI3IQWqRFz9FWGUI79DK/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5GgmT%2FbtsDnaLZmhj%2FBgoI3IQWqRFz9FWGUI79DK%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" width="707" height="189" data-origin-width="1225" data-origin-height="328"/></span></figure>
</p>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">2. uptime 명령이 대상 서버에서 잘 실행되는지 먼저 확인하기 위해 Playbook을 작성했다.</p>
<pre id="code_1705148678860" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>---
- hosts: all
tasks:
- name: get uptime
ansible.builtin.shell:
cmd: uptime</code></pre>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">3. 문법 오류 확인 후 Playbook을 실행한다. 아래의 실행 결과를 보면 Playbook 실행에 대한 결과가 표시되지만 uptime 명령의 실행 결과는 볼 수 없다.</p>
<pre id="code_1705148760012" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>$ ansible-playbook -i ./inventory --syntax-check uptime.yml
playbook: uptime.yml
$ ansible-playbook -i ./inventory uptime.yml
PLAY [all] ****************************************************************************
TASK [Gathering Facts] ****************************************************************
ok: [tnode1]
TASK [get uptime] *********************************************************************
changed: [tnode1]
PLAY RECAP ****************************************************************************
tnode1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0</code></pre>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">4. uptime 명령 실행 결과를 확인하기 위해 debug 모듈을 사용한다. Examples를 확인해보니 shell 모듈을 통해 실행한 명령의 결과를 register라는 파라미터를 사용하여 result 변수에 담고 있다. 그리고 debug 모듈에서는 이 변수를 var 파라미터에 지정하여 결과를 표시한다는 것을 알 수 있었다.</p>
<p><figure class="imageblock alignCenter" data-ke-mobileStyle="widthOrigin" data-origin-width="631" data-origin-height="218"><span data-url="https://blog.kakaocdn.net/dn/bWpUJv/btsDqhXpxt5/Tc6kK0LExJmJ1sYGG4SZ21/img.png" data-lightbox="lightbox"><img src="https://blog.kakaocdn.net/dn/bWpUJv/btsDqhXpxt5/Tc6kK0LExJmJ1sYGG4SZ21/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWpUJv%2FbtsDqhXpxt5%2FTc6kK0LExJmJ1sYGG4SZ21%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" width="564" height="195" data-origin-width="631" data-origin-height="218"/></span></figure>
</p>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">5. 조금 더 자세한 내용을 보기 위해 debug 모듈의 파라미터를 살펴보니 var 파라미터에는 변수를 사용할 수 있고, 이미 Jinja2의 컨텍스트에서 실행되고 있기 때문에 {{ }}로 래핑할 필요가 없다는 것을 알 수 있었다.</p>
<p><figure class="imageblock alignCenter" data-ke-mobileStyle="widthOrigin" data-origin-width="1342" data-origin-height="498"><span data-url="https://blog.kakaocdn.net/dn/9b7BP/btsDqiaTCqi/qxn0okswYp9NS3j6TWds70/img.png" data-lightbox="lightbox"><img src="https://blog.kakaocdn.net/dn/9b7BP/btsDqiaTCqi/qxn0okswYp9NS3j6TWds70/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9b7BP%2FbtsDqiaTCqi%2Fqxn0okswYp9NS3j6TWds70%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" width="731" height="271" data-origin-width="1342" data-origin-height="498"/></span></figure>
</p>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">6. 새롭게 알게된 내용을 적용하여 Playbook을 갱신해본다.</p>
<pre id="code_1705149339528" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>---
- hosts: all
tasks:
- name: get uptime
ansible.builtin.shell:
cmd: uptime
register: result
- name: Print return information
ansible.builtin.debug:
var: result</code></pre>
<p data-ke-size="size16"> </p>
<p data-ke-size="size16">7. Playbook을 실행해보니 이전과 다르게 결과가 표시된다.</p>
<pre id="code_1705149323568" class="bash" data-ke-language="bash" data-ke-type="codeblock"><code>$ ansible-playbook -i ./inventory --syntax-check uptime.yml
playbook: uptime.yml
$ ansible-playbook -i ./inventory uptime.yml
PLAY [all] ****************************************************************************
TASK [Gathering Facts] ****************************************************************
ok: [tnode1]
TASK [get uptime] *********************************************************************
changed: [tnode1]
TASK [Print return information] *******************************************************
ok: [tnode1] => {
"result": {
"changed": true,
"cmd": "uptime",
"delta": "0:00:00.005270",
"end": "2024-01-13 21:34:23.242619",
"failed": false,
"msg": "",
"rc": 0,
"start": "2024-01-13 21:34:23.237349",
"stderr": "",
"stderr_lines": [],
"stdout": " 21:34:23 up 1 day, 2:03, 2 users, load average: 0.00, 0.00, 0.00",
"stdout_lines": [
" 21:34:23 up 1 day, 2:03, 2 users, load average: 0.00, 0.00, 0.00"
]
}
}
PLAY RECAP ****************************************************************************
tnode1 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0</code></pre>
<p data-ke-size="size16"> </p>
↧