웹사이트 검색

Ansible로 다단계 환경을 관리하는 방법


소개

Ansible은 다양한 환경에서 인프라와 애플리케이션을 설정하고 관리하는 데 사용되는 강력한 구성 관리 시스템입니다. Ansible은 읽기 쉬운 구문, 유연한 워크플로 및 강력한 도구를 제공하지만 배포 환경 및 기능에 따라 달라지는 많은 수의 호스트를 관리하기 어려울 수 있습니다.

이 가이드에서는 Ansible을 사용하여 다단계 배포 환경에서 작업하기 위한 몇 가지 전략에 대해 설명합니다. 일반적으로 여러 단계에 대한 요구 사항으로 인해 구성 요소의 수와 구성이 달라집니다. 예를 들어 개발 서버의 메모리 요구 사항은 스테이징 및 프로덕션의 메모리 요구 사항과 다를 수 있으며 이러한 요구 사항을 나타내는 변수의 우선 순위를 명시적으로 제어하는 것이 중요합니다. 이 기사에서는 이러한 차이점을 추상화할 수 있는 몇 가지 방법과 구성 재사용을 장려하기 위해 Ansible이 제공하는 몇 가지 구조에 대해 설명합니다.

Ansible로 다단계 환경을 관리하기 위한 불완전한 전략

Ansible 내에서 환경을 관리할 수 있는 여러 가지 방법이 있지만 Ansible 자체는 독선적인 솔루션을 제공하지 않습니다. 오히려 환경 관리에 사용할 수 있는 많은 구조를 제공하고 사용자가 선택할 수 있도록 합니다.

이 가이드에서 시연할 접근 방식은 Ansible 그룹 변수와 여러 인벤토리에 의존합니다. 그러나 고려해야 할 몇 가지 다른 전략이 있습니다. 아래에서 이러한 아이디어 중 일부와 복잡한 환경에서 구현할 때 문제가 발생할 수 있는 이유를 살펴보겠습니다.

Ansible의 권장 전략을 시작하려면 Ansible 그룹 및 다중 인벤토리 사용 섹션으로 건너뛰십시오.

그룹 변수에만 의존

언뜻 보면 그룹 변수가 Ansible이 요구하는 환경 간의 모든 분리를 제공하는 것처럼 보일 수 있습니다. 특정 서버를 개발 환경에 속하도록 지정할 수 있고 다른 서버는 스테이징 및 프로덕션 영역에 지정할 수 있습니다. Ansible을 사용하면 쉽게 그룹을 생성하고 그룹에 변수를 할당할 수 있습니다.

그러나 그룹 교차는 이 시스템에 심각한 문제를 야기합니다. 그룹은 종종 둘 이상의 차원을 분류하는 데 사용됩니다. 예를 들어:

  • 배포 환경(로컬, 개발, 스테이지, 프로덕션 등)
  • 호스트 기능(웹 서버, 데이터베이스 서버 등)
  • 데이터 센터 지역(NYC, SFO 등)

이러한 경우 호스트는 일반적으로 범주당 하나의 그룹에 속합니다. 예를 들어, 호스트는 NYC(데이터 센터 지역)의 스테이지(배포 환경)에 있는 웹 서버(기능적)일 수 있습니다.

동일한 변수가 호스트에 대해 둘 이상의 그룹에 의해 설정되는 경우 Ansible은 우선 순위를 명시적으로 지정할 방법이 없습니다. 다른 값을 재정의하기 위해 배포 환경과 관련된 변수를 선호할 수 있지만 Ansible은 이를 정의하는 방법을 제공하지 않습니다.

대신 Ansible은 마지막으로 로드된 값을 사용합니다. Ansible은 그룹을 알파벳순으로 평가하므로 사전 순서에서 마지막에 있는 그룹 이름과 관련된 변수가 우선합니다. 이는 예측 가능한 동작이지만 명시적으로 그룹 이름 알파벳순을 관리하는 것은 관리 관점에서 이상적이지 않습니다.

그룹 하위 항목을 사용하여 계층 구조 설정

