본문 바로가기
걸어서 개발 속으로

LFG 배포 자동화

by puy0 2023. 3. 26.

https://github.com/geonho1943/LFG

 

GitHub - geonho1943/LFG: "Looking For Group" service

"Looking For Group" service. Contribute to geonho1943/LFG development by creating an account on GitHub.

github.com

 

만들고 있는 LFG 서비스를 서버에 배포했다

 

배포하기전에는

새로운 기능을 완성한 프로젝트를

이상이 없는지 확인 후 커밋 하면 끝이었다

 

하지만 지금은

빌드하고 서버에 빌드파일을 교체, 실행 해줘야 한다

빌드 > FTP 접속 > 빌드 파일 추가 > ssh 접속 >

기존 서비스 로그 확인 > 서비스 프로세스 종료 > 프로세스 종료 확인 >

추가한 빌드 파일 권한 변경 > 추가한 빌드 파일 실행  > 새로운 서비스 로그 확인 > 서비스 정상작동 확인

 

 

같은 과정이 반복되다 보니 자동으로 배포가 되도록 구현하고 싶었다

 

그리고 서비스에 큰 수정사항이 없을때

서버를 갱신할 필요를 느끼지 못했는데

그렇게 갱신하지않을경우 깃허브의 프로젝트 내용과

실제 실행중인 서버의 내용이 다르게 되기때문에

배포 자동화를 도입 하기로 했다

 

 

처음시도하는 자동 배포기 때문에

공부에 시간을 아끼지않았다

구글링, 유튜브, 기술 블로그, chatgpt, 공식문서 등등 다양한 방법으로

서칭했고 더블체크 했다

 

 

배포자동화를 알게 되면서

CI/CD 에 대해서도 알아봤는데

CI/CD(Continuous Delivery)의 CD와

CD(Continuous Deployment) 의 CD

둘을 구분하고 있었다

배포 deploy가 중요한것이다

 

나의 경우 어떻게 프로젝트를 만들어나갈지 고민했다

빌드시 자동배포를 우선목표로 하고

자동배포의 경우 분명 실수가 생겨 기능에 문제가 생길수 있으니

test case를 도입하여

좀더 신뢰 할수 있는 환경을 목표로 잡았다

 

 

 

 

자동배포에 필요한 개념서칭

자동화 툴 선택 - github action

github action 의 사용법 - actions quickstart

원하는 기능구현에 필요한 액션 - ssh-scp-ssh-pipelines

기능 구현 하기

    프로잭트 리포지터리 접근

    Java JDK 설치

    gradlew 로 빌드

    ssh 접속

    빌드파일 전송

    필요 권한으로 빌드파일 백그라운드 실행

배포 자동화 성공

 

 

 

webhook는 외부 클라이언트에 알람을 주는등의

기능으로 별도의 툴이 아니라 push 이벤트의 트리거를 해주는 역할이다

Jenkins 나 CircleCI 를 사용할까 생각했지만

배포만을 위한 외부 서버(인스턴스)가 이상적인 상황이 아니라서

github action이 나에게 가장 적합했다

단점이라면 github 에 public 리포지터리가 있어야

github action을 사용 할수 있다는것이다

나의경우에는 이미 github/public에 올리고 있었기 떄문에 해당사항이 아니다

 

지금 오라클은 워크플로를 지원하지 않는다

aws가 이렇게 반갑다니,,

최근에 오라클로 옮겼는대 여기서 aws가 보인다 ㅠㅠ

아쉽지만 직접 워크플로우를 작성해 준다

 

 

+ chatgpt를 시도해보았다

더보기

chatgpt는 간혹 거짓정보를 알려줄때가 있으니 하나하나 검증하면서 양식을 맞춰가야 한다

거짓말gpt

oracleLinux8 이라는 단어는 공식문서 자체에도 없도 지원하지않는다..

직접 작성하는것이 빠를것 같아 chatGPT는 다음에 사용하기로 했다

 

 

직접 공식문서의 quick start 를 해봤다

첫 Action 성공

https://docs.github.com/en/github-ae@latest/actions/quickstart

 

Quickstart for GitHub Actions - GitHub AE Docs

Introduction You only need a GitHub repository to create and run a GitHub Actions workflow. In this guide, you'll add a workflow that demonstrates some of the essential features of GitHub Actions. The following example shows you how GitHub Actions jobs can

docs.github.com

 

