본문 바로가기

개인공부

[Linux / SSH / IoT] Ansible을 활용한 환경 구성 자동화

데이터의 다양성과 실제성을 확보하기 위해서

지난시간에 어렵게 설정했던 센서 환경을 새로운 보드 3개에 추가로 구현해야한다.

여간 귀찮은 일이 아니기 때문에  이번 시간에는 새로운 리눅스 환경에서

내가 원하는 환경 풀을 간편하게 자동으로 구축하는 방법을 사용해 보자.


Ansible이란?

여러 개의 서버 및 리눅스 기반 디바이스를 효율적으로 관리하기 위해 고안된 환경 구성 자동화 도구 (Infrastructure as a Code)

 

다양한 여러 리눅스 기반의 기기들의 각종 패키지 설치 및 설정 파일 수정, bash 쉘 스크립트 실행 등,

많은 기기에 동시에 동일한 환경을 일괄적으로 작업해야 하는 상황에 자주 사용된다.

 

쉽게 말해, ansible로 연결된 모든 리눅스 기기에 bash 명령어를 자동으로, 순차적으로, 동시에 실행시킬 수 있다. (가장 중요)

 

이 라이브러리를 이용하여 앞서 설정해두었던 모든 환경을, 새로운 디바이스에 손쉽게 (딸깍으로) 설정하는 것이 가능하다.

 

멱등성

을 지원하여, state: installed로 명시된 yum모듈을 실행할 때 해당 패키지가 이미 설치되어있다면 불필요한 재설치 없이 성공으로 처리된 뒤 종료된다.

 

처음에 이런 라이브러리가 있다는 이야기를 선배님께 듣고, 직접 사용해보려고 여기저기 찾아본 결과,

초보자가 이해하기 쉽게 (혹은 사용하기 쉽게) 적어놓은 글은 많이 없는 것 같아 조금의 난항을 겪었다.

따라서 여기에서는 나같은 초보자도 쉽게 따라할 수 있도록 최대한 직관적이고 순차적으로 설명해 보려고 한다.

 

* 아래 위키독스 글을 참고하여 작성하였다

https://wikidocs.net/book/6350

 


Ansible 기본 구성 및 개념

Ansible의 기본 구성 및 개념

 

1. 제어노드

  • 모든 기기의 환경 설정을 제어하는 메인 노드. Ansible은 이 노드 (장치)에만 설치하면 된다.
  • 필자는 윈도우 데스크탑(에 설치한 Ubuntu) 환경을 제어노드로 사용하였다.

2. 매니지드 노드

  • 관리(작업) 대상 노드. 지금 상황에서는 khadas와 라즈베리파이 장치를 말한다.
  • 제어노드와의 ssh연결 및 통신을 통해 원격으로 환경 구성을 당하는 주체
  • 이 노드들은 호스트라고 하며, 다음에 설명할 인벤토리를 통해 호스트를 그룹별로 관리한다.

3. 인벤토리

  • 제어노드와 연결되는 호스트의 엔트리 리스트. 그룹별로 나뉘어져 작성된다.
  • 예를 들어 khadas와 라즈베리파이 장치의 환경 구성을 다르게 하고 싶다면, 두 개의 그룹을 만들어 각각의 그룹명 아래에 엔트리를 기술한다.
  • 한 엔트리는 그룹명, 호스트명, ip주소, 포트번호, 유저명 등으로 구성된다.

4. 모듈

  • Ansible이 실행하는 bash 실행 명령어. apt, cp, mkdir 등이 해당된다.
  • 모듈에 파라미터를 달아서 실행 옵션을 선택할 수 있다.
  • 예를 들어, cp 모듈은 src 파라미터와 dest 파라미터를 받아서 src 파일을 dest에 복사하는 모듈이다.

