Ansible์„ ์‚ฌ์šฉํ•˜์—ฌ Rails ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ์„œ๋ฒ„ ์„ค์ •

์–ผ๋งˆ ์ „๊นŒ์ง€๋งŒ ํ•ด๋„ ์ €๋Š” Rails ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด ์„œ๋ฒ„๋ฅผ ์ค€๋น„ํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ Ansible ํ”Œ๋ ˆ์ด๋ถ์„ ์ž‘์„ฑํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋†€๋ž๊ฒŒ๋„ ๊ฐ„๋‹จํ•œ ๋‹จ๊ณ„๋ณ„ ๋งค๋‰ด์–ผ์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์ฑ„ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ํ”Œ๋ ˆ์ด๋ถ์„ ๋ณต์‚ฌํ•˜๊ณ  ์‹ถ์ง€ ์•Š์•˜๊ณ , ๊ฒฐ๊ตญ ๋ฌธ์„œ๋ฅผ ์ฝ๊ณ  ๋ชจ๋“  ๊ฒƒ์„ ์ง์ ‘ ์ˆ˜์ง‘ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์ด ๊ธฐ์‚ฌ์˜ ๋„์›€์œผ๋กœ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด ํ”„๋กœ์„ธ์Šค์˜ ์†๋„๋ฅผ ๋†’์ด๋„๋ก ๋„์šธ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๋จผ์ € ์ดํ•ดํ•ด์•ผ ํ•  ์ ์€ ansible์ด SSH๋ฅผ ํ†ตํ•ด ์›๊ฒฉ ์„œ๋ฒ„์—์„œ ์‚ฌ์ „ ์ •์˜๋œ ์ž‘์—… ๋ชฉ๋ก์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ํŽธ๋ฆฌํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋งˆ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•˜๊ณ  ๋„์ปค, ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ๊ธฐํƒ€ ๊ธฐ๋Šฅ์„ ์ฆ‰์‹œ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹ค์šดํƒ€์ž„ ์—†์ด ๋ฐฐํฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ”Œ๋ ˆ์ด๋ถ์„ ์ž‘์„ฑํ•˜๋ ค๋ฉด ์ •ํ™•ํžˆ ๋ฌด์—‡์„ ํ•˜๊ณ  ์‹ถ์€์ง€, ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” GitHub์—์„œ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด์ง„ ํ”Œ๋ ˆ์ด๋ถ์ด๋‚˜ "๋ณต์‚ฌํ•˜๊ณ  ์‹คํ–‰ํ•˜๋ฉด ์ž‘๋™ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค."์™€ ๊ฐ™์€ ๊ธฐ์‚ฌ์— ๋งŒ์กฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋ฌด์—‡์ด ํ•„์š”ํ•œ๊ฐ€?

์ด๋ฏธ ๋งํ–ˆ๋“ฏ์ด ํ”Œ๋ ˆ์ด๋ถ์„ ์ž‘์„ฑํ•˜๋ ค๋ฉด ๋ฌด์—‡์„ ํ•˜๊ณ  ์‹ถ์€์ง€, ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์—‡์ด ํ•„์š”ํ•œ์ง€ ๊ฒฐ์ •ํ•ฉ์‹œ๋‹ค. Rails ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ nginx, postgresql(redis ๋“ฑ)๊ณผ ๊ฐ™์€ ์—ฌ๋Ÿฌ ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํŠน์ • ๋ฒ„์ „์˜ Ruby๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. rbenv(rvm, asdf...)๋ฅผ ํ†ตํ•ด ์„ค์น˜ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๊ฒƒ์„ ๋ฃจํŠธ ์‚ฌ์šฉ์ž๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ํ•ญ์ƒ ๋‚˜์œ ์ƒ๊ฐ์ด๋ฏ€๋กœ ๋ณ„๋„์˜ ์‚ฌ์šฉ์ž๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น ๊ถŒํ•œ์„ ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์„œ๋ฒ„์— ์—…๋กœ๋“œํ•˜๊ณ  nginx, postgres ๋“ฑ์— ๋Œ€ํ•œ ๊ตฌ์„ฑ์„ ๋ณต์‚ฌํ•˜๊ณ  ์ด๋Ÿฌํ•œ ๋ชจ๋“  ์„œ๋น„์Šค๋ฅผ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ ์ผ๋ จ์˜ ์ž‘์—…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ๋ฃจํŠธ๋กœ ๋กœ๊ทธ์ธ
  2. ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€ ์„ค์น˜
  3. ์ƒˆ ์‚ฌ์šฉ์ž ์ƒ์„ฑ, ๊ถŒํ•œ ๊ตฌ์„ฑ, SSH ํ‚ค
  4. ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€(nginx ๋“ฑ)๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  5. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์‚ฌ์šฉ์ž๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฆ‰์‹œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)
  6. ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋กœ ๋กœ๊ทธ์ธ
  7. rbenv์™€ Ruby ์„ค์น˜
  8. ๋ฒˆ๋“ค๋Ÿฌ ์„ค์น˜
  9. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ์—…๋กœ๋“œ
  10. ํ‘ธ๋งˆ ์„œ๋ฒ„ ์‹œ์ž‘

๋˜ํ•œ, ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„๋Š” capistrano๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ ์–ด๋„ ์ฆ‰์‹œ ์ฝ”๋“œ๋ฅผ ๋ฆด๋ฆฌ์Šค ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋ณต์‚ฌํ•˜๊ณ , ์„ฑ๊ณต์ ์ธ ๋ฐฐํฌ ์‹œ ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋กœ ๋ฆด๋ฆฌ์Šค๋ฅผ ์ „ํ™˜ํ•˜๊ณ , ๊ณต์œ  ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ ๊ตฌ์„ฑ์„ ๋ณต์‚ฌํ•˜๊ณ , puma๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ์ž‘์—…์€ Ansible์„ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ์š”?

