..

a101) ansible 체험기

마지막 숙제인 만큼 이것저것 해보자는 의미로 시작했지만.. 생각보다 더 잘 안되서 아쉽다. 테스트를 하려고 한 내용은 ‘ec2 생성 -> 키등록 -> 생성한 ec2에 role배포’ 였다…

준비 작업

먼저 ec2를 생성하기 위해 aws sdk 설치가 필요하다. ansible이 python으로 구현되어있기 때문에 boto3을 설치했다. 이렇게 설치를 하고 나면 aws내의 리소스를 컨트롤 할 수 있다. 현재 접속 중인 인스턴스에게 충분한 권한이 있어 설치 후, 아래와 같이 ec2 정보를 불러오는 것이 가능하다. (ec2 full access로 권한 부여된 상태)

$ sudo apt-get install python3-pip
$ pip install boto3

1-0

인스턴스를 생성하기 전, 사용할 role을 설치하였다.🔗

$ ansible-galaxy role init --init-path ./roles role.test
$ ansible-galaxy role install -p roles Oefenweb.wordpress

role에서 넣을 변수를 확인해보니 password란이 있어, ansible-vault로 암호화하였다. 지난번에 한 것과 동일하게 ansible-vault로 암호화 시 사용한 비밀번호는 aws secretmanager에 넣어놨다.

$ ansible-vault create vars/secret.yml
New Vault password: qwe123
Confirm New Vault password: qwe123

# vars/secret.yml
dbpass: qwe123

# get-vault-passwd.sh 
#!/bin/sh
aws secretsmanager get-secret-value --secret-id ansiblepasswd | jq -r .SecretString | jq -r .ansible_passwd

파일 작성

ansible.cfg & inventory

# ansible.cfg
[defaults]
inventory = ./inventory
remote_user = ubuntu
ask_pass = false
roles_path= ./roles
vault_password_file=./get-vault-passwd.sh 

