Ansible
- 개요 및 장점
- Agentless
- Puppet, Chef와 달리 에이전트를 설치할 필요가 없다. OpenSSH 또는 WinRM을 이용하여 각 노드에 앤서블 모듈을 푸시하여 그것을 통해 설정 구성을 실행한다.
- 고도의 프로그래밍 기술 불필요
- 쉬운 팀 간 작업 공유
- 멱등성 지원
- 멱등성이란 몇 번을 연산해도 항상 같은 결과가 나오는 성질.
- 패키지 등을 재설치하지 않고 일부만 변경 가능
- 중복 방지
- Shell, Command, File Module은 멱등성 미지원
- 700가지 이상 대다수의 서버와 네트워크 장비 지원
- Agentless
- 앤서블에서 [서버 <--> 노드] 통신 조건
- 프로토콜
- 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
- apt install -y ansible
- 모든 서버 및 노드에서 설정 : 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
- passwd root
- 앤서블 서버에 인증키 설정
- 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
- hosts 파일에 노드 추가
- ansible all -m ping -k
- SSH password:
- 초록색으로 SUCCESS가 뜨면 인증키 저장 성공.
- SSH password:
- 그룹핑 이후
- 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 all -m apt -a "name=apache2 state=present" -k
- 앤서블 서버에서 설정 : 1개
- 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
- vim nginx_install.yaml
- 일괄적으로 3개의 노드에 태스크별로 설치, 인덱스 페이지 변경, 실행까지 됨.
- yaml 파일 작성
- 설치 및 ansible 모듈
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를 제공한다.
- https://app.vagrantup.com/boxes/search
- 원하는 이미지명이 centos/7임을 확인하여 Ruby 기반으로 Vagrantfile을 작성한다.
- cmd창에서 vagrant up
- vagrant up --provider virtualbox
- 어차피 디폴트가 버츄얼박스이긴 함.
- 네트워크 인터페이스 선택
- 꽤 오랜 시간 후 완료됨
- vagrant up --provider virtualbox
- 구동 상태 확인
- vagrant status
- running
- vagrant status
- ssh 접속
- vagrant ssh
- cat /vagrant/Vagrantfile
- 작성한 파일 확인
- ip a
- IP 적용 확인
- ansible --version
- 앤서블 버전 확인
- cat /vagrant/Vagrantfile
- vagrant ssh
Role
- 디렉토리
- defaults
- 디폴트 변수를 가진다.
- 우선순위 최하
- files
- 노드에 배포할 정적인 파일들이 위치
- ex) 웹 페이지, 환경 설정 파일 등
- 노드에 배포할 정적인 파일들이 위치
- handlers
- 핸들러를 선언
- meta
- 롤에 대한 추가 정보
- ex) 작성자 정보, 호환 버전 등
- 롤에 대한 추가 정보
- tasks (required)
- playbook에서 사용되는 태스크들을 기입
- templates
- 템플릿, 진자2(index.j2)
- vars
- 변수들에 대한 정보를 모아둔다.
- defaults
- 구성 방법
- 수동 mkdir
- ansible-galaxy
- 자동적으로 롤 디렉토리를 만들 수 있다.
- 또는 타인의 구성을 가져와 적용할 수 있다.
- 예시
- ansible-galaxy search --galaxy-tags nginx
- https://galaxy.ansible.com/
- ansible-galaxy install jdauphant.nginx
- 예시
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"