Pre-Project 스택오버플로우 클론을 진행하면서 프론트엔드와 협업을 진행했고, API 통신을 위해 배포를 진행해야했다.
배포를 진행할 때 선택할 수 있는 선택지가 2가지가 있었다.
이 두 가지 중 하나를 선택하여야했다. 간단한건 첫 번째이지만 추후 Main-Project를 들어가서 배포를 진행하기 위해선 두 번째가 필수아닌 필수라고 생각했다.
AWS를 사용한 배포도 여러가지가 있다.
- AWS + S3 + Code Deploy
- AWS + S3 + Github Actions
- AWS + Docker + Github Actions
- etc...
위보다 더 많겠지만 내가 아는건 여기까지라 세 가지 중에 하나를 선택해서 배포를 진행하고 환경을 구성해야했다.
그래서 Docker를 EC2에서도 사용해보고 싶고, CI/CD에서 활용해보고 싶어 3번을 선택했다.
최소한으로 과금을 줄이고 AWS를 적게 사용하고 싶기도 했다. 전에 임시로 하나 만들고 삭제했는데 통장에서 300원씩 나갔다... 상당히 신경쓰였다..
일단 서론은 여기서 마치고
많은 블로그들을 참조하여 간단하게 배포를 진행할 것이다.
틀린 부분들도 있을 수 있다. 그땐 댓글로 조언을 해주시면 감사하겠습니다.
물론 제가 또 까먹고 다시 구글링을 할 경우를 대비하여 작성하는 글입니다!
그래서 최대한 쉽게 작성할 계획입니다!
순서는
- 애플리케이션 프로젝트 생성 및 도커 레포 생성
- AWS EC2 생성 및 docker & docker compose 설치
- Github actions 설정
- EC2 docker 설정
- 테스트
1번 애플리케이션 생성에선 Spring Boot를 통해 애플리케이션을 생성할 것입니다. 다른 애플리케이션을 생성하는 프레임워크를 사용해도 됩니다.. 워낙 간단하게 만들 것입니다.
프로젝트 폴더 구조입니다.
여기서 Dockerfile이라는 이름으로 파일을 생성 후 밑에 코드를 작성합니다.
FROM openjdk:11
ARG JAR_FILE=build/libs/cicdTest-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
도커파일은 이미지를 빌드하기 위해 작성한 파일이고 이 이미지를 기반으로 컨테이너가 실행됩니다.
즉, '프로젝트 빌드 파일을 실행하겠다' 입니다.
여기서 openjdk:11로 제가 만든 프로젝트는 11번이므로 다른 버전을 사용하시면 위 버전을 맞게 변경하셔야합니다.
애플리케이션을 구성 및 생성을 다하시면 깃헙 저장소에 등록 및 푸시를 한번해주세요! 추후 깃헙 레퍼지토리를 만들고 연결하기 귀찮아서 IDE에서 깃헙과 연결하여 간단하게 만들고 푸시까지 진행하였습니다.
도커를 올릴 허브를 만들기 위해 새로운 레포지토리를 만들겁니다.
간단하므로 글로 설명하겠습니다.
- 회원가입 및 로그인
- create repository를 선택하여
뒤 레포지토리 이름 작성해주시고 생성누르시면 끝입니다. 예를들어 junyoungs7/repo라는 이름으로 계속 사용할 것입니다.
이 부분은 구글링을 조금만하시면 많이 찾을 수 있는 부분이라 간단하게 알려드립니다.
검색을 통해 ec2 인스턴스 창으로 넘어갑니다.
인스턴스 생성 혹은 시작을 통해 만들 준비를 합니다.
작성할 부분은 아주 간단하게 두 가지정도 됩니다.
인스턴스 이름을 적어줍니다. 아무거나 혹은 사용자 입맛에 맞게 작성해주세요.
저는 프리티어를 사용하기위해 기본 설정으로 되어있는 이 부분은 건들지않고 넘어갔습니다.
키 페어는 꼭 안전하게 보관하셔야합니다. 이 부분도 이름은 각자 알맞게 작성해주시고, RSA 유형에 .pem형식으로 키 페어를 생성해주세요.
스토리지를 프리티어 또한 30GB까지 사용할 수 있어 이 부분은 해도되고 안해도되고? 입니다만 전 했습니다. 앞 빈칸에 30을 작성했습니다.
그 후 인스턴스 시작을 누르시면 인스턴스가 생성됩니다.
인스턴스에 로그인하기 위해선 우선 인스턴스 체크박스에서 체크 혹은 인스턴스 ID를 눌러 선택하시고 우측 상단 연결 버튼을 누르시면
이런 창이 나옵니다. 그 후 키 페어를 통해 로그인을 할 것이기 때문에 SSH 클라이언트를 선택 후 밑에 있는 설명을 기반으로 설정 후 로그인을 진행해줍니다.
간단하게 설명하면 (전 맥으로 진행했습니다.)
- 터미널에서 다운받은 키 페어를 chmod를 통해 파일의 권한을 변경 후,
- ssh -i "키 페어가 있는 경로" ec2-user@{퍼블릭 DNS}를 입력하여 로그인을 합니다.
sudo yum update -y
위 명령어를 통해 인스턴스에 있는 모든 패키지를 업데이트했습니다.
sudo yum install docker -y
도커를 설치하고
docker -v
도커 버전 확인하고
sudo service docker start
도커 실행하고
sudo usermod -aG docker ec2-user
도커 그룹에 sudo 추가하여 인스턴스 접속 후 도커를 바로 제어할 수 있도록 했습니다.
인스턴스를 재접속한 후
docker run hello-world
를 통해 도커의 실행을 테스트하였습니다.
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
위 명령어를 통해 Docker Compose 설치 스크립트를 다운로드합니다.
sudo chmod +x /usr/local/bin/docker-compose
다운로드한 파일에 실행 권한을 부여합니다.
docker-compose --version
설치가 완료되었는지 확인합니다.
이제 Docker Compose가 EC2 인스턴스에 설치되었습니다. Docker Compose를 사용하여 애플리케이션의 컨테이너 구성을 정의하고 실행할 수 있습니다. 일반적으로 docker-compose.yml 또는 비슷한 이름의 YAML 파일을 생성하고, 컨테이너 및 네트워크 구성, 볼륨 마운트 등을 정의합니다. 그런 다음 docker-compose up 명령을 사용하여 애플리케이션을 실행하고 docker-compose down 명령을 사용하여 중지할 수 있습니다.
포트 8080을 열어주어 테스트시 요청을 보내기위해 설정을 한다.
해당 인스턴스를 밑으로 내리다보면 인바운드 규칙이있는데 규칙을 추가하여 포트범위를 8080과 0.0.0.0/0으로 설정하여 추가한다.
이 부분에 들어가기전, 1번에서 만든 애플리케이션을 깃헙 저장소에 등록합니다.
저장소 생성 및 등록은 넘어가겠습니다.
우선 깃헙으로 넘어가 레포지토리를 확인합니다.
Java with Gradle을 선택해줍니다.
만약 안보이신다면 검색을 통해 선택해주세요.
선택하시면 위 사진처럼 저 경로에 파일이 생기고, 작성할 수 있는 스크립트가 생깁니다. 여기서 바로 작성하셔도 되지만 전 여기서 초록색 버튼 Commit changes를 선택한 후 IDE에서 pull받고 거기서 작성하겠습니다.
여기서 작성하셔도 상관없습니다!! 작성하고 pull받으셔도 됩니다.
요런 폴더 구조가 생기고 클릭해보시면 아까 그대로 스크립트가 작성되어있습니다.
# 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.
# This workflow will build a Java project with Gradle 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-gradle
name: Java CI with Gradle
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
# gradle caching - 빌드 시간 향상
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Build with Gradle
run: |
chmod +x ./gradlew
./gradlew clean build -x test
- name: Docker build & push to docker repo
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -f Dockerfile -t ${{ secrets.DOCKER_REPO }}/ci-cd_test .
docker push ${{ secrets.DOCKER_REPO }}/ci-cd_test:latest
- name: Deploy to server
uses: appleboy/ssh-action@master
id: deploy
with:
host: ${{ secrets.HOST }}
username: ec2-user
key: ${{ secrets.KEY }}
envs: GITHUB_SHA
script: |
sudo docker rm -f $(docker ps -qa)
sudo docker pull ${{ secrets.DOCKER_REPO }}/ci-cd_test
docker-compose up -d
docker image prune -f
나누어 설명드리겠습니다.
name: Java CI with Gradle
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Build with Gradle
run: |
chmod +x ./gradlew
./gradlew clean build -x test
- name: Docker build & push to docker repo
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -f Dockerfile -t ${{ secrets.DOCKER_REPO }}/ci-cd_test .
docker push ${{ secrets.DOCKER_REPO }}/ci-cd_test:latest
- name: Deploy to server
uses: appleboy/ssh-action@master
id: deploy
with:
host: ${{ secrets.HOST }}
username: ec2-user
key: ${{ secrets.KEY }}
envs: GITHUB_SHA
script: |
sudo docker rm -f $(docker ps -qa)
sudo docker pull ${{ secrets.DOCKER_REPO }}/ci-cd_test
docker-compose up -d
docker image prune -f
이렇게 주어진 GitHub Actions 스크립트는 Gradle을 사용하여 Java 프로젝트를 빌드하고, Docker 이미지를 빌드하고 푸시한 후 서버에 배포하는 작업을 자동화합니다.
${{ }}로 표시된 것들은
여기서 키-값 형태로 저장하여 사용합니다.
다른 분들은 스크립트에 properties와 같은 설정 파일들을 secret에 저장하여 파일을 copy를 통해 생성하는 경우도 있습니다. 저는 현재 간단하게 배포를 진행 중이고, 숨길 파일 혹은 값들도 없어 위처럼 진행했습니다.
secret에 저장할 때 값들을 잘 넣어주셔야 추후 푸시하고 테스트할때 에러가 나지않습니다. secret에 저장한 후 수정할때에는 원래 알던 수정이 아니라 재입력을 받게되어 어디가 틀렸는지 알기 어렵습니다. 처음 등록할때 제대로 한번 더 더블체크 후 넣어주세요!!! 저 여기서 삽질 엄청 많았습니다!!!
우선 서버의 루트 디렉토리로 이동합니다.
docker compose를 사용하기 위해서 yml파일을 세팅해줍니다.
version: '3'
services:
web:
container_name: web
image: junyoungs7/test // 처음 도커허브에 레포지토리를 만든 부분을 써주시면 됩니다.
expose:
- 8080
ports:
- 8080:8080
컨테이너는 호스트의 8080 포트와 컨테이너의 8080 포트를 매핑하여 외부로부터 접근할 수 있도록 합니다.
마지막으로 간단하게 코드를 변경하고 푸시를 한 후, 해당 깃헙 레퍼지토리에 들어가 Actions탭을 클릭해보면
요렇게 푸시가 되고 빌드가 되고 배포가 될것입니다.
ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
라는 오류는 ec2의 /etc/ssh/sshd_config위치에
PubkeyAuthentication yes
PubkeyAcceptedKeyTypes=+ssh-rsa
코드 두줄을 추가한후 ssh server를 재시동해주면 된다.
만약 빌드, 배포, ec2에 image가 저장은 되었는데 실행이 되지 않으면
docker run -d -p 8080:8080 junyoungs7/ci-cd_test를 통해 도커를 실행한다.
혹은
docker-compose.yml의 들여쓰기를 다시 확인하길 바랍니다. 또는
sudo docker rm -f $(docker ps -qa)
sudo docker pull junyoungs7/ci-cd_test
cd /usr/local/bin
sudo docker-compose up -d
docker image prune -f
저도 자동실행이 되지않아 docker-compose파일을 /usr/local/bin에 다시 만들고 스크립트를 위와 같이 디렉토리를 옮기는 식으로 진행했다.
미치는줄 알았다...... 너무 많은 에러들과 싸웠다.... 토 나온다.....
https://velog.io/@rmswjdtn/Spring-Docker-Github-Action-Spring-Boot-%EC%9E%90%EB%8F%99%EB%B0%B0%ED%8F%AC%ED%99%98%EA%B2%BD-%EB%A7%8C%EB%93%A4%EA%B8%B0#4-docker-compose
https://velog.io/@tilsong/%EC%BD%94%EB%93%9C-Push%EB%A1%9C-%EB%B0%B0%ED%8F%AC%EA%B9%8C%EC%A7%80-Github-Actions-Docker#4-%EB%B9%8C%EB%93%9C-%EA%B2%B0%EA%B3%BC%EB%AC%BC%EC%9D%84-%EB%B0%B0%ED%8F%AC%ED%95%A0-%EC%84%9C%EB%B2%84-%EC%84%B8%ED%8C%85
https://zzang9ha.tistory.com/404#%F0%9F%8C%88%C2%A0-deploy-to-aws-ec2using-ssh
https://velog.io/@leeeeeyeon/Github-Actions%EA%B3%BC-Docker%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-CICD-%EA%B5%AC%EC%B6%95#github-actions-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%8C%8C%EC%9D%BC-%EC%9E%91%EC%84%B1
https://jinjinyang.tistory.com/46
많이도 참조했다...ㅋㅋㅋㅋㅋㅋ