Ansible을 사용하면 인벤토리에서 [groupname:children] 구문을 사용하여 그룹을 다른 그룹에 할당할 수 있습니다. 이렇게 하면 특정 그룹의 이름을 다른 그룹의 구성원으로 지정할 수 있습니다. 하위 그룹은 상위 그룹이 설정한 변수를 무시할 수 있습니다.

일반적으로 이것은 자연 분류에 사용됩니다. 예를 들어 dev, stage, prod 그룹을 포함하는 environments라는 그룹이 있을 수 있습니다. 이는 environment 그룹에서 변수를 설정하고 dev 그룹에서 변수를 재정의할 수 있음을 의미합니다. 마찬가지로 web, databaseloadbalancer 그룹을 포함하는 functions라는 상위 그룹을 가질 수 있습니다.

이 사용법은 하위 그룹이 상위 그룹만 재정의하기 때문에 그룹 교차 문제를 해결하지 못합니다. 하위 그룹은 상위 내에서 변수를 재정의할 수 있지만 위의 조직은 환경기능과 같은 그룹 범주 간의 관계를 설정하지 않았습니다. 두 범주 간의 변수 우선 순위는 아직 정의되지 않았습니다.

비자연적인 그룹 구성원을 설정하여 이 시스템을 악용하는 것이 가능합니다. 예를 들어 가장 높은 우선 순위에서 가장 낮은 우선 순위로 다음과 같은 우선 순위를 설정하려는 경우:

  • 개발 환경
  • 지역
  • 기능

다음과 같이 그룹 구성원을 할당할 수 있습니다.

. . .
[function:children]
web
database
loadbalancer
region

[region:children]
nyc
sfo
environments

[environments:children]
dev
stage
prod

region 그룹이 function 그룹의 하위이므로 지역 변수가 기능 변수를 재정의할 수 있도록 여기에서 계층 구조를 설정했습니다. 마찬가지로 environments 그룹에 설정된 변수는 다른 변수를 재정의할 수 있습니다. 즉, dev, nycweb 그룹에서 동일한 변수를 다른 값으로 설정하면 각 그룹에 속한 호스트가 이들은 dev의 변수를 사용합니다.

이것은 원하는 결과를 달성하고 또한 예측 가능합니다. 그러나 이는 직관적이지 않으며 실제 자식과 계층 구조를 설정하는 데 필요한 자식 사이의 구분을 혼란스럽게 합니다. Ansible은 구성이 명확하고 신규 사용자도 쉽게 따라할 수 있도록 설계되었습니다. 이러한 유형의 해결 방법은 해당 목표를 손상시킵니다.

명시적 로드 순서를 허용하는 Ansible 구성 사용

Ansible에는 vars_filesinclude_vars와 같이 명시적인 가변 로드 순서 지정을 허용하는 몇 가지 구조가 있습니다. 파일 내에서 정의된 순서대로 추가 변수를 명시적으로 로드하기 위해 Ansible 재생 내에서 사용할 수 있습니다. vars_files 지시문은 플레이 컨텍스트 내에서 유효하지만 include_vars 모듈은 작업에서 사용할 수 있습니다.

일반적인 아이디어는 group_vars에서 기본 식별 변수만 설정한 다음 이를 활용하여 원하는 나머지 변수와 함께 올바른 변수 파일을 로드하는 것입니다.

예를 들어 group_vars 파일 중 일부는 다음과 같습니다.

---
env: dev
---
env: stage
---
function: web
---
function: database

그러면 각 그룹에 중요한 변수를 정의하는 별도의 vars 파일이 생깁니다. 이들은 일반적으로 명확성을 위해 별도의 vars 디렉토리에 보관됩니다. group_vars 파일과 달리 include_vars를 처리할 때 파일에는 .yml 파일 확장자가 포함되어야 합니다.

vars 파일에서 server_memory_size 변수를 다른 값으로 설정해야 한다고 가정해 보겠습니다. 개발 서버는 프로덕션 서버보다 작을 수 있습니다. 또한 웹 서버와 데이터베이스 서버의 메모리 요구 사항이 다를 수 있습니다.

