Skip to content

#90DaysOfDevOps - Tags, Variables, Inventory & Database Server config - Day 68

Tag, Variable, Inventory 및 Database 서버 구성

Tag

어제 세션에 playbook을 남겨두었으므로 모든 작업을 실행하고 해당 playbook 내에서 play해야 합니다. 즉, 웹서버와 로드밸런서 play 및 작업을 모두 실행해야 완료할 수 있습니다.

하지만 Tag를 사용하면 원하는 경우 이러한 작업을 분리할 수 있습니다. 이는 환경에 매우 크고 긴 playbook이 있는 경우 효율적인 방법이 될 수 있습니다.

이 경우 playbook 파일에서는 ansible-scenario5를 사용하고 있습니다.

- hosts: webservers
  become: yes
  vars:
    http_port: 8000
    https_port: 4443
    html_welcome_msg: "Hello 90DaysOfDevOps - Welcome to Day 66!"
  roles:
    - common
    - apache2
  tags: web

- hosts: proxy
  become: yes
  roles:
    - common
    - nginx
  tags: proxy

그런 다음 ansible-playbook playbook5.yml --list-tags를 사용하여 이를 확인할 수 있으며, list Tag는 우리가 playbook에서 정의한 Tag의 윤곽을 나타냅니다.

이제 프록시만 타깃팅하려면 ansible-playbook playbook5.yml --tags proxy를 실행하면 아래에서 볼 수 있듯이 프록시에 대해서만 playbook을 실행할 수 있습니다.

Tag는 작업 수준에서도 추가할 수 있으므로 원하는 위치와 작업을 세분화할 수 있습니다. 예를 들어 애플리케이션 중심 Tag가 될 수도 있고, 작업을 살펴보고 설치, 구성 또는 제거에 따라 작업에 Tag를 지정할 수도 있습니다. 사용할 수 있는 또 다른 매우 유용한 Tag는 다음과 같습니다.

tag: always 이것은 명령에 어떤 --tags를 사용하든 상관없이 항상 값으로 Tag가 지정된 항목이 있으면 ansible-playbook 명령을 실행할 때 항상 실행되도록 보장합니다.

Tag를 사용하여 여러 Tag를 함께 묶을 수도 있으며, ansible-playbook playbook5.yml --tags proxy,web을 실행하도록 선택하면 해당 Tag가 있는 모든 항목이 실행됩니다. 물론 이 예제에서는 playbook을 실행하는 것과 같은 의미이지만, 다른 play가 여러 개 있는 경우에는 이 방법이 의미가 있을 것입니다.

둘 이상의 Tag를 정의할 수도 있습니다.

Variable

Ansible에는 크게 두 가지 유형의 Variable이 있습니다.

  • User created
  • Ansible Facts

Ansible Facts

playbook을 실행할 때마다 "Gathering facts"라는 정의되지 않은 작업이 있었는데, 이러한 Variable 또는 fact를 사용하여 자동화 작업을 수행할 수 있습니다.

다음 ansible proxy -m setup 명령을 실행하면 JSON 형식의 많은 출력을 볼 수 있습니다. 이를 사용하려면 터미널에 많은 정보가 있어야 하므로 ansible proxy -m setup >> facts.json을 사용하여 파일로 출력하고 싶습니다. 여기에서 이 파일을 볼 수 있습니다.

이 파일을 열면 명령에 대한 모든 종류의 정보를 볼 수 있습니다. IP 주소, 아키텍처, 바이오스 버전을 확인할 수 있습니다. 이 정보를 활용하여 playbook에 사용하려는 경우 유용한 정보가 많이 있습니다.

한 가지 아이디어는 웹서버의 IP 주소를 하드코딩한 nginx template mysite.j2 내에서 이러한 Variable 중 하나를 잠재적으로 사용하는 것입니다. mysite.j2에 for 루프를 생성하면 [webservers] 그룹을 순환하여 2개 이상의 웹서버를 자동으로 동적으로 생성하거나 이 로드 밸런서 구성에 추가할 수 있습니다.

#Dynamic Config for server {{ ansible_facts['nodename'] }}
    upstream webservers {
  {% for host in groups['webservers'] %}
        server {{ hostvars[host]['ansible_facts']['nodename'] }}:8000;
    {% endfor %}
    }

    server {
        listen 80;

        location / {
                proxy_pass http://webservers;
        }
    }

위의 결과는 지금과 동일하게 보이지만 웹 서버를 더 추가하거나 제거하면 프록시 구성이 동적으로 변경됩니다. 이 기능을 사용하려면 이름 확인을 구성해야 합니다.

User created

User created Variable은 우리가 직접 만든 Variable입니다. playbook을 살펴보면 vars:가 있고 거기에 3개의 Variable 목록이 있는 것을 볼 수 있습니다.

- hosts: webservers
  become: yes
  vars:
    http_port: 8000
    https_port: 4443
    html_welcome_msg: "Hello 90DaysOfDevOps - Welcome to Day 68!"
  roles:
    - common
    - apache2
  tags: web