[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false


# inventory
tnode1
tnode2
tnode3

variable

# vars/wp.yml
	wordpress_installs:
	- name: wordpress
	  dbname: wordpress
	  dbuser: wordpress
	  dbpass: !vault | 
	          $ANSIBLE_VAULT;1.1;AES256
	           {{ ansible vault secret정보 }} 
	  dbhost: localhost
	  path: /var/www
	  url: http://localhost
	  title: wordpress
	  admin_name: admin
	  admin_email: root@localhost.localdomain
	  admin_password: !vault | 
	          $ANSIBLE_VAULT;1.1;AES256
	           {{ ansible vault secret정보 }} 
	  themes:
	    - name: twentytwelve
	      activate: true
	    - name: twentythirteen
	  plugins:
	    - name: contact-form-7
	      activate: false
	    - name: simple-fields
	  users: {}
	  queries: []


# vars/ec2.yml
# security_group과 vpc_subnet_id를 잘 맞춰서 써줘야지.. 아니면 default sg,vpc를 사용하게 된다.
vm_name: "testserver"
image_id: "ami-0382ac14e5f06eb95" #ubuntu
instance_type: "t3.medium"
key_name: "nyoung"
security_group: "sg-050094e736daa3955"
region_name: "ap-northeast-2"
user_name: "ubuntu"
vpc_subnet_id: "subnet-0633258a6f7a419ef"

playbook

# 진행 순서
# (localhost에서)
# create ec2 vm > print vm private ip > add hosts file > add inventory file 
# (이후에 등록되는 testserver에서)
# copy pub key > wordpress role  


- hosts: localhost
  vars_files:
    - vars/ec2.yml
  tasks:
    - name: Create ec2 vm
      amazon.aws.ec2_instance:
        name: " {{ vm_name }} "
        image_id: " {{ image_id }} "
        instance_type: " {{ instance_type }} "
        key_name: " {{ key_name }} "
        security_group: " {{ security_group }} "
        network:
          assign_public_ip: true
        region: " {{ region_name }} "
      register: ec2_info

    - name: Print vm private ip
      ansible.builtin.debug:
        var: ec2_info.instances[0].private_ip_address

    - name: add hosts file
      ansible.builtin.shell: |
        echo " {{ ec2_info.instances[0].private_ip_address }}  testserver" >> /etc/hosts 
    - name: add inventory file
      ansible.builtin.shell: |
        echo "testserver" >> /inventory
 
- hosts: testserver
  tasks:
    - name: copy pub key
      ansible.posix.authorized_key:
        user: " {{ user_name }} "
        state: present
        key: " {{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }} "

  vars_files:
    - vars/wp.yml
  roles:
    - role: Oefenweb.wordpress

실행하면서 수정한 것들

hosts: localhost

문법 체크시 문제 없고, 추가될 호스트에 대해 아직 모르기 때문에 warning이 발생한다. 1-1

늘 그렇듯.. 문법이 통과 되었어도 오류는 발생한다. 사실 이 사이에서도 sg, subnet을 잘못맞춰서 몇번 다시 만들었다.. 여기서 발생한 오류는 ec2가 온전히 생기기 전에 다음 태스크를 수행하려하다보니 오류가 발생했다. (이 때까지만해도 ip도 public으로 잘못 넣었었다..) 1-2

wait_for이라는 모듈을 사용하여 22번 포트가 열리면 다음 태스크를 수행하도록 했다. 다음 태스크인 hosts file과 inventory file에 작성되는 것이 플레이북 실행시마다 쌓이기 때문에, lineinfile이라는 모듈로 변경하였다. path의 파일에 line에서 지정한 문자가 있을 시 추가되지 않는다.

    - name: check ec2 vm
      ansible.builtin.wait_for: 
        host: " {{ item.public_dns_name }} " 
        port: 22 
        delay: 10  
        timeout: 300
      with_items: " {{ ec2_info.instances }} "

    - name: add hosts file
      lineinfile:
        path: /etc/hosts
        line: " {{ ec2_info.instances[0].private_ip_address }}  testserver" 
        state: present
      
    - name: add inventory file
      lineinfile:
        path: ./inventory
        line: "testserver"
        state: present

이 때 생성되는 ec2는 IMDSv1으로 생성된다. module에서는 옵션이 없는 것으로 확인했는데.. 만약 ansible로 ec2를 생성하여 사용해야한다면, 이부분은 바꾸고 써야 할 것 같다.

등록을 완료 후, target host 변경 전 인벤토리를 refresh해서 새로 생긴 testserver의 존재를 ansible server에게 알려준다.

    - name: refresh inventory
      ansible.builtin.meta: refresh_inventory

여기서부터 또다시 키와의 오류를 만나 한참을 헤맸다. ansible이 testserver를 알지만 ssh 접속이 안되어있는 상태로 gathering facts를 하다 오류가 발생한다. 그렇기 때문에, hosts: testserver로 넘어가기 전에 public key가 넘어가야한다 생각해서 여기서 넘겨보려고 했지만.. 실패했다. 한참 씨름하다 안되겠다 싶어서 public key를 복사해서 testserver의 authorized_key 파일에 넣어주고, 서버에서 한번 접속하여 재접근시 prompt 안뜨도록 했다.

수정된 첫번째 playbook
- hosts: localhost
  vars_files:
    - vars/ec2.yml
  tasks:
    - name: Create ec2 vm
      amazon.aws.ec2_instance:
        name: " {{ vm_name }} "
        image_id: " {{ image_id }} "
        instance_type: " {{ instance_type }} "
        key_name: " {{ key_name }} "
        security_group: " {{ security_group }} "
        vpc_subnet_id: " {{ vpc_subnet_id }} "
        network:
          assign_public_ip: true
        region: " {{ region_name }} "
        state: present
        user_data: " "
      register: ec2_info

    - name: check ec2 vm
      ansible.builtin.wait_for: 
        host: " {{ item.public_dns_name }} " 
        port: 22 
        delay: 10  
        timeout: 300
      with_items: " {{ ec2_info.instances }} "

    - name: Print vm public ip
      ansible.builtin.debug:
        var: ec2_info.instances[0].private_ip_address

    - name: add hosts file
      lineinfile:
        path: /etc/hosts
        line: " {{ ec2_info.instances[0].private_ip_address }}  testserver" 
        state: present
      
    - name: add inventory file
      lineinfile:
        path: ./inventory
        line: "testserver"
        state: present

    - name: refresh inventory
      ansible.builtin.meta: refresh_inventory

hosts: testserver

testserver에서는 role을 실행하는 플레이북을 작성하였다. role 사용을 위해 몇가지 패키지 설치가 선행되어야 해서 설치하는 태스크 후에 롤을 실행했다. 🔗

- hosts: testserver
  tasks:
  - name: install pkg
    ansible.builtin.apt:
      name: 
        - php
        - mysql-server
        - apache2
        - php-mysql
      state: present

- hosts: testserver
  vars_files:
    - vars/wp.yml
  roles:
    - role: Oefenweb.wordpress
      become: true

이 때, 계속해서 ansible-vault를 복호화하지 못하는 오류가 있었는데.. get-vault-passwd.sh를 실행하는 권한이 없어서였다. $ chmod +x ./get-vault-passwd.sh

권한 부여 후에는 value만 가져와야하는데 {key: value}를 가져와서 문제가 되었다. 변수파일 (vars/wp.yml)에서 !vault로 작성했던 부분들을 lookup을 사용하여 변경하였다. vars/secret.yml의 파일이 yaml형식이며, 여기서 dbpass의 value를 가져오도록 했다. “{{ lookup(‘file’, ‘/home/ubuntu/my-ansible/vars/secret.yml’) | from_yaml | json_query(‘dbpass’) }}”

이 후엔, mysql에 db와 user가 준비되어있지 않아 오류가 발생하였다.

CREATE database wordpress;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'qwe123';
CREATE USER 'wordpress'@localhost IDENTIFIED BY 'qwe123';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@localhost;
FLUSH PRIVILEGES;

role을 쓰는게 익숙하지도 않고, 꼼꼼하게 읽지 않아서 그런지 이후에도 자잘자잘한 오류들을 마주했다. 변수파일 (vars/wp.yml)작성할 때, 그냥 밑에 있던 퀵스타트 샘플을 복사하고 vault부분만 변경하여 사용하였는데.. 그 곳에 적혀있던 플러그인이 없다거나 필수 변수값이 없다거나하는 오류들이 있었다. 몇개를 고쳐주고 나니 오류없이 플레이북이 종료되긴했지만 skipped=15를 보고 찝찝함만 생겼다. 외부에서는 접근이 안되는 것을 보고 이건 그냥 통과지 설치에 성공한게 아니구나 싶었다.. ㅠ 방화벽도 확인하고 변수의 url도 변경해주었지만, 불가했다. 누군가 만들어 둔 role을 사용하는게 아무리 좋다해도, 이렇게 제대로 읽지도 않고 하면 온갖 곳에서 문제가 나온다.. 😇