[배포3] SpringBoot, Docker, Nginx, githubAction 무중단 배포 : docker compose 파일 생성과 githubAction Yaml 파일 생성

디하·2024년 2월 19일
2

배포

목록 보기
3/8
post-thumbnail

docker compose 생성🧞‍♂️


🌟 dockercompose 생성 전에 springboot project에 설정해둘 파일 설정해놓기!

src/resource/ application.yml

spring:
  profiles:
    active: local
    group:
      local: common
      blue: blue, common
      green: green, common

server:
  env: blue

---

spring:
  config:
    activate:
      on-profile: common

serverName: common


---

spring:
  config:
    activate:
      on-profile: blue

server:
  port: 8080

serverName: blue_server

---

spring:
  config:
    activate:
      on-profile: green

server:
  port: 8081

serverName: green_server

---





docker compose 생성🧞‍

1. ubuntu 서버에 docker-compose-blue.yml 파일 생성

vim docker-compose-blue.yml

i를 누르고 --insert-- 모드로 아래 사진 처럼 내용을 작성해 준다

  • image: docker username/ 새로 생성할 서버 이름

version: '3.8'

services:
  blue:
    image: {dockerHubUserName}/boardServer:latest
    container_name: blue
    ports:
      - "8080:8080"
    environment:
      - PROFILES=blue
      - ENV=blue

esc -> :wq! 로 저장 후 나가기

2. docker-compose-green 파일 만들기

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

현재 파일을 복제해서 이름을 바꿔서 저장해준다

vim docker-compose-green.yml

blue->green으로 바꿔주고 포트번호를 8081로 변경해준다


version: '3.8'

services:
  green:
    image: {dockerHubUserName}/boardServer:latest
    container_name: green
    ports:
      - "8081:8081"
    environment:
      - PROFILES=green
      - ENV=green

파일 내용 확인 하기

cat docker-compose-blue.yml

cat명령어로 vim 수정으로 들어가지 않아도 안에 내용을 확인할 수 있다


2. github actions

name: CICD

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 21
      uses: actions/setup-java@v3
      with:
        java-version: '21'
        distribution: 'temurin'
    
    - name: Build with Gradle
      uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
      with:
       arguments: build
        # run : ./gradlew clean build --exclude-task 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 }}/boardServer .
    - name: Push Docker
      run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/boardServer:latest

인텔리제이에서 project -> new file
Dockerfile 생성

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

Dockerfile에 위에 내용을 작성해줌


github에서 secret 설정

이렇게 공개되면 안되는 중요한 정보를 담아준다 생각하면 된다


ec2 pem 키 설정

mac 에서 pem키를 그냥 열수 없기 때문에 어떻게 접근해야하냐면 vscode로 파일을 열면

-----BEGIN RSA PRIVATE KEY-----
.
.
.
-----END RSA PRIVATE KEY-----

이 내용 전부를 긁어서 secrets에 설정하면 된다



cicd.yml 파일을 아래처럼 다 완성해주었다

name: CICD

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 21
      uses: actions/setup-java@v3
      with:
        java-version: '21'
        distribution: 'temurin'
    
    - name: Build with Gradle
      uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
      with:
       arguments: build
        # run : ./gradlew clean build --exclude-task 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 }}/board_server .
    - name: Push Docker
      run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/board_server:latest
      
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Set target IP
        run: |
          STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.BOARD_SERVER_IP }}/env")
          echo $STATUS
          if [ $STATUS = 200 ]; then
            CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.BOARD_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
          else 
            echo "CURRENT_PORT=8081" >> $GITHUB_ENV
            echo "STOPPED_PORT=8080" >> $GITHUB_ENV
            echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV
          fi
          
      - name: Docker compose
        uses: appleboy/ssh-action@master
        with:
          username: ubuntu
          host: ${{ secrets.BOARD_SERVER_IP }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script_stop: true
          script: |
            sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/board_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.BOARD_SERVER_IP }}:${{env.STOPPED_PORT}}/env
          max-attempts: 5
          retry-delay: 20s

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

이렇게 하고
springboot project git commit -> push 를 통해서 빌드 실행해주었다

하지만 바로 오류가 나기 시작했다 ㅎㅎ

이 밑에는 그 오류들을 해결해 나간 기록들이다!

