IaaS, Infrastructure as a Service
  • 클라우드를 통해 가상머신 환경을 온디맨드로 제공

IaC, Infrastructure as Code
  • 인프라스트럭쳐 상태를트소프트웨어가 자동으로 실행할 수 있는 코드 형태로 기술

  • 여기서 말하는 인프라는 "시스템을 가동하기 위해 전제가 되는 주변 환경 모두"를 가르킴

  • 엄밀하게는 서버와 네트워크 계층을 다루는 것을 IaC, 미들웨어와 애플리케이션 배포 등의 상위 계층을 다루는 것을 CaC(Configutation as Code)라고도 하지만 넓은 의미로 IaC의 한 요소로 간주

  • 작업에서의 노동 시간 감소화 효율화에 의한 비용 감소

  • 코드화에 의한 고도의 품질 보증

  • IaC를 실현할 도구:

    • 이전에는 shell script, shell의 조합

    • 현재는 구성 관리 도구 사용 - Chef, Puppet, Ansible

DevOps
  • "개발(Dev) 계층과 운용(Ops) 계층의 밀접한 연결에 의한 소프트웨어 라이프 사이클의 단기화화라는 축을 중심으로 한 방법과 기술 등의 구체적인 것에서부터 조직론에서 경영 철학에 이르는 추상적인 개념까지 다양한 문맥에서 사용되어 여러가지 의미가 추가됨

  • 데브옵스 맥락에서 생각하면, 제일 중요한 것은 CI(Continuous Integration)에 의한 연결이며, IaC로 인프라를 자동화함으로써 개발에서 테스트, 인프라 설치에 이르기까지 시스템 릴리즈에 필요한 전 과정을 자동화하고 똑똑하게 통합할 수 있음

Ansible?

  • 미국 레드헷사가 제공

  • 파이썬으로 개발

  • NASA(미국항공우주국)와 같은 대규모 조직에서도 도입

  • 앤서블이 내세운 모토: "모든 사람을 위한 자동화(Automation for Everyone)"

  • 앤서블이 지향하는 방향성: "누군가는 사용하기 쉽다"가 아닌 "누구나 사용하기 쉽다", 국소적인 생산성이 아닌 조직 전체의 생산성.

  • "fail-fast" 사상을 따라 자동으로 반환 코드를 확인하고 태스크가 실패하면 그 부분에서 플레이북을 정지

앤서블의 구성

  1. 본체

    앤서블 소프트웨어 그 자체로, 서버/클라이언트 구성과 같은 형태가 아니며 상주 프로세스를 둘 필요가 없다. 한 번 설치하면 필요할 때 명령을 실행하는 것으로 충분하다.

  2. 인벤터리(Inventory)

    앤서블이 작업할 대상 머신. "어디에서" 앤서블을 실행하는가?

    인벤터리는 앤서블에서 조작 대상이 되는 서버 접속 정보를 나타낸다. 인벤터리는 여러 개의 서버를 그룹화해 정의하거나 각각의 서버와 그룹에 대해 변수를 사용한 파라미터를 설정할 수 있다.

  3. 모듈(Module)

    앤서블에서 실행되는 개별 작업의 정의. "무엇을" 앤서블에서 실행하는가?

    앤서블에서 실행된 하나하나의 명령 같은 것. ansible-doc -l 명령어로 공식 모듈을 확인할 수 있다.

  4. 플레이북(Playbook)

    모듈 호출의 중심에 있는 앤서블 코드. "어떻게" 앤서블을 실행하는가?

    앤서블에서 스크립트(=코드)이며 앤서블을 사용할 때 필요한 작업은 플레이북의 구현과 실행이라고 할 수 있다. YAML로 작성한다.

앤서블의 특징

Ansible deployment architecture

Agentless

기존에 존재하던 구성 관리 도구인 Chef와 Puppet은 루비로 작성되었고, 작업 대상 머신에 전용 에이전트가 중앙 서버에 접근해 코드를 취득한 다음 에이전트가 스스로 해당 머신에 적합한 상태를 설정한다. 이렇게 중앙서버에서 설정을 가져오는 것을 pull type 아키텍처라고 한다.

이에 반해 앤서블에서 채용한 에이전트리스 모델은 push type 아키텍처로, 앤서블이 설치된 중앙 머신이 각 실행 대상에게 로그인해서 직접 명령을 실행한다.
네트워크 접속은 일반 SSH를 이용한다. 즉, 사람이 로그인할 때와 동일하게 실행 대상 서버에 로그인한다.

Idempotency

