4.CI/CD 구축하기 - Ansible사용하기

2023. 4. 7. 17:41초기 과업/BackEnd

작성자알 수 없는 사용자

728x90
반응형

 

안녕하세요. 기깔나는 사람들에서 백앤드를 맡고있는 Hardy입니다.

 

이제 CI/CD 마지막을 향해 달려왔어요

 

1,2,3 번 목차를 하느라 고생하셨습니다.

 

이제 마지막으로 ansible로 바꾸는 작업을 진행해 보도록 하겠습니다

 

 


Ansible이란?

인프라스트럭처 자동화 툴 중 하나로서, 서버, 네트워크, 애플리케이션 등을 자동화하고 관리하기 위한 오픈소스 소프트웨어입니다. Ansible은 특수한 에이전트가 필요하지 않고 SSH 프로토콜을 이용하여 원격 서버에 명령을 전송하고 작업을 수행 합니다.

 

Ansible은 Playbook을 사용하여 원격 서버에 작업을 수행하면 playbook은 ymal파일에 정의 되어 있습니다.

짧게나마 써본 경험으로는 같은 환경을 구성해야하는 서버가 많을때 직접하지 않고 ansible로 자동화하여 구성하면 빠르게 끝나는것 같습니다!

 

 


 

 

Ansible 설치하기

 

ansible을 사용하기 위해 인스턴스 및 도커를 설치해볼께요! 도커를 설치하는 이유는 도커 이미지를 만들기 위해서 사용합니다.

 

아래글에 가시면 도커 및 인스턴스를 생성하는 방법을 보실 수 있어요!!

도커 및 인스턴스 생성

 

도커 및 인스턴스가 생성되었다면  아래 명령어로 ansible을 설치하겠습니다

sudo apt install ansible

 

설치가 완료 되었다면 Inventory를 설정하겠습니다

 

여기서 Inventory란 쉽게 이야기 하면 Ansible서버가 관리하고 명령을 내리는 서버주소를 보관하는 곳이라고 생각하면 됩니다.

 

Inventory위치는 /etc/ansible/hosts입니다. 해당 파일에 관리할 서버를 입력해주시면 됩니다. 

관리할 서버

 

 

여기서 중요한점!!!!

위에서 말한것처럼 Ansible은 ssh통신을 합니다. 즉 내가 관리할 대상과 ssh통신이 가능해야합니다!!!

 

앞에 목록을 따라 오셨다면 키를 생성하고 , 키를 원격서버에 저장하는 방법을 아실꺼에요!!

 

해당 방식을 ansible -> green , ansible -> nginx , ansible -> blue , nginx-> green , nginx->blue , jenkins->ansible 이렇게 접근이 가능하게 먼저 설정을 해주셔야 합니다!!!

 


 

Jenkins에 안시블 설정하기

어디서 많이 보셨죠?!

 

 

Nginx설정할때 봤던 화면이에요!

 

Dashboard > Jenkinse 관리 > System에 들어가셔서 Ansible서버에 주소를 입력해주시고 TestConfiguration을 눌러주세요!!

만약 Success가 나왔다면 성공적으로 연결이 되었습니다

 

여기까지가 Jenkins와 Ansible을 연결하기가 끝이 났습니다 간단하죠!

 

 




Ansible Playbook 만들기

 

젠킨스 파이프 라인에서 수행될 playbook을 한번 만들어 보도록 할게요!!

 

만들어진 playbook은 ansible서버에 위치해야합니다.

 

젠킨스가 ansible에 ssh명령으로 실행할 예정이기 때문입니다.

 

 

1. install-docker-playbook.yml