5. 태스크 (작업)

  • 모듈의 모음집. 코딩으로 비유하자면 모듈은 인스트럭션(명령어) 한 줄이고, 태스크는 인스트럭션을 모은 메서드(함수)이다.
  • 모듈을 차례로 실행하면서 어떠한 의미있는 기능을 수행하는 단위이다.
  • ad-hoc 명령어로 태스크 하나를 실행 할 수 있다.

6. 플레이북

  • 여러 태스크를 원하는 순서대로 작성한 파일. 마찬가지로 코딩에 비유하자면 main함수라고 볼 수 있다.
  • 태스크를 순서대로 수행하며 환경을 설정하는 말 그대로 플레이 북의 역할을 수행한다. (요리 레시피 북이라 생각하면 편하다)
  • yaml 파일 형태로 작성된다.
  • 보통 이 플레이북을 호스트 그룹 단위로 실행하여, 동일한 환경을 자동으로 구성하는데 사용한다.

Ansible 설치 및 환경 설정

1. 제어노드에 ansible 설치

sudo apt install ansible

사진에서는 이미 설치되어 있기 때문에 설치된 내용이 없다.

2. 제어노드에서 ssh 키 생성

ssh-keygen -t rsa -b 4096

 

- 4096비트짜리 키 생성

- 키 생성시 비밀번호를 설정할 수 있고, 생성하지 않으려면 그냥 모든 내용 무시하고 엔터 세 번만 누르면 된다.

 

3. 호스트에 키 복사

ssh-copy-id [유저명]@[대상서버IP]

 

- 호스트(매니지드 노드)에 내가 설정한 ssh 키를 복사해서 준다. 이때, 호스트는 제어노드와 연결된 상태여야한다.

- 포트포워딩과 같이 포트번호가 필요한 경우 아래 명령어를 사용하여 포트번호를 지정할 수 있다.

ssh-copy-id -p [포트번호] [유저명]@[대상서버IP]

 

4. ssh 접속 확인

ssh (-p [포트번호]) [유저명]@[IP주소]

 

- 위 명령어를 실행했을때, ssh 키를 묻지 않고 접속이 된다면 성공.

- 확인 후 exit을 입력하여 원격 접속을 종료한다.

- 포트번호는 마찬가지로 필요한 경우 지정

접속 성공 확인

 

5. 인벤토리 생성 및 설정

 

- 인벤토리를 나타내는 설정파일은 hosts.ini파일이다.

-  hosts.ini는 상황에 따라 한 환경에서 여러 개가 존재 할 수 있다.

- 따라서 Ansible은 현재 태스크를 실행할 대상 인벤토리, 즉 hosts.ini를 찾는 정책이 아래와 같이 존재한다

  • 우선 ANSIBLE_INVENTORY 환경변수가 설정되어있는지 확인한다.
  • 다음으로 현재 경로에 ansible.cfg 파일이 있고, 그 안에 인벤토리 경로가 있는지 확인한다.
  • 다음으로 ~/ansible.cfg 경로에 파일이 있는지 확인한다.
  • 마지막으로 시스템 기본경로 ( /etc/ansible/hosts )에 hosts.ini가 있는지 확인한다.

- 위 우선순위에 따라 hosts.ini파일을 찾기 때문에, 그냥 냅다 hosts.ini만 만들어놓고 태스크를 실행할 수 없다.

- ansible-sensor 폴더를 하나 만들어 그 안에 hosts.ini 파일을 생성하도록 하자.

이런 식으로 작성

※이렇게 하면 위에서 말한 4가지 정책으로 지금 만든 ini파일을 찾을수 없는 것 아니냐? >> 맞다. 실제로 못 찾는다.

그래서 우리는 명령어를 실행할 때 -i 옵션과 사용할 hosts.ini 경로를 붙여줌으로써 알려주기로 한다.

hosts.ini

[그룹명]
호스트명1 ansible_host=IP주소  ansible_port=포트번호 ansible_user=유저명
호스트명2 ansible_host=IP주소  ansible_port=포트번호 ansible_user=유저명

 