멱등성. "어떤 작업을 여러 번 실행해도 결과가 항상 같다다는 성질이다. 앤서블에 대해서는 각 모듈의 내부에서 무엇을 실행할 것인가를 "절차적"으로 다루는 것이 아니라, 최종 본래의 형태를 "선언적"으로 다뤄 멱등성이 보장되도록 하는 것이다. "파일 A를 배치한다"는 처리를 예로 멱등성의 유무에 따라 동작이 어떻게 달라지는지 보자.

멱등성을 고려하지 않은 경우

"파일 A를 어디에 복사한다"라는 절차 그 자체가 설정돼 있으며 작업 실행 전의 파일 설치 상황은 고려하지 않는다. 이미 파일이 있는 경우에도 다시 복사하거나, 작업 대상의 상태에 따라 필요 없는 처리가 실행되는 것처럼 기대하지 않은 결과가 발생할 우려가 있다.

멱등성이 보장된 경우

"파일 A가 어디에 존재한다"라는 최종적인 상태가 정의돼 있으며, 먼저 파일이 설치 상태를 확인한 다음 처리가 실행된다. 이미 같은 파일이 있으면 정의된 상태를 만족하므로 변경에 따른 처리를 실행하지 않는다. 설치돼 있지 않거나 다른 내용의 파일이 있는 경우에 대해서만 파일을 복사한다.

여기서 말하는 멱등성이란 작업 대상의 상태가 항상 같게 되는 것을 가리키는 것은 아니다. 예를 들어 "패키지를 최신 버전으로 유지"라고 정의한 경우에는 그 패키지의 최신 버전이 외부 요인에 의해 달라져, 실제 결과가 달라질 수 있다. 어디까지나 플레이북에 작성된 목적에 기분을 둘 때 결과가 일정하게 되는 점에 주의해야 한다.

Reusability

재사용성. "높은 재사용성" 즉, 범용성을 유지할 수 있으면 앤서블을 계속 사용함에 따라 구현 등에 따른 시간이 줄어들 것이다. 모듈 이외에도 플레이북 측에서도 재사용을 위한 구조로 Role이 있다.

앤서블 설정 파일

  • INI 형식의 설정 파일
    (위에 있을 수록 우선순위 높음)

    1. ANSIBLE_CONFIG 환경 변수에 지정한 파일

    2. 현재 디렉토리에 있는 ansible.cfg 파일

    3. 사용자 홈 디렉토리에 .ansible.cfg 파일

    4. /etc/ansible/ansible.cfg 파일(글로벌한 기본 설정)

Playbook

예) 플레이북 디렉토리 구조
./
├── hosts
└── site.yml
  • YAML 형식으로 쓰인 시스템 정의서 같은 것

  • name, hosts 와 같은 것을 directive 혹은 attribute 라고 함

site.yml
--- // (1)
- name: 플레이북 튜토리얼 // (2)
  hosts: all // (2)
  ...
  1. YAML 도큐먼트임을 선언하는 것

  2. 로그에 표시되는 이름

  3. 베포 대상 호스트 지정. all은 인벤토리로 정의된 모든 호스트를 대상으로 함

Note
site.yml

site.yml 이란 이름은 플레이북의 파일 이름을 관례로 사용한 것. 여러 개의 파일로 구성하는 경우 "거점"이 되는 파일이라는 정도의 의미가 아닐까 생각.

Playbook 실행

$ ansible-playbook -i hosts site.yml
PLAY [플레이북 튜토리얼] ********************

TASK [setup] *************************** // (1)
ok: [machine]

...
  1. task에 따로 지정하지 않아도 setup 태스트가 실행한 로그

  • 플레이북을 실행할 때 처음에 자동으로 setup 모듈이 실행됨

  • 각 호스트 정보를 수집. 수집된 정보를 Facts 라고 함

  • ansible all -i hosts -m setup 으로 확인 가능

자주 사용하는 모듈

  • file - 파일과 디렉터리의 상태 작업

  • copy - 파일을 작업 대상에게 전송

  • lineinfile - 기존 파일을 행 단위로 수정

  • command - 임의의 명령 실행

  • raw - 파이썬을 거치지 않는 명령을 저레벨로 실행

    • SSH를 통해서 명령어 실행

    • 가능하면 사용하지 않는 것이 좋음

      • 앤서블에 대응하는 파이썬을 설치하기 위해 사용

      • 네트워크 기기 등, 파이썬이 내장되지 않은 환경을 조작하기 위해 사용