- name: Install Docker on Ubuntu    // 해당 Playbook에 최상위 이름
  hosts: all                        // inventory에서 관리되는 서버에게 모두 적용하겠다
  become: yes                      // 관리자 권한 으로 실행
 
  tasks:                          // 작업을 수행하기 위한 단위로 구성된 실행 가능한 코드 블록
   - name: apt-update            // apt-update
     become: yes
     apt:
       update_cache: yes         // apt-update를 하는 구문

   - name: install-package      // docker 설치시 필요한 패키지 설치
     become: yes
     apt:
       name:
         - apt-transport-https
         - ca-certificates
         - curl
         - gnupg-agent
         - software-properties-common

   - name: Download Docker GPG key    // gpg key설치
     get_url:
      url: https://download.docker.com/linux/ubuntu/gpg
      dest: /tmp/docker.gpg
     become: yes


   - name: regist-repository        // apt repository 설정
     become: yes
     apt_repository:
      repo: 'deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable'
      state: present

   - name: second-apt-update        // apt-update
     become: yes
     apt:
        update_cache: yes

   - name: install-docker           // docker 설치
     become: yes
     apt:
       name:
         - docker-ce
         - docker-ce-cli
         - containerd.io

   - name: docker-chmod             // docker.sock 권한 변경
     become: yes
     file:
        path: /var/run/docker.sock
        mode: '0666'

   - name: install-docker-compose    // 도커 컴포즈 다운로드
     become: yes
     shell: |
        sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
        sudo chmod +x /usr/local/bin/docker-compose

   - name: docker-compose-chmod      // docker-compose 권한 변경
     become: yes
     file:
        path: /usr/local/bin/docker-compose
        mode: u+x

   - name: link-docker-compose
     become: yes
     file:
         src: /usr/local/bin/docker-compose
         dest: /usr/bin/docker-compose
         state: link

   - name: check-docker-version
     command: docker --version

   - name: check-docker-compose-version
     command: docker-compose --version
     
   - name: Install-pip
     become: yes
     raw: |
        apt update
        apt install -y python3-pip
     changed_when: false

   - name: Install Docker package
     pip:
       name: docker
       state: present
     become: yes
     changed_when: false

 

우선 쉽게 생각하시면 기존에 우분투 서버에서 도커를 설치하는 명령어를 그대로 나열했다고 생각하시면 됩니다!

playbook을 만드는 방법은 각각의 작업의 이름을 정하고 수행할 명령어들을 ansible이 제공하는 문법에 맞게 사용하시면 됩니다.

 

 

2. docker-image-create.yml

- name: copy-jar                     
  hosts:
   - blue                 // inventory에서 blue , green에서 만 실행하겠다
   - green 
  become: true
  tasks:
    - name: copy
      copy:                // inventory에 지정된 서버로 파일을 copy
        src: app.jar       // 현재 위치의 jar파일을 green , blue서버에 /home/ubuntu/app.jar로 복사하겠다
        dest: /home/ubuntu/app.jar

    - name: copy-docker-file
      copy:
        src: dockerfile    // 현재 위치에 있는 dockerfile을 green , blue서버에 copy
        dest: /home/ubuntu/dockerfile
   
    - name: image-delete
      command: docker rmi back_server:latest // 이미 생선된 도커이미지가 있다면 삭제
      ignore_errors: yes

    - name: build-image  // 도커 이미지 빌드
      docker_image:
       build:
        path: /home/ubuntu/
       name: back_server:latest
       force_tag: yes

 

3. deploy.yml

해당 코드 블럭을 너무 길기 때문에 조금씩 잘라서 설명 하겠습니다.

- name: move-file                    
  hosts: blue:green                 
  tasks:
   - name : copy-move                 
     copy:
          src: /home/ubuntu/app
          dest: /home/ubuntu/
          
   - name: add-permission
     become: yes
     become_method: sudo
     file:
      path: /home/ubuntu/app/docker-compose.yml
      mode: '+x'

move-file

해당 작업은 blue green서버를 대상으로 현재 ansible에 있는 app을 copy를 합니다.

여기서 copy는 전송이라고 생각하시면 됩니다.

 

add-permission