ํŒŒ์ผ ๊ตฌ์กฐ

Ansible์€ ์—„๊ฒฉํ•˜๊ฒŒ ํŒŒ์ผ ๊ตฌ์กฐ ๋ชจ๋“  ํŒŒ์ผ์— ๋Œ€ํ•ด ๋ชจ๋“  ํŒŒ์ผ์„ ๋ณ„๋„์˜ ๋””๋ ‰ํ† ๋ฆฌ์— ๋ณด๊ด€ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค. ๋”์šฑ์ด, ๊ทธ๊ฒƒ์ด ๋ ˆ์ผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž์ฒด์— ์žˆ์„ ๊ฒƒ์ธ์ง€ ์•„๋‹ˆ๋ฉด ๋ณ„๋„๋กœ ์ ์šฉ๋  ๊ฒƒ์ธ์ง€๋Š” ๊ทธ๋‹ค์ง€ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ณ„๋„์˜ Git ์ €์žฅ์†Œ์— ํŒŒ์ผ์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ์ €๋Š” Rails ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ /config ๋””๋ ‰ํ† ๋ฆฌ์— ansible ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ชจ๋“  ๊ฒƒ์„ ํ•˜๋‚˜์˜ ์ €์žฅ์†Œ์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ํŽธ๋ฆฌํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ํ”Œ๋ ˆ์ด๋ถ

ํ”Œ๋ ˆ์ด๋ถ์€ ํŠน์ˆ˜ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ Ansible์ด ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…๊ณผ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๋Š” yml ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š” ์ฒซ ๋ฒˆ์งธ ํ”Œ๋ ˆ์ด๋ถ์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

---
- name: Simple playbook
  hosts: all

์—ฌ๊ธฐ์„œ๋Š” ๊ฐ„๋‹จํžˆ ํ”Œ๋ ˆ์ด๋ถ์˜ ์ด๋ฆ„์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งํ•ฉ๋‹ˆ๋‹ค. Simple Playbook ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋‚ด์šฉ์€ ๋ชจ๋“  ํ˜ธ์ŠคํŠธ์— ๋Œ€ํ•ด ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. /ansible ๋””๋ ‰ํ† ๋ฆฌ์— ์ด๋ฆ„์œผ๋กœ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. playbook.yml ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ์„ ์‹คํ–‰ํ•ด ๋ณด์„ธ์š”:

ansible-playbook ./playbook.yml

PLAY [Simple Playbook] ************************************************************************************************************************************
skipping: no hosts matched

Ansible์€ all ๋ชฉ๋ก๊ณผ ์ผ์น˜ํ•˜๋Š” ํ˜ธ์ŠคํŠธ๋ฅผ ๋ชจ๋ฅธ๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. ํŠน๋ณ„๋ชฉ๋ก์— ๊ธฐ์žฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์žฌ๊ณ  ํŒŒ์ผ.

๋™์ผํ•œ ansible ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

123.123.123.123

์ด๊ฒƒ์ด ๋ฐ”๋กœ ํ˜ธ์ŠคํŠธ(์ด์ƒ์ ์œผ๋กœ๋Š” ํ…Œ์ŠคํŠธ์šฉ VPS ํ˜ธ์ŠคํŠธ์ด๊ฑฐ๋‚˜ localhost๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Œ)๋ฅผ ์ง€์ •ํ•˜๊ณ  ์ด๋ฆ„์œผ๋กœ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. inventory.
์ธ๋ฒคํ† ๋ฆฌ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ ansible์„ ์‹คํ–‰ํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ansible-playbook ./playbook.yml -i inventory
PLAY [Simple Playbook] ************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************

PLAY RECAP ************************************************************************************************************************************

์ง€์ •๋œ ํ˜ธ์ŠคํŠธ์— ๋Œ€ํ•œ SSH ์•ก์„ธ์Šค ๊ถŒํ•œ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ansible์€ ์›๊ฒฉ ์‹œ์Šคํ…œ์— ์—ฐ๊ฒฐํ•˜๊ณ  ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค. (๊ธฐ๋ณธ TASK [์‚ฌ์‹ค ์ˆ˜์ง‘]) ๊ทธ ํ›„ ์‹คํ–‰์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ๋ณด๊ณ ์„œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค(PLAY RECAP).

๊ธฐ๋ณธ์ ์œผ๋กœ ์—ฐ๊ฒฐ์€ ์‹œ์Šคํ…œ์— ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ŠคํŠธ์— ์—†์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ํ”Œ๋ ˆ์ด๋ถ ํŒŒ์ผ์—์„œ remote_user ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์‚ฌ์šฉ์ž๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์›๊ฒฉ ์‹œ์Šคํ…œ์— ๋Œ€ํ•œ ์ •๋ณด๋Š” ์ข…์ข… ๋ถˆํ•„์š”ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

---
- name: Simple playbook
  hosts: all
  remote_user: root
  become: true
  gather_facts: no

ํ”Œ๋ ˆ์ด๋ถ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๊ณ  ์—ฐ๊ฒฐ์ด ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. (๋ฃจํŠธ ์‚ฌ์šฉ์ž๋ฅผ ์ง€์ •ํ•œ ๊ฒฝ์šฐ ์ƒ์Šน๋œ ๊ถŒํ•œ์„ ์–ป์œผ๋ ค๋ฉด be: true ์ง€์‹œ์–ด๋„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์„œ์— ๊ธฐ๋ก๋œ ๋Œ€๋กœ: become set to โ€˜trueโ€™/โ€™yesโ€™ to activate privilege escalation. ์ด์œ ๊ฐ€ ์™„์ „ํžˆ ๋ช…ํ™•ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ).