Inventory

  • 정적 인벤토리 파일 또는 동적 인벤토리 스크립트 로 정의

    • 인벤토리 파일

      • INI 형식의 파일에 호스트 정보를 간단하게 기술

      • 작업 대상 호스트의 접속 정보를 미리 알고 있는 것을 전제로 함

    • 동적 인벤토리 스크립트

      • 호스트 정보를 JSON 형식의 표준 출력으로 표시할 스크립트

      • 앤서블 명령으로 실행할 때 실시간으로 스크립트가 실행

      • 스크립트 외부 시스템에 접근할 때, 동적으로 호스트 정보를 가져올 수 있음

정적 인벤토리 파일 작성 방법

[app] (1)
app1 ansible_host=some.app.host
app2 ansible_host=another.app.host

[db]
db1 ansible_host=db.1.host
db2 ansible_host=db.2.host

[app:vars] (2)
admin_username=app_user
admin_uid=1001
admin_has_data=False (3)

[db:vars]
admin_username=app_user
admin_uid=1002
admin_has_data=True

[korea] (4)
app1

[usa] (4)
app2
  1. [..] 으로 구분된 부분을 섹션이라 함(INI 형식에서 제목 역할)
    앤서블에서는 [<그룹 이름>] 형식으로 섹션을 지정해 호스트를 특정 그룹에 할당

  2. [<그룹 이름>:vars] 형식으로 그룹 변수 전용 섹션 사용 가능

  3. 부울값은 True 혹은 False 와 같이 대문자로 시작해야 함

  4. 호스트를 여러 그룹에 할당 가능

인벤토리 변수를 YAML 파일에 정의

  • 인벤토리 변수는 전용 YAML 파일에 정의 가능

  • 앤서블에서 정한 변수를 정의하는 파일 규칙

    • 호스트 변수를 정의하는 파일은 host_vars/<호스트 이름>.yml

    • 그룹 변수를 정의하는 파일은 group_vars/<그룹 이름>.yml

    • host_vars 디렉토리, group_vars 디렉토리는 인벤토리 파일 또는 플레이북 파일과 같은 디렉토리에 있어야 함

  • 인벤토리 변수 우선순위
    (우선순위 높음 → 낮음)

    1. 플레이북에 있는 변수를 정의한 YAML 파일

    2. 인벤토리에 있는 변수를 정의한 YAML 파일

    3. 인벤토리 파일에서 정의한 변수

예) 앤서블에서 정한 변수를 정의하는 파일 규칙
./
├── hosts
├── group_vars
│   ├── app.yml
│   └── db.yml
└── host_vars
    ├── app1.yml
    └── app2.yml
group_vars/app.yml
---
admin_username: app_user
admin_uid: 1001
admin_has_data: False
# admin_has_data: FALSE (1)
# admin_has_data: false
# admin_has_data: no
  1. yml에서는 여러가지 타입으로 사용 가능

group_vars/db.yml
---
admin_username: app_user
admin_uid: 1002
admin_has_data: True
# admin_has_data: TRUE
# admin_has_data: true
# admin_has_data: yes
host_vars/app1.yml
---
ansible_host: some.app.host

기본값을 정의하는 그룹 변수 파일

  • all이라는 이름은 "인텐토리 내의 모든 호스트가 할당된 특별한 그룹 이름"

  • 기본값을 설정할 때 용이

  • group_vars/all.yml 과 같이 사용 가능

  • 우선순위가 가장 낮게 설정
    all 그룹 변수 < 다른 그룹 변수 < 호스트 변수

Variable

  • 환경에 따라 값을 다르게 사용하는 데 사용

    • 사람이 정한 "보통 변수" 와 호스트가 상태에 따라 자동으로 값을 설정하는 "Facts" 로 구분

    • 코드를 변경하지 않고 다양한 환경에서 플레이북 사용 가능

      → 플레이북의 범용성 향상

  • 반복해서 나오는 값의 정의를 정리하는 데 사용

    • 파일 경로가 반복해서 나오는 경우 등에 유용

    • 입력할 때 실수하는 것을 방지하고 값을 바꿀 때도 한 곳만 변경

      → 플레이북의 유지 보수성 향상

변수 이름을 작성하는 규칙

  • 알파벳 대소문자, 숫자, 언더바 사용 가능

  • 숫자로 시작 불가

  • 변수 이름에 하이픈, 공백, 한글 사용 불가

  • 변수 이름은 앤서블에서 파이썬의 속성으로 처리되므로 파이썬 예약어(and, form, to)와 같은 것 사용 불가

변수를 정의하는 방법

