인프라 구축하기

안준성·2024년 4월 27일

Project::BoardPick

목록 보기
8/11
post-thumbnail

무릇 공부도 책상 정리가 우선인 법.
본격적인 개발에 앞서 인프라를 구축해보자.

전체적인 구조로는
Docker container 위에서 백엔드 서버가 돌아가고
AWS EC2에서 이를 호스팅한다.
DB는 Amazon RDS를 사용해서 연결해줬다.
또한 GitHub Actions workflow로 CI/CD를 구축했다.

CI/CD 파이프라인은
push or pull request 발생 시
docker build & test -> Docker Hub로 push -> AWS EC2에서 pull -> 컨테이너 재실행
순으로 구성했다.

이를 위해 필요한 각종 설정들에 대해 알아보자.


Dockerfile

먼저 나의 Spring 프로젝트를 빌드해줄 Dockerfile을 작성한다.
자세한 작성법은 나도 잘 모르고 그냥 Spring Boot Docker를 참고했다.

아래는 내 Dockerfile

FROM eclipse-temurin:17-jdk-alpine
VOLUME /tmp
COPY /build/libs/*SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

아 참고로 여기서 jdk로 eclipse-temurin을 쓰는데
이게 m1 mac 기준으로 호환이 안돼서
나중에 빌드할 때 --platform linux/amd64 옵션으로
타킷 플랫폼을 명시해줘야 했다.


AWS EC2

백엔드 서버를 호스팅할 인스턴스가 필요하다.
나는 가난하기 때문에 아이디를 새로 파서 프리티어를 이용해준다.

EC2 인스턴스를 생성해서 각종 설정들을 해주면 끝
(나도 다른 블로그 보고 따라했다.)

아 미리 말하자면 서버에 docker도 깔아야 한다.
여러분들이 충분히 할 수 있다고 믿지만
하나 팁을 주자면
sudo amazon-linux-extras install docker 요놈은 이제 안 먹고
대신 sudo dnf install docker로 해줘야 한다.

그런 다음은 당연하게도 도커를 실행시켜줘야 한다.
sudo service docker start

그리고 나를 주인이라고 인식할 수 있게 사용자 그룹에 나를 포함시킨다.
sudo usermod -a -G docker $USER

나는 42서울 본투비루트 오너이기 때문에 쉽게 할 수 있었다.

Amazon RDS

우리 프로젝트에선 DB서버가 필요하다.

처음엔 직접 DB를 설치해서 돌리려고 했는데
팀원분이 RDS에 대해 알려주셨다.

RDS에 대해 쉽게 설명하자면
인터넷을 통해 접속하는 클라우드형 DB 서버 같은 느낌이다.

나는 Spring Data JPA를 쓸것이므로
application.properties에서 RDS의 엔드포인트와 포트번호를 설정해주면 끝이다.
(해당 블로그를 참고했다.)

확실히 옛날에 대학 다닐 때와 비교해보면 엄청 쉬워진거 같다.


GitHub Actions

이제 필요한 조각들은 다 세팅 됐으므로
하나로 묶을 차례다.

CI/CD 파이프라인을 구축할 수 있는 도구는 많지만
오늘은 GitHub Actions를 이용해보겠다. (사실 처음해봄)

일단 GitHub에서 기본 템플릿같은 걸 제공해준다.
나는 Docker Image 어쩌고를 선택했고
여기엔 docker build에 대한 workflow가 작성이 되어 있다.

이제 나에게 필요한 것은 Docker Hub로 push하는 것과
EC2 인스턴스에서 pull하고 컨테이너 재실행 까지 하는 것이다!

여기서부턴 GPT와의 협업에도 살짝 어려움을 느꼈지만
다행히 좋은 블로그를 발견해서 따라했다.
(사실 아직 안따라해봐서 좋은 블로그인지는 모름)

...

이거 보고 하다가 일단 빌드 방식도 나랑 좀 다르고
마지막에 if로 분기 처리하는 것도 좀 별론 것 같아서
좀 다르게 했다.

근데 계속 ssh 인증에러가 떠서 ssh 키도 계속 새로 넣어보고
방법이 잘못됐나 하고 방법도 계속 바꿔보다
yml파일 indent 때문에 또 스트레스 엄청 받고~

여튼 결국 알고보니 ssh 키가 문제였는데,
나는 ssh키가 인스턴스의 ~/.ssh/에 있는 놈인줄 알았는데
요건 public key였고
private key는 인스턴스 키페어 생성할 때 다운받아진 *.pem이었다.

여튼 우여곡절 끝에 드디어 초록불을 볼 수 있었다.
(금방 할 줄 알았는데 하루 종일 이것만 했다)

아래는 내 workflow yml 파일

name: CI/CD

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]

env:
  IMAGE_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/boardpick-server:latest
  CONTAINER: boardpick-server

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build the Docker image
        run: docker build . --platform linux/amd64 --file Dockerfile --tag ${{ env.IMAGE_TAG }}

      - name: Login to Docker Hub
        run: echo "${{ secrets.DOCKERHUB_ACCESS_TOKEN }}" | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin

      - name: Push the Docker image
        run: docker push ${{ env.IMAGE_TAG }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: pull and re-run
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
          script: |
            echo "${{ secrets.DOCKERHUB_ACCESS_TOKEN }}" | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
            docker stop ${{ env.CONTAINER }} || true
            docker rm ${{ env.CONTAINER }} || true
            docker pull ${{ env.IMAGE_TAG }}
            docker run -p 80:8080 -d --name ${{ env.CONTAINER }} ${{ env.IMAGE_TAG }}

여기서 docker run -p 80:8080
AWS EC2의 80포트를 컨테이너 내부의 8080포트에 바인딩해주는 작업이다.

이게 중요했던게
EC2의 보안그룹 인바운드로 내 IP에서의 HTTP 요청만 허용해놨었는데
이게 기본적으로 80포트고,
컨테이너 내부의 스프링 애플리케이션은 기본적으로 8080포트라서
이를 바인딩해줘야 http://EC2-엔드포인트:80를 통해
백엔드 서버로 접속할 수 있었다.

뭐 삽질은 많이 했지만
그래도 덕분에 여기 들어있는 내용에 대해 많이 파악하고 넘어갈 수 있었다.


최종 결과

DB connection 및 서버 접속


간단해보이지만 무려
보안그룹 + 포트 바인딩 + DB connection의 콤비네이션이다.

System Architecture

workflow

profile
안녕하세요

1개의 댓글

comment-user-thumbnail
2024년 7월 15일

인프라 어려워요잉

답글 달기