- hosts: proxy
  become: yes
  roles:
    - common
    - nginx
  tags: proxy

그러나 Variable을 해당 파일로 이동하여 playbook에 Variable이 없도록 할 수 있습니다. 이 작업을 수행하되, ansible-scenario6 폴더로 이동하겠습니다. 해당 폴더의 루트에 group_vars 폴더를 만들겠습니다. 그런 다음 all이라는 또 다른 폴더를 만듭니다(모든 그룹이 이 Variable을 가져옵니다). 이 폴더에 common_variables.yml이라는 파일을 만들고 playbook의 Variable을 이 파일에 복사합니다. Variable과 함께 playbook에서 Variable을 제거합니다.

http_port: 8000
https_port: 4443
html_welcome_msg: "Hello 90DaysOfDevOps - Welcome to Day 68!"

이 Variable을 전역 Variable로 연결하기 때문에 여기에 NTP 및 DNS 서버도 추가할 수 있습니다. Variable은 우리가 만든 폴더 구조에서 설정됩니다. 이제 playbook이 얼마나 깔끔해졌는지 아래에서 확인할 수 있습니다.

- hosts: webservers
  become: yes
  roles:
    - common
    - apache2
  tags: web

- hosts: proxy
  become: yes
  roles:
    - common
    - nginx
  tags: proxy

그 Variable 중 하나는 http_port로, 아래와 같이 mysite.j2 내의 for 루프에서 이 Variable을 다시 사용할 수 있습니다:

#Dynamic Config for server {{ ansible_facts['nodename'] }}
    upstream webservers {
  {% for host in groups['webservers'] %}
        server {{ hostvars[host]['ansible_facts']['nodename'] }}:{{ http_port }};
    {% endfor %}
    }

    server {
        listen 80;

        location / {
                proxy_pass http://webservers;
        }
    }

또한, 어떤 웹서버를 사용하고 있는지 파악할 수 있도록 roles/apache2/templates/index.HTML.j2 파일에 분석 가능한 사실을 정의할 수도 있습니다.

<html>

<h1>{{ html_welcome_msg }}! I'm webserver {{ ansible_facts['nodename'] }} </h1>

</html>

Variable을 변경하여 ansible-playbook playbook6.yml 명령을 실행한 결과, 로드밸런서에 도달하면 그룹에 있는 웹서버 중 하나에 도달한 것을 볼 수 있습니다.

또한 host_vars라는 폴더를 추가하고 web01.yml을 생성하여 원하는 경우 특정 메시지를 표시하거나 호스트별로 표시되는 내용을 변경할 수 있습니다.

Inventory 파일

지금까지 호스트를 결정하기 위해 /etc/ansible 폴더에 있는 기본 호스트 파일을 사용했습니다. 그러나 프로덕션 및 스테이징과 같이 환경마다 다른 파일을 사용할 수 있습니다. 더 많은 환경을 만들지는 않겠습니다. 하지만 호스트 파일은 만들 수 있습니다.

서버와 노드의 다양한 Inventory에 대해 여러 개의 파일을 만들 수 있습니다. 우리는 ansible-playbook -i dev playbook.yml을 사용하여 이를 호출합니다. 호스트 파일 내에 Variable을 정의한 다음 이를 출력하거나 playbook의 다른 곳에서 해당 Variable을 활용할 수도 있습니다. 예를 들어 아래 예제 및 교육 과정에서는 호스트 파일에서 생성된 환경 Variable을 로드밸런서 웹 페이지 template에 추가하여 웹 페이지 메시지의 일부로 환경을 표시했습니다.

Database 서버 배포

아직 전원을 켜고 구성하지 않은 머신이 하나 더 있습니다. vagrant 파일이 있는 곳에서 vagrant up db01을 사용하여 이 작업을 수행할 수 있습니다. 전원이 켜지고 액세스할 수 있게 되면 ssh-copy-id db01을 사용하여 SSH 키를 복사하여 액세스할 수 있도록 해야 합니다.

여기서는 ansible-scenario7 폴더에서 작업할 것입니다.

그런 다음 ansible-galaxy init roles/mysql을 사용하여 "MySQL"이라는 새 Role에 대한 새 폴더 구조를 만들어 보겠습니다.

playbook에서 Database 구성을 위한 새로운 play 블록을 추가하겠습니다. /etc/ansible/hosts 파일에 그룹 Database가 정의되어 있습니다. 그런 다음 Database 그룹에 공통 Role과 이전 단계에서 생성한 MySQL이라는 새 Role을 갖도록 지시합니다. 또한 Database 그룹에 Database Tag를 지정하고 있는데, 이는 앞서 설명한 것처럼 원하는 경우 이러한 Tag에 대해서만 실행하도록 선택할 수 있음을 의미합니다.

- hosts: webservers
  become: yes
  roles:
    - common
    - apache2
  tags:
    web

- hosts: proxy
  become: yes
  roles:
    - common
    - nginx
  tags:
    proxy

- hosts: database
  become: yes
  roles:
    - common
    - mysql
  tags: database

