본문 바로가기

Automation/system

[자동화] AI 개발환경 구축기 #2-IaC Automation(Ansible)

머신러닝과 딥러닝, 그리 AI(인공지능)!!!

AI 서비스를 개발하기 위한 환경을 만들어본다.

최종 목표는 Kubeflow 기반의 AutoML 환경 구성이고, IaC(Infra as Code) 기반으로 Automation 하는것이 목적이다.

 

 

2편 "IaC Automation" Ansible 환경 구성

 

[Ansible System 요구사항]

  • Ansible Control Node (이하 Master) : Linux, Pyhton 2.6 이상
  • Ansible Members (이하 Woker) : Python 2.6이상
가. Ansible Master 설정

"AI 개발환경 구축기 #1편"의 내용을 수정해서 IaC를 위한 Ansible 환경을 구성한다.

 

1. Vagrantfile 수정 - Ansible Master 설정 추가

기존의 Vagrantfile을 수정하여 Ansible Master에 필요한 환경을 추가한다.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

    #ansible-server
    config.vm.define "ansible-master" do |master|
        master.vm.box = "ubuntu/bionic64"
        master.vm.provider "virtualbox" do |vb|
            vb.name = "ansible-master"
        end

        master.vm.host_name = "ansible-master"
        master.vm.network "public_network", ip: "192.168.1.11"
        master.vm.network:forwarded_port, host: 61122, guest: 22, auto_correct: true, id: "ssh"
        #master.vm.synced_folder "../shared_data", "/shared_data", disabled: true
        master.vm.provision:shell, inline: "apt-get install -y ansible"
        master.vm.provision:shell, inline: "apt-get install -y sshpass"
        master.vm.provision:shell, path: "bootstrap.sh"
        cfg.vm.provision:file, source: "setup-ansible-master.yml", destination: "setup-ansible-master.yml"
        cfg.vm.provision:shell, inline: "ansible-playbook setup-ansible-master.yml"
        cfg.vm.provision:file, source: "setup_ssh_ansible.yml", destination: "setup_ssh_ansible.yml"
        cfg.vm.provision:shell, inline: "ansible-playbook setup_ssh_ansible.yml", privileged: false
    end
end

[Vagrant 설정 추가]

  • cfg.vm.provision:file, source: "aaa", destination: "bbb" : 호스트 서버의 "aaa" 파일을 게스트 머신 "bbb" 파일로 복사
  • cfg.vm.provision:shell, inline: "ansible-playbook bbb.yml" : Ansible Playbook 실행

[Ansible Playbook 추가]

  • setup-ansible-master.yml : Ansible Master Server가 멤버(Worker)를 관리하기 위한 환경을 설정
  • setup-ssh-ansible.yml : Ansible Master Server에것 멤버(Worker)로 SSH Connection하기 위한 환경을 설정

Playbook 파일을 두개로 나눈 이유는 Ansible의 모든 멤버에 적용해야하는 설정내용과, Master에만 적용하면되는 설정을 구분해서 Ansible을 실행하기 위함이다.

 

[주의사항]

1. Ansible Master에서 각 Worker로 SSH 접속 시 별도의 암호를 입력하지않고 접속하기위해 Master의 Public Key를 Worker 들에 등록하더라도 Master에 sshpass를 설치하지 않으면 오류가 발생한다

 

2. bootstrap.sh를 통해 각 Node의 /etc/hosts 파일에 도메인과 IP를 등록했다. ansible 의 authorized_key 모듈 등 ssh 접속 시 /etc/ansible/hosts의 도메인명(또는 IP)과 /etc/hosts가 일치하지 않으면 오류가 발생한다. 나는 bootstrap.sh를 먼저 실행하지 않아 Master의 /etc/hosts에 Worker의 도메인이 등록되지 않은채로 authorized_key를 실행해서 오류가 발생했다. 실행 순서에도 주의가 필요하다.

 

2. Ansible Master 설정 Playbook(setup-ansible-master.yml) 작성

Ansible 실행을 위한 Python 경로와 구성 Inventory를 설정하기 위한 Playbook을 작성한다.

 

---
- name: Setup for the Ansible's Environment
  hosts: localhost
  gather_facts: no

  tasks:
    - name: Add "/etc/ansible/hosts"
      blockinfile:
        path: /etc/ansible/hosts
        block: |
          [webserver]
          192.168.1.12
          [all:vars]
          ansible_python_interpreter=/usr/bin/python3

[Playbook 설명]

  • --- : Playbook 시작
  • hosts: localhost -> 해당 Playbook이 실행되는 호스트(머신)만 적용
  • blockinfile : path 에 지정한 file에 내용을 추가 (실제 Master에서 관리할 Inventory를 작성하고, Python 경로를 설정하였음)

3. Ansible SSH Connection 환경 설정 Playbook(setup-ssh-ansible.yml) 작성

Ansible은 Agentless 기반ㅇ로 별도의 Agent를 설치할 필요가 없이 멤버들에 SSH 접속하려 명령을 Push하는 방식으로 자동화를 수행한다. 이를 위해 Master와 Worker간 SSH Connection 환경을 설정할 필요가 있다.

 

---
- name: Automate SSH connection from Ansible-Master to Workers
  hosts: all
  connection: local
  serial: 1
  gather_facts: no
  vars:
    ansible_password: vagrant
    ansible_python_interpreter: /usr/bin/python3

  tasks:
    - debug: var=ansible_host
    - name: SSH-KEY scanning from Ansible Inventory
      command: /usr/bin/ssh-keyscan -t ecdsa {{ ansible_host }}
      register: keyscan

    - name: Register ssh-key
      lineinfile:
        path: ~/.ssh/known_hosts
        line: "{{ item }}"
        create: yes
      with_items:
        - "{{ keyscan.stdout_lines }}"

    - name: Create authorized_keys
      command: "ssh-keygen -b 2048 -t rsa -f ~/.ssh/id_rsa -q -N ''"
      ignore_errors: yes
      run_once: true

    - name: Register authorized_key to each member
      authorized_key:
        user: vagrant
        state: present
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

[SSH-KEY scanning from Ansible Inventory 설명]

  • command : key-value 형태가 아닌 일반적인 명령어 수행을 위한 모듈(shell 모듈과 유사)
  • register : 명령의 실행 결과를 변수로 저장하기 위한 모듈

/usr/bin/ssh-keyscan은 서버간 SSH Connection을 위해 Password 입력 없이 연결할 수 있도록 Host based Authontication을 설정을 위해 사용한다. 즉 Ansible Inventory에 등록된 모든 멤버들의 ssh-key를 스캐닝하여 "keyscan" 변수에 저장한다.

 

  • command :  key-value 형태가 아닌 일반적인 명령어를 실행할 때 사용하는 모듈(shell 모듈과 유사)
  • /usr/bin/ssh-keyscan : 노드(서버)간 SSH Connection에서 패스워드를 사용하지 않고 연결할 수 있도록 Host based Authontication을 설정한다. (모든 노드에서 SELinux와 Firewall을 disable 하고 사용해도 됨)
  • {{ ansible-hosts }} : ansible inventory(/etc/ansible/hosts)에 등록되어 있는 멤버들의 domain, ip 정보
  • register : ansible playbook에서 명령의 실행 결과를 변수로 사용하기 위한 모듈

즉 Inventory에 등록된 멤버(worker)들로 부터 ssh-key를 스케닝하고, "keyscan" 변수에 저장

 

 

[Register ssh-key 설명]

  • lineinfile : 이미 존재하는 파일에 한줄의 내용을 추가하기 위한 모듈(중복되지 않음)

즉 ~/.ssh/known_hosts 파일에 "keyscan" 변수에 저장된 내용을 추가.

 

 

[Create authorized-keys 설명]

  • ssh-keygen -b 2048 -t rsa -f ~/.ssh/id_rsa -q -N
  • -t rsa : RSA 방식 암호화
  • -f ~/.ssh/id_rsa : 키 생성위치 지정
  • -N : new_passphrase (비공개키, 자동로그인)

~/.ssh 디렉토리 내에 Private Key(id_rsa)와 Public Key(id_rsa.pub)가 생성됨.  Worker에서 Master로 SSH 접속 시 비밀번호 입력없이 접속하기 위해서는 Master의 Public Key를 Worker의 ~/.ssh/authorized-keys에 등록해야함

 

 

[Register authorized_keys to each member 설명]

  • authorized_key 모듈 : Master의 Public Key를 Work들에게 전파(등록)함.
  • Work의 계정은 vagrant를 사용

Master에서 Worker에 암호 입력 없이 SSH 접속을 하기위해 Master의 Public Key를  Work에 등록하면 Private Key를 통해 Worker에 SSH 접속이 가능함

 

 

나. Ansible Worker 추가

Vagrantfile에 추가적인 작업 노드(Worker)를 추가한다.

    #ansible-worker-01
    config.vm.define "ansible-worker-01" do |worker|
        worker.vm.box = "ubuntu/bionic64"
        worker.vm.provider "virtualbox" do |vb|
            vb.name = "ansible-worker-01"
            vb.customize ["modifyvm", :id, "--cpus", 1]
            vb.customize ["modifyvm", :id, "--memory", 512]
        end

        worker.vm.host_name = "ansible-worker-01"
        worker.vm.network:public_network, ip: "192.168.1.12"
        worker.vm.network:forwarded_port, guest: 22, host: 61222, auto_correct: true, id: "ssh"             
        worker.vm.provision:shell, inline: "apt-get update -y"
        worker.vm.provision:shell, path: "bootstrap.sh"
    end

Worker로 암호입력없이 로그인이 가능하도록 Worker의 sshd_config 파일을 수정하는 스크립트는 1편에서  "bootstrap.sh" 의 setup_ssh()에 추가했다.

 

[참고 : setup_ssh()]

setup_ssh() {
    apt-get install -y sshpass
    sed -i -e 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
    systemctl restart sshd
}

[주의사항]

SSH는 보안 상 매우 중요하기 때문에 암호기반 인증 보다는 공개키 기반 인증을 설정하는 것이 중요하다. sshd_config 설정에서 "PasswordAuthentication yes"로 설정하는 것 보다는 "PubkeyAuthetication yes", "PasswordAuthentication no" 설정이 더 바람직해 보인다.

 

그런데 PasswordAuthentication의  default 값이 "yes" 인 것으로 알고 있는데... 생각해 보면 조금 이상하다.

왜인지 sshd_config를 설정해주지 않으면 Ansible로 최초 배포 시 에러가 발생했었다. 찜찜한데... 이 부분은 다시 확인해보는게 좋겠다.

 

다. 실행 및 결과 확인

1. vagrant provision

- 오류여부 확인

 

2. vagrant status 

3. vagrant ssh ansible-master

- ansible all -m ping

- cat /etc/hosts

- cat /etc/ansible/hosts

 

4. vagrant ssh ansible-worker01

- cat /etc/hosts

- cat ~/.ssh/authorized_keys

 


여기까지 AI 개발환경 구축을 IaC(Infrastructure as Code)기반의 인프라를 구성해보았다. 이제 Ansible 기반의 Kubernets Cluster를 배포하고, K8S 클러스터에 Kubspray를 배포한다.

 

3편 Ansible를 활용한 Kubernetes Cluster 환경 구성(작성중)