이제 배포를 위한 워크플로우를 작성해보자

아래는 내가 사용할 엑션들의 마켓플레이스 래퍼런스 링크다

https://github.com/marketplace/actions/get-or-create-an-oracle-cloud-infrastructure-registry-ocir-repository

 

Get or create an Oracle Cloud Infrastructure Registry (OCIR) repository - GitHub Marketplace

Create or return the URI and OCID for an existing Oracle Cloud Infrastructure Registry (OCIR) repository

github.com

 

+ 오라클의 권장 연결방법 OCI CLI 시도

더보기

아래는 워크플로를 작성하기위한 변수들의 공식문서 안내링크 이다

참고해서 그때그때 적용해주면 된다.

리전 변수 공식문서

https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/clienvironmentvariables.htm

 

CLI Environment Variables

The CLI respects and applies configurations specified by option, environment variable, or OCI config file entry in the following order of precedence: The value specified in the command option. The value specified in the environment variable. The value spec

docs.oracle.com

춘천 리전 을 복사해서 변수에 입력

 

이런식으로 변수들을 대입해주면 푸시가 일어 났을때

자동 배포가 진행될것이다

 

하지만 실패했다

OCI CLI 를 사용 하면 공식 지원하는 자동화 방법 이다 보니

가장 권장되는 방법일것이라 생각했지만

연결에 필요한 작업이 너무 복잡했다

리전부터 테넌시 등등..

기존의 배포 절차와 비슷하게, 간단하게 접근하기위해 다른 방법을 찾아봤다

 

 

 

그래서 다른 방법을 찾았다

 

우선 github action 의 ssh 연결에 가장 많이 사용하는

appleboy/ssh-action 이다

 

https://github.com/marketplace/actions/ssh-remote-commands

 

SSH Remote Commands - GitHub Marketplace

Executing remote ssh commands

github.com

 

+ appleboy/ssh-action 시도

 

더보기
- name: multiple command
  uses: appleboy/ssh-action@v0.1.8
  with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.KEY }}
    port: ${{ secrets.PORT }}
    script: |
      whoami
      ls -al

appleboy/ssh-action 의 연결을 위한 주요 스크립트다

uses의 0.1.8 버전은 현재의 최신 버전이며

직접 사용할때는 마켓플레이리스트에서 최신버전과 동일한지 확인 해야 하고

버전별 바뀐 스크립트 규칙을 확인해야 한다

변수를 바인딩하여 ssh 접속의 기본 정보들을 전달 한다

script: | 후에 명령어는 기존 터미널에서 사용하는 셀 명령어 그대로 입력해서

사용하기 매우 편리하다

빌드된 파일을 전송할때도 ftp를 사용하지않고 put으로 해결할수 있다

 

나는 ftp 를 이용하거나 파일 복붙이 있을시 pbcopy를 사용하는등등 put 을 사용 해본적이 없었고

나에게 익숙하지않아서 일수도 있지만

더 좋은 액션을 찾기로 했다

 

 

 

더 좋은 액션을 찾을수 있었다

https://github.com/marketplace/actions/ssh-scp-ssh-pipelines 

 

ssh-scp-ssh-pipelines - GitHub Marketplace

Pipelines: ssh -> scp -> ssh

github.com

 

결과적으로 내가 결정하게된 액션으로

 

ssh 기반의 파일전송 방법인 scp를 기준으로 그 행위의 앞,뒤에 스크립트를 작성할수있다

빌드파일 전송의 앞뒤로 스크립트를 분리 할수있으니

한눈에 어떤 디랙터리에서 무엇을 하는지 알기 쉽다고 판단 했다

또한 이 액션으로 ssh 연결과 빌드파일전송 문제를 해결했다

 

가장 큰 해결 사항인 서버 인스턴스에 ssh접속과 파일 이동을 성공 했으니

부수적인 사항을 해결하면 배포 자동화가 마무리 된다

 

 

- 기능 구현 하기

    프로잭트 리포지터리 접근

    Java JDK 설치

    gradlew 로 빌드

    ssh 접속

    빌드파일 전송

    필요 권한으로 빌드파일 백그라운드 실행

배포 자동화 성공.

 