์•„๋งˆ๋„ ansible์ด Python ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์‚ฌ์‹ค๋กœ ์ธํ•ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ์ˆ˜๋™์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ansible_python_interpreter: /usr/bin/python3 

๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ Python์ด ์žˆ๋Š” ์œ„์น˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. whereis python.

์‹œ์Šคํ…œ ํŒจํ‚ค์ง€ ์„ค์น˜

Ansible์˜ ํ‘œ์ค€ ๋ฐฐํฌํŒ์—๋Š” ๋‹ค์–‘ํ•œ ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€ ์ž‘์—…์„ ์œ„ํ•œ ๋งŽ์€ ๋ชจ๋“ˆ์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์–ด๋–ค ์ด์œ ๋กœ๋“  bash ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด์ œ ์‹œ์Šคํ…œ์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๋ ค๋ฉด ์ด๋Ÿฌํ•œ ๋ชจ๋“ˆ ์ค‘ ํ•˜๋‚˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. VPS์— Ubuntu Linux๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์„ธ์š”. apt-get ะธ ๊ทธ๊ฒƒ์„ ์œ„ํ•œ ๋ชจ๋“ˆ. ๋‹ค๋ฅธ ์šด์˜ ์ฒด์ œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์ฒ˜์Œ์— ์šฐ๋ฆฌ๊ฐ€ ๋ฌด์—‡์„ ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€ ๋ฏธ๋ฆฌ ์•Œ์•„์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•œ ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์‹ญ์‹œ์˜ค.) ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ๋ฌธ์€ ์œ ์‚ฌํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์ž‘์—…์œผ๋กœ ํ”Œ๋ ˆ์ด๋ถ์„ ๋ณด์™„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

---
- name: Simple playbook
  hosts: all
  remote_user: root
  become: true
  gather_facts: no

  tasks:
    - name: Update system
      apt: update_cache=yes
    - name: Install system dependencies
      apt:
        name: git,nginx,redis,postgresql,postgresql-contrib
        state: present

์ž‘์—…์€ Ansible์ด ์›๊ฒฉ ์„œ๋ฒ„์—์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…๊ณผ ์ •ํ™•ํžˆ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์—์„œ ์‹คํ–‰์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž‘์—…์— ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํŠน์ • ๋ชจ๋“ˆ์˜ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ชจ๋“ˆ์ด ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ apt: update_cache=yes - apt ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ผ๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ๋ช…๋ น์€ ์กฐ๊ธˆ ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํŒจํ‚ค์ง€ ๋ชฉ๋ก์„ apt ๋ชจ๋“ˆ์— ์ „๋‹ฌํ•˜๊ณ  ํ•ด๋‹น ํŒจํ‚ค์ง€๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. state ๋˜์–ด์•ผํ•œ๋‹ค present, ์ฆ‰, ์ด๋Ÿฌํ•œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•œ๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. ๋น„์Šทํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ฐ„๋‹จํžˆ ๋ณ€๊ฒฝํ•˜์—ฌ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ์ง€์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. state. ๋ ˆ์ผ์ด postgresql๊ณผ ์ž‘๋™ํ•˜๋ ค๋ฉด ์ง€๊ธˆ ์„ค์น˜ ์ค‘์ธ postgresql-contrib ํŒจํ‚ค์ง€๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ์ด๋ฅผ ์•Œ๊ณ  ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Ansible ์ž์ฒด๋กœ๋Š” ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํ”Œ๋ ˆ์ด๋ถ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๊ณ  ํŒจํ‚ค์ง€๊ฐ€ ์„ค์น˜๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž์™€ ์ž‘์—…ํ•˜๊ธฐ ์œ„ํ•ด Ansible์—๋Š” user๋ผ๋Š” ๋ชจ๋“ˆ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž‘์—…์„ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. (๋งค๋ฒˆ ์ „์ฒด ๋‚ด์šฉ์„ ๋ณต์‚ฌํ•˜์ง€ ์•Š๋„๋ก ์ด๋ฏธ ์•Œ๋ ค์ง„ ํ”Œ๋ ˆ์ด๋ถ ๋ถ€๋ถ„์„ ๋Œ“๊ธ€ ๋’ค์— ์ˆจ๊ฒผ์Šต๋‹ˆ๋‹ค.)

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Add a new user
      user:
        name: my_user
        shell: /bin/bash
        password: "{{ 123qweasd | password_hash('sha512') }}"

์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด์— ๋Œ€ํ•œ schell๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ˜ธ์ŠคํŠธ๋งˆ๋‹ค ์‚ฌ์šฉ์ž ์ด๋ฆ„์ด ๋‹ฌ๋ผ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋ฆฌ๊ณ  ํ”Œ๋ ˆ์ด๋ถ์— ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ผ๋ฐ˜ ํ…์ŠคํŠธ๋กœ ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๋‚˜์œ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. ๋จผ์ € ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณ€์ˆ˜์— ์ž…๋ ฅํ•˜๊ณ , ๊ธฐ์‚ฌ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์—์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"

๋ณ€์ˆ˜๋Š” ์ด์ค‘ ์ค‘๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”Œ๋ ˆ์ด๋ถ์— ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

์ธ๋ฒคํ† ๋ฆฌ ํŒŒ์ผ์— ๋ณ€์ˆ˜ ๊ฐ’์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

123.123.123.123

