이번에 새로 만든 홈서버도 장만했을 겸 해서 그 테스트로 전에 만든 간단한 스프링 서버를 스근하게 올려서 테스트를 해보려고 한다.
이번 과정을 통해서 그 동안 학부에서 들었던 컴퓨터 네트워크 지식을 어떻게 적용할 수 있는지 깨닫게 되었다.
요약:
1. tcp/ip + 포트 포워딩 + 라우터 등에 대한 지식
2. docker 와 github action 에 관한 관련 설정 파일과 세팅 등에 대한 지식
스프링 프르젝트 최상위 파일에서 해당 위치에 이미지를 빌드 위한 Dockerfile 을 생성 합니다.
# base image
FROM openjdk:17-jdk
# 빌드 파일의 경로
ARG JAR_FILE=build/libs/*.jar
# 빌드 파일을 app.jar 컨테이너로 복사
COPY ${JAR_FILE} app.jar
# jar 파일 실행
ENTRYPOINT ["java","-jar","/app.jar"]
다음으론 스프링 프로젝트 최상위 파일에서 .github/workflows/ 생성 후 해당 파일 안에 github action 을 설정할 [파일이름].yml 파일을 생성 합니다.
name: CI/CD
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
- name: Grant execute permission for gradlew
run : chmod +x gradlew
- name: Build with Gradle
run: ./gradlew clean build
- name: Build Docker & Push
run : |
docker login -u ${{ secrets.DOCKER_USERNAME}} -p ${{ secrets.DOCKER_PASSWORD }}
docker build --platform linux/arm64/v8 -t ${{ secrets.DOCKER_REPO }}/spring-app .
docker push ${{ secrets.DOCKER_REPO }}/spring-app
- name : Docker deploy
uses : appleboy/ssh-action@master
with :
host : ${{ secrets.HOST }}
username : ${{ secrets.USERNAME }}
key : ${{ secrets.SSH_PRIVATE_KEY }}
port : ${{ secrets.SSH_PORT }}
script: |
cd app
sudo rm concal.log
sudo docker stop $(docker ps -q) && sudo docker rm $(docker ps -a -q)
sudo docker image rm ${{ secrets.DOCKER_REPO }}/spring-app
sudo docker pull ${{ secrets.DOCKER_REPO }}/spring-app
sudo docker run -p 50000:8080 -d ${{ secrets.DOCKER_REPO }}/spring-app
sudo docker logs -f spring-app &> concal.log &
docker image prune -f
GitHub Actions 워크플로우 파일 분석
1. 워크플로우 트리거: 이 워크플로우는 `main` 브랜치에 푸시할 때 실행됩니다.
2. 빌드 작업:
- `ubuntu-latest` 환경에서 실행됩니다.
- `actions/checkout@v3` 액션을 사용하여 소스 코드를 체크아웃합니다.
- `actions/setup-java@v3` 액션을 사용하여 Java 17 버전을 설치합니다.
- `gradlew` 파일에 실행 권한을 부여합니다.
- `./gradlew clean build` 명령어로 Gradle을 사용하여 프로젝트를 빌드합니다.
3. Docker 이미지 빌드 및 푸시:
- Docker 레지스트리에 로그인합니다.
- `docker build` 명령어로 Docker 이미지를 빌드합니다.
- `docker push` 명령어로 Docker 이미지를 Docker 레지스트리에 푸시합니다.
4. 원격 서버에 배포:
- `appleboy/ssh-action@master` 액션을 사용하여 원격 서버에 SSH 접속합니다.
- 원격 서버에서 기존 Docker 컨테이너를 중지하고 삭제합니다.
- 새로운 Docker 이미지를 pull하고 실행합니다.
- 컨테이너 로그를 `concal.log` 파일에 저장합니다.
- 불필요한 Docker 이미지를 정리합니다.
추가 정보
- GitHub Actions는 소프트웨어 개발 워크플로우를 자동화할 수 있는 강력한 도구입니다.
- 이 워크플로우는 CI/CD 파이프라인을 구축하여 빌드, 테스트, 배포 프로세스를 자동화하고 있습니다.
- 다양한 액션을 사용하여 각 단계를 효과적으로 수행할 수 있습니다.
- 비밀 키와 같은 중요한 정보는 GitHub 리포지토리의 시크릿 기능을 사용하여 안전하게 관리할 수 있습니다.
해당 설정 파일에서 보이는 secrets.[변수 이름] 의 형태는 레포지토리 -> Settings -> Secrets and Variables -> Actions 에 들어가서 설정할 수 있다.
다음에는 이제 라즈베리파이에서 서버로 동작하기 위한 설정이 필요하다. 가장 중요한 것은 ssh 설정과 ssh 로 접근 하기 위한 라우터에서의 포트 포워딩이다.
먼저 라즈베리파이의 터미널에 접속하여서 ssh-keygen 을 통해서 ssh 키를 생성 후에 따로 추가 설정을 하지 않았으면 .ssh 디렉토리 생성 후 해당 디렉토리에 키가 저장이된다. 해당 디렉토리 안에는 id_rsa.pub 와 id_rsa 라는 파일 두 개가 생성이 될 텐데 id_rsa 는 ssh private key , id_rsa.pub 는 public key를 각각 저장하고 있다. 이 중 id_rsa.pub 키는 같은 위치에 authorized_keys라는 파일을 생성 후 해당 내용을 복사 하도록 하자.
이제 private key는 위의 Secrets and variables 에서 github action이 해당 서버에 ssh 접근 할 때 사용하도록 저장해주도록 하자. 여기에서는 SSH_PRIVATE_KEY로 저장을 하였다.
https://github.com/appleboy/ssh-action?tab=readme-ov-file
GitHub - appleboy/ssh-action: GitHub Actions for executing remote ssh commands.
GitHub Actions for executing remote ssh commands. Contribute to appleboy/ssh-action development by creating an account on GitHub.
github.com
다음은 외부 네트워크에서 해당 서버에 접속하도록 라우터에서 포트 포워딩을 설정해야한다. 터미널에서 route -n 을 통해서 라우터의 내부 ip 를 확인한 후에 해당 아이피를 인터넷 브라우저에서 입력하여 라우터 로그인 창을 띄운 후 로그인 하도록 하자. 보통 라우터마다 로그인 방식이 다르니 검색을 하여 자신의 라우터 모델에 따라 적용하도록 하자.
이제 포트 포워딩을 진행을 해야하는데 ifconfig 을 통해서 서버의 내부 아이피를 확인 한다. 우리는 ssh을 활용을 하고 있으니 22번 포트를 라우터의 8000 번 포트와 묶어주었다.(라우터의 포트는 다른 것으로 하여도 무방하다. 8000:22)
다음으로는 위의 github action 설정 파일에서 해주었으면 생략을 해도 좋은 파트다. 이제 이미지를 생성하여 컨테이너에 올렸을 때 도커 컨테이너와 서버의 포트를 맵핑을 진행을 해주어야 한다.
sudo docker run -p 50000:8080 -d ${{ secrets.DOCKER_REPO }}/spring-app
여기에서 볼 수 있는 것 처럼 -p 옵션을 통해서 컨테이너를 동작시킬 때 포트를 맵핑하는 것이 가능하다. 여기애서는 스프링 서버를 올릴 려고 하고 있는데 스프링부트는 기본적으로 톰캣을 사용하기에 톰켓의 기본 할당 포트인 8080 포트를 서버의 특정 포트로 할당한다. 여기서 중요한 것이 서버의 특정 포트는 위의 라우터 포트 포워딩을 통해서 한 번 더 라우터의 포트와 포워딩이 되어 있어야한다. 해당 서버의 포트와 물린 라우터의 포트는 우리가 외부에서 스프링 서버에 접근하기 위한 포트로 사용된다.
정리를 하자면
http://[라우터 IP]:[라우터 port]/[api] -> [라우터 port]:[서버 port] -> [서버 port]:[도커 port]
이런 식으로 포트포워딩을 진행해주어야지 외부에서 해당 도커 컨테이너로 접근이 가능하다.
[CI/CD] LLMOps / MLOps 찍먹해보기 (0) | 2024.05.16 |
---|---|
[홈서버] 홈서버 만들기 (0) | 2024.04.27 |