github actions 오류

1. build docker 오류

  1. springboot project 에 있는 Dockerfile 수정해주기
FROM amazoncorretto:21-alpine-jdk
ARG JAR_FILE=*.jar
ARG PROFILES
ARG ENV
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "Dspring.profiles.active=${PROFILES}", "-Dserver.env=${ENV}", "-jar", "app.jar"]

ARG JAR_FILE=target/.jar -> ARG JAR_FILE=build/libs/.jar 으로 변경
target/ 폴더안에 jar이 있지 않기 때문이라고 판단 했기 때문이다

  1. build/libs/ *jar 파일이 없었다
    아래 사진 처럼 jar 파일이 있어야 했는데 없었다


bootjar를 클릭해주면 bootjar이 빌드되는데
그러면 libs 폴더안에 jar 파일이 생성이 된다

그러고 나면 위에 build docker 오류는 해결이 되었다

2. docker compose 오류

빌드 단계에서는 성공을 하더니 deploy 단계에서 오류에 봉착했다..🥲

구글링을 하다가 하나의 글에서 본 걸 보고 혹시나 해서 적용을 했는데 이 오류에서 벗어날 수 있었다

그건 ec2에서 보안그룹 인바운드 규칙 설정 중 ssh 서버를 내IP로 설정해두어
ip가 막혀서 연결이 안되는 오류였다

이렇게 다 0.0.0.0/0 서버로 지정해 주니 deploy 단계중 dockercompose 오류에서 빠져나올 수 있었다


😫 대망의 health check 오류

정말... 이 오류에서 빠져나오기 까지 꽤 오랜 시간이 걸렸다..
도대체 무엇인지 모르는 상태에서 오류라... 서치를 해도 뚜렷한 답을 찾지 못했다

결국 내가 수정한 부분들이.. 이 오류를 빠져나오게 해주었기에 정확한 방법은 아니지만 공유해보려고 한다

  1. /etc/nginx/conf.d/default.conf 파일에서 ip 주소변경해주기
    처음엔 여기서 인스턴스 프라이빗 Ipv4 주소를 넣어주었다
    그리고 application.yml 에서 탄력적 Ip주소를 넣어 jar 파일을 구워서 보docker로 푸시만 해주면 되는 줄 알았다

하지만, 이 부분에서 탄력적 Ip 로 정확하게 연결되어있는지를 확인이 되지 않았고, 여기서 헬스체크 오류가 난다고 판단을 했다

그래서 저 빨간색 네모 박스 부분에 탄력적ip를 넣어주었고
application.yml 에서는 탄력적 ip 서버를 삭제해주었다

spring:
  profiles:
    active: local
    group:
      local: common
      blue: blue, common
      green: green, common

server:
  env: blue

---

spring:
  config:
    activate:
      on-profile: common

serverName: common


---

spring:
  config:
    activate:
      on-profile: blue

server:
  port: 8080
  #address: ${AWS_PUBLIC_IP}

serverName: blue_server

---

spring:
  config:
    activate:
      on-profile: green

server:
  port: 8081
  #address: ${AWS_PUBLIC_IP}

serverName: green_server

---

-> 주석처리된 부분이 없애준 부분

nginx -s reload

끝으로 nginx -s reload를 해주어서 파일 변경된 부분을 반영해주었다

이렇게 해서 헬스체크 오류에서 빠져나올 수 있었다
만약 헬스체크에서 계속 반복적인 오류가 난다면
Ip연결이 제대로 되어있는지 확인해 보면 좋을 것 같다!


드디어 배포 성공!!

배포가 성공한 뒤 이게 제대로 배포가 되었는지 확인하기 위해선 두가지를 확인해봐야한다

  1. docker 에서 서버가 제대로 열렸는지 확인

    blue / green 서버가 교체가 잘되는 것을 확인 할 수 있다


  1. 탄력적 ip로 사이트 들어가보기

무중단 배포가 잘 이루어졌으면 탄력적 Ip로 접근이 가능해져야합니다
저는 아직 도메인 설정을 안해줬기 때문에 탄력적 ip로 접근해보았습니다
이렇게 잘 열리면 무중단 배포가 잘 뜨게 됩니다

profile
🖥️ ⌨️🖱️🩵

0개의 댓글

관련 채용 정보