[all:vars]
user=my_user
user_password=123qweasd

์ง€์‹œ์‚ฌํ•ญ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”. [all:vars] - ๋‹ค์Œ ํ…์ŠคํŠธ ๋ธ”๋ก์€ ๋ณ€์ˆ˜(vars)์ด๋ฉฐ ๋ชจ๋“  ํ˜ธ์ŠคํŠธ(all)์— ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

๋””์ž์ธ๋„ ํฅ๋ฏธ๋กญ๋„ค์š” "{{ user_password | password_hash('sha512') }}". ๋ฌธ์ œ๋Š” ansible์ด ๋‹ค์Œ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋ฅผ ์„ค์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. user_add ์ˆ˜๋™์œผ๋กœ ํ•˜๋ ค๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”. ๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์ €์žฅํ•˜๋ฏ€๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฏธ๋ฆฌ ํ•ด์‹œ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•˜๋ฉฐ, ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ด ๋ช…๋ น์ด ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์ž…๋‹ˆ๋‹ค.

sudo ๊ทธ๋ฃน์— ์‚ฌ์šฉ์ž๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ˆ„๊ตฌ๋„ ์šฐ๋ฆฌ๋ฅผ ์œ„ํ•ด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ทธ ์ „์— ๊ทธ๋Ÿฌํ•œ ๊ทธ๋ฃน์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Ensure a 'sudo' group
      group:
        name: sudo
        state: present
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"
        groups: "sudo"

๋ชจ๋“  ๊ฒƒ์ด ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. apt์™€ ๋งค์šฐ ์œ ์‚ฌํ•œ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ๋ฃน์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๊ทธ๋ฃน ๋ชจ๋“ˆ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ด ๊ทธ๋ฃน์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋“ฑ๋กํ•˜๋ฉด ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค(groups: "sudo").
๋น„๋ฐ€๋ฒˆํ˜ธ ์—†์ด ๋กœ๊ทธ์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ์ด ์‚ฌ์šฉ์ž์—๊ฒŒ SSH ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋„ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

---
- name: Simple playbook
  # ...
  tasks:
    # ...
    - name: Ensure a 'sudo' group
      group:
      name: sudo
        state: present
    - name: Add a new user
      user:
        name: "{{ user }}"
        shell: /bin/bash
        password: "{{ user_password | password_hash('sha512') }}"
        groups: "sudo"
    - name: Deploy SSH Key
      authorized_key:
        user: "{{ user }}"
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
        state: present

์ด ๊ฒฝ์šฐ ๋””์ž์ธ์ด ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค. "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" โ€” id_rsa.pub ํŒŒ์ผ์˜ ๋‚ด์šฉ(์ด๋ฆ„์€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ), ์ฆ‰ SSH ํ‚ค์˜ ๊ณต๊ฐœ ๋ถ€๋ถ„์„ ๋ณต์‚ฌํ•˜์—ฌ ์„œ๋ฒ„์˜ ์‚ฌ์šฉ์ž์— ๋Œ€ํ•ด ์ธ์ฆ๋œ ํ‚ค ๋ชฉ๋ก์— ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

์—ญํ• 

ํ™œ์šฉ์„ ์œ„ํ•œ ์„ธ ๊ฐ€์ง€ ์ž‘์—…์€ ๋ชจ๋‘ ํ•˜๋‚˜์˜ ์ž‘์—… ๊ทธ๋ฃน์œผ๋กœ ์‰ฝ๊ฒŒ ๋ถ„๋ฅ˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ๊ทธ๋ฃน์€ ๋„ˆ๋ฌด ์ปค์ง€์ง€ ์•Š๋„๋ก ๋ฉ”์ธ ํ”Œ๋ ˆ์ด๋ถ๊ณผ ๋ณ„๋„๋กœ ๋ณด๊ด€ํ•ด ๋‘๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด Ansible์€ ์—ญํ• .
๋งจ ์ฒ˜์Œ์— ํ‘œ์‹œ๋œ ํŒŒ์ผ ๊ตฌ์กฐ์— ๋”ฐ๋ฅด๋ฉด ์—ญํ• ์€ ๋ณ„๋„์˜ ์—ญํ•  ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ์—ญํ• ์—๋Š” ์ž‘์—…, ํŒŒ์ผ, ํ…œํ”Œ๋ฆฟ ๋“ฑ ๋””๋ ‰ํ„ฐ๋ฆฌ ๋‚ด์— ๋™์ผํ•œ ์ด๋ฆ„์„ ๊ฐ€์ง„ ๋ณ„๋„์˜ ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
ํŒŒ์ผ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ./ansible/roles/user/tasks/main.yml (main์€ ์—ญํ• ์ด ํ”Œ๋ ˆ์ด๋ถ์— ์—ฐ๊ฒฐ๋  ๋•Œ ๋กœ๋“œ๋˜๊ณ  ์‹คํ–‰๋  ๊ธฐ๋ณธ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์—ญํ•  ํŒŒ์ผ๋„ ์—ฌ๊ธฐ์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.) ์ด์ œ ์‚ฌ์šฉ์ž์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ์ž‘์—…์„ ์ด ํŒŒ์ผ๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# Create user and add him to groups
- name: Ensure a 'sudo' group
  group:
    name: sudo
    state: present

- name: Add a new user
  user:
    name: "{{ user }}"
    shell: /bin/bash
    password: "{{ user_password | password_hash('sha512') }}"
    groups: "sudo"

- name: Deploy SSH Key
  authorized_key:
    user: "{{ user }}"
    key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
    state: present