해당 작업은 app에 들어있는 docker-compose의 실행권한을 변경합니다.

 

 

- name: move-nginx
  hosts: nginx
  tasks:
   - name : copy-nginx-conf    
     copy:
          src: /home/ubuntu/nginx/
          dest: /home/ubuntu/nginx/

   - name: add-permission
     become: yes
     become_method: sudo
     file:
      path: /home/ubuntu/nginx/conf.d/docker-compose.yml
      mode: '+x'

copy-nginx-conf

해당 작업은 nginx서버를 대상으로 현재 ansible에 있는nginx을 copy를 합니다.

여기서 copy는 전송이라고 생각하시면 됩니다.

 

add-permission

해당 작업은 nginx/conf.d 에 들어있는 docker-compose의 실행권한을 변경합니다.

 

 

 

- name: check-app-status
  hosts: blue
  tasks:

    - name: check-container-status
      shell: |
        docker ps -q --filter "name=server_1"
      register: container_status
      ignore_errors: yes

    - name: create-current-app
      become: yes
      shell: echo "blue" > /home/ubuntu/current.txt
      when: container_status.stdout != ""
      delegate_to: 52.79.99.80

    - name: create-current-app
      become: yes
      shell: echo "green" > /home/ubuntu/current.txt
      when: container_status.stdout == ""
      delegate_to: 52.79.99.80

 
    - name: run-docker-compose-on-app1
      become: yes
      shell: |
             cd /home/ubuntu/app &&
             docker-compose up -d
      when: container_status.stdout != "" 
      delegate_to: 3.38.126.146

    - name: run-docker-compose-on-app
      become: yes
      shell: |
             cd /home/ubuntu/app &&
             docker-compose up -d
      when: container_status.stdout == ""

check-container-status

blue서버를 대상으로 현재 server_1컨테이너가 구동중인지 확인합니다.  그 결과값을 register이라는 문법을 통해 container_status에 결과를 저장합니다.

 

create-current-app

container_status에 저장된 값의 stdout != "" 인경우는 blue에서 현재 컨테이너가 돌고 있음을 의미합니다.

즉 조건문이라고 생각하시면 됩니다. conatiner_status.stdout !=""인 경우에만 실행됩니다.

 conatiner_status.stdout !="" 맞다면 delegate_to라는 명령어를 통해 52.79.99.80(nginx서버)에 ssh통신으로 echo "blue" > /home/ubuntu/current.txt를 실행합니다!

stdout ==""인경우에는  delegate_to라는 명령어를 통해 52.79.99.80(nginx서버)에 ssh통신으로 echo "green" > /home/ubuntu/current.txt를 실행합니다

 

rund-docker-compose-on-app

container_status에 저장된 값의 stdout != "" 인경우는 delegate_to라는 명령어를 통해 3.38.126.146(nginx서버)에 ssh통신으로 docker-compose를실행합니다!

 

rund-docker-compose-on-app

container_status에 저장된 값의 stdout == "" 인경우는 blue서버 에서 docker-compose를 실행합니다

 

 

- name: update-nginx-config
  hosts: nginx
  become: yes
  tasks:

    - name: check-container-status
      shell: cat /home/ubuntu/current.txt
      register: current
      ignore_errors: yes

    - name: run-docker-compose-on-nginx
      become: yes
      shell: |
             cd /home/ubuntu/nginx/conf.d &&
             docker-compose up -d
  
    - name: update-nginx-blue
      command: mv /home/ubuntu/nginx/conf.d/nginx-blue.conf /home/ubuntu/nginx/conf.d/nginx.conf
      when: current.stdout == "green"

    - name: update-nginx-green
      command: mv /home/ubuntu/nginx/conf.d/nginx-green.conf /home/ubuntu/nginx/conf.d/nginx.conf
      when: current.stdout == "blue"

    - name: reload-nginx
      command: docker exec nginx_server nginx -s reload

 

check-container-status