이제 Role 폴더 구조 내에서 트리가 자동으로 생성되었으므로 다음을 채워야 합니다:

Handlers - main.yml

# handlers file for roles/mysql
- name: restart mysql
  service:
    name: mysql
    state: restarted

Tasks - install_mysql.yml, main.yml & setup_mysql.yml

install_mysql.yml - 이 작업은 MySQL을 설치하고 서비스가 실행 중인지 확인하기 위해 수행됩니다.

- name: "Install Common packages"
  apt: name={{ item }} state=latest
  with_items:
   - python3-pip
   - mysql-client
   - python3-mysqldb
   - libmysqlclient-dev

- name: Ensure mysql-server is installed latest version
  apt: name=mysql-server state=latest

- name: Installing python module MySQL-python
  pip:
    name: PyMySQL

- name: Ensure mysql-server is running
  service:
    name: mysql
    state: started

main.yml은 이러한 파일에서 작업을 가져오도록 제안하는 포인터 파일입니다.

# tasks file for roles/mysql
- import_tasks: install_mysql.yml
- import_tasks: setup_mysql.yml

setup_mysql.yml - 이 작업은 Database와 Database 사용자를 생성합니다.

- name: Create my.cnf configuration file
  template: src=templates/my.cnf.j2 dest=/etc/mysql/conf.d/mysql.cnf
  notify: restart mysql

- name: Create database user with name 'devops' and password 'DevOps90' with all database privileges
  community.mysql.mysql_user:
    login_unix_socket: /var/run/mysqld/mysqld.sock
    login_user: "{{ mysql_user_name }}"
    login_password: "{{ mysql_user_password }}"
    name: "{{db_user}}"
    password: "{{db_pass}}"
    priv: '*.*:ALL'
    host: '%'
    state: present

- name: Create a new database with name '90daysofdevops'
  mysql_db:
    login_user: "{{ mysql_user_name }}"
    login_password: "{{ mysql_user_password }}"
    name: "{{ db_name }}"
    state: present

위에서 비밀번호, 사용자 이름 및 Database와 같은 일부 구성을 결정하기 위해 몇 가지 Variable을 사용하고 있음을 알 수 있으며, 이 Variable은 모두 group_vars/all/common_variables.yml 파일에 저장되어 있습니다.

http_port: 8000
https_port: 4443
html_welcome_msg: "Hello 90DaysOfDevOps - Welcome to Day 68!"

mysql_user_name: root
mysql_user_password: "vagrant"
db_user: devops
db_pass: DevOps90
db_name: 90DaysOfDevOps

또한 template 폴더에 아래와 같은 my.cnf.j2 파일이 있습니다:

[mysql]
bind-address = 0.0.0.0

playbook 실행

이제 VM이 실행 중이고 구성 파일이 준비되었으므로 이제 playbook을 실행할 준비가 되었습니다. 다음 ansible-playbook playbook7.yml을 실행하면 이전에 수행한 모든 작업이 포함된 playbook을 실행할 수 있고, ansible-playbook playbook7.yml --tags database 명령으로 Database 그룹에 배포하여 새 구성 파일만 실행하도록 선택할 수도 있습니다.

Database Tag에 대해서만 실행했지만, 오류가 발생했습니다. 이 오류는 pip3(파이썬)가 설치되어 있지 않다는 것을 알려줍니다. 이 오류는 일반 작업에 추가하여 해결할 수 있습니다.

위의 문제를 수정하고 playbook을 다시 실행했더니 성공적으로 변경되었습니다.

이제 새로 구성한 db01 서버에서 모든 것이 우리가 원하는 대로 작동하는지 확인해야 합니다. Control Node에서 ssh db01 명령을 사용하여 이 작업을 수행할 수 있습니다.

MySQL에 연결하기 위해 sudo /usr/bin/mysql -u root -p를 사용하고 프롬프트에서 root에 대한 vagrant 암호를 제공했습니다.

연결이 완료되면 먼저 DevOps라는 사용자가 생성되었는지 확인합니다. select user, host from mysql.user;

이제 SHOW DATABASES; 명령을 실행하여 생성된 새 Database를 확인할 수 있습니다.

루트를 사용하여 연결했지만 이제 sudo /usr/bin/MySQL -u devops -p를 사용하여 동일한 방법으로 DevOps 계정으로 로그인할 수도 있지만 여기서 암호는 DevOps90입니다.

제가 발견한 한 가지는 setup_mysql.ymllogin_unix_socket: /var/run/mysqld/mysqld.sock 줄을 추가해야 db01 MySQL 인스턴스에 성공적으로 연결할 수 있었고 이제 이 작업을 실행할 때마다 사용자를 만들 때 변경 사항을 보고하므로 어떤 제안이라도 대단히 감사하겠습니다.

자료

위에 나열된 마지막 재생 목록은 이 섹션의 많은 코드와 아이디어가 나온 곳이며, 동영상 형식의 훌륭한 리소스이자 워크스루입니다.

Day 69에서 봐요!