๊ธฐ๋ณธ ํ”Œ๋ ˆ์ด๋ถ์—์„œ ์‚ฌ์šฉ์ž ์—ญํ• ์„ ์‚ฌ์šฉํ•˜๋„๋ก ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

---
- name: Simple playbook
  hosts: all
  remote_user: root
  gather_facts: no

  tasks:
    - name: Update system
      apt: update_cache=yes
    - name: Install system dependencies
      apt:
        name: git,nginx,redis,postgresql,postgresql-contrib
        state: present

  roles:
    - user

๋˜ํ•œ ๋‹ค๋ฅธ ๋ชจ๋“  ์ž‘์—…๋ณด๋‹ค ๋จผ์ € ์‹œ์Šคํ…œ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋ธ”๋ก ์ด๋ฆ„์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. tasks ๊ทธ๊ฒƒ๋“ค์€ ๋‹ค์Œ์—์„œ ์ •์˜๋ฉ๋‹ˆ๋‹ค. pre_tasks.

nginx ์„ค์ •

Nginx๊ฐ€ ์ด๋ฏธ ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•˜๋ฉฐ ์ด๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ญํ• ์—์„œ ๋ฐ”๋กœ ํ•ด๋ณด์ž. ํŒŒ์ผ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

- ansible
  - roles
    - nginx
      - files
      - tasks
        - main.yml
      - templates

์ด์ œ ํŒŒ์ผ๊ณผ ํ…œํ”Œ๋ฆฟ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ฐจ์ด์ ์€ Ansible์ด ํŒŒ์ผ์„ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ์ง์ ‘ ๋ณต์‚ฌํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ…œํ”Œ๋ฆฟ์—๋Š” j2 ํ™•์žฅ์ž๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ ๋™์ผํ•œ ์ด์ค‘ ์ค‘๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€์ˆ˜ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

nginx๋ฅผ ํ™œ์„ฑํ™”ํ•˜์ž main.yml ํŒŒ์ผ. ์ด๋ฅผ ์œ„ํ•ด systemd ๋ชจ๋“ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” nginx๋ฅผ ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ(์ฆ‰, ์‹คํ–‰ํ•ด์•ผ ํ•จ) ์ฆ‰์‹œ ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค.
์ด์ œ ๊ตฌ์„ฑ ํŒŒ์ผ์„ ๋ณต์‚ฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

- name: Copy the nginx.conf
  copy:
    src: nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: yes

- name: Copy template my_app.conf
  template:
    src: my_app_conf.j2
    dest: /etc/nginx/sites-available/my_app.conf
    owner: root
    group: root
    mode: '0644'

๊ธฐ๋ณธ nginx ๊ตฌ์„ฑ ํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค(์„œ๋ฒ„์—์„œ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์ง์ ‘ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Œ). ๊ทธ๋ฆฌ๊ณ  sites_available ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์šฐ๋ฆฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ ๊ตฌ์„ฑ ํŒŒ์ผ๋„ ์žˆ์Šต๋‹ˆ๋‹ค(ํ•„์ˆ˜๋Š” ์•„๋‹ˆ์ง€๋งŒ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค). ์ฒซ ๋ฒˆ์งธ ๊ฒฝ์šฐ์—๋Š” ๋ณต์‚ฌ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ์„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค(ํŒŒ์ผ์€ ๋‹ค์Œ ์œ„์น˜์— ์žˆ์–ด์•ผ ํ•จ). /ansible/roles/nginx/files/nginx.conf). ๋‘ ๋ฒˆ์งธ์—์„œ๋Š” ๋ณ€์ˆ˜ ๊ฐ’์„ ๋Œ€์ฒดํ•˜์—ฌ ํ…œํ”Œ๋ฆฟ์„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ…œํ”Œ๋ฆฟ์€ ๋‹ค์Œ ์œ„์น˜์— ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. /ansible/roles/nginx/templates/my_app.j2). ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค:

upstream {{ app_name }} {
  server unix:{{ app_path }}/shared/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name {{ server_name }} {{ inventory_hostname }};
  root {{ app_path }}/current/public;

  try_files $uri/index.html $uri.html $uri @{{ app_name }};
  ....
}

์‚ฝ์ž…๋ฌผ์— ์ฃผ์˜ํ•˜์„ธ์š” {{ app_name }}, {{ app_path }}, {{ server_name }}, {{ inventory_hostname }} โ€” ์ด๋Š” Ansible์ด ๋ณต์‚ฌํ•˜๊ธฐ ์ „์— ํ…œํ”Œ๋ฆฟ์œผ๋กœ ๋Œ€์ฒดํ•  ๊ฐ’์„ ๊ฐ–๋Š” ๋ชจ๋“  ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์–‘ํ•œ ํ˜ธ์ŠคํŠธ ๊ทธ๋ฃน์— ๋Œ€ํ•ด ํ”Œ๋ ˆ์ด๋ถ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์žฌ๊ณ  ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[production]
123.123.123.123

[staging]
231.231.231.231

[all:vars]
user=my_user
user_password=123qweasd

[production:vars]
server_name=production
app_path=/home/www/my_app
app_name=my_app

[staging:vars]
server_name=staging
app_path=/home/www/my_stage
app_name=my_stage_app

