Ansible


  • 개요 및 장점
    • Agentless
      • Puppet, Chef와 달리 에이전트를 설치할 필요가 없다. OpenSSH 또는 WinRM을 이용하여 각 노드에 앤서블 모듈을 푸시하여 그것을 통해 설정 구성을 실행한다.
    • 고도의 프로그래밍 기술 불필요
    • 쉬운 팀 간 작업 공유
    • 멱등성 지원
      • 멱등성이란 몇 번을 연산해도 항상 같은 결과가 나오는 성질.
      • 패키지 등을 재설치하지 않고 일부만 변경 가능
      • 중복 방지
      • Shell, Command, File Module은 멱등성 미지원
    • 700가지 이상 대다수의 서버와 네트워크 장비 지원
  • 앤서블에서 [서버 <--> 노드] 통신 조건
    • 프로토콜
      • Linux : SSH
      • Windows : WinRM(Windows Remote Management)
    • 포트
      • Linux : 22
      • Windows : 5985(HTTP), 5986(HTTPS)
    • 사용자
      • vagrant 동일
  • 실습
    • 설치 및 ansible 모듈
      • 앤서블 서버에서 설정 : 1개
        • apt install -y ansible
          • Ansible Core 설치
        • apt install -y sshpass
          • CentOS에선 한 번에 설치?
        • ls /usr/bin/ansible*
          • 모듈 확인
          • ansible : 단일 태스크
          • ansible-playbook
      • 모든 서버 및 노드에서 설정 : 4개
        • passwd root
          • 루트 패스워드 설정
        • apt update
        • ssh 서비스 config 파일 수정
          • sed -i "s/^PasswordAuthentication no/PasswordAuthentication yes/g" /etc/ssh/sshd_config
          • sed -i "s/^#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
          • systemctl restart sshd
      • 앤서블 서버에 인증키 설정
        • hosts 파일에 노드 추가
          • echo 10.2.11.121 >> /etc/ansible/hosts
          • echo 10.2.11.122 >> /etc/ansible/hosts
          • echo 10.2.11.123 >> /etc/ansible/hosts
        • 인증키 저장
          • ansible all -m ping
            • yes * 3
      • ansible all -m ping -k
        • SSH password:
          • 초록색으로 SUCCESS가 뜨면 인증키 저장 성공.
      • 그룹핑 이후
        • ansible nginx -m ping -k
      • echo 10.2.11.121 >> customized_invent.lst
      • echo 10.2.11.122 >> customized_invent.lst
      • ansible -i customized_invent.lst all -m ping -k
      • ansible all -m ping --list-hosts
      • 모듈 사이트
      • ansible -i customized_invent.lst 10.2.11.121 -m shell -a "df -h" -k
        • 쉘을 통해 명령어를 실행할 수 있는데, 이 때 옵션을 붙인다면 더블 쿼테이션으로 묶어주어야 한다.
      • ansible all -m user -a "name=nsuser01" -k
        • Ansible Node에 유저를 추가할 수 있다.
      • ansible all -m shell -a "tail -n 1 /etc/passwd" -k
        • Node마다 passwd 파일의 뒤에서부터 한 줄 읽어오는 것이다.
      • state 종류
        • present : 설치
        • absent : 삭제
        • latest : 최신 버전 설치
        • build-dep : 패키지 빌드 종속성 설치 확인 (dependency)
      • ansible all -m user -a "name=nsuser01 state=absent" -k
        • state=absent 로 삭제한다.
        • 결과에 "changed"=true면 뭔가 변경에 성공한 것.
      • ansible all -m shell -a "tail -n 1 /etc/passwd" -k
        • 삭제가 되었는지 확인해본다.
      • 웹 서버
        • ansible all -m apt -a "name=apache2 state=present" -k
          • state=present로 설정해 웹 서버를 설치한다.
          • Ubuntu : apache2
          • CentOS : httpd
        • 노드의 IP 주소로 브라우저에서 접속
          • 주소창에 10.2.11.121~3 -> Apache2 Ubuntu Default Page
        • 인덱스 페이지 변경
          • apt install -y curl
          • curl httpd.apache.org -o index.html
          • ls
            • index.html을 받아온 것을 확인.
          • ansible all -m copy -a "src=index.html dest=/var/www/html/index.html" -k
            • 앤서블 서버로부터 각 노드들에게 파일을 일괄적으로 덮어쓰기(없다면 생성)
          • 다시 브라우저로 접속해보면 페이지가 바뀌어 있음.
        • 웹 서버 서비스 중지
          • ansible all -m service -a "name=apache2 state=stopped" -k
          • 접속해보면 연결할 수 없음.
          • 속성 종류
            • reloaded
            • restarted
            • running
            • started
            • stopped
        • 웹 서버 삭제
          • ansible all -m apt -a "name=apache2 state=absent" -k
    • ansible-playbook 모듈
      • 사전적 의미 : 각본, 계획, 전술
      • 시스템 정의서 - 자동으로 실행되는 코드
      • 멱등성 적용
        • ansible localhost -c local -m lineinfile -a "path=customized_invent.lst line=192.168.0.204"
        • 노드는 건드리지 않기에 -k 옵션이 필요없다.
      • yaml 파일을 이용한 nginx 배치 실행
        • yaml 파일 작성
          •  
        • 앤서블 서버에서 실행
          • vim nginx_install.yaml
            • VSC에서 작성한 파일 긁어서 넣기
          • ansible-playbook nginx_install.yaml -k
        • 일괄적으로 3개의 노드에 태스크별로 설치, 인덱스 페이지 변경, 실행까지 됨.