-여기까지 제대로 따라왔다면, 아래 ping 명령어를 실행했을 때, 다음과 같은 결과가 출력된다.

cd ansible-sensor
ansible all -m ping -i ./hosts.ini

핑퐁이 되는 모습 (SUCCESS)

 

6. 플레이북 코드 작성 예제

 

- yaml 파일 형식으로 플레이북을 작성한다.

- 여기서는 지금까지 내가 한 khadas 환경 구성을 자동화하는 코드를 예제로 사용한다.

 

sensor-playbook.yml

---
- name: Khadas VIM4 센서 환경 풀 세팅 (기본 설정 + WiringPi)
  hosts: all # hosts.ini 파일에 정의된 모든 호스트에 적용
  become: true
  vars:
    # 한국 시간 설정
    target_timezone: "Asia/Seoul"
   
    # 기본 필수 패키지
    base_packages:
      - git
      - vim
      - curl
      - wget
      - net-tools   # ifconfig 등 네트워크 도구
      - htop        # 시스템 모니터링
      - build-essential # gcc, make 등 컴파일 도구 (필수)
      - python3-dev
      - python3-pip

    # WiringPi 소스 경로 (Khadas 공식)
    wiringpi_repo: "https://github.com/khadas/WiringPi"
    wiringpi_dest: "/home/{{ ansible_user }}/WiringPi"

  tasks:
    # -------------------------------------------------------
    # 1단계: 시스템 기본 설정
    # -------------------------------------------------------
    - name: 1. 패키지 캐시 업데이트 및 시스템 업그레이드
      apt:
        update_cache: yes
        upgrade: yes
      tags: system

    - name: 2. 타임존 설정 (Asia/Seoul)
      timezone:
        name: "{{ target_timezone }}"
      tags: system

    - name: 3. 필수 개발 도구 및 유틸리티 설치
      apt:
        name: "{{ base_packages }}"
        state: present
      tags: system

    # -------------------------------------------------------
    # 2단계: WiringPi 설치 및 빌드
    # -------------------------------------------------------
    - name: 4. Khadas WiringPi 깃허브 클론 (다운로드)
      git:
        repo: "{{ wiringpi_repo }}"
        dest: "{{ wiringpi_dest }}"
        version: master
        force: yes
      become: no  # 사용자 권한으로 다운로드 (빌드 편의성)
      tags: wiringpi

    - name: 5. WiringPi 빌드 스크립트 실행 (./build)
      shell: |
        ./build clean
        ./build
        ldconfig
      args:
        chdir: "{{ wiringpi_dest }}"
      become: yes # 설치 시 시스템 영역 건드림
      tags: wiringpi

    # -------------------------------------------------------
    # 3단계: 설치 확인
    # -------------------------------------------------------
    - name: 6. gpio 버전 확인 (설치 검증)
      command: gpio -v
      register: gpio_version
      changed_when: false
      tags: verify

    - name: 7. 결과 출력
      debug:
        msg:
          - "설치가 완료되었습니다!"
          - "GPIO 버전 정보: {{ gpio_version.stdout_lines[0] }}"

 

-  작성 완료 후, 아래 코드를 실행하면 다음과 같은 결과가 출력된다.

- 실행이 조금 오래 걸리더라도, 절대 강제종료 (ctrl + c)를 하지 않는 것을 추천한다. (필자 기준 약 1~2분 소요)

ansible-playbook -i hosts.ini sensor-playbook.yml --ask-become-pass

recap 출력됨


아래는 gpio 설정이 되어있지 않았던 khadas 기기(server1)에 ansible 실행 후 gpio readall 명령어를 실행 했을 때의 모습이다.

딸깍 한줄로 환경 구성 성공

 

이제 환경 구성을 자동화 하였으니, 다음 시간에는 총 4개의 기기에 센서를 모두 설치한 상태에서

AoI 기반 큐 관리 알고리즘을 고찰하는 것부터 시작해보겠다.