์ด์ œ ํ”Œ๋ ˆ์ด๋ถ์„ ์‹œ์ž‘ํ•˜๋ฉด ๋‘ ํ˜ธ์ŠคํŠธ ๋ชจ๋‘์— ๋Œ€ํ•ด ์ง€์ •๋œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋™์‹œ์— ์Šคํ…Œ์ด์ง• ํ˜ธ์ŠคํŠธ์˜ ๊ฒฝ์šฐ ๋ณ€์ˆ˜๋Š” ์—ญํ•  ๋ฐ ํ”Œ๋ ˆ์ด๋ถ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ nginx ๊ตฌ์„ฑ์—์„œ๋„ ํ”„๋กœ๋•์…˜ ํ˜ธ์ŠคํŠธ์™€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. {{ inventory_hostname }} ์žฌ๊ณ  ํŒŒ์ผ์— ์ง€์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํŠน๋ณ„ํ•œ ansible ๋ณ€์ˆ˜ ํ”Œ๋ ˆ์ด๋ถ์ด ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ํ˜ธ์ŠคํŠธ๊ฐ€ ์—ฌ๊ธฐ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ ํ˜ธ์ŠคํŠธ์— ๋Œ€ํ•œ ์ธ๋ฒคํ† ๋ฆฌ ํŒŒ์ผ์„ ๊ฐ–๊ณ  ์‹ถ์ง€๋งŒ ํ•œ ๊ทธ๋ฃน์— ๋Œ€ํ•ด์„œ๋งŒ ์‹คํ–‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

ansible-playbook -i inventory ./playbook.yml -l "staging"

๋˜ ๋‹ค๋ฅธ ์˜ต์…˜์€ ์—ฌ๋Ÿฌ ๊ทธ๋ฃน์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ์ธ๋ฒคํ† ๋ฆฌ ํŒŒ์ผ์„ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ํ˜ธ์ŠคํŠธ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ธ ๊ฒฝ์šฐ ๋‘ ๊ฐ€์ง€ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

nginx ์„ค์ •์œผ๋กœ ๋Œ์•„๊ฐ€ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ํŒŒ์ผ์„ ๋ณต์‚ฌํ•œ ํ›„ sites_available์—์„œ my_app.conf๋กœ ์—ฐ๊ฒฐ๋˜๋Š” sitest_enabled์˜ ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  nginx๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์„ธ์š”.

... # old code in mail.yml

- name: Create symlink to sites-enabled
  file:
    src: /etc/nginx/sites-available/my_app.conf
    dest: /etc/nginx/sites-enabled/my_app.conf
    state: link

- name: restart nginx
  service:
    name: nginx
    state: restarted

์—ฌ๊ธฐ์—์„œ๋Š” ๋ชจ๋“  ๊ฒƒ์ด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ํ•œ ๋ฒˆ ์ƒ๋‹นํžˆ ํ‘œ์ค€์ ์ธ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ansible ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•œ ๊ฐ€์ง€ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋งค๋ฒˆ nginx๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ์˜๋ฏธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ "์ด๋ ‡๊ฒŒ ํ•˜์„ธ์š”"์™€ ๊ฐ™์€ ๋ช…๋ น์„ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ  ๊ตฌ๋ฌธ์€ "์ด๊ฒƒ์€ ์ด ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค"์™€ ๋น„์Šทํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ด๊ฒƒ์ด ๋ฐ”๋กœ Ansible์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฃน์ด ์ด๋ฏธ ์กด์žฌํ•˜๊ฑฐ๋‚˜ ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€๊ฐ€ ์ด๋ฏธ ์„ค์น˜๋œ ๊ฒฝ์šฐ ansible์€ ์ด๋ฅผ ํ™•์ธํ•˜๊ณ  ์ž‘์—…์„ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค. ๋˜ํ•œ ํŒŒ์ผ์ด ์ด๋ฏธ ์„œ๋ฒ„์— ์žˆ๋Š” ๊ฒƒ๊ณผ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๋ฉด ํŒŒ์ผ์ด ๋ณต์‚ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ํŒŒ์ผ์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ์—๋งŒ ์ด๋ฅผ ํ™œ์šฉํ•˜๊ณ  nginx๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๋“ฑ๋ก ์ง€์‹œ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

# Copy nginx configs and start it
- name: enable service nginx and start
  systemd:
    name: nginx
    state: started
    enabled: yes

- name: Copy the nginx.conf
  copy:
    src: nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: yes
  register: restart_nginx

- name: Copy template my_app.conf
  template:
    src: my_app_conf.j2
    dest: /etc/nginx/sites-available/my_app.conf
    owner: root
    group: root
    mode: '0644'
  register: restart_nginx

- name: Create symlink to sites-enabled
  file:
    src: /etc/nginx/sites-available/my_app.conf
    dest: /etc/nginx/sites-enabled/my_app.conf
    state: link

- name: restart nginx
  service:
    name: nginx
    state: restarted
  when: restart_nginx.changed

๊ตฌ์„ฑ ํŒŒ์ผ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ณต์‚ฌ๋ณธ์ด ๋งŒ๋“ค์–ด์ง€๊ณ  ๋ณ€์ˆ˜๊ฐ€ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค. restart_nginx. ๊ทธ๋ฆฌ๊ณ  ์ด ๋ณ€์ˆ˜๊ฐ€ ๋“ฑ๋ก๋œ ๊ฒฝ์šฐ์—๋งŒ ์„œ๋น„์Šค๊ฐ€ ๋‹ค์‹œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ฌผ๋ก  ๊ธฐ๋ณธ ํ”Œ๋ ˆ์ด๋ถ์— nginx ์—ญํ• ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํฌ์ŠคํŠธ๊ทธ๋ ˆSQL ์„ค์ •

nginx์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ systemd๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ postgresql์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž์ฒด์— ์•ก์„ธ์Šคํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์‚ฌ์šฉ์ž๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์—ญํ• ์„ ๋งŒ๋“ค์–ด๋ณด์ž /ansible/roles/postgresql/tasks/main.yml:

# Create user in postgresql
- name: enable postgresql and start
  systemd:
    name: postgresql
    state: started
    enabled: yes