Vagrant


 

  • Ansible은 Configuration, Orchestration 기능만 수행할 수 있지만 Vagrant를 통해 Bootstrapping까지 할 수 있다.
    • 가상 머신 생성 및 OS 설치가 가능
  • 설치
    • 홈페이지에서 설치 파일 다운로드
    • 재부팅
    • cmd창 열고 vagrant init
      • Vagrantfile이 만들어지는데 이게 중요한 것.
  • 실습
    • Windows cmd 접속
    • Vagrantfile 생성
      • :d
      • cd ansible
      • vagrant init
    • 플러그인 설치
      • vagrant plugin install vagrant-vbguest --plugin-version 0.21
    • Box = VM, Vagrant에서 Box Image를 제공한다.
    • cmd창에서 vagrant up
      • vagrant up --provider virtualbox
        • 어차피 디폴트가 버츄얼박스이긴 함.
        • 네트워크 인터페이스 선택
        • 꽤 오랜 시간 후 완료됨
    • 구동 상태 확인
      • vagrant status
        • running
    • ssh 접속
      • vagrant ssh
        • cat /vagrant/Vagrantfile
          • 작성한 파일 확인
        • ip a
          • IP 적용 확인
        • ansible --version
          • 앤서블 버전 확인

Role


  • 디렉토리
    • defaults
      • 디폴트 변수를 가진다.
      • 우선순위 최하
    • files
      • 노드에 배포할 정적인 파일들이 위치
        • ex) 웹 페이지, 환경 설정 파일 등
    • handlers
      • 핸들러를 선언
    • meta
      • 롤에 대한 추가 정보
        • ex) 작성자 정보, 호환 버전 등
    • tasks (required)
      • playbook에서 사용되는 태스크들을 기입
    • templates
      • 템플릿, 진자2(index.j2)
    • vars
      • 변수들에 대한 정보를 모아둔다.
  • 구성 방법
    • 수동 mkdir
    • ansible-galaxy
      • 자동적으로 롤 디렉토리를 만들 수 있다.
      • 또는 타인의 구성을 가져와 적용할 수 있다.

Source Codes


Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :
  