---
server_memory_size: 512mb
---
server_memory_size: 4gb
---
server_memory_size: 1gb
---
server_memory_size: 2gb

그런 다음 group_vars 파일에서 호스트에 할당된 값을 기반으로 올바른 vars 파일을 명시적으로 로드하는 플레이북을 만들 수 있습니다. 로드된 파일의 순서에 따라 마지막 값이 우선 순위로 결정됩니다.

vars_files를 사용하면 플레이 예는 다음과 같습니다.

---
- name: variable precedence test
  hosts: all
  vars_files:
    - "vars/{{ env }}.yml"
    - "vars/{{ function }}.yml"
  tasks:
    - debug: var=server_memory_size

기능 그룹이 마지막에 로드되기 때문에 server_memory_size 값은 var/web.ymlvar/database.yml 파일에서 가져옵니다.

  1. ansible-playbook -i inventory example_play.yml
Output
. . . TASK [debug] ******************************************************************* ok: [host1] => { "server_memory_size": "1gb" # value from vars/web.yml } ok: [host2] => { "server_memory_size": "1gb" # value from vars/web.yml } ok: [host3] => { "server_memory_size": "2gb" # value from vars/database.yml } ok: [host4] => { "server_memory_size": "2gb" # value from vars/database.yml } . . .

로드할 파일의 순서를 바꾸면 배포 환경 변수의 우선 순위를 높일 수 있습니다.

---
- name: variable precedence test
  hosts: all
  vars_files:
    - "vars/{{ function }}.yml"
    - "vars/{{ env }}.yml"
  tasks:
    - debug: var=server_memory_size

플레이북을 다시 실행하면 배포 환경 파일에서 적용되는 값이 표시됩니다.

  1. ansible-playbook -i inventory example_play.yml
Output
. . . TASK [debug] ******************************************************************* ok: [host1] => { "server_memory_size": "512mb" # value from vars/dev.yml } ok: [host2] => { "server_memory_size": "4gb" # value from vars/prod.yml } ok: [host3] => { "server_memory_size": "512mb" # value from vars/dev.yml } ok: [host4] => { "server_memory_size": "4gb" # value from vars/prod.yml } . . .

작업으로 작동하는 include_vars를 사용하는 동등한 플레이북은 다음과 같습니다.

---
- name: variable precedence test
  hosts: localhost
  tasks:
    - include_vars:
        file: "{{ item }}"
      with_items:
        - "vars/{{ function }}.yml"
        - "vars/{{ env }}.yml"
    - debug: var=server_memory_size

이것은 Ansible이 매우 유용할 수 있는 명시적 순서 지정을 허용하는 영역 중 하나입니다. 그러나 이전 예제와 마찬가지로 몇 가지 중요한 단점이 있습니다.

우선 vars_filesinclude_vars를 사용하려면 그룹에 밀접하게 연결된 변수를 다른 위치에 배치해야 합니다. group_vars 위치는 vars 디렉토리에 있는 실제 변수의 스텁이 됩니다. 이것은 다시 한 번 복잡성을 추가하고 명확성을 감소시킵니다. 사용자는 올바른 변수 파일을 호스트에 일치시켜야 합니다. 이는 group_vars를 사용할 때 Ansible이 자동으로 수행하는 작업입니다.

더 중요한 것은 이러한 기술에 의존하는 것이 필수가 된다는 것입니다. 모든 플레이북에는 올바른 순서로 올바른 변수 파일을 명시적으로 로드하는 섹션이 필요합니다. 이것이 없는 플레이북은 관련 변수를 사용할 수 없습니다. 또한 임시 작업에 대해 ansible 명령을 실행하는 것은 변수에 의존하는 모든 작업에 대해 거의 완전히 불가능합니다.

Ansible 권장 전략: 그룹 및 다중 인벤토리 사용

지금까지 다단계 환경을 관리하기 위한 몇 가지 전략을 살펴보고 이것이 완벽한 솔루션이 아닐 수 있는 이유에 대해 논의했습니다. 그러나 Ansible 프로젝트는 환경 전체에서 인프라를 가장 잘 추상화하는 방법에 대한 몇 가지 제안을 제공합니다.

권장되는 접근 방식은 각 운영 환경을 완전히 분리하여 다단계 환경에서 작업하는 것입니다. 단일 인벤토리 파일 내에서 모든 호스트를 유지 관리하는 대신 각 개별 환경에 대한 인벤토리가 유지 관리됩니다. 별도의 group_vars 디렉토리도 유지 관리됩니다.

기본 디렉토리 구조는 다음과 같습니다.

.
├── ansible.cfg
├── environments/         # Parent directory for our environment-specific directories
│   │
│   ├── dev/              # Contains all files specific to the dev environment
│   │   ├── group_vars/   # dev specific group_vars files
│   │   │   ├── all
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts         # Contains only the hosts in the dev environment
│   │
│   ├── prod/             # Contains all files specific to the prod environment
│   │   ├── group_vars/   # prod specific group_vars files
│   │   │   ├── all
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts         # Contains only the hosts in the prod environment
│   │
│   └── stage/            # Contains all files specific to the stage environment
│       ├── group_vars/   # stage specific group_vars files
│       │   ├── all
│       │   ├── db
│       │   └── web
│       └── hosts         # Contains only the hosts in the stage environment
│
├── playbook.yml
│
└── . . .

보시다시피 각 환경은 뚜렷하고 구획화되어 있습니다. 환경 디렉토리에는 인벤토리 파일(임의의 hosts 이름 지정)과 별도의 group_vars 디렉토리가 포함되어 있습니다.

디렉토리 트리에 명백한 중복이 있습니다. 각 개별 환경에 대한 webdb 파일이 있습니다. 이 경우 복제가 바람직합니다. 코드 또는 구성 변경과 마찬가지로 한 환경에서 먼저 변수를 수정하고 테스트 후 다음 환경으로 이동하여 변수 변경을 환경 전체에 롤아웃할 수 있습니다. group_vars 변수는 각 환경의 현재 기본값을 추적합니다.

한 가지 제한 사항은 환경 전체에서 기능별로 모든 호스트를 선택할 수 없다는 것입니다. 다행스럽게도 이것은 위의 변수 중복 문제와 같은 범주에 속합니다. 작업을 위해 모든 웹 서버를 선택하는 것이 때때로 유용하지만 거의 항상 환경 전체에서 한 번에 하나씩 변경 사항을 롤아웃하려고 합니다. 이렇게 하면 프로덕션 환경에 영향을 미치는 실수를 방지할 수 있습니다.

교차 환경 변수 설정

권장 설정에서 불가능한 한 가지는 환경 간 변수 공유입니다. 교차 환경 변수 공유를 구현할 수 있는 방법에는 여러 가지가 있습니다. 가장 간단한 방법 중 하나는 파일 대신 디렉토리를 사용하는 Ansible의 기능을 활용하는 것입니다. 각 group_vars 디렉토리 내의 all 파일을 all 디렉토리로 교체할 수 있습니다.

디렉토리 내에서 파일의 모든 환경 관련 변수를 다시 설정할 수 있습니다. 그런 다음 교차 환경 변수를 포함하는 파일 위치에 대한 심볼릭 링크를 만들 수 있습니다. 이 두 가지 모두 환경 내의 모든 호스트에 적용됩니다.

계층 구조 어딘가에 교차 환경 변수 파일을 생성하여 시작하십시오. 이 예에서는 environments 디렉터리에 배치합니다. 해당 파일에 모든 교차 환경 변수를 배치합니다.

  1. cd environments
  2. touch 000_cross_env_vars

다음으로 group_vars 디렉토리 중 하나로 이동하고 all 파일의 이름을 바꾸고 all 디렉토리를 만듭니다. 이름이 바뀐 파일을 새 디렉터리로 이동합니다.

  1. cd dev/group_vars
  2. mv all env_specific
  3. mkdir all
  4. mv env_specific all/

다음으로 교차 환경 변수 파일에 대한 심볼릭 링크를 만들 수 있습니다.

  1. cd all/
  2. ln -s ../../../000_cross_env_vars .

각 환경에 대해 위의 단계를 완료하면 디렉터리 구조가 다음과 같이 표시됩니다.

.
├── ansible.cfg
├── environments/
│   │
│   ├── 000_cross_env_vars
│   │
│   ├── dev/
│   │   ├── group_vars/
│   │   │   ├── all/
│       │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│   │   │   │   └── env_specific
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts
│   │
│   ├── prod/
│   │   ├── group_vars/
│   │   │   ├── all/
│   │   │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│   │   │   │   └── env_specific
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts
│   │
│   └── stage/
│       ├── group_vars/
│       │   ├── all/
│       │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│       │   │   └── env_specific
│       │   ├── db
│       │   └── web
│       └── hosts
│
├── playbook.yml
│
└── . . .

000_cross_env_vars 파일 내에 설정된 변수는 우선 순위가 낮은 각 환경에서 사용할 수 있습니다.

기본 환경 인벤토리 설정

ansible.cfg 파일에서 기본 인벤토리 파일을 설정할 수 있습니다. 이것은 몇 가지 이유로 좋은 생각입니다.

첫째, ansibleansible-playbook에 대한 명시적 인벤토리 플래그를 생략할 수 있습니다. 따라서 다음을 입력하는 대신:

  1. ansible -i environments/dev -m ping

다음을 입력하여 기본 인벤토리에 액세스할 수 있습니다.

  1. ansible -m ping

둘째, 기본 인벤토리를 설정하면 원치 않는 변경이 스테이징 또는 프로덕션 환경에 실수로 영향을 미치는 것을 방지할 수 있습니다. 기본적으로 개발 환경을 사용하면 가장 중요하지 않은 인프라가 변경 사항의 영향을 받습니다. 새로운 환경에 대한 변경 사항을 홍보하는 것은 -i 플래그가 필요한 명시적 작업입니다.

기본 인벤토리를 설정하려면 ansible.cfg 파일을 엽니다. 구성에 따라 프로젝트의 루트 디렉터리 또는 /etc/ansible/ansible.cfg에 있을 수 있습니다.

참고: 아래 예제는 프로젝트 디렉토리에서 ansible.cfg 파일을 편집하는 방법을 보여줍니다. 변경 사항에 /etc/ansibile/ansible.cfg 파일을 사용하는 경우 아래 편집 경로를 수정하십시오. /etc/ansible/ansible.cfg를 사용할 때 인벤토리가 /etc/ansible 디렉토리 외부에서 유지되는 경우 상대 경로 대신 절대 경로를 사용해야 합니다. 인벤토리 값을 설정할 때 경로.

  1. nano ansible.cfg

위에서 언급했듯이 개발 환경을 기본 인벤토리로 설정하는 것이 좋습니다. 포함된 호스트 파일 대신 전체 환경 디렉토리를 선택할 수 있는 방법에 주목하십시오.

[defaults]
inventory = ./environments/dev

이제 -i 옵션 없이 기본 인벤토리를 사용할 수 있습니다. 기본이 아닌 인벤토리는 우발적인 변경으로부터 보호하는 데 도움이 되는 -i를 사용해야 합니다.

결론

이 기사에서는 여러 환경에서 호스트를 관리하기 위해 Ansible이 제공하는 유연성을 살펴보았습니다. 이를 통해 사용자는 호스트가 여러 그룹의 구성원일 때 변수 우선 순위를 처리하기 위한 다양한 전략을 채택할 수 있지만 모호함과 공식적인 지침의 부족은 어려울 수 있습니다. 모든 기술과 마찬가지로 조직에 가장 적합한 기술은 사용 사례와 요구 사항의 복잡성에 따라 달라집니다. 필요에 맞는 전략을 찾는 가장 좋은 방법은 실험하는 것입니다. 아래 댓글에서 사용 사례와 접근 방식을 공유하세요.