상세 컨텐츠

본문 제목

25.03.24. Ansible로 자동화 작업 효율화: Action과 IaC의 활용법

AWS CLOUD SCHOOL 9기

by AI Engineer crystal 2025. 3. 24. 09:31

본문

IaC

1. Infra Provision = Deployment

  • Infra Provision은 인프라를 준비하는 과정이고, Deployment는 실제로 준비된 인프라에 애플리케이션을 배포하는 과정입니다. 두 개념은 비슷하지만, Provision은 리소스를 설정하는 단계이고, Deployment는 설정된 리소스에 애플리케이션을 배포하는 단계입니다.

2. File → Provider (Hypervisor): 수정한 내용만 반영

  • IaC에서는 코드로 인프라를 정의하는데, 이때 파일을 작성하고 해당 파일을 **Provider (예: AWS, Azure 등)**에 전달하여 인프라를 설정합니다. 예를 들어, 하이퍼바이저나 클라우드 환경을 사용하여 리소스를 배포합니다.
  • 중요한 점은 수정한 내용만 반영된다는 점입니다. 즉, 이전에 배포한 인프라는 그대로 두고, 수정된 부분만 업데이트할 수 있습니다.

3. 코드 재사용

  • 한 번 작성한 IaC 코드는 여러 번 재사용할 수 있습니다. 예를 들어, 같은 네트워크 설정이나 서버 구성을 반복해서 사용할 때 코드만 수정하고 그대로 재사용할 수 있어 효율적입니다.

4. Helm

  • Helm은 Kubernetes 환경에서 애플리케이션을 배포하고 관리하는 도구입니다. Kubernetes 클러스터에 애플리케이션을 쉽게 설치하고 업데이트할 수 있게 도와줍니다.

1. 가상 머신 네트워크 문제 해결 (virsh 명령어 사용)

  • 문제: 오랜 시간 동안 ‘일시중지’ 상태였던 가상 머신을 재실행하면 네트워크 연결에 문제가 발생할 수 있습니다.
  • 해결 방법:
    1. ping을 통해 네트워크 연결 상태를 먼저 확인합니다.
    2. 연결이 되지 않으면, 아래 명령어를 사용해 가상 머신을 정지 후 다시 시작합니다. reboot 명령어는 사용하지 않습니다.
virsh destroy rocky1
virsh destroy rocky2
virsh destroy rocky3
virsh destroy rocky4

virsh start rocky1
virsh start rocky2
virsh start rocky3
virsh start rocky4

2. Playbook 기본 내용

Ansible Playbook은 자동화된 작업을 정의하는 파일로, 기본적인 Playbook 구조는 다음과 같습니다:

- name: 전체 작업명 > 로그에 표시됨
  hosts: 대상 [all, 그룹이름, localhost]
  become: yes  # root 권한으로 작업을 처리 (sudo 대체)
  gather_facts: yes  # 대상의 정보를 수집 (default: yes)
  tasks:
    - name: 첫 번째 작업
      yum:  # 모듈 이름
        name: httpd
        state: present
    - name: 두 번째 작업
      yum:
        name: git
        state: present

3. 변수 사용하기

변수를 사용하여 동적으로 값을 설정하고 작업을 관리할 수 있습니다.

[root@stg ansiblelab]# cat vartest.yml
- name: var test
  hosts: localhost
  gather_facts: true  # 기본값
  become: true
  tasks:
    - name: tes1
      debug:
        msg: "테스트 로그"

4. 변수 출력 예시

[root@stg ansiblelab]# cat vartest.yml
- name: var test
  hosts: localhost
  gather_facts: true  # 기본값
  become: true
  vars:
    myname: "홍길동"
  tasks:
    - name: tes1
      debug:
        msg: "테스트 로그"
    - name: test2
      debug:
        msg: "패키지 매니저: {{ ansible_pkg_mgr }}, 배포판: {{ ansible_distribution }}"
    - name: test3
      debug:
        msg: "나의 이름: {{ myname }}"

5. 변수가 많을 경우 별도의 파일로 관리

변수가 많을 경우, 별도의 파일로 관리하고 이를 Playbook에서 호출하여 사용할 수 있습니다. vars_files를 사용하여 변수 파일을 로드할 수 있습니다.

  1. vars.yml (변수 파일)
name1: "길동"
names:
  - "영수"
  - "광수"
  - "영철"
  1. Playbook에서 vars_files로 호출
