[Tistory] PLANIT 리팩토링 – CI/CD 구축하기

원글 페이지 : 바로가기

PLANIT, ‘ 관광정보 공공데이터를 사용한 여행 정보 제공 서비스’를 만들었다. 그 중 내가 대표적으로 담당한 기능은 hotplace 게시글 기능이었다. 다녀온 관광지에 대한 후기를 작성할 수 있고, 그 후기를 지역 별로 모아보는 기능이었는데, 전체 조회 페이지에서 후기글에 담겨져 있는 사진을 모두 보여주다보니 고화질 사진을 업로드 하지 못하고 업로드 할 수 있는 사진 크기를 제한해야만 했다. 그래서 파일 업로드 기능을 AWS S3 + Lambda를 사용해 개선하기로 마음 먹었고, 그 김에 미루어두었던 CI/CD 공부를 함께 하며 AWS를 사용한 배포 환경을 더 완벽하게 구축해두고, 이후에 리팩토링을 진행해보기로 했다! S3 + Lambda를 제외하고 전체적으로 생각한 Build flow는 다음과 같다. 이를 구현하기 위해 Docker와 Github Action을 통한 CI/CD를 구현했다. 왜 Docker와 Github Action을 사용하는가? Docker는 컨테이너 기반의 오픈소스 가상화 플랫폼을 말한다. 배에 싣는 화물 수송용 컨테이너처럼 서버에서도 다양한 OS환경, 여러 프로그램들을 화물과 비유하여 컨테이너에 싣고 여러 곳으로 운반하여 배포하는 것이다. 이러한 도커를 사용하는 이유는 다음과 같다. 독립적인 개발 환경을 보장한다 ( 서버 설정에 대한 부분을 도커 컨테이너 위에서 진행한다면, 도커 컨테이너에 여러 소프트웨어를 설치하고, 설정 파일을 수정해도 호스트 OS에는 영향을 전혀 주지 않는다. ) 배포 서버, 개발 서버 모두 동일한 환경에서 실행이 가능하다 ( 개발 시에 컨테이너 내부에서 작업 후에 배포하려고 한다면, 이 내부 작업을 ‘도커 이미지’ 라고 하는 일종의 패키지로 만들어 배포 서버에 전달 ) Github Action은 대표적인 CI/CD 툴이다. CI/CD는 지속적 통합(Continuous Integration) 및 지속적 전달(Continuous Delivery) 또는 지속적 배포(Continuous Deployment)를 나타내는 용어로, 소프트웨어 개발 및 배포 프로세스를 자동화하고 지속적인 품질 향상을 도모하기 위한 방법이다. CI/CD가 성공적으로 구축되면 간단한 코드 변경이 정기적으로 마스터에 커밋되고, 자동화된 빌드 및 테스트 프로세스를 거치며 다양한 사전 프로덕션 환경으로 승격되며, 문제가 발견되지 않으면 최종적으로 배포된다. 이러한 일련의 작업이 자동으로 수행되므로, 신속한 배포 및 빠른 피드백이 가능하다. Docker 설정 0. 로컬 및 배포를 수행 할 EC2 Instance에 docker 설치 아래는 ec2에서 docker를 설치하는 코드다. $ sudo apt-get update
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add –
$ sudo add-apt-repository \
“deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable”
$ sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io
$ docker -v 1. Docker Hub 가입/로그인 및 Repository 생성 Public Repository는 여러 개 생성 할 수 있지만, Private Repository는 계정 당 하나만 생성할 수 있기 때문에 repository는 public으로 생성했다. 2. local에서 jar 파일 정상적으로 생성되는 지, Build가 가능한 지 확인하기 maven 환경에서는 pom.xml 파일이 있는 디렉토리에서 mvn package 명령어를 통해 프로젝트를 build 할 수 있다. 성공적으로 실행하면 build success 와 함께 프로젝트 내 package 폴더에 jar 파일 정상적으로 생성 된 것을 확인할 수 있다. 프로젝트를 java -jar target/enjoytrip-0.0.1-SNAPSHOT.jar 명령어를 통해 실행하고, 성공하면 다음 절차로 넘어간다 🛠️ Trouble Shooting – mvn not found 에러 Intellij와 같은 IDE에서는 기본적으로 Maven에 대한 지원을 해주기 때문에 따로 명령어를 사용하지 않아도 가능하지만 터미널에서 명령어를 직접 사용할 경우에는 사용자가 직접 PC에 설치를 해주어야 한다. (mac에서는 brew install mvn으로 설치 가능하다) 3. Dockerfile 작성 및 실행 1) Dockerfile 작성 FROM openjdk:17-alpine
COPY target/enjoytrip-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT [“java”, “-jar”, “app.jar”] FROM openjdk:17-alpine : Docker를 올릴 때 jdk17 버전을 사용하겠다는 선언 COPY target/enjoytrip-0.0.1-SNAPSHOT.jar app.jar : 프로젝트 빌드 후 생성 된 jar 파일을 컨테이너의 루트 디렉토리에 app.jar의 이름으로 복사 ENTRYPOINT [“java”,”-jar”,”/app.jar”] : 도커파일이 도커엔진을 통해서 컨테이너로 올라갈 때, 도커 컨테이너의 시스템 진입점이 어디인지를 선언하는 커맨드. 이 커맨드는 java -jar 명령어를 이용해서 컨테이너의 루트에 위치한 app.jar을 실행하라는 뜻이다. 2) Docker image 생성 그리고 docker는 다음과 같은 명령어를 사용해서 build 하고, docker image가 생성된다. docker build -t enjoytrip . –platform linux/x86_64 M1칩의 경우 linux/arm64/v8 베이스로 이미지 빌드를 하는데, 아직 arm64의 경우 과도기라 해당 하는 이미지가 없는 경우가 있어서 –platform linux/x86_64 을 덧붙여서 플랫폼을 명시해주어야 한다고 한다. 3) Dockerhub push 그리고 이렇게 생성된 이미지 파일을 docker push {dockerhub 경로명} (이 프로젝트의 경우 docker push nueahx7674/planit) 명령어를 통해 Dockerhub에 push 할 수 있다. 아래 tags 부분을 확인하여, docker image가 dockerhub에 정상적으로 push 되는 것을 확인할 수 있다. Github Action을 통한 CD 구축 이렇게 docker에 이미지가 잘 올라가는 것을 확인 했으면, 이제는 master에 변동사항이 push 될 때마다 build 재실행 > docker push > ec2 배포가 적용 될 수 있도록 CI/CD를 구축하는 작업이 필요하다. 이를 위한 절차는 다음과 같다. 1. secrets 등록하기 프로젝트를 build 할 때 필요하지만 외부에 공개되면 안 되는 정보는 github repository의 secrets 에 등록할 수 있다. 레포지토리 Settings > Secrets and variables > Actions 에서 등록할 수 있다. 이 때 등록이 필요한 정보는 아래와 같다. DOCKER_ID : Docker-hub 이메일 DOCKER_PASSWORD : Docker-hub 비밀번호 DOCKER-REPO : Docke-hub Repository 이름 EC2_HOST : EC2 public IP address EC2_PRIVATE_KEY : EC2 key pair pem 키 값을 복사한 내용 EC2_USERNAME : EC2 인스턴스가 ubuntu라면 ubuntu, linux라면 ec2-user PROPERTIES_xxx : properties 파일 내용 그리고 이렇게 등록한 정보는 Github action을 생성한 후 작성할 yml 파일에서 ${{ 변수명 }} 의 형태로 사용 가능하다. 2. Github action 생성 프로젝트 Repository에서 Actions > Java with Maven을 선택하고 Github Action 을 생성한다. 그리고 CI/CD 수행을 위한 yml 파일을 다음과 같이 작성한다. # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: CD

on:
push:
branches: [ “master” ]
pull_request:
branches: [ “master” ]

jobs:
build:

runs-on: ubuntu-latest

steps:
– uses: actions/checkout@v3
– name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: ’17’
distribution: ‘temurin’
cache: maven

– name: Make application.properties
run: echo “${{ secrets.APPLICATION }}” > ./src/main/resources/application.properties
shell: bash

– name: Build with Maven
run: mvn -B package –file pom.xml

– name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

– name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ secrets.DOCKER_REPO }}:latest

– name: Setup SSH
uses: webfactory/ssh-agent@v0.5.3
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

– name: Deploy to AWS EC2
run: |
ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} <

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다