티스토리 뷰

반응형

이제 본격적으로 Github Action 사용한다.

 

그 전에 docker compose 파일을 만들어야 하기에, 만약 컨테이너 안에 접속되어 있다면 exit를 이용해 ubuntu 서버로 나가자.

 

vim docker-compose-blue.yml

yml 파일은 다음과 같이 작성한다.

 

version: '3.8'

services:
  blue:
    image: docker 레포지토리 사용자 이름/live_server:latest
    container_name: blue
    ports:
      - "8080:8080"
    environment:
      - PROFILES=blue
      - ENV=blue

그리고 green을 위해서 하나 더 만든다.

cp로 copy한다.

 

cp docker-compose-blue.yml ./docker-compose-green.yml
vim docker-compose-green.yml

 

green은 8081로 설정했으므로 8081로 설정한다.

version: '3.8'

services:
  green:
    image: docker 레포지토리 사용자 이름/live_server:latest
    container_name: green
    ports:
      - "8081:8081"
    environment:
      - PROFILES=green
      - ENV=green

 

이제 github로 간다.

 

github Actions 설정하기

github의 Actions에 들어가서, workflow yourself로 들어가서 설정한다.

해당 yaml 파일을 만들 때 이렇게 한다.

name: CI

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

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest  #우분투로 가상을 쓴다.
    steps:
      - uses: actions/checkout@v3 #uses는 깃허브 액션의 템플릿. 이미 만들어진 체크아웃
      - name: Install JDK 11
        uses: actions/setup-java@v3 #마찬가지
        with:
          java-version: '11'
          distribution: 'temurin'

      - name: Build with Maven #단위는 네임 별로 끊어서 간다.
        run: |
          chmod 777 ./mvnw  #프로젝트를 빌드하기 위해서 권한을 모두 준다.
          ./mvnw clean package -Dtestskip

      - name: Login to DockerHub  #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 }}/live_server .  #이미지 만드는 과정
      - name: Push Docker
        run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/live_server:latest #dokcerhub에 올린다.
        
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Set target IP
        run: |
          STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.LIVE_SERVER_IP }}/env")
          echo $STATUS
          if [ $STATUS = 200 ]; then
            CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.LIVE_SERVER_IP }}/env")
          else
            CURRENT_UPSTREAM=green
          fi
          echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
          if [ $CURRENT_UPSTREAM = blue ]; then
            echo "CURRENT_PORT=8080" >> $GITHUB_ENV
            echo "STOPPED_PORT=8081" >> $GITHUB_ENV
            echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
          elif [ $CURRENT_UPSTREAM = green ]; then
            echo "CURRENT_PORT=8081" >> $GITHUB_ENV
            echo "STOPPED_PORT=8080" >> $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.LIVE_SERVER_IP }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script_stop: true
          script: |
            sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/live_server: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: http://${{ secrets.LIVE_SERVER_IP }}:${{env.STOPPED_PORT}}/env
          max-attempts: 3
          retry-delay: 10s

      - name: Change nginx upstream
        uses: appleboy/ssh-action@master
        with:
          username: ubuntu
          host: ${{ secrets.LIVE_SERVER_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.LIVE_SERVER_IP }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script_stop: true
          script: |
            sudo docker stop ${{env.CURRENT_UPSTREAM}}
            sudo docker rm ${{env.CURRENT_UPSTREAM}}

 

먼저 빌드 과정을 거치고, build가 되면 정상적으로 실행을 한다.

 

gradle 버전은 이렇게 바뀐다.

 

name: CI

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 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Build with Gradle
        run: |
          chmod +x ./gradlew
          ./gradlew clean build

      - 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 }}/spring-boot-developer .
      - name: Push Docker
        run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/spring-boot-developer:latest
        
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Set target IP
        run: |
          STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.LIVE_SERVER_IP }}/env")
          echo $STATUS
          if [ $STATUS = 200 ]; then
            CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.LIVE_SERVER_IP }}/env")
          else
            CURRENT_UPSTREAM=green
          fi
          echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
          if [ $CURRENT_UPSTREAM = blue ]; then
            echo "CURRENT_PORT=8080" >> $GITHUB_ENV
            echo "STOPPED_PORT=8081" >> $GITHUB_ENV
            echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
          elif [ $CURRENT_UPSTREAM = green ]; then
            echo "CURRENT_PORT=8081" >> $GITHUB_ENV
            echo "STOPPED_PORT=8080" >> $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.LIVE_SERVER_IP }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script_stop: true
          script: |
            sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/spring-boot-developer: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: http://${{ secrets.LIVE_SERVER_IP }}:${{env.STOPPED_PORT}}/env
          max-attempts: 3
          retry-delay: 10s

      - name: Change nginx upstream
        uses: appleboy/ssh-action@master
        with:
          username: ubuntu
          host: ${{ secrets.LIVE_SERVER_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.LIVE_SERVER_IP }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script_stop: true
          script: |
            sudo docker stop ${{env.CURRENT_UPSTREAM}}
            sudo docker rm ${{env.CURRENT_UPSTREAM}}

 

Dockerfile도 만들어준다.

FROM openjdk:17-jdk-slim
ARG JAR_FILE=build/libs/*.jar
ARG PROFILES
ARG ENV
ENTRYPOINT ["java", "-Dspring.profiles.active=${PROFILES}", "-Dserver.env=${ENV}", "-jar", "app.jar"]

 

여기서 spring.profiles.active는 앞서 설정해줬던 yml 파일에 있는 값들이 들어간다.

 

 

 

Docker secret 설정

Github Action에서 secret 설정을 좀 해줘야 한다.

Docker에 접속하기 위해서이다.

 

settings - settings and variables- actions에 들어가서 new repository secret을 만든다.

 

이름은 다음과 같이 입력

 

DOCKERHUB_USERNAME

secret에는 유저 이름을 써준다.

그렇게 하나 추가

 

그리고 DOCKERHUB_TOKEN이라고 하나 더 만든다.

저장해놨던 token을 secret에 추가해서 만든다.

 

EC2_SSH_KEY도 추가해준다.

.pem에 있는 파일을 추가해주는 것이다.

 

LIVE_SERVER_IP도 secret으로 추가해준다.

 

secret에다 담아둬서 github에서의 yml을 실행할 때 볼 수 없게 만든다.

 

이러면 이제 build까지는 잘 실행되는 걸 볼 수 있다.

 

배포 (Deploy)

이제 배포에 대한 설명으로 넘어가자.

 

EC2 환경에서 pull을 받고 실행을 시켜야 한다.

현재 blue 서버가 실행이 있다고 해보자. 그러면 현재 blue인지 green인지 일단 체크를 한다.

deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Set target IP
        run: |
          STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.LIVE_SERVER_IP }}/env")
          echo $STATUS
          if [ $STATUS = 200 ]; then
            CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.LIVE_SERVER_IP }}/env")
          else
            CURRENT_UPSTREAM=green
          fi
          echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV
          if [ $CURRENT_UPSTREAM = blue ]; then
            echo "CURRENT_PORT=8080" >> $GITHUB_ENV
            echo "STOPPED_PORT=8081" >> $GITHUB_ENV
            echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV
          elif [ $CURRENT_UPSTREAM = green ]; then
            echo "CURRENT_PORT=8081" >> $GITHUB_ENV
            echo "STOPPED_PORT=8080" >> $GITHUB_ENV
            echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV
          else
            echo "error"
            exit 1
          fi

curl은 요청을 날리는 건데, http:// secret.LIVE_SERVER_IP /env 요청에 대한 응답을 반환한다.

http 코드를 가지고 와서 설정하겠다 이런 것이다.

echo로 status 변수에 있는 코드를 받아서 출력해준다.

 

만약에 status code가 200이라면, 해당 서버에 env라는 요청이 날라간다.

처음에 요청 할 때는 404여서 green으로 연결된다.

 

green이라는 값을 Github env에 넣어준다.

 

그렇게 blue냐 green이냐에 따라 포트를 8080 또는 8081로 포트를 켜준다.

     
      - name: Docker compose
        uses: appleboy/ssh-action@master
        with:
          username: ubuntu
          host: ${{ secrets.LIVE_SERVER_IP }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script_stop: true
          script: |
            sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/spring-boot-developer: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: http://${{ secrets.LIVE_SERVER_IP }}:${{env.STOPPED_PORT}}/env
          max-attempts: 3
          retry-delay: 10s

      - name: Change nginx upstream
        uses: appleboy/ssh-action@master
        with:
          username: ubuntu
          host: ${{ secrets.LIVE_SERVER_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.LIVE_SERVER_IP }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script_stop: true
          script: |
            sudo docker stop ${{env.CURRENT_UPSTREAM}}
            sudo docker rm ${{env.CURRENT_UPSTREAM}}

그 다음에는 docker-compose를 실행시킨다.

 

github action에서 EC2로 접속을 할 건데, 그걸 자동으로 해줄 수 있게끔 username을 설정해준다.

나머지도 compose를 통해 설정해주면 자동 deploy 방식 끝이다.

반응형