[root@stg ansiblelab]# cat vartest.yml
- name: var test
  hosts: localhost
  gather_facts: true
  become: true
  vars_files:
    - vars.yml
  tasks:
    - name: tes1
      debug:
        msg: "테스트 로그"
    - name: test2
      debug:
        msg: "패키지 매니저: {{ ansible_pkg_mgr }}, 배포판: {{ ansible_distribution }}"
    - name: test3
      debug:
        msg: "나의 이름: {{ myname }}"
    - name: test4
      debug:
        msg: "file1: {{ name1 }}"
    - name: test5
      debug:
        msg: "file2: {{ names[0] }}, {{ names[1] }}, {{ names[2] }}"

- name: sshd 설정 플레이
  hosts: all
  become: true
  tasks:
    - name: root 가 패스워드로 SSH 로그인하는 것을 금지
      lineinfile:
        dest: /etc/ssh/sshd_config
        regexp: '^PermitRootLogin\\s+'
        line: PermitRootLogin without-password
        validate: sshd -t -f %s
      notify:
        - sshd 재시작

handlers:
  - name: sshd 재시작
    service:
      name: sshd
      state: restarted

1. regexp: '^PermitRootLogin\\s+'

  • *regexp*는 정규 표현식(Regular Expression)을 사용하여 수정할 파일에서 특정한 문자열을 찾는 조건을 정의합니다.
  • 여기서 사용된 정규 표현식 ^PermitRootLogin\\s+은 다음과 같은 의미입니다:
    • ^: 이 기호는 라인의 시작을 의미합니다. 즉, PermitRootLogin이 라인의 처음에 위치한 경우만 찾겠다는 뜻입니다.
    • PermitRootLogin: PermitRootLogin이라는 텍스트를 찾습니다. 이는 SSH 설정 파일에서 root 사용자의 로그인 방식을 설정하는 항목입니다.
    • \\s+: \\s는 공백 문자(공백, 탭 등)를 의미합니다. 그리고 +는 1개 이상의 공백 문자가 있을 수 있음을 의미합니다. 즉, PermitRootLogin 뒤에 여러 공백이 있을 수 있다는 의미입니다.
    이 정규 표현식은 PermitRootLogin으로 시작하며, 뒤에 공백이 하나 이상 있는 라인을 찾는 조건입니다. 예를 들어, PermitRootLogin yes나 PermitRootLogin without-password 등과 같은 라인을 찾습니다.

2. line: PermitRootLogin without-password

  • *line*은 regexp로 찾은 라인을 이 값으로 교체하겠다는 설정입니다.
  • 여기서 PermitRootLogin without-password는 root 사용자가 패스워드 없이 SSH 로그인하도록 설정하는 값입니다.
    • PermitRootLogin without-password는 root 사용자가 비밀번호를 사용하지 않고 SSH로 로그인할 수 있도록 설정합니다. 즉, 비밀번호 인증을 금지하고, 키 기반 인증(public key authentication)만 허용하도록 설정하는 것입니다.
    • 이 설정은 보안 상으로 중요한 설정으로, root 계정으로의 직접적인 로그인 시 비밀번호를 사용하지 못하게 하여, 보안을 강화하는 데 사용됩니다.

3. validate: sshd -t -f %s

  • *validate*는 파일이 수정된 후, 변경 내용이 올바른지 확인하는 명령을 실행하도록 합니다. 이 경우, sshd -t -f %s 명령어가 사용되었습니다.
  • %s는 lineinfile 모듈에서 수정된 파일의 경로를 자동으로 넣어줍니다. 즉, 실제로 /etc/ssh/sshd_config 파일을 검사하는 방식입니다.
  • sshd -t -f:
    • sshd -t는 SSH 설정 파일을 테스트하는 명령입니다. 이 명령어는 SSH 서버가 설정 파일을 읽고 오류가 있는지 확인하는 역할을 합니다.
    • f %s에서 %s는 lineinfile 모듈이 수정한 파일 경로(/etc/ssh/sshd_config)로 바뀝니다. 즉, 설정 파일을 검증하여 구문에 오류가 있는지 확인합니다.
    이 과정은 파일 변경 후 SSH 설정에 오류가 없는지 검사하는 중요한 과정으로, 설정 파일에 문법적 오류가 있을 경우 SSH 서버가 정상적으로 동작하지 않을 수 있기 때문에 이를 방지하기 위해 사용됩니다.

ansible all -m shell -a "cat /etc/httpd/conf/httpd.conf | grep Listen”