- 작성한 셀스크립트 yml 파일 -

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: Create Properties
        uses: actions/checkout@v3
      - run: touch ./src/main/resources/application-awsMariaDB.properties
      - run: echo "${{ secrets.APPLICATION_AWSMARIADB_PROPERTIES }}" > ./src/main/resources/application-awsMariaDB.properties
      - run: cat ./src/main/resources/application-awsMariaDB.properties

      - name: Setup JDK 17
        uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: '17'

      - name: Build with Gradle
        run: |
          chmod +x gradlew
          ./gradlew build
      - name: ssh connection
        uses: cross-the-world/ssh-scp-ssh-pipelines@latest
        with:
          host: ${{ secrets.HOST }}
          port: ${{ secrets.PORT }}
          user: ${{ secrets.USER }}
          key: ${{ secrets.KEY }}
          scp: |
            ./build/libs/LFG*-SNAPSHOT.jar => /home/support800/server/
          last_ssh: |
            cd /home/${{ secrets.USER }}/server/
            sudo -S sh -c "nohup java -jar LFG*-SNAPSHOT.jar &" <<< "${{ secrets.PW }}"

 

- name: Create Properties

 

uses: actions/checkout@v3

로 내 리포지터리를 사용할수 있도록 함과 동시에

문제점인 propertise 파일을 Repository secrets 변수 바인딩으로

해결해야 한다

gitignore 에 의해 유출되면 안되는,누락된 파일을 생성하는 부분이다

 

 

- name: Setup JDK 17

 

uses: actions/setup-java@v3

로 빌드에 필요한 Java 17 JDK 를 설치한다

 

 

- name: Build with Gradle

파일은 일반 사용자가 빌드 할수 있도록 권한설정과 함께

gradlew로 빌드 한다

 

 

- name: ssh connection

가장 시간이 많이 소모된 부분으로

uses: cross-the-world/ssh-scp-ssh-pipelines@latest 를 사용해

ssh 접속과 빌드된 파일의 이동, 실행 등을 수행하는

가장 중요한 부분이다

이 액션은 yml을 작성할때 github 마켓플레이스 에서 ssh 검색시 최상단에 추천해주는

액션이다

 

 

 

위의 과정을 구현 하는동안 3가지의 큰 문제점이 있었다

1. 프로잭트파일의 노출되어서는 안되는 환경변수들의 하드코딩을 피하기위한

propertise 파일을 gitignore 설정으로 리포지터리에 포함 시키지 않아

필수 정보들의 누락으로 빌드가 불가능한 상황

 

러너에서 생성된 파일은 스크립트가 끝나면 누군가에게 보여지거나 하지않기때문에

환경변수 파일을 만들어서 빌드하고 러너가 끝날시 버려지는 방식을 선택 했다

 

 

2. ssh 접속에 필요한 정보들을 정상적으로 받아올수 없어

ssh접속에 어려움을 겪었다 

Actions의 Repository secrets 를 사용했어야 하는데

Codespaces의 변수를 설정해서 한동안 고생 했다

UI 가 비슷해서 햇갈린것 같다..

 

수정된 파일의 경우 푸시를 통해서만 러너 실행이 가능 해서

하루에 2,30번 푸시를 하는경우도있었다

스크립트를 작성할때 미리 시도해볼수 있는 환경이었다면

더욱 과감하게 이것저것 시도 할수 있을것이라 생각했다

 

커밋,푸시 횟수의 기록이 남는다는것은 부담스러웠지만

연연하지않고 다수의 시도 끝에 배포 자동화에 성공 했다

 

 

3. 일반 사용자계정으로 tomcat 기본 포트(80)을 정상적으로 실행할수 없다

러너의 스크립트가 일반 사용자로 루트 권한을 이용해 빌드파일을 실행하는 방법으로 해결했다

github action log

 

이번 배포 자동화를 하면서 오린시간이 소요되었다

리눅스 명령어를 오래 사용하면서

자주사용하는 명령어만 사용하다보니

셀스크립트를 작성할때 다소 딜레이가 있었다

이번에 좋은 경험을 했다고 생각한다

 

계속해서 다양한 셀스크립트를 만들어본다면,

충분히 지금구현한 배포 자동화를 더 개선할수 있을것이라 생각한다

'걸어서 개발 속으로' 카테고리의 다른 글

내 서비스에 로그 적용  (1) 2023.05.06
로그 남기기  (0) 2023.05.03
오라클 인스턴스 생성 기록  (0) 2023.03.25
LFG서버 배포  (0) 2023.03.11
ChatGPT 에게 물어본 생성자 VS get/set  (0) 2023.03.02

댓글