안녕하세요. 요즘 스위프 3기에서 진행하는 읽는 곳곳이라는 프로젝트에 집중하고 있는데요. Vercel
로 배포된 프론트 서버와 통신하기 위해 백엔드 서버도 구축해야 했습니다. 근데 코드가 변경됨에 따라 지속적으로 재배포하기 너무 힘들어서 GitHub Actions
을 공부하게 됐고 나중에 쓸 일이 많을 것 같아서 정리해 놓으려 합니다. Git Action은 GitHub의 강력한 기능 중 하나로, 소스 코드 저장소에 통합된 CI/CD
도구입니다. 본 글에서는 Git Action을 활용하여 간단한 CI/CD 파이프라인을 구축하는 방법을 소개합니다.
이 포스팅의 핵심 기술 스택으로는 Java 17
, Spring Boot 3.2.2
, Gradle
, Nginx
, Docker
, 그리고 AWS
가 포함됩니다.
GitHub Actions 사용하기 전 재배포 프로세스
EC2 우분투 서버에 직접 접근
하여 Vim
, Nginx
, Timezone
설정해준뒤 다음과 같은 과정을 거칩니다.
rm -rf readeve-BackEnd
git clone https://github.com/SWYP-3-Reading-everywhere/readeve-BackEnd.git
cd readeve-BackEnd
# 여기서 application-secret.yml파일 수동 추가!!
./gradlew build -x test
cd /build/libs
nohup java -jar book_everywhere-0.0.1-SNAPSHOT.jar &
sudo nginx -t
sudo service nginx reload
이 부분에서 build하다가 EC2 서버가 멈추면 인스턴스를 중지했다가 다시 시작하고.. 엄청 비효율적이라는 걸 알 수 있었습니다.
이 부분을 직접 치지 않고 deploy파일을 사용하는 방법이 있습니다. 하지만 이 방법도 EC2 인스턴스에 직접 접근해서 deploy 하기 때문에 시간도 걸리고 귀찮음이 크죠 ((궁금하시다면 https://developing-mango.tistory.com/44))
GitHub Actions CI/CD.yml
그래서 다음과 같은 GitHub Actions / CICD.yml파일을 구성했습니다.
name: CICD
on:
push:
branches: [ "dev" ]
pull_request:
branches: [ "dev" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
if: github.repository == 'SWYP-3-Reading-everywhere/readeve-BackEnd'
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Gradle
run: |
echo ${{secrets.APPLICATION_SECRET}} | base64 --decode > ./src/main/resources/application-secret.yml
cat ./src/main/resources/application-secret.yml
chmod +x ./gradlew
./gradlew build -x test
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Docker
run: docker build --platform linux/amd64 -t ${{ secrets.DOCKERHUB_USERNAME }}/bookeverywhere .
- name: Push Docker
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/bookeverywhere:latest
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Set target IP
run: |
STATUS=$(curl -o /dev/null -w "%{http_code}" "https://${{ secrets.BOOKEVERYWHERE_URL }}/env")
echo $STATUS
if [ "$STATUS" = "200" ]; then
CURRENT_UPSTREAM=$(curl -s "https://${{ secrets.BOOKEVERYWHERE_URL }}/env" | jq -r '.data')
else
CURRENT_UPSTREAM=green
fi
echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
if [ "$CURRENT_UPSTREAM" = "blue" ]; then
echo "CURRENT_PORT=8081" >> $GITHUB_ENV
echo "STOPPED_PORT=8082" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
elif [ "$CURRENT_UPSTREAM" = "green" ]; then
echo "CURRENT_PORT=8082" >> $GITHUB_ENV
echo "STOPPED_PORT=8081" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV
else
echo "error"
exit 1
fi
- name: Docker compose
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.BOOKEVERYWHERE_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/bookeverywhere:latest
sudo docker-compose -f docker-compose-${{env.TARGET_UPSTREAM}}.yml up -d
- name: Check deploy server URL
uses: jtalk/url-health-check-action@v3
with:
url: https://${{ secrets.BOOKEVERYWHERE_URL }}/env #:${{env.STOPPE}}
max-attempts: 5
retry-delay: 10s
- name: Change nginx upstream
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.BOOKEVERYWHERE_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker exec -i nginxserver bash -c 'echo "set \$service_url ${{ env.TARGET_UPSTREAM }};" > /etc/nginx/conf.d/service-env.inc && nginx -s reload'
- name: Stop current server
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.BOOKEVERYWHERE_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker stop ${{env.CURRENT_UPSTREAM}}
sudo docker rm ${{env.CURRENT_UPSTREAM}}
자 이후 아래 하나하나 뜯어가면서 어떤 설정을 하는지 설명드리겠습니다.
트리거 조준 (on)
on:
push:
branches: [ "dev" ]
pull_request:
branches: [ "dev" ]
이 파이프라인은 dev 브랜치에 대한 push와 pull\_request
이벤트가 발생할 때 실행됩니다. 즉, dev 브랜치로 코드가 푸시되거나, dev 브랜치로 풀 리퀘스트가 생성될 때 이 파이프라인이 작동합니다.
하지만 여기에 문제가 있습니다. 저는 프로젝트를 Organization
의 Repository
를 fork해서 사용하는데 그 fork branch에 push를 해도 CICD가 동작하는 것이었습니다. fork
한 프로젝트는 실제 배포과정으로 이동하면 안 되기에 나중에 예외처리 해주었습니다
작업 권한 (permissions)
permissions:
contents: read
이 파이프라인은 저장소의 컨텐츠를 읽을 수 있는 권한을 가지고 있습니다. 이는 코드를 체크아웃하거나, 저장소의 다른 정보에 접근할 필요가 있을 때 필요한 설정입니다.
GitHub Actions 작업 (Job)
이 파이프라인은 두 가지 주요 작업을 정의합니다: Build와 Deploy.
빌드 (Build)
jobs:
build:
runs-on: ubuntu-latest
if: github.repository == 'SWYP-3-Reading-everywhere/readeve-BackEnd'
steps:
이 작업은 ubuntu-latest 환경에서 실행되며, 현재 GitHub 저장소가 SWYP-3-Reading-everywhere/readeve-BackEnd일 때만 실행됩니다. 여기서 if 문은 방금 위에서 말씀드렸던 개인 Repository에서 push 된 프로젝트를 배포하지 않게 하기 위한 조건문입니다
steps 아래에는 빌드를 위한 다양한 단계가 정의됩니다. 다양한 단계 이전에 기본적인 문법부터 알고 가겠습니다.
name
워크플로우, 작업, 또는 단계의 이름을 지정합니다. 이름은 워크플로우 실행 로그에서 해당 작업이나 단계를 쉽게 식별할 수 있게 해 줍니다. 아래 보이시는 사진과 같이 단계(steps)의 이름으로 성공과 실패를 보여줍니다.
uses
작업 단계에서 GitHub Marketplace나 다른 저장소에 호스팅되는 작업을 사용할 때 지정합니다. 예를 들어, actions/checkout@v3는 GitHub Marketplace에 호스팅되는 checkout 액션의 버전 3을 사용하겠다는 의미입니다.
with
uses로 지정된 액션에 전달할 입력 파라미터들을 정의합니다. 예를 들어, java-version이나 distribution과 같은 파라미터들을 지정하여 액션의 동작을 커스터마이즈할 수 있습니다.
Set up JDK 17
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
uses: actions/setup-java@v3 :
uses 키워드는 GitHub Actions
마켓플레이스에서 제공하는 특정 액션을 사용하겠다는 의미입니다. 여기서는 setup-java
액션의 버전 3을 사용하여 Java 환경을 설정합니다. setup-java는 GitHub에서 제공하는 공식 Java 설치 액션으로, 지정된 버전의 JDK를 설치하고 설정합니다.
with:
이들은 액션 실행에 필요한 구성 옵션을 제공합니다.
- java-version: '17': JDK의 버전을 지정합니다. 이 예시에서는 '17'을 사용하여 JDK 17을 설치하도록 설정합니다. 문자열 형태로 버전 번호를 명시해야 합니다.
- distribution: 'temurin': 사용할 JDK 배포판을 지정합니다. 'temurin'은 Eclipse Foundation에서 관리하는 AdoptOpenJDK의 후속 프로젝트입니다. 여기서는 템루린 배포판을 사용하여 JDK를 설치합니다.
Build with Gradle
- name: Build with Gradle
run: |
echo ${{secrets.APPLICATION_SECRET}} | base64 --decode > ./src/main/resources/application-secret.yml
cat ./src/main/resources/application-secret.yml
chmod +x ./gradlew
./gradlew build -x test
run :
run 키워드는 직접 쉘 명령어들을 실행하겠다는 것을 의미합니다. |
기호는 여러 줄에 걸쳐 명령어들을 작성할 수 있게 해 줍니다.
- echo ${{secrets.APPLICATION_SECRET}} | base64 --decode > ./src/main/resources/application-secret.yml: GitHub Secrets에 저장된 APPLICATION_SECRET 값을 base64로 디코드 하여 application-secret.yml 파일에 저장합니다. 이 파일은 애플리케이션의 중요한 설정 정보를 포함할 수 있으며, 보안상의 이유로 GitHub 리포지토리에 직접 포함시키지 않고 Secrets를 통해 관리합니다.
- cat ./src/main/resources/application-secret.yml: 디코드된 application-secret.yml 파일의 내용을 출력합니다. 이는 디버깅 목적으로 파일이 올바르게 생성되었는지 확인하기 위해 사용될 수 있습니다.
- chmod +x ./gradlew: 프로젝트 루트에 있는 Gradle 래퍼 스크립트(gradlew)에 실행 권한을 부여합니다. 이는 Linux나 macOS 환경에서 스크립트를 실행 가능하게 만듭니다.
- ./gradlew build -x test: 실제로 Gradle 빌드를 실행하는 명령어입니다. build 태스크를 실행하여 프로젝트를 컴파일하고 패키징합니다. -x test 옵션은 테스트를 제외하고 빌드를 실행하라는 의미입니다. 이는 CI 과정에서 테스트 없이 빌드만 수행하고자 할 때 유용합니다.
여기서 Git secerts를 관리하는 방법
은 https://developing-mango.tistory.com/65 를 참고하시기 바랍니다!
Login to DockerHub
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
이 스텝은 Docker 이미지를 Docker Hub에 푸시하기 전에 필요합니다. Docker Hub에 성공적으로 로그인한 후에만, Docker 이미지를 Docker Hub의 리포지토리에 푸시할 수 있습니다. 따라서, 이 작업을 통해 CI/CD 파이프라인에서 Docker 이미지를 자동으로 빌드하고 푸시하는 과정을 안전하게 수행할 수 있습니다.
여기서 DockerHub_TOKEN은 다음과 같은 과정으로 발급받으실 수 있습니다.
- Docker Hub 로그인
- 계정 설정 접근
- Security 탭 이동
- New Access Token 생성
- 액세스 토큰 설명 입력
- 액세스 토큰 발급
- 액세스 토큰 복사
여기서 액세스 토큰은 창을 닫으면 다시는 확인하실 수 없습니다. 꼭 잘 저장해 놓도록 합니다. 아래는 예시화면입니다.
Build Docker & Push Docker
- name: Build Docker
run: docker build --platform linux/amd64 -t ${{ secrets.DOCKERHUB_USERNAME }}/bookeverywhere .
- name: Push Docker
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/bookeverywhere:latest
이 두 단계는 묶어서 설명하겠습니다, GitHub Actions 워크플로우는 Docker 이미지를 자동으로 빌드하고, 빌드된 이미지를 Docker Hub에 안전하게 푸시합니다. 이 과정은 소프트웨어 배포의 자동화와 CI/CD 파이프라인의 일환으로 중요합니다. GitHub Secrets를 사용함으로써, 사용자 이름과 같은 민감한 정보를 안전하게 관리하며 Docker Hub 인증을 수행할 수 있습니다.
배포 (Deploy)
자 이제 빌드 과정이 끝났고 Secrets로 관리된 여러 중요 정보가 포함된 Docker 파일이 Docker-hub에 업로드 됐습니다!
Set target IP
- name: Set target IP
run: |
STATUS=$(curl -o /dev/null -w "%{http_code}" "https://${{ secrets.BOOKEVERYWHERE_URL }}/env")
echo $STATUS
if [ "$STATUS" = "200" ]; then
CURRENT_UPSTREAM=$(curl -s "https://${{ secrets.BOOKEVERYWHERE_URL }}/env" | jq -r '.data')
else
CURRENT_UPSTREAM=green
fi
echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
if [ "$CURRENT_UPSTREAM" = "blue" ]; then
echo "CURRENT_PORT=8081" >> $GITHUB_ENV
echo "STOPPED_PORT=8082" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
elif [ "$CURRENT_UPSTREAM" = "green" ]; then
echo "CURRENT_PORT=8082" >> $GITHUB_ENV
echo "STOPPED_PORT=8081" >> $GITHUB_ENV
echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV
else
echo "error"
exit 1
fi
타겟 URL의 상태 확인
- curl 명령어를 사용해 ${{ secrets.BOOKEVERYWHERE_URL }}/env 주소로 HTTP 요청을 보내고, 그 응답 상태 코드를 STATUS 변수에 저장합니다. 여기서, BOOKEVERYWHERE_URL은 GitHub Secrets에 저장된 환경 변수로, 프로젝트 백엔드 서버의 URL입니다.
- 요청의 HTTP 상태 코드가 200 (성공)인 경우, 동일한 URL에서 JSON 형식의 데이터를 가져와 jq 명령어를 사용하여 JSON 객체의 data 필드 값을 CURRENT_UPSTREAM 변수에 저장합니다.
- 만약 상태 코드가 200이 아닌 경우, CURRENT_UPSTREAM을 기본값인 green으로 설정합니다.
현재 배포 상태에 따른 변수 설정
- CURRENT_UPSTREAM 변수의 값에 따라 다음 동작을 결정합니다. blue 또는 green 값에 따라 서로 다른 포트 번호와 타겟 업스트림을 설정합니다.
- blue 상태일 경우:
- 현재 서비스가 사용하는 포트(CURRENT_PORT)를 8081로 설정합니다.
- 중단될 서비스 포트(STOPPED_PORT)를 8082로 설정합니다.
- 다음 타겟 업스트림(TARGET_UPSTREAM)을 green으로 설정합니다.
- green 상태일 경우:
- 현재 서비스가 사용하는 포트를 8082로 설정합니다.
- 중단될 서비스 포트를 8081로 설정합니다.
- 다음 타겟 업스트림을 blue로 설정합니다.
- blue 상태일 경우:
- 설정된 이러한 변수들은 후속 작업에서 사용됩니다. 예를 들어, Docker 컨테이너를 조정하거나, Nginx 설정을 변경하는 등의 작업에 이 변수들이 활용됩니다.
- ${{ secrets.BOOKEVERYWHERE_URL }}/env 부분은 현재 저의 프로젝트가 Route53을 통하여 api.bookeverywhere.site 라는 서브 도메인으로 배포되어있습니다. 이부분에 관한 헬스 체크 부분이며 아래는 HealthCheck에 따른 Java Code입니다.
@RestController
@RequestMapping("/**") // 모든 요청을 처리합니다.
public class UniversalController {
@Value("${server.env}")
private String env;
@Value("${server.port}")
private String serverPort;
@Value("${server.serverAddress}")
private String serverAddress;
@Value("${serverName}")
private String serverName;
@GetMapping("/health")
public CMRespDto<?> healthRequest() {
Map<String, String> responseData = new TreeMap<>();
responseData.put("serverName", serverName);
responseData.put("serverAddress", serverAddress);
responseData.put("serverPort", serverPort);
responseData.put("env", env);
return new CMRespDto<>(HttpStatus.OK, responseData, "health checking complete");
}
@GetMapping("/env")
public CMRespDto<?> envRequest() {
return new CMRespDto<>(HttpStatus.OK, env, ".env checking complete");
}
아래는 도메인에 따른 check API의 Json
결과물입니다.
Docker compose
- name: Docker compose
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.BOOKEVERYWHERE_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/bookeverywhere:latest
sudo docker-compose -f docker-compose-${{env.TARGET_UPSTREAM}}.yml up -d
입력 변수
- username: ubuntu: 원격 서버에 로그인할 때 사용할 사용자 이름입니다. 이 예제에서는 ubuntu 사용자로 로그인합니다.
- host: ${{ secrets.BOOKEVERYWHERE_IP }}: 원격 서버의
탄력적IP
입니다. 이 값은 GitHub Secrets에 저장되어 있으며, 여기서는 BOOKEVERYWHERE_IP라는 이름의 시크릿을 참조합니다. - key: ${{ secrets.EC2_SSH_KEY }}: SSH 로그인을 위한 비공개 키입니다. 이 역시 GitHub Secrets에 저장된 EC2_SSH_KEY라는 시크릿을 사용합니다. 즉 EC2에 설정된 pem입니다. 연결프로그램 -> visual studio code로 실행하시면 pem값을 볼수 있습니다. 처음부터 끝까지 다 긁어서 사용하시면 됩니다.
- script_stop: true: 스크립트 실행 중 오류가 발생하면 즉시 중단합니다.
실행 스크립트
- sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/bookeverywhere:latest: Docker Hub에서 최신 버전의 bookeverywhere 이미지를 가져옵니다. 이미지의 저장소 이름은 GitHub Secrets에 저장된 DOCKERHUB_USERNAME을 사용하여 지정됩니다.
- sudo docker-compose -f docker-compose-${{env.TARGET_UPSTREAM}}.yml up -d: docker-compose 명령을 사용하여 서비스를 배포합니다. 사용할 docker-compose 파일은 TARGET_UPSTREAM 환경 변수의 값에 따라 동적으로 결정됩니다. 예를 들어, TARGET_UPSTREAM의 값이 blue라면 docker-compose-blue.yml 파일을 사용하여 서비스를 시작합니다. -d 옵션은 백그라운드에서 컨테이너를 실행하라는 의미입니다.
Check deploy server URL
- name: Check deploy server URL
uses: jtalk/url-health-check-action@v3
with:
url: https://${{ secrets.BOOKEVERYWHERE_URL }}/env
max-attempts: 5
retry-delay: 10s
사용된 파라미터:
- url: 이것은 확인할 대상 URL입니다. 여기서는 GitHub Secrets에서 BOOKEVERYWHERE_URL 값을 가져와 사용합니다. 실제 값은 api.bookeverywhere.site로 Route53에 등록되어있는 백엔드 서브 URL입니다. 이 URL은 HTTPS 프로토콜을 사용합니다. /env 경로는 특정 환경 설정이나 상태를 반환하는 엔드포인트일 수 있습니다.
- max-attempts: 이 옵션은 액션이 URL에 대해 성공적인 응답을 받을 때까지 시도할 최대 횟수를 지정합니다. 여기서는 최대 5번까지 시도합니다.
- retry-delay: 이것은 재시도 사이의 지연 시간(초)입니다. 만약 첫 번째 시도가 실패한다면, 이 옵션에 설정된 시간만큼 기다린 후 다시 시도합니다. 여기서는 10초의 지연 시간을 설정했습니다.
동작 방식:
- URL 접근: 액션은 설정된 url로 HTTP 요청을 보냅니다.
- 응답 확인: 서버로부터의 응답을 받고, HTTP 상태 코드를 확인합니다. 일반적으로 200 OK 상태 코드는 요청이 성공적으로 처리되었음을 의미합니다.
- 재시도 로직: 만약 요청이 실패하거나 시간 초과 등으로 인해 200 OK 외의 응답을 받는 경우, 설정된 retry-delay 후에 요청을 max-attempts에 도달할 때까지 재시도합니다.
- 결과 처리: 최대 시도 횟수에 도달하거나 성공적인 응답을 받으면, 해당 단계의 실행이 완료됩니다. 모든 시도가 실패하면, 이 단계는 에러를 반환할 수 있으며, 이는 워크플로우의 다음 단계 실행에 영향을 줄 수 있습니다.
Change nginx upstream
- name: Change nginx upstream
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.BOOKEVERYWHERE_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker exec -i nginxserver bash -c 'echo "set \$service_url ${{ env.TARGET_UPSTREAM }};" > /etc/nginx/conf.d/service-env.inc && nginx -s reload'
입력 변수 설명:
- username: ubuntu - 원격 서버에 접속할 때 사용하는 사용자 이름입니다. 본 예제에서는 ubuntu 사용자로 접속을 진행합니다.
- host: ${{ secrets.BOOKEVERYWHERE_IP }} - EC2 서버의 탄력적IP를 지정합니다. 이 값은 GitHub Secrets에 BOOKEVERYWHERE_IP라는 이름으로 저장되어 있습니다.
- key: ${{ secrets.EC2_SSH_KEY }} - SSH 접속을 위해 사용되는 개인 키입니다. GitHub Secrets에 저장된 EC2_SSH_KEY 값을 사용합니다. 즉 EC2에 설정된 pem입니다. 연결프로그램 -> visual studio code로 실행하시면 pem값을 볼수 있습니다. 처음부터 끝까지 다 긁어서 사용하시면 됩니다.
- script_stop: true - 스크립트 실행 중 오류가 발생하면 실행을 즉시 중단하도록 설정합니다.
실행 스크립트 설명:
- 스크립트는 NGINX 서버 설정에 새로운 업스트림 값을 설정하고, NGINX를 재로드하는 명령어를 포함합니다. 이는 sudo docker exec -i nginxserver bash -c 명령을 사용하여 nginxserver라는 이름의 Docker 컨테이너 내에서 실행됩니다.
- echo "set \$service_url ${{ env.TARGET_UPSTREAM }};" > /etc/nginx/conf.d/service-env.inc 명령을 통해, NGINX 설정 파일인 service-env.inc에 새로운 업스트림 URL을 설정합니다. 여기서 ${{ env.TARGET_UPSTREAM }}는 GitHub Actions 워크플로우의 환경 변수에서 가져온 값으로, 동적으로 변할 수 있는 타겟 업스트림을 나타냅니다.
- nginx -s reload 명령을 사용하여 NGINX 설정 변경 사항을 적용하기 위해 NGINX를 안전하게 재로드합니다.
Stop current server
- name: Stop current server
uses: appleboy/ssh-action@master
with:
username: ubuntu
host: ${{ secrets.BOOKEVERYWHERE_IP }}
key: ${{ secrets.EC2_SSH_KEY }}
script_stop: true
script: |
sudo docker stop ${{env.CURRENT_UPSTREAM}}
sudo docker rm ${{env.CURRENT_UPSTREAM}}
입력 변수 설명:
- username: ubuntu - 원격 서버에 접속할 때 사용하는 사용자 이름입니다. 이 예제에서는 ubuntu 사용자로 접속합니다.
- host: ${{ secrets.BOOKEVERYWHERE_IP }} - 원격 서버의 탄력적 IP입니다. 이 값은 GitHub Secrets에 저장되어 있으며, BOOKEVERYWHERE_IP라는 이름의 시크릿을 참조합니다.
- key: ${{ secrets.EC2_SSH_KEY }} - SSH 로그인을 위한 비공개 키입니다. 이 키도 GitHub Secrets에 저장된 EC2_SSH_KEY라는 이름의 시크릿을 사용합니다.
(EC2 pem)
- script_stop: true - 스크립트 실행 중 오류가 발생하면 즉시 실행을 중단하도록 설정합니다.
실행 스크립트 설명:
- 스크립트는 두 단계로 구성됩니다:
- 서버 중지: sudo docker stop ${{env.CURRENT_UPSTREAM}} 명령을 사용하여 현재 실행 중인 서버를 중지합니다. 여기서 ${{env.CURRENT_UPSTREAM}}는 GitHub Actions의 환경 변수에서 가져온 값으로, 중지할 컨테이너의 이름이나 ID를 나타냅니다.
- 컨테이너 삭제: sudo docker rm ${{env.CURRENT_UPSTREAM}} 명령을 통해 중지된 컨테이너를 삭제합니다. 이는 시스템에서 불필요한 리소스를 정리하고, 동일한 이름의 컨테이너를 다시 시작할 때 충돌을 방지하는 데 도움이 됩니다.
결론
포스팅이 엄청 길어졌는데요. 제가 말씀드리고 싶은 건 GitHub Actions를 사용한 CI/CD 파이프라인 구축은 코드 배포 과정을 자동화하여 개발 생산성과 배포의 안정성을 크게 향상한다는 겁니다. EC2에 수동으로 접근하여 deploy 명령어를 일일이 타이핑하는 것보다 GitHub Actions를 통해 개발자는 수동 배포로 인한 실수를 줄이고, 시간을 절약할 수 있습니다. 또한, Docker와 같은 컨테이너 기술과 GitHub Secrets를 활용하여 보안성을 강화하고, 유연한 배포 전략을 쉽게 실행할 수 있습니다. 읽는 곳곳 프로젝트와 같은 소프트웨어 개발에 GitHub Actions를 적용함으로써, 팀의 작업 효율성을 높이고 사용자에게 지속적으로 안정적인 서비스를 제공할 수 있습니다.
긴 글 읽어주셔서 감사합니다
'Git' 카테고리의 다른 글
[GitHub Actions] CI/CD 주요정보 Secrets로 관리하기 (0) | 2024.03.03 |
---|---|
[Git] 원격 저장소 명령어 (0) | 2024.02.07 |
[Git] github push, commit 관련 명령어 정리 (0) | 2023.11.29 |
[Git] pull request 사용하여 편하게 리뷰하기 (2) | 2023.11.17 |