0. 환경
Spring Boot 3.xx
Java17
JDK corretto17
1. AWS EC2 인스턴스 생성
1) 이름 입력, Amazon Linux 선택
2) 키페어 생성
생성한 키페어는 따로 저장해서 보관해두자
3) 스토리지 구성
프리티어 기준 최대 용량인 30GB로 바꿔준다.
4) 인스턴스 생성
2. 보안그룹(인바운드) 규칙 편집
1) 인스턴스 ID를 클릭
2) 보안 탭 > 보안그룹 클릭
3) 인바운드 규칙 편집 클릭
4) 규칙 추가
다음 세 가지 규칙을 추가해준다.
꼭 MySQL일 필요는 없고, 자신이 사용하는 것에 맞게 선택해주면 된다.
없다면 사용자 지정 TCP를 선택해서 포트 범위를 직접 설정해준다 (ex. MongoDB라면 27017)
규칙을 모두 추가했으면 우측 하단의 '규칙 저장' 클릭
3. AWS EC2 접속
1) Git Bash 접속
Git Bash를 열고 다음 내용을 입력한다.
다른 계정이 아니라 ec2-user를 사용해야 한다.
ssh -i {키페어 경로} ec2-user@{퍼블릭IPv4}
나는 바탕화면에 .ssh라는 폴더에 my-ec2-key.pem을 저장했기 때문에 다음과 같은 경로를 가진다.
(ssh -i 를 적고 커서 부분에 pem 파일을 끌어다 놓으면 알아서 경로가 입력된다)
ssh -i /c/Users/{유저}/Desktop/.ssh/my-ec2-key.pem ec2-user@{퍼블릭IPv4}
접속에 성공하면 다음과 같이 뜬다.
4. AWS EC2에 도커 설치
Docker 설치
다음을 순서대로 수행한다.
//업데이트
sudo yum update -y
//도커 설치
sudo yum install docker -y
//버전 확인
docker -v
//도커 실행
sudo service docker start
//도커 그룹에 사용자 추가
sudo usermod -aG docker ec2-user
//도커 관련 권한
sudo chmod 666 /var/run/docker.sock
도커 그룹에 사용자를 추가했다면, 다음에 접속할 때는 sudo 없이 명령어를 입력할 수 있다. (ex: docker run hello-world)
5. Dockerfile 생성
루트 프로젝트 하위에 파일 생성
파일 내용은 다음과 같다.
FROM amazoncorretto:17
ARG JAR_FILE_PATH=/build/libs/*.jar
COPY $JAR_FILE_PATH app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Spring Boot + Docker + EC2 배포 내용이 궁금하다면 다음 포스팅을 보면 된다. 포스팅 이동
6. Github Actions 생성
1) Java with Gradle 선택
깃허브 레포지토리 > Actions 탭 > Java with Gradle Configure 클릭
클릭하면 다음과 같은 gradle.yml 파일이 생성된다.
파일명은 필요에 따라 변경하면 된다.
7. gradle.yml 작성
먼저 전체 스크립트를 보고 하나씩 뜯어보자.
name: CI/CD
on:
push:
branches: [ "main" ]
jobs:
CICD:
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'
## Create YML
- name : Create application-secret.yml File
run : |
echo "${{secrets.APPLICATION_SECRET_YML}}" > src/main/resources/application-secret.yml
find src
## Permission for gradlew
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
shell: bash
## Build Gradle
- name: Build with Gradle
run: ./gradlew build
## Build and Push to Docker Hub
- name: Docker build & push to Hub
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p "${{ secrets.DOCKER_PASSWORD }}"
docker build -f Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/{{ secrets.DOCKER_REPO }} .
docker push ${{ secrets.DOCKER_USERNAME }}/{{ secrets.DOCKER_REPO }}
## Deploy EC2
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ec2-user
key: ${{ secrets.PRIVATE_KEY }}
script: |
sudo docker rm -f $(sudo docker ps -qa) # Remove all running containers
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/{{ secrets.DOCKER_REPO }}
sudo docker run -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/{{ secrets.DOCKER_REPO }}
1) 워크플로우 트리거
on:
push:
branches: [ "main" ]
해당 Github Actions 플로우는 main 브랜치에 push가 발생할 때 수행된다.
2) Java 설정
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- actions/checkout@v3: 현재 브랜치의 저장소 코드 가져오기
- actions/setup-java@v3: 해당 액션을 통해 JDK를 설정
나는 17버전을 쓰고 있어서 java-version을 17로 설정했다.
3) .yml 파일 생성
- name : Create application-secret.yml File
run : |
echo "${{secrets.APPLICATION_SECRET_YML}}" > src/main/resources/application-secret.yml
find src
application.yml이나 properties에는 DB정보와 같은 민감 정보가 있어서 저장소에 올리지 않는 편이다.
나는 application.yml과 민감 정보를 가진 application-secret.yml을 분리했고, 저장소에는 application.yml만 있다.
프로젝트를 빌드하기 위해서는 application-secret.yml 파일이 필요하기 때문에 빌드 전에 생성해주자.
${{ secrets.APPLICATION_SECRET_YML }} 은 내가 설정해둔 secrets 값이다.
secrets는 다음과 같이 설정할 수 있다.
레포지토리 Settings 탭 > Secrets and Variables > Actions > New repository secret
이름을 APPLICATION_YML로 정하고 Secret 부분에 application-secret.yml 내용을 입력해준다.
나는 다음과 같은 secrets가 등록되어 있다.
- APPLICATION_SECRET_YML: application-secret.yml 파일 내용
- DOCKER_PASSWORD: 도커 비밀번호
- DOCKER_USERNAME: 도커 아이디
- DOCKER_REPO: 도커 레포지토리
- HOST: EC2 퍼블릭 IPv4
- PRIVATE_KEY: EC2 .pem 키 내용 (Git Bash에서 cat 명령어로 내용을 확인할 수 있다)
4) gradle 빌드
## Permission for gradlew
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
shell: bash
## Build Gradle
- name: Build with Gradle
run: ./gradlew build
./graldew build를 통해 빌드하기 전에, chmod +x ./gradlew를 통해 gradlew 스크립트에 대한 실행 권한을 허용해주었다.
처음에 안 해줬더니 허용 거부 오류가 떴었다.
5) 도커 허브에 이미지 업로드
## Build and Push to Docker Hub
- name: Docker build & push to Hub
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p "${{ secrets.DOCKER_PASSWORD }}"
docker build -f Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }} .
docker push ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }}
도커 이미지를 허브에 업로드 하기 위해 Dockerfile을 통해 이미지를 생성(build)하고 업로드(push)하는 과정이다.
6) EC2에 도커 이미지 기반 컨테이너 실행
## Deploy EC2
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ec2-user
key: ${{ secrets.PRIVATE_KEY }}
script: |
sudo docker rm -f $(sudo docker ps -qa) # Remove all running containers
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }}
sudo docker run -d -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }}
- appleboy/ssh-action@master: SSH를 사용하여 원격 서버에 연결하고, 해당 서버에서 스크립트 실행
이제 EC2에서 허브에 올린 이미지를 pull 받아서 EC2 서버로 가져와, 이미지를 기반으로 컨테이너를 실행하여 배포한다.
여기서 script를 보면, rm > pull > run 과정을 거치는데 다음과 같은 역할을 한다.
1. EC2 서버에 실행 중인 모든 Docker 컨테이너 종료 및 제거
2. Docker 이미지를 허브에서 EC2 서버로 가져오기
3. Docker 이미지 기반으로 컨테이너 실행
7) 브랜치에 Push
푸시하면 Actions 탭에서 해당 작업 확인할 수 있다.
8. 배포 확인
주소창에 {IPv4}:8080 을 입력해보면 정상적으로 배포된 것을 확인할 수 있다.
코드 내용을 변경하고 Push했을 때도 자동으로 배포되는지 확인해보자.
다음과 같이 Hello에서 Bye로 변경하고 Push했다.
@RestController
public class TestController {
@GetMapping("/")
public String getHome() {
return "Bye!";
}
}
워크플로우가 정상적으로 끝나고 새로고침F5 해보자
Push한 내용으로 자동 배포된 것을 확인할 수 있다.
+ 소소한 트러블 슈팅
'DevOps' 카테고리의 다른 글
[DevOps] 윈도우 ElasticSearch 8.x 다운로드 및 키바나 연동 (0) | 2024.07.28 |
---|---|
[Docker] AWS EC2 + Docker를 사용한 Spring Boot 프로젝트 배포 (0) | 2023.09.14 |
[Docker] Docker Hub에 도커 이미지 업로드 (0) | 2023.05.22 |
[Jenkins] Jenkins와 깃허브 연동 (0) | 2023.05.08 |
[JenKins] JenKins 설치 (0) | 2023.05.08 |