- name: change the web port
  hosts: all
  become: true
  vars_files:
    - vars.yaml
  tasks:
    - name: find and change webport
      lineinfile:
        dest: /etc/httpd/conf/httpd.conf
        regexp: '^Listen\\s[0-9]+'
        line: Listen {{ webport }}
        validate: httpd -t -f %s
      notify:
        - restart webport
    - name: make directory
      file:
        path: /var/www/html
        state: directory
    - name: make file
      file:
        path: /var/www/html/index.html
        state: touch
    - name: add material in index.html
      blockinfile:
        dest: /var/www/html/index.html
        block: |
          [test page]
          - Hi
          - Hello

  handlers:
    - name: restart webport
      service:
        name: httpd
        state: restarted

tasks 섹션 설명:

1. find and change webport:

  • 목적: /etc/httpd/conf/httpd.conf 파일에서 Apache의 포트를 변경합니다.
  • lineinfile 모듈을 사용하여 해당 파일에서 Listen으로 시작하는 라인을 찾아서 webport 변수로 지정된 값으로 변경합니다.
  • regexp: '^Listen\\s[0-9]+': Listen으로 시작하는 라인(포트 번호를 설정하는 라인)을 찾습니다.
  • line: Listen {{ webport }}: webport 변수에 지정된 값으로 Listen 라인을 수정합니다.
  • validate: httpd -t -f %s: 수정 후에 httpd 설정이 유효한지 검증합니다. 만약 유효하지 않으면 에러가 발생하고, 변경이 되지 않습니다.
  • notify: 변경이 완료되면 restart webport 핸들러가 실행됩니다.

2. make directory:

  • 목적: /var/www/html 디렉토리를 생성합니다.
  • file 모듈을 사용하여 해당 경로에 디렉토리가 없으면 새로 생성합니다.
  • state: directory: 디렉토리를 생성하도록 지정합니다.

3. make file:

  • 목적: /var/www/html/index.html 파일을 생성합니다.
  • file 모듈을 사용하여 해당 경로에 파일을 생성합니다. 만약 파일이 존재하지 않으면 새로 만듭니다.
  • state: touch: touch는 파일을 생성하거나 파일의 최종 수정 시간을 갱신하는 역할을 합니다. 파일이 없다면 새로 생성합니다.

4. add material in index.html:

  • 목적: index.html 파일에 내용 추가
  • blockinfile 모듈을 사용하여 /var/www/html/index.html 파일에 특정 블록을 추가합니다.
  • block: |: 블록 내용으로 주어진 여러 줄의 텍스트를 index.html에 추가합니다.
  • 해당 블록 내용:
  • [test page] - Hi - Hello
  • 이 내용은 index.html 파일에 추가됩니다.

handlers 섹션 설명:

1. restart webport:

  • 목적: Apache HTTPD 서비스를 재시작하여 포트 변경이 반영되도록 합니다.
  • service 모듈을 사용하여 httpd 서비스를 재시작합니다.
  • state: restarted: 서비스를 재시작합니다.
  • 이 핸들러는 위의 notify에서 호출되며, 웹 포트가 변경될 때마다 Apache가 재시작됩니다.

Jenkins 설치 및 Ansible과 연동

Jenkins 설치 (Ansible이 설치된 stg 서버에서 실행)

  1. 시스템 업데이트
  2. sudo dnf update -y
  3. 필요한 패키지 설치
    • Git, Java, wget 설치
    sudo dnf install -y git java-21-openjdk wget
    
    • Amazon Linux 2에서 Java 설치 방법:
      • Java 버전 확인
      sudo yum list | grep java
      
      • Java 17 설치 (Amazon Corretto 17)
      sudo yum install -y java-17-amazon-corretto-devel.x86_64
      
  4. Java 버전 확인 및 설정
    • 사용 가능한 Java 버전 확인
    sudo java -version
    
    • 두 개 이상의 Java 버전이 있을 경우 사용할 버전 선택
    sudo alternatives --config java
    
    • Java 21만 보인다면 '1' 선택
  5. Jenkins 설치를 위한 저장소 추가
    • RHEL 저장소 추가
    sudo dnf install -y epel-release
    
    • wget 설치
    sudo dnf install -y wget
    
    • Jenkins 저장소 추가
    sudo wget -O /etc/yum.repos.d/jenkins.repo <https://pkg.jenkins.io/redhat-stable/jenkins.repo>
    
    • Jenkins의 pub 키를 추가하여 저장소 접근을 허용
    sudo rpm --import <https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key>
    
  6. Jenkins 설치
  7. sudo dnf install -y jenkins
  8. Jenkins 서비스 시작 및 활성화
    • 서비스 재로드
    sudo systemctl daemon-reload
    
    • Jenkins 시작
    sudo systemctl start jenkins
    