변수를 정의하는 레이어를 크게 4개로 구분
  1. 모듈이 자동으로 정의(Facts)

  2. 인벤토리(그룹/호스트) 레벨에서 정의

  3. 앤서블이 실행될 때 정의

  4. 플레이북에서 정의

앤서블이 실행할 때 변수를 정의하는 옵션

  • --extra-vars(-e) 옵션 사

  • 띄어쓰기로 구별하는 key=value 형식

$ ansible-playbook -i hosts -e 'nginx_version=1.10.2 nginx_user=nginx' site.yml # (1)
$ ansible-playbook -i hosts -e '{"nginx_post": 8080}' site.yml # (2)
$ ansible-playbook -i hosts -e '@extra-vars.yml' site.yml # (3)
  1. --extra-vars(-e) 옵션 사용하며, 띄어쓰기로 구별하는 key=value 형식

  2. (1) 방식으로 사용하면 모두 string으로 다뤄야하므로, 숫자나 불리언 값 등을 다루려면 JSON 형식으로 정의

  3. @을 붙히면 YAML 형식으로 변수를 정의한 파일 읽기 가능

플레이북에서 변수를 정의

  • vars 지시자로 직접 정의

    vars:
      nginx_port: 8080
  • 외부 파일에서 변수 읽어 들이기

    vars_files:
      - some_vars.yml

변수의 우선순위

우선순위 높음 → 낮음

  1. 엑스트라 변수(명령을 실행할 때에 -e 로 전달한 것)

  2. 태스트 변수(지정한 태스크에서만 유효)

  3. 블록 변수(태스크를 모아 놓은 블록에서만 유효)

  4. 롤의 vars에서 변수를 정의한 파일 / include_vars 모듈로 읽은 변수를 정의한 파일

  5. 플레이의 vars_files 지시자로 읽은 변수를 정의한 파일

  6. 플레이의 vars_prompt 지시자로 입력한 변수*

  7. 플레이에서 vars로 정의한 변수

  8. set_fact로 정의한 값

  9. register로 정의한 값

  10. Host의 Fact정보(setup이 수집한 정보)

  11. 플레이북 디렉토리에서 host_vars의 호스트 변수를 정의한 파일

  12. 플레이북 디렉토리에서 group_vars의 그룹 변수를 정의한 파일

  13. 인벤토리 디렉토리에서 host_vars의 호스트 변수를 정의한 파일

  14. 인벤토리 디렉토리에서 group_vars의 그룹 변수를 정의한 파일

  15. 인벤토리 파일(Dynamic 포함)에서 정의한 변수

  16. 롤의 default에서 디폴트 변수로 정의한 파일

* 플레이북을 실행할 때에 프롬프트에서 변수의 설정값을 수동으로 입력하는 vars_prompt 지시자도 있으나, 프롬프트를 주로 사용하게 되면 플레이북을 자동으로 실행할 수 없게 되므로 이 지시자는 제한적으로 사용해야 함

Jinja2

  • 파이썬으로 작성된 템플릿 엔진

  • Flask(웹 어플리케이션 프레임워크)에서 HTML에 동적인 값을 설정할 때 사용되는 엔진

  • 앤서블에서 플레이북에 있는 변수 정보를 확장할 때 사용

debug-var.yml
---
- name: 변수의 동작을 확인
  hosts: localhost
  vars:
    my_var: kim
  task:
    - name: my_var 값을 디버깅으로 확인
      debug:
        msg: "변수 my_var 값은 {{ my_var }}이다"
$ ansible-playbook debug-var.yml
PLAY [변수의 동작을 확인] **********************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [my_var 값을 디버깅으로 확인] **************************************************
ok: [localhost] => {
  "msg": "변수 my_var 값은 kim이다"
}

PLAY RECAP *********************************************************************
localhost                      : ok=2   changed=0   unreachable=0   failed=0
  • 변수를 {{}} 로 묶으면 앤서블을 실행할 때 변수가 값으로 변경됨

  • YAML 문법상 제약에서 문자열의 앞, 뒷부분에 변수를 활용할 때에는 double-quote로 묶어야 함

  • 계층 구조로 된 데이터도 사용 가능

    admin_user:
      name: jun
      uid: 1001
    사용자 이름은 {{ admin_user.name }}의 UID는 {{ admin_user.uid }}입니다.
  • https://docs.ansible.com/ansible/2.4/playbooks_templating.html#templating-jinja2

Role

플레이북 내용을 기능 단위로 나누어 공통 부붐으로 관리/재사용하기 위한 구조

Reference