nginx가 설치되어 있는 서버에서 current.txt를 읽어서 current에 저장을 합니다.

 

run-docker-compose-on-nginx

docker-compose로 nginx를 실행 시킵니다.

 

update-nginx-blue

current에 저장된 값이 green이면 nginx-blue.conf를 nginx.conf로 변경합니다.

 

update-nginx-blue

current에 저장된 값이 green이면 nginx-green.conf를 nginx.conf로 변경합니다.

 

reload-nginx

nginx서버를 리로드 시킵니다.

 

- name: stop-docker-compose-on-app1
  hosts: green
  tasks:

    - name: check-container-status
      shell: cat /home/ubuntu/current.txt
      register: current
      ignore_errors: yes 
      delegate_to: 52.79.99.80

    - name: stop-app1
      become: yes
      shell: |
             cd  /home/ubuntu/app/ &&
             docker-compose  down
      when: current.stdout == "green"

- name: stop-docker-compose-on-app
  hosts: blue
  tasks:

    - name: check-container-status
      shell: cat /home/ubuntu/current.txt
      register: current
      ignore_errors: yes
      delegate_to: 52.79.99.80

    - name: stop-app
      become: yes
      shell: |
              cd /home/ubuntu/app/ &&
              docker-compose down
      when: current.stdout == "blue"

check-container-status

nginx서버로 부터 ssh통신(delegate_to)을 통해서 current.txt 읽어서 current에 저장합니다.

 

stop-app1

current의 값이 green이면 green서버에 있는 도커 컨테이너를 중지 합니다.

 

check-container-status

nginx서버로 부터 ssh통신(delegate_to)을 통해서 current.txt 읽어서 current에 저장합니다.

 

stop-app1

current의 값이 blue이면 blue서버에 있는 도커 컨테이너를 중지 합니다.

 

이렇게 deploy.yml파일이 끝이 났습니다.

 


 

 

DockerFile 만들기

 

stage('install-docker') {
            steps {

                sshagent(['13.125.205.132-ssh']) {
                    sh 'ssh ubuntu@13.125.205.132 "ansible-playbook install-docker-playbook.yml"'
                }

            }
        }
        stage('build-image') {
            steps {
                script {
                    sshagent(['13.125.205.132-ssh']) {
                        sh 'scp app.jar ubuntu@13.125.205.132:/home/ubuntu/'
                        sh 'scp dockerfile ubuntu@13.125.205.132:/home/ubuntu/'
                        sh 'ssh ubuntu@13.125.205.132 "ansible-playbook docker-image-create.yml"'
                    }
                }
            }
        }

        stage('deploy') {
            steps {
                script {
                    sshagent(['13.125.205.132-ssh']) {
                        sh 'scp -r nginx ubuntu@13.125.205.132:/home/ubuntu/'
                        sh 'scp -r app ubuntu@13.125.205.132:/home/ubuntu/'
                        sh 'ssh ubuntu@13.125.205.132 "ansible-playbook deploy.yml"'
                    }
                }
            }
        }

각각의 stage에서 필요한 파일들을 ansible 서버로 옮기고 그 stage에 맞는 yml파일을 실행시킵니다.

 

install-docker

ssh통신으로 ansbile서버에서 install-docker-book.yml을 실행 시킵니다.

 

build-Image

sh 통신으로 app.jar 파일과 dockerfile을  ansible 서버로 전송합니다.

그 이후 ansible명령어로 docker-image-create.yml을 실행합니다.

 

deploy

sh 통신으로 nginx구성 파일과 app구성파일을  ansible 서버로 전송합니다.

그 이후 ansible명령어로 deploy.yml을 실행합니다.

 

 

이제 모든 설정이 완료 되었습니다!!!!!

 

Gitea에 push를 하고 stage를 확인하시면 자동적으로 ansible을 호출하고 blue/green배포를 하시는걸 볼 수 있어요!!

 

 

 

 

728x90
반응형