Vagrant.configure("2") do |config|

  #==============#
  # CentOS nodes #
  #==============#
  
  #Ansible-Node01
  config.vm.define "ansible-node01" do |cfg|
    cfg.vm.box = "centos/7"
    cfg.vm.provider "virtualbox" do |vb|
      vb.name = "Ansible-Node01"
    end
    cfg.vm.host_name = "ansible-node01"
    cfg.vm.network "public_network", ip: "172.30.1.201"
    cfg.vm.network "forwarded_port", guest: 22, host: 60011, auto_correct: true, id: "ssh"
    cfg.vm.synced_folder ".", "/vagrant", disabled: true 
    cfg.vm.provision "shell", path: "bash_ssh_conf_4_CentOS.sh"
  end

  #==============#
  # Ubuntu nodes #
  #==============#
  
  #Ansible-Node04
  config.vm.define "ansible-node04" do |cfg|
    cfg.vm.box = "ubuntu/trusty64"
  cfg.vm.provider "virtualbox" do |vb|
    vb.name = "Ansible-Node04"
  end
  cfg.vm.host_name = "ansible-node04"
  cfg.vm.network "public_network", ip: "172.30.1.204"
  cfg.vm.network "forwarded_port", guest: 22, host: 60014, auto_correct: true, id: "ssh"
  cfg.vm.synced_folder ".", "/vagrant", disabled: true
 end
  
  #================#
  # Ansible Server #
  #================#

    config.vm.define "ansible-server" do |cfg|
    cfg.vm.box = "centos/7" # '='가 필수적으로 필요 
    cfg.vm.provider "virtualbox" do |vb|
      vb.name = "Ansible-Server" # '='가 필수적으로 필요 
    end
    cfg.vm.host_name = "ansible-server" # '='가 필수적으로 필요 
    cfg.vm.network "public_network", ip: "172.30.1.200"
    cfg.vm.network "forwarded_port", guest: 22, host: 60010, auto_correct: true, id: "ssh"
    cfg.vm.synced_folder ".", "/vagrant"
    cfg.vm.provision "shell", inline: "yum install epel-release -y"
    cfg.vm.provision "shell", inline: "yum install ansible -y"
	  cfg.vm.provision "file", source: "ansible_env_ready.yml", 
	    destination: "ansible_env_ready.yml"
	  cfg.vm.provision "shell", inline: "ansible-playbook ansible_env_ready.yml"

    # generate n input keys
    cfg.vm.provision "file", source: "auto_pass.yml", 
      destination: "auto_pass.yml"
    cfg.vm.provision "shell", inline: "ansible-playbook auto_pass.yml", privileged: false
    
    # facts
    cfg.vm.provision "file", source: "facts.yml", 
      destination: "facts.yml"
    cfg.vm.provision "file", source: "facts_collector.yml", 
      destination: "facts_collector.yml"

    # install nginx
    cfg.vm.provision "file", source: "CentOS.yml", 
      destination: "CentOS.yml"
    cfg.vm.provision "file", source: "Ubuntu.yml", 
      destination: "Ubuntu.yml"
    cfg.vm.provision "file", source: "nginx_install_w_template.yml", 
      destination: "nginx_install_w_template.yml"
    cfg.vm.provision "file", source: "index.j2", 
      destination: "index.j2"
    
    # remove nginx
    cfg.vm.provision "file", source: "CentOS_remo.yml", 
      destination: "CentOS_remo.yml"
    cfg.vm.provision "file", source: "Ubuntu_remo.yml", 
      destination: "Ubuntu_remo.yml"
    cfg.vm.provision "file", source: "nginx_remove_w_if.yml", 
      destination: "nginx_remove_w_if.yml"
    end
  end

 

ansible_env_ready.yml

---
- name: Setup for the Ansible's Environment
  hosts: localhost
  gather_facts: no
  
  tasks:
    - name: Add "/etc/ansible/hosts"
      blockinfile: 
        path: /etc/ansible/hosts
        block: |
          [nodes]
          172.30.1.201
          172.30.1.204
          
    - name: Create vim env's directories & files
      shell: "{{ item }}"
      with_items:
        - "mkdir -p /home/vagrant/.vim/autoload /home/vagrant/.vim/bundle"
        - "touch /home/vagrant/.vimrc"
        - "touch /home/vagrant/.bashrc"
      
    - name: Install vim-enhanced
      yum: 
        name: vim-enhanced
        state: present
        
    - name: Install git
      yum: 
        name: git
        state: present
        
    - name: Download pathogen.vim
      shell: "curl -fLo /home/vagrant/.vim/autoload/pathogen.vim
              https://tpo.pe/pathogen.vim"
      
    - name: Git clone vim-ansible-yaml
      git:
        repo: https://github.com/chase/vim-ansible-yaml.git
        dest: /home/vagrant/.vim/bundle/vim-ansible-yaml
        
    - name: Configure vimrc
      lineinfile: 
        path: /home/vagrant/.vimrc
        line: "{{ item }}"
      with_items:
        - "set number"
        - "execute pathogen#infect()"
        - "syntax on"

    - name: Configure Bashrc
      lineinfile:   
        path: /home/vagrant/.bashrc
        line: "{{ item }}"
      with_items:
        - "alias ans='ansible'"
        - "alias anp='ansible-playbook'"

 