- name: Create database user
  become_user: postgres
  postgresql_user:
    name: "{{ db_user }}"
    password: "{{ db_password }}"
    role_attr_flags: SUPERUSER

- name: Create database
  become_user: postgres
  postgresql_db:
    name: "{{ db_name }}"
    encoding: UTF-8
    owner: "{{ db_user }}"

์ธ๋ฒคํ† ๋ฆฌ์— ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์„ค๋ช…ํ•˜์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์€ postgresql_db ๋ฐ postgresql_user ๋ชจ๋“ˆ์˜ ๊ตฌ๋ฌธ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด๋ฏธ ์—ฌ๋Ÿฌ ๋ฒˆ ์ˆ˜ํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์„ค๋ช…์„œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๊ฐ€์žฅ ํฅ๋ฏธ๋กœ์šด ์ง€์‹œ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. become_user: postgres. ์‚ฌ์‹ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ postgres ์‚ฌ์šฉ์ž๋งŒ์ด postgresql ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋กœ์ปฌ๋กœ๋งŒ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋ฌผ๋ก  ์•ก์„ธ์Šค ๊ถŒํ•œ์ด ์žˆ๋Š” ๊ฒฝ์šฐ).
๋˜ํ•œ ์ƒˆ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋„๋ก pg_hba.conf์— ํ–‰์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” nginx ๊ตฌ์„ฑ์„ ๋ณ€๊ฒฝํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  ๊ธฐ๋ณธ ํ”Œ๋ ˆ์ด๋ถ์— postgresql ์—ญํ• ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

rbenv๋ฅผ ํ†ตํ•ด Ruby ์„ค์น˜

Ansible์—๋Š” rbenv ์ž‘์—…์„ ์œ„ํ•œ ๋ชจ๋“ˆ์ด ์—†์ง€๋งŒ git ์ €์žฅ์†Œ๋ฅผ ๋ณต์ œํ•˜์—ฌ ์„ค์น˜๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ด ๋ฌธ์ œ๋Š” ๊ฐ€์žฅ ๋น„ํ‘œ์ค€์ ์ธ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค. ๊ทธ๋…€๋ฅผ ์œ„ํ•œ ์—ญํ• ์„ ๋งŒ๋“ค์–ด ๋ด…์‹œ๋‹ค /ansible/roles/ruby_rbenv/main.yml ์ž‘์„ฑ์„ ์‹œ์ž‘ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

# Install rbenv and ruby
- name: Install rbenv
  become_user: "{{ user }}"
  git: repo=https://github.com/rbenv/rbenv.git dest=~/.rbenv

์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๋ชฉ์ ์œผ๋กœ ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž ์•„๋ž˜์—์„œ ์ž‘์—…ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์‹œ make_user ์ง€์‹œ์–ด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. rbenv๋Š” ์ „์—ญ์ด ์•„๋‹Œ ํ™ˆ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์„ค์น˜๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ git ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ repo ๋ฐ dest๋ฅผ ์ง€์ •ํ•˜์—ฌ ์ €์žฅ์†Œ๋ฅผ ๋ณต์ œํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ, bashrc์— rbenv init๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ๊ทธ๊ณณ์˜ PATH์— rbenv๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด lineinfile ๋ชจ๋“ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

- name: Add rbenv to PATH
  become_user: "{{ user }}"
  lineinfile:
    path: ~/.bashrc
    state: present
    line: 'export PATH="${HOME}/.rbenv/bin:${PATH}"'

- name: Add rbenv init to bashrc
  become_user: "{{ user }}"
  lineinfile:
    path: ~/.bashrc
    state: present
    line: 'eval "$(rbenv init -)"'

๊ทธ๋Ÿฐ ๋‹ค์Œ ruby_build๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

- name: Install ruby-build
  become_user: "{{ user }}"
  git: repo=https://github.com/rbenv/ruby-build.git dest=~/.rbenv/plugins/ruby-build

๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ Ruby๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” rbenv, ์ฆ‰ bash ๋ช…๋ น์„ ํ†ตํ•ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

- name: Install ruby
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    rbenv install {{ ruby_version }}
  args:
    executable: /bin/bash

์šฐ๋ฆฌ๋Š” ์–ด๋–ค ๋ช…๋ น์„ ๋ฌด์—‡์œผ๋กœ ์‹คํ–‰ํ• ์ง€ ๋งํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” ansible์ด ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— bashrc์— ํฌํ•จ๋œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” rbenv๊ฐ€ ๋™์ผํ•œ ์Šคํฌ๋ฆฝํŠธ์—์„œ ์ง์ ‘ ์ •์˜๋˜์–ด์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ฌธ์ œ๋Š” ์‰˜ ๋ช…๋ น์ด Ansible ๊ด€์ ์—์„œ ๋ณผ ๋•Œ ์ƒํƒœ๊ฐ€ ์—†๋‹ค๋Š” ์‚ฌ์‹ค ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ์ด ๋ฒ„์ „์˜ Ruby๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ž๋™์œผ๋กœ ํ™•์ธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ ์Šค์Šค๋กœ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

- name: Install ruby
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    if ! rbenv versions | grep -q {{ ruby_version }}
      then rbenv install {{ ruby_version }} && rbenv global {{ ruby_version }}
    fi
  args:
    executable: /bin/bash

๋‚จ์€ ๊ฒƒ์€ ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ์„ค์น˜ํ•˜๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค:

- name: Install bundler
  become_user: "{{ user }}"
  shell: |
    export PATH="${HOME}/.rbenv/bin:${PATH}"
    eval "$(rbenv init -)"
    gem install bundler

๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ, ๊ธฐ๋ณธ ํ”Œ๋ ˆ์ด๋ถ์— ruby_rbenv ์—ญํ• ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

๊ณต์œ  ํŒŒ์ผ.

์ผ๋ฐ˜์ ์œผ๋กœ ์—ฌ๊ธฐ์—์„œ ์„ค์ •์„ ์™„๋ฃŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์œผ๋กœ ๋‚จ์€ ๊ฒƒ์€ capistrano๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ฝ”๋“œ ์ž์ฒด๊ฐ€ ๋ณต์‚ฌ๋˜๊ณ  ํ•„์š”ํ•œ ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค(๋ชจ๋“  ๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑ๋œ ๊ฒฝ์šฐ). ๊ทธ๋Ÿฌ๋‚˜ capistrano์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ๊ตฌ์„ฑ ํŒŒ์ผ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. database.yml ๋˜๋Š” .env nginx์šฉ ํŒŒ์ผ ๋ฐ ํ…œํ”Œ๋ฆฟ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ ํ•˜๋‚˜์˜ ๋ฏธ๋ฌ˜ํ•จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ๋ณต์‚ฌํ•˜๊ธฐ ์ „์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

# Copy shared files for deploy
- name: Ensure shared dir
  become_user: "{{ user }}"
  file:
    path: "{{ app_path }}/shared/config"
    state: directory

์šฐ๋ฆฌ๋Š” ํ•˜๋‚˜์˜ ๋””๋ ‰ํ† ๋ฆฌ๋งŒ ์ง€์ •ํ•˜๊ณ  ansible์€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ƒ์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์•ค์„œ๋ธ” ๋ณผํŠธ

์šฐ๋ฆฌ๋Š” ๋ณ€์ˆ˜์— ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ๊ฐ™์€ ๋น„๋ฐ€ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ด๋ฏธ ์ ‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ƒ์„ฑํ•œ ๊ฒฝ์šฐ .env ์‹ ์ฒญ์„œ ํŒŒ์ผ๊ณผ database.yml ๊ทธ๋Ÿฌ๋ฉด ๊ทธ๋Ÿฌํ•œ ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ํ›จ์”ฌ ๋” ๋งŽ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฟ๋ณด๋Š” ๋ˆˆ์œผ๋กœ๋ถ€ํ„ฐ ์ˆจ๊ธฐ๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค ์•ค์„œ๋ธ” ๋ณผํŠธ.

๋ณ€์ˆ˜์— ๋Œ€ํ•œ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. /ansible/vars/all.yml (์—ฌ๊ธฐ์„œ ์ธ๋ฒคํ† ๋ฆฌ ํŒŒ์ผ(production.yml, stage.yml ๋“ฑ)์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‹ค์–‘ํ•œ ํ˜ธ์ŠคํŠธ ๊ทธ๋ฃน์— ๋Œ€ํ•ด ๋‹ค์–‘ํ•œ ํŒŒ์ผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)
์•”ํ˜ธํ™”ํ•ด์•ผ ํ•˜๋Š” ๋ชจ๋“  ๋ณ€์ˆ˜๋Š” ํ‘œ์ค€ yml ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ํŒŒ์ผ๋กœ ์ „์†ก๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

# System vars
user_password: 123qweasd
db_password: 123qweasd

# ENV vars
aws_access_key_id: xxxxx
aws_secret_access_key: xxxxxx
aws_bucket: bucket_name
rails_secret_key_base: very_secret_key_base

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ํŒŒ์ผ์„ ์•”ํ˜ธํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ansible-vault encrypt ./vars/all.yml

๋‹น์—ฐํžˆ ์•”ํ˜ธํ™”ํ•  ๋•Œ ๋ณตํ˜ธํ™”๋ฅผ ์œ„ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ช…๋ น์„ ํ˜ธ์ถœํ•œ ํ›„ ํŒŒ์ผ ๋‚ด๋ถ€์— ๋ฌด์—‡์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

...์— ์˜ํ•˜์—ฌ ansible-vault decrypt ํŒŒ์ผ์˜ ์•”ํ˜ธ๋ฅผ ํ•ด๋…ํ•˜๊ณ  ์ˆ˜์ •ํ•œ ๋‹ค์Œ ๋‹ค์‹œ ์•”ํ˜ธํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž‘์—…ํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ์ผ์˜ ์•”ํ˜ธ๋ฅผ ํ•ด๋…ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์•”ํ˜ธํ™”ํ•˜์—ฌ ์ €์žฅํ•˜๊ณ  ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”Œ๋ ˆ์ด๋ถ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. --ask-vault-pass. Ansible์€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์š”์ฒญํ•˜๊ณ , ๋ณ€์ˆ˜๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ , ์ž‘์—…์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋Š” ์•”ํ˜ธํ™”๋œ ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ํ˜ธ์ŠคํŠธ ๊ทธ๋ฃน ๋ฐ Ansible Vault์— ๋Œ€ํ•œ ์ „์ฒด ๋ช…๋ น์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ansible-playbook -i inventory ./playbook.yml -l "staging" --ask-vault-pass

ํ•˜์ง€๋งŒ ํ”Œ๋ ˆ์ด๋ถ๊ณผ ์—ญํ• ์— ๋Œ€ํ•œ ์ „์ฒด ํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•˜์ง€๋Š” ์•Š๊ณ  ์ง์ ‘ ์ž‘์„ฑํ•ด ๋ณด์„ธ์š”. Ansible์€ ๊ทธ๋Ÿฐ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ์ž‘์—…์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋ฉด Ansible์ด ํ•ด๋‹น ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€