Jenkins가 빌드를 실행할 수 있도록 설정하는 과정

  1. Jenkins 사용자에 대한 셸 변경: Jenkins가 쉘을 사용할 수 있도록 변경합니다. 기본적으로 Jenkins는 쉘을 사용할 수 없지만, 이를 /bin/bash로 변경하여 쉘을 사용할 수 있도록 설정합니다.
  2. usermod -s /bin/bash jenkins
  3. Jenkins 사용자 확인: Jenkins 사용자의 정보를 확인하여 쉘이 제대로 변경되었는지 확인합니다.위와 같이 /bin/bash가 설정되어 있으면 Jenkins 사용자가 쉘을 사용할 수 있도록 설정된 것입니다.
  4. cat /etc/passwd | grep jenkins jenkins:x:990:989:Jenkins Automation Server:/var/lib/jenkins:**/bin/bash**
  5. /etc/sudoers 파일 수정: vi /etc/sudoers 명령을 통해 필요한 사용자나 그룹에 대한 sudo 권한을 추가할 수 있습니다. (여기서는 구체적인 내용은 없지만, 권한을 부여하는 작업이 진행될 수 있습니다.)
  6. SSH 키 파일 확인 및 복사:
  7. ansible.pem ansible.pem.pub config known_hosts
  8. Jenkins 사용자에게 SSH 키 복사:
    • Ansible이 접근할 수 있도록 ~/.ssh 파일들을 Jenkins 사용자에게 복사합니다.
    cp ~/.ssh/* /var/lib/jenkins
    
  9. Jenkins 사용자에게 권한 변경: 복사된 SSH 키 파일들에 대한 소유권을 jenkins 사용자에게 변경합니다.
  10. chown jenkins.jenkins /var/lib/jenkins/.ssh/*
  11. 권한 확인: ls -al 명령을 사용하여 SSH 키 파일들이 jenkins 사용자에게 올바르게 설정되었는지 확인합니다.
    total 20
    drwx------  2 jenkins jenkins   81 Mar 24 15:38 .
    drwxr-xr-x 16 jenkins jenkins 4096 Mar 24 15:37 ..
    -rw-------  1 jenkins jenkins 2590 Mar 24 15:38 ansible.pem
    -rw-r--r--  1 jenkins jenkins  562 Mar 24 15:38 ansible.pem.pub
    -rw-------  1 jenkins jenkins   90 Mar 24 15:38 config
    -rw-r--r--  1 jenkins jenkins  875 Mar 24 15:38 known_hosts
    
  12. ls -al /var/lib/jenkins/.ssh

1. Action의 기본 개념

  • ActionAnsible 모듈을 실행하는 역할을 합니다. 즉, action은 실제로 어떤 작업을 실행하는 방법을 정의합니다.
  • Action을 사용할 때는 다양한 모듈을 실행할 수 있으며, action을 사용하면 동적으로 모듈을 호출하는 방식으로 유용하게 활용할 수 있습니다.

예제 1: 일반적인 모듈 실행

- name: 예제 1 - 일반적인 모듈 실행
  copy:
    src: /tmp/example.txt
    dest: /home/user/example.txt
  • 위와 같은 방식으로, 특정 모듈을 명시적으로 호출하여 작업을 실행할 수 있습니다.
  • 예를 들어 copy, yum, apt 모듈을 사용할 때는 항상 해당 모듈 이름을 명시적으로 작성해야 합니다.

예제 2: Action을 활용한 동적 모듈 호출

- name: test
  action: "{{ ansible_pkg_mgr }}"
  name: httpd
  state: present
  • 위 예시에서 ansible_pkg_mgr 변수를 사용하여 **패키지 관리 모듈(yum, apt)**을 동적으로 호출할 수 있습니다.
  • action을 사용하면 변수에 따라 다른 모듈을 호출할 수 있기 때문에, 다양한 환경에서 Playbook을 간결하고 유연하게 작성할 수 있습니다.

2. 일반적으로는 모듈 직접 사용이 더 적합

  • Action을 사용하는 것보다 copy:, command:, shell: 등의 모듈을 직접 사용하는 것이 가독성유지보수성 측면에서 더 좋습니다.
  • 하지만 특정 환경에서 동적으로 모듈을 호출해야 하는 경우에는 action을 활용할 수 있습니다.

관련글 더보기