auto_pass.yml

---
- name: Create authority between server and nodes
  hosts: nodes
  connection: local
  serial: 1
  gather_facts: no
  vars:
    ansible_password: vagrant

  tasks:
    - name: ssh-keyscan for known_hosts file
      command: /usr/bin/ssh-keyscan -t ecdsa {{ ansible_host }}
      register: keyscan

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

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

    - name: input key for each node
      connection: ssh
      authorized_key:
        user: vagrant
        state: present
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

 

facts.yml

---
- name: print ipv4.address for nodes
  hosts: nodes
  #gather_facts: no

  tasks:
    - name: debug by msg
      debug:
        msg:
          - "eth0's ip {{ ansible_eth0.ipv4.address }}"
          - "eth1's ip {{ ansible_eth1.ipv4.address }}"

    - name: debug by var
      debug:
        var: "{{ item }}"
      with_items:
        - hostvars[inventory_hostname]['ansible_eth0']['ipv4']['address']
        - hostvars[inventory_hostname]['ansible_eth1']['ipv4']['address']

 

facts_collector.yml

---
- name: Collect facts for each node
  hosts: nodes

  tasks:
    - name: generate facts
      setup:
      register: facts

    - name: save facts
      local_action:
        module: copy
        content: "{{ facts | to_nice_json }}"
        dest: ./{{ ansible_hostname }}_facts_by_collector.txt

 

CentOS.yml

- name: install epel-release
  action: "{{ ansible_pkg_mgr }} name=epel-release state=latest"
- name: install nginx web server
  action: "{{ ansible_pkg_mgr }} name=nginx state=present"
- name: upload default index.html for web server
  get_url: url=https://www.nginx.com dest=/usr/share/nginx/html/ mode=0644
  notify:
    - restart nginx web server

 

Ubuntu.yml

- name: install nginx web server
  action: "{{ ansible_pkg_mgr }} name=nginx state=present update_cache=yes"
- name: upload default index.html for web server
  shell: "sudo curl -fLo /usr/share/nginx/html/index.html https://www.nginx.com/"
  notify:
    - restart nginx web server

 

nginx_install_w_template.yml

---
- name: Install nginx on the nodes
  hosts: nodes
  become: yes
  vars: 
    nu: "{{ groups.nodes | count }}"
    idx: "{{ groups.nodes.index(inventory_hostname)+1 | int }}"
    lnx_name: "{{ 'CentOS' if ansible_distribution == 'CentOS'
                   else 'Ubuntu' if ansible_distribution == 'Ubuntu'
                   else 'Just Linux' }}"
    
  tasks:
    - name: nginx for any linux
      include_tasks: "{{ lnx_name }}.yml"
      
    - name: create web page for each node
      template:
        src: index.j2
        dest: /usr/share/nginx/html/index.html
        mode: 0644
        backup: yes

  handlers:
    - name: restart nginx web server
      service: name=nginx state=restarted

 

index.j2

<!doctype html>
<!Create by ansible template at {{ ansible_date_time.iso8601 }}>
<html>
  <head>
    <title>Nginx Web Server</title>
  </head>
  <body>
    <p><font color=pink size=5>Welcome to Ansible world!</font></p>
    <p><font size=5>Here is Nginx Cluster <font color=red>{{ idx }}</font>/{{ nu }}</font></p>
  </body>
</html>

 

CentOS_remo.yml

- name: remove epel-release
  action: "{{ ansible_pkg_mgr }} name=epel-release state=absent"
- name: remove nginx web server
  action: "{{ ansible_pkg_mgr }} name=nginx state=absent"

 

Ubuntu_remo.yml

- name: remove nginx web server
  action: "{{ ansible_pkg_mgr }} name=nginx state=absent autoremove=yes"

 

nginx_remove_w_if.yml

---
- name: Remove nginx on the nodes
  hosts: nodes
  become: yes
  vars:
    lnx_name: "{{ 'CentOS' if ansible_distribution == 'CentOS'
                   else 'Ubuntu' if ansible_distribution == 'Ubuntu'
                   else 'Just Linux' }}"

  tasks:
    - name: nginx for any linux
      include_tasks: "{{ lnx_name }}_remo.yml"

'IT > 인프라 자동화' 카테고리의 다른 글

AWX 설치 방법  (0) 2021.11.26

+ Recent posts