앤서블
고친 사람 github-actions[bot]
앤서블은 여러 서버에 같은 설정을 한 번에 입혀 주는 도구입니다. 서버마다 무엇이 깔려 있고 어떤 파일이 있어야 하는지를 파일에 적어 둡니다. 앤서블이 서버에 하나씩 접속해 그 모습대로 맞춥니다. 서버마다 늘 떠 있는 관리 프로그램을 두지 않고 원격 접속으로 일합니다. 서버 쪽에는 원격 접속과 Python 만 있으면 됩니다.
쉽고 빠른 이해
무슨 일을 하나 — 서버에 접속해 손으로 치던 설치·설정 명령을 파일 하나로 옮깁니다. 예를 들어 「웹 서버 열 대에 nginx 를 깔고 설정 파일을 넣어라」를 파일에 적고 명령 한 번으로 끝냅니다.
왜 쓰나 — 서버마다 손으로 맞추면 한두 대씩 빠뜨리거나 조금씩 다르게 맞춥니다. 누가 무엇을 바꿨는지도 남지 않습니다.
어떻게 도나
- 관리할 서버 목록과 할 일 목록을 각각 파일에 적습니다
- 내 컴퓨터에서 명령을 부르면 앤서블이 서버마다 원격 접속합니다
- 할 일마다 지금 모습을 보고, 적힌 모습과 다를 때만 고칩니다
대가 — 명령을 부를 때만 맞춥니다. 그 사이에 누가 손으로 고치면 다음 실행 때까지 모릅니다. 파일에서 할 일을 지워도 서버에 이미 깐 것은 남습니다.
언제 쓰나 — 이미 떠 있는 서버 여러 대를 같은 설정으로 맞출 때 씁니다. 서버를 고치지 않고 새 이미지로 갈아 끼우는 곳이나 컨테이너로 애플리케이션을 돌리는 곳에서는 맞출 것이 적어 덜 씁니다.
상세
앤서블(Ansible)은 Red Hat 이 관리하는 오픈 소스 설정 관리 도구입니다. 설정 관리는 서버를 미리 적어 둔 상태에 맞추는 일입니다. 무엇이 깔리고 어떤 설정 파일이 놓일지를 먼저 파일에 적습니다. 이렇게 인프라를 코드 파일로 적어 관리하는 방식을 코드형 인프라라고 합니다. 앤서블도 이 방식을 따릅니다. 앤서블 자신은 Python 으로 짠 명령줄 프로그램입니다. 내 컴퓨터나 배포 서버에 깔아 씁니다.
이 절은 웹 서버 두 대에 nginx 를 깔고 설정 파일을 넣는 작은 예를 따라갑니다. 그 과정에서 인벤토리, 모듈, 플레이북, 핸들러를 차례로 봅니다. 뒤쪽에서는 앤서블이 한 번 돌 때 무슨 일이 일어나는지와 앤서블이 맡지 않는 일을 봅니다.
손으로 맞추는 서버
서버를 새로 받으면 할 일이 정해져 있습니다. 패키지를 깔고, 설정 파일을 고치고, 서비스를 켭니다. 한 대라면 SSH(Secure Shell)로 접속해 명령 몇 줄을 치면 끝납니다. SSH 는 다른 컴퓨터에 암호화된 통로로 접속해 명령을 치는 방법입니다.
서버가 열 대로 늘면 같은 명령을 열 번 칩니다. 그중 한 대에서 한 줄을 빠뜨려도 알아채기 어렵습니다. 몇 달 뒤에는 서버마다 조금씩 다른 상태가 됩니다. 이렇게 같아야 할 서버가 서로 달라지는 일을 드리프트라고 합니다.
명령을 셸 스크립트로 묶어도 문제가 남습니다. 스크립트는 「이 명령을 쳐라」를 적습니다. 이미 깔린 서버에서 다시 돌리면 설치 명령이 또 돕니다. 설정 파일 끝에 같은 줄이 두 번 붙기도 합니다. 앤서블은 명령 대신 「이 패키지가 깔려 있어야 한다」 같은 결과를 적는 쪽을 택합니다.
에이전트 없는 구조
앤서블을 부르는 컴퓨터를 제어 노드라고 부릅니다. 설정을 받아 맞춰지는 쪽은 관리 대상 서버입니다. 제어 노드는 관리 대상 서버에 SSH 로 접속해 일을 시킵니다.
퍼펫이나 셰프 같은 다른 설정 관리 도구는 관리 대상 서버마다 에이전트를 깝니다. 에이전트는 서버에 늘 떠 있으면서 중앙 서버의 지시를 받아 수행하는 프로그램입니다. 앤서블은 에이전트를 두지 않습니다. 관리 대상 서버에 필요한 것은 SSH 접속과 Python 뿐입니다. 그래서 새 서버를 관리에 넣을 때 따로 깔 것이 거의 없습니다.
flowchart TD
subgraph 제어노드["제어 노드"]
I["인벤토리 · 서버 목록"]
P["플레이북 · 할 일 목록"]
A["ansible-playbook 명령"]
end
subgraph 웹["web 그룹"]
W1["web1"]
W2["web2"]
end
subgraph 디비["db 그룹"]
D1["db1"]
end
I --> A
P --> A
A -->|SSH| W1
A -->|SSH| W2
A -->|SSH| D1
그림의 인벤토리와 플레이북이 앤서블에 넘기는 파일 둘입니다. 다음 소절들에서 하나씩 봅니다.
ansible-playbook 은 이 두 파일을 받아 플레이북을 돌리는 명령입니다.
Windows 서버는 SSH 대신 WinRM(Windows Remote Management, 윈도우 원격 관리)으로 접속하기도 합니다.
인벤토리
인벤토리는 앤서블이 관리할 서버의 목록입니다. 서버를 그룹으로 묶어 적습니다. 아래는 가장 단순한 꼴인 INI(initialization, 초기화 설정) 형식의 인벤토리입니다. INI 는 대괄호로 구역을 나누고 그 아래에 값을 적는 글자 형식입니다.
[web]
web1.example.com
web2.example.com
[db]
db1.example.com
[web] 과 [db] 가 그룹 이름입니다. 뒤에서 할 일을 적을 때 「web 그룹에 하라」처럼 그룹 이름으로 대상을 고릅니다.
인벤토리는 YAML(YAML Ain't Markup Language)로도 적습니다. YAML 은 들여쓰기로 계층을 나타내는 설정 파일 형식입니다.
클라우드처럼 서버가 수시로 늘고 주는 곳에서는 클라우드에 서버 목록을 물어 인벤토리를 그때그때 만들기도 합니다. 이를 동적 인벤토리라고 합니다.
모듈
앤서블이 서버에서 하는 일 하나하나는 모듈이 맡습니다. 모듈은 한 가지 일을 하는 작은 프로그램입니다. 패키지를 까는 모듈, 파일을 복사하는 모듈, 서비스를 켜고 끄는 모듈이 따로 있습니다.
모듈에는 명령이 아니라 원하는 결과를 넘깁니다. 패키지 모듈에 「nginx 가 깔려 있어야 한다」를 넘기면 모듈은 먼저 nginx 가 이미 깔렸는지 봅니다. 깔려 있으면 아무것도 하지 않고, 없을 때만 깝니다.
그래서 같은 작업을 여러 번 돌려도 결과가 같습니다. 두 번째부터는 바뀌는 것이 없습니다. 몇 번을 해도 한 번 한 것과 같은 이 성질이 멱등성입니다. 앤서블의 기본 모듈은 대부분 멱등하게 만들어져 있습니다.
예외가 있습니다. 셸 명령을 그대로 넘기는 command 모듈과 shell 모듈은 명령을 매번 칩니다.
모듈이 그 명령이 무엇을 바꾸는지 모르기 때문입니다. 이 둘을 쓰면 멱등성은 작업을 쓰는 사람이 챙겨야 합니다.
플레이북
할 일을 적는 파일이 플레이북입니다. 인벤토리처럼 YAML 로 적습니다.
아래 플레이북은 web 그룹의 서버에 nginx 를 깔고 설정 파일을 넣은 뒤 nginx 를 켭니다.
notify 와 handlers 는 뒤의 「핸들러」 소절에서 풉니다.
- name: 웹 서버 준비
hosts: web
become: true
tasks:
- name: nginx 설치
ansible.builtin.apt:
name: nginx
state: present
- name: 설정 파일 넣기
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: nginx 재시작
- name: nginx 켜기
ansible.builtin.service:
name: nginx
state: started
handlers:
- name: nginx 재시작
ansible.builtin.service:
name: nginx
state: restarted
맨 바깥 덩어리 하나를 플레이라고 부릅니다. 플레이는 「어느 서버에」와 「무엇을」을 짝짓습니다.
hosts: web 이 대상 그룹입니다. become: true 는 관리자 권한으로 바꿔서 하라는 뜻입니다. 대개 sudo 를 거칩니다.
tasks 아래 항목 하나하나가 태스크입니다. 태스크 하나가 모듈 하나를 부릅니다.
ansible.builtin.apt 는 Debian 계열 Linux 의 패키지 관리자 apt 를 다루는 모듈입니다.
state: present 가 「깔려 있어야 한다」라는 결과입니다. 「깔아라」가 아닙니다.
태스크는 적힌 순서대로 돕니다.
템플릿과 변수
두 번째 태스크의 template 모듈은 파일을 복사하되 안의 빈칸을 채워서 넣습니다.
nginx.conf.j2 의 확장자 j2 는 Jinja2 를 뜻합니다. Jinja2 는 글자 파일 안에 {{ 변수 }} 꼴로 빈칸을 두는 템플릿 문법입니다.
worker_processes {{ nginx_workers }};
nginx_workers 값은 변수로 따로 줍니다. 인벤토리에서 그룹마다, 서버마다 다른 값을 줄 수 있습니다.
그러면 설정 파일 틀 하나로 서버마다 다른 값을 넣습니다.
앤서블은 작업을 시작하기 전에 서버의 운영체제, 메모리 크기, 주소 같은 정보를 모읍니다. 이 정보를 팩트라고 부릅니다. 팩트도 변수처럼 템플릿과 조건에 쓸 수 있습니다.
핸들러
nginx 는 설정 파일이 바뀌면 다시 시작해야 새 설정을 읽습니다. 설정이 그대로인데 재시작하면 쓸데없이 연결만 끊깁니다.
핸들러는 이 문제를 풉니다. 핸들러는 다른 태스크가 부를 때만 도는 태스크입니다.
앞 플레이북의 「설정 파일 넣기」 태스크에 붙은 notify: nginx 재시작 이 핸들러를 부르는 줄입니다.
이 부름은 그 태스크가 서버를 실제로 바꿨을 때만 나갑니다. 설정 파일이 이미 같으면 핸들러는 돌지 않습니다.
부름을 받은 핸들러는 플레이의 태스크가 다 끝난 뒤에 돕니다. 여러 태스크가 같은 핸들러를 불러도 한 번만 돕니다.
flowchart TD
T["설정 파일 넣기 태스크"] --> Q{"서버를 실제로 바꿨나"}
Q -->|아니다| N["부름 없음 · 재시작 안 함"]
Q -->|바꿨다| C["nginx 재시작 부름을 모아 둔다"]
C --> E["플레이의 태스크가 다 끝난다"]
E --> H["nginx 재시작 핸들러가 한 번 돈다"]
한 번의 실행
플레이북은 ansible-playbook 명령에 인벤토리와 플레이북 파일을 넘겨 돌립니다.
먼저 서버 한 대 안에서 태스크 하나가 어떻게 도는지 봅니다.
제어 노드는 태스크마다 그 태스크가 부르는 모듈 프로그램을 SSH 로 서버에 보냅니다. 모듈은 서버 안에서 Python 으로 돕니다. 그래서 관리 대상 서버에 Python 이 있어야 합니다. 모듈은 결과를 JSON(JavaScript Object Notation)으로 돌려줍니다. JSON 은 중괄호와 따옴표로 값을 적는 글자 형식입니다. 결과를 받으면 제어 노드는 보냈던 모듈 파일을 서버에서 지웁니다.
sequenceDiagram
participant 운영자
participant 제어노드 as 제어 노드
participant 서버 as 관리 대상 서버
운영자->>제어노드: ansible-playbook 실행
제어노드->>서버: SSH 접속
제어노드->>서버: 모듈 프로그램을 보낸다
서버->>서버: 모듈이 지금 상태를 보고 필요하면 고친다
서버-->>제어노드: 결과를 JSON 으로 돌려준다
제어노드->>서버: 보낸 모듈 파일을 지운다
제어노드-->>운영자: 서버별 결과 요약
태스크마다 결과는 셋 중 하나로 찍힙니다.
| 결과 | 뜻 |
|---|---|
ok |
이미 적힌 모습이라 아무것도 안 바꿨다 |
changed |
적힌 모습과 달라서 고쳤다 |
failed |
고치다 실패했다 |
실행이 끝나면 서버마다 이 셋을 센 요약이 나옵니다. 멱등한 플레이북이라면 두 번째 실행에서 changed 가 0 이어야 합니다.
두 번째에도 changed 가 나오는 태스크가 있으면 그 태스크가 멱등하지 않다는 신호입니다.
서버가 여러 대면 순서가 정해져 있습니다. 앤서블은 태스크 하나를 대상 서버 전부에 돌리고 나서 다음 태스크로 넘어갑니다. 한 서버에서 태스크가 실패하면 그 서버는 남은 태스크에서 빠집니다. 다른 서버는 계속 돕니다. 아래 그림은 web2 가 둘째 태스크에서 실패한 경우입니다.
flowchart TD
subgraph T1["태스크 1 · nginx 설치"]
A1["web1 · ok"]
B1["web2 · ok"]
end
subgraph T2["태스크 2 · 설정 파일 넣기"]
A2["web1 · changed"]
B2["web2 · failed"]
end
subgraph T3["태스크 3 · nginx 켜기"]
A3["web1 · ok"]
end
T1 --> T2
T2 -->|web2 는 빠진다| T3
앞서 성공한 태스크를 되돌리지는 않습니다. 원인을 고치고 다시 돌리면 이미 맞춰진 태스크는 ok 로 지나갑니다.
미리 보기
--check 를 붙이면 앤서블은 서버를 바꾸지 않고 무엇을 바꿀지만 알려 줍니다. --diff 를 함께 붙이면 파일이 어떻게 달라질지도 보여 줍니다.
운영 서버에 돌리기 전에 이 둘로 먼저 확인합니다.
다만 모든 모듈이 미리 보기를 지원하지는 않습니다. command 와 shell 모듈은 명령을 쳐 보지 않고는 결과를 모르므로 미리 보기에서 건너뜁니다.
롤
플레이북이 커지면 같은 태스크 묶음을 여러 플레이북에서 쓰게 됩니다. 롤은 태스크·핸들러·템플릿·변수를 정해진 폴더 구조로 묶은 단위입니다. 「nginx 롤」을 하나 만들어 두면 여러 플레이북이 그 롤을 불러 씁니다.
남이 만든 롤과 모듈은 Ansible Galaxy 에서 내려받습니다.
모듈과 롤을 한 꾸러미로 묶어 배포하는 단위를 컬렉션이라고 부릅니다.
앞 플레이북의 ansible.builtin.apt 에서 ansible.builtin 이 컬렉션 이름입니다.
비밀 값
설정에는 데이터베이스 비밀번호나 API(Application Programming Interface, 응용 프로그램 인터페이스) 키 같은 비밀 값이 들어갑니다. 플레이북은 Git 저장소에 넣어 두는 경우가 많아 비밀 값을 평문으로 둘 수 없습니다.
ansible-vault 는 변수 파일을 암호로 암호화합니다. 암호화한 파일은 저장소에 넣어도 내용이 안 보입니다.
플레이북을 돌릴 때 암호를 넘기면 앤서블이 그때 풀어서 씁니다.
앤서블이 맡지 않는 일
앤서블에는 상태 파일이 없습니다. 무엇을 만들었는지 따로 기억하지 않고 돌 때마다 서버를 직접 봅니다.
그래서 플레이북에서 태스크를 지워도 그 태스크가 깔았던 패키지는 서버에 남습니다.
없애려면 state: absent 처럼 「없어야 한다」를 적은 태스크를 따로 두어야 합니다.
앤서블은 부를 때만 돕니다. 늘 떠 있는 에이전트가 없으니 두 실행 사이에 누가 손으로 고친 것은 다음 실행 때에야 되돌아갑니다. 이런 방식을 밀어 넣기(push)라고 합니다. 에이전트가 주기적으로 중앙 서버에서 설정을 가져가 맞추는 방식은 끌어오기(pull)입니다.
서버 자체를 새로 띄우는 일을 프로비저닝이라고 합니다. 이 일은 주로 테라폼 같은 프로비저닝 도구가 맡습니다. 흔한 나눔은 테라폼이 서버를 띄우고 앤서블이 그 안을 채우는 꼴입니다. 앤서블에도 클라우드 자원을 만드는 모듈이 있습니다. 다만 테라폼처럼 만든 것을 기억해 두었다가 지워 주지는 않습니다.
서버 안을 채우는 다른 길도 있습니다. 머신 이미지는 패키지와 설정을 미리 넣어 둔 서버의 원본입니다. 이미지로 서버를 띄우면 서버마다 설정을 입힐 일이 줄어듭니다. 이미지를 만들 때 그 안을 채우는 데 앤서블을 쓰기도 합니다.
같은 일을 하는 다른 도구
설정 관리 도구는 에이전트를 두는지와 무엇으로 적는지로 갈립니다.
| 도구 | 에이전트 | 설정을 전하는 방식 | 무엇으로 적나 |
|---|---|---|---|
| 앤서블 | 없다 · SSH | 밀어 넣기 | YAML |
| 퍼펫 | 있다 | 끌어오기 | 퍼펫 전용 언어 |
| 셰프 | 있다 | 끌어오기 | Ruby |
| 솔트스택 | 있다 · 없이도 된다 | 둘 다 | YAML |
에이전트가 있으면 서버가 스스로 주기적으로 설정을 맞춥니다. 대신 서버마다 에이전트를 깔고 관리해야 합니다. 앤서블은 그 품이 없는 대신 맞추는 시점을 사람이나 CI/CD(Continuous Integration/Continuous Delivery, 지속적 통합·배포) 파이프라인이 정해야 합니다.
맞는 경우와 안 맞는 경우
앤서블은 이미 떠 있는 서버 여러 대를 같은 모습으로 맞출 때 쓸모가 큽니다. 에이전트를 깔 수 없거나 깔기 싫은 곳에서도 SSH 만 되면 씁니다. 네트워크 장비 설정에 쓰는 팀도 많습니다. 한 번 쓰고 버릴 셸 스크립트를 옮겨 적기도 어렵지 않습니다. 할 일을 순서대로 적는 꼴이 스크립트와 닮았기 때문입니다.
서버를 오래 두고 고쳐 쓰지 않는 곳에는 덜 맞습니다. 서버를 고치는 대신 새 이미지로 갈아 끼우는 불변 인프라에서는 서버 안을 맞출 일이 이미지를 만들 때 한 번뿐입니다. 컨테이너로 애플리케이션을 돌리는 곳도 비슷합니다. 설정이 컨테이너 이미지 안에 들어가므로 서버마다 맞출 것이 적습니다.
관련 항목
앤서블이 따르는 인프라 관리 방식
설정 관리 · 코드형 인프라 · 선언적 설정 · 멱등성 · 프로비저닝 · 불변 인프라 · GitOps
앤서블 설정을 이루는 구성 요소
인벤토리 (앤서블) · 플레이북 · 모듈 (앤서블) · 태스크 (앤서블) · 핸들러 (앤서블) · 롤 (앤서블) · 컬렉션 (앤서블) · 팩트 (앤서블)
앤서블이 기대는 기반 기술
SSH · WinRM · Python · YAML · Jinja2 · JSON · sudo
앤서블이 막으려는 장애
구성 드리프트 · 스노우플레이크 서버 · 설정 불일치 · 수작업 변경
앤서블과 같은 일을 두고 겨루는 도구
퍼펫 · 셰프 · 솔트스택 · CFEngine
앤서블과 일을 나누는 도구
테라폼 · Packer · 머신 이미지 · cloud-init · 컨테이너 · Kubernetes
앤서블을 돌리고 넓히는 도구
ansible-playbook · ansible-vault · Ansible Galaxy · AWX · CI/CD · Git
앤서블을 만든 회사와 맞추는 대상
다른 이름: Ansible · ansible