GitHub Actions WorkFlow 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 name:  cicd-V2 on:   push:      paths:      -  'springboot-CICD/**'      tags:      -  'v[0-9]+.[0-9]+.[0-9]+'    pull_request:      types:  [opened , synchronize , closed ]     branches:  ["release-dev" , "develop" , "release-prod" ]     paths:      -  'springboot-CICD/**'  jobs:   test:      if:  github.event.action  ==  'opened'  ||  github.event.action  ==  'synchronize'      runs-on:  ubuntu-latest      steps:      -  name:  checkout        uses:  actions/checkout@v4      -  name:  Set  up  JDK  17        uses:  actions/setup-java@v4        with:          java-version:  17          distribution:  'temurin'      -  name:  Grant  execute  permission  for  gradlew        run:  |          cd springboot-CICD         chmod +x gradlew -  name:  Build  with  Gradle       run:  |          cd springboot-CICD         ./gradlew build   set-environment:      if:  github.event.pull_request.merged  ==  true  ||  github.ref_type  ==  'tag'      runs-on:  ubuntu-latest      outputs:        environment:  ${{  steps.set-env.outputs.environment  }}      steps:      -  name:  set  env        id:  set-env        run:  |                   if [[ ${{ github.ref_type }} == "tag" ]]; then           echo "environment=develop" >> $GITHUB_OUTPUT            exit 0         fi         if  [[ ${{ github.ref_type }}   ==  "branch"  ]];  then            echo  "environment=dev"  >>  $GITHUB_OUTPUT            if  [[ ${{ github.base_ref }}   ==  "release-prod"  ]];  then              echo  "environment=prod"  >>  $GITHUB_OUTPUT             elif  [[ ${{ github.base_ref }}   ==  "develop"  ]];  then              echo  "environment=develop"  >>  $GITHUB_OUTPUT            fi          fi      -  name:  check  env        run:  echo  ${{  steps.set-env.outputs.environment  }}    image-build:      if:  needs.set-environment.outputs.environment  !=  'develop'      runs-on:  ubuntu-latest      needs:  [ set-environment  ]     permissions:        id-token:  write        contents:  read      strategy:        matrix:          environment:  [ "${{ needs.set-environment.outputs.environment }} "  ]     environment:  ${{  matrix.environment  }}      steps:      -  name:  checkout  the  code        uses:  actions/checkout@v4      -  name:  Configure  AWS  Credentials        id:  credentials        uses:  aws-actions/configure-aws-credentials@v4        with:          aws-region:  ${{  vars.AWS_REGION  }}          role-to-assume:  ${{  secrets.AWS_ROLE_TO_ASSUME  }}      -  name:  Login  to  Amazon  ECR        id:  login-ecr        uses:  aws-actions/amazon-ecr-login@v2        with:          mask-password:  'true'      -  name:  docker  build  &  push        run:  |          docker build -f ./springboot-CICD/Dockerfile --tag ${{ secrets.REGISTRY }}/${{ vars.REPOSITORY }}:${{ github.sha }} ./springboot-CICD         docker push ${{ secrets.REGISTRY }}/${{ vars.REPOSITORY }}:${{ github.sha }}   deploy:      if:  needs.set-environment.outputs.environment  !=  'prod'      runs-on:  ubuntu-latest      needs:  [ set-environment , image-build  ]     permissions:        id-token:  write        contents:  read      strategy:        matrix:          environment:  ["${{ needs.set-environment.outputs.environment }} " ]     environment:  ${{  matrix.environment  }}      steps:      -  name:  checkout  the  code        uses:  actions/checkout@v4      -  name:  Configure  AWS  Credentials        id:  credentials        uses:  aws-actions/configure-aws-credentials@v4        with:          aws-region:  ${{  vars.AWS_REGION  }}          role-to-assume:  ${{  secrets.AWS_ROLE_TO_ASSUME  }}      -  name:  setup  kubectl        uses:  azure/setup-kubectl@v3        with:          version:  latest      -  name:  setup  helm        uses:  azure/setup-helm@v3        with:          version:  v3.11.1      -  name:  access  kubernetes        run:  |          aws eks update-kubeconfig --name ${{ vars.CLUSTER_NAME }} -  name:  deploy       id:  status        run:  |          helm upgrade --install spring-boot-app kubernetes/spring-boot-app --create-namespace --namespace spring-boot-${{ vars.SUFFIX }} \         --set image.tag=${{ github.sha }} \         --set image.repository=${{ secrets.REGISTRY }}/${{ vars.REPOSITORY }} -  name:  notify       if:  always()        uses:  slackapi/slack-github-action@v1.24.0        with:          payload:  |            {             "text": "message",             "blocks": [               {                 "type": "section",                 "text": {                   "type": "mrkdwn",                   "text": "Environment : ${{ matrix.environment }}, Deploy Result : ${{ steps.status.outcome }}, Repository : ${{ github.repository }}."                 }               }             ]           } env:         SLACK_WEBHOOK_URL:  ${{  secrets.SLACK_WEBHOOK_URL  }}          SLACK_WEBHOOK_TYPE:  INCOMING_WEBHOOK    create-pr-develop:      if:  needs.set-environment.outputs.environment  ==  'develop'  &&  github.ref_type  ==  'tag'      runs-on:  ubuntu-latest      needs:  [set-environment ]     steps:      -  name:  checkout        uses:  actions/checkout@v4      -  name:  gh  auth  login        run:  |          echo ${{ secrets.PERSONAL_ACCESS_TOKEN }} | gh auth login --with-token -  name:  create  branch       run:  |          git checkout -b release/${{ github.ref_name }}         git push origin release/${{ github.ref_name }} -  name:  create  pr       run:  |          gh pr create --base develop --head release/${{ github.ref_name }} --title "release/${{ github.ref_name }} -> develop" --body "release pr"   create-pr-prod:      if:  needs.set-environment.outputs.environment  ==  'develop'  &&  github.event.pull_request.merged  ==  true      runs-on:  ubuntu-latest      needs:  [set-environment ]     steps:      -  name:  checkout        uses:  actions/checkout@v4      -  name:  gh  auth  login        run:  |          echo ${{ secrets.PERSONAL_ACCESS_TOKEN }} | gh auth login --with-token -  name:  create  pr       run:  |          gh pr create --base release-prod --head ${{ github.ref_name }} --title "${{ github.head_ref }} -> ${{ github.ref_name }} -> release-prod" --body "release pr"   approve:      if:  needs.set-environment.outputs.environment  ==  'prod'      runs-on:  ubuntu-latest      environment:  approve-process      needs:  [set-environment , image-build ]     steps:      -  name:  approve        run:  |          echo "Approve Done"   prod-deploy:      runs-on:  ubuntu-latest      needs:  [ approve  ]     permissions:        id-token:  write        contents:  read      strategy:        matrix:          environment:  ["${{ needs.set-environment.outputs.environment }} " ]     environment:  ${{  matrix.environment  }}      steps:      -  name:  checkout  the  code        uses:  actions/checkout@v4      -  name:  Configure  AWS  Credentials        id:  credentials        uses:  aws-actions/configure-aws-credentials@v4        with:          aws-region:  ${{  vars.AWS_REGION  }}          role-to-assume:  ${{  secrets.AWS_ROLE_TO_ASSUME  }}      -  name:  setup  kubectl        uses:  azure/setup-kubectl@v3        with:          version:  latest      -  name:  setup  helm        uses:  azure/setup-helm@v3        with:          version:  v3.11.1      -  name:  access  kubernetes        run:  |          aws eks update-kubeconfig --name ${{ vars.CLUSTER_NAME }} -  name:  deploy       id:  status        run:  |          helm upgrade --install spring-boot-app kubernetes/spring-boot-app --create-namespace --namespace spring-boot-${{ vars.SUFFIX }} \         --set image.tag=${{ github.sha }} \         --set image.repository=${{ secrets.REGISTRY }}/${{ vars.REPOSITORY }} -  name:  notify       if:  always()        uses:  slackapi/slack-github-action@v1.24.0        with:          payload:  |            {             "text": "message",             "blocks": [               {                 "type": "section",                 "text": {                   "type": "mrkdwn",                   "text": "Environment : ${{ matrix.environment }}, Deploy Result : ${{ steps.status.outcome }}, Repository : ${{ github.repository }}."                 }               }             ]           } env:         SLACK_WEBHOOK_URL:  ${{  secrets.SLACK_WEBHOOK_URL  }}          SLACK_WEBHOOK_TYPE:  INCOMING_WEBHOOK  
이번에 소개하고자 하는 WorkFlow 전체적인 코드 입니다.
하나씩 소개 하도록 하겠습니다.
트리거 구성 1 2 3 4 5 6 7 8 9 10 11 12 13 name:  cicd-V2 on:   push:      paths:      -  'springboot-CICD/**'      tags:      -  'v[0-9]+.[0-9]+.[0-9]+'    pull_request:      types:  [opened , synchronize , closed ]     branches:  ["release-dev" , "develop" , "release-prod" ]     paths:      -  'springboot-CICD/**'  
트리거 구성 코드 입니다. 여기서 name 은 ‘cicd-V2’ 로 임의로 지정 했습니다.
‘pull_request’ 경우에는 발생될때 트리거가 발동 되지만 ‘opened’, ‘synchronize’, ‘closed’ 한에서만 발동 됩니다. 그리고 브랜치 경우 “release-dev”, “develop”, “release-prod” 한에서만 발동 됩니다.
Job ‘test’ 구성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 test:   if:  github.event.action  ==  'opened'  ||  github.event.action  ==  'synchronize'    runs-on:  ubuntu-latest    steps:    -  name:  checkout      uses:  actions/checkout@v4    -  name:  Set  up  JDK  17      uses:  actions/setup-java@v4      with:        java-version:  17        distribution:  'temurin'    -  name:  Grant  execute  permission  for  gradlew      run:  |        cd springboot-CICD       chmod +x gradlew -  name:  Build  with  Gradle     run:  |        cd springboot-CICD       ./gradlew build 
Job 에서 ‘test’ 구성 입니다. 앞서 말씀드렸던 CI 역활을 하고 있다고 보시면 됩니다. 여기서 if 조건을 확인 할 수 있는데 PR 을 오픈되거나 PR 동기화 할때
다음에 steps 입니다. 임의로 지정한 ‘checkout’ 이라는 name 보면 uses key 로 설정한 checkout 볼수 있는데 github repository 를 가져오는 역활을 합니다.
그 다음은 해당 어플리케이션을 build 통해 test 코드가 문제가 없는지 체크를 합니다.
Job ‘set-environment’ 구성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 set-environment:   if:  github.event.pull_request.merged  ==  true  ||  github.ref_type  ==  'tag'    runs-on:  ubuntu-latest    outputs:      environment:  ${{  steps.set-env.outputs.environment  }}    steps:    -  name:  set  env      id:  set-env      run:  |               if [[ ${{ github.ref_type }} == "tag" ]]; then         echo "environment=develop" >> $GITHUB_OUTPUT          exit 0       fi       if  [[ ${{ github.ref_type }}   ==  "branch"  ]];  then          echo  "environment=dev"  >>  $GITHUB_OUTPUT          if  [[ ${{ github.base_ref }}   ==  "release-prod"  ]];  then            echo  "environment=prod"  >>  $GITHUB_OUTPUT           elif  [[ ${{ github.base_ref }}   ==  "develop"  ]];  then            echo  "environment=develop"  >>  $GITHUB_OUTPUT          fi        fi    -  name:  check  env      run:  echo  ${{  steps.set-env.outputs.environment  }}  
Job ‘set-environment’ 경우는 CD 작업일 경우 배포전 배포 할 환경을 판단하는 Job 입니다.
Job ‘image-build’ 구성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 image-build:  if:  needs.set-environment.outputs.environment  !=  'develop'   runs-on:  ubuntu-latest   needs:  [ set-environment  ]  permissions:     id-token:  write     contents:  read   strategy:     matrix:       environment:  [ "${{ needs.set-environment.outputs.environment }} "  ]  environment:  ${{  matrix.environment  }}   steps:   -  name:  checkout  the  code     uses:  actions/checkout@v4   -  name:  Configure  AWS  Credentials     id:  credentials     uses:  aws-actions/configure-aws-credentials@v4     with:       aws-region:  ${{  vars.AWS_REGION  }}       role-to-assume:  ${{  secrets.AWS_ROLE_TO_ASSUME  }}   -  name:  Login  to  Amazon  ECR     id:  login-ecr     uses:  aws-actions/amazon-ecr-login@v2     with:       mask-password:  'true'   -  name:  docker  build  &  push     run:  |       docker build -f ./springboot-CICD/Dockerfile --tag ${{ secrets.REGISTRY }}/${{ vars.REPOSITORY }}:${{ github.sha }} ./springboot-CICD      docker push ${{ secrets.REGISTRY }}/${{ vars.REPOSITORY }}:${{ github.sha }} 
그 다음은 Job 조건에서 ‘image-build’ 입니다. CD 진행 할때 진행되는 Job 입니다. if 조건에 앞써 Job 실행 중 ‘set-environment’ 과정에서 배포 환경 값이 ‘develop’ 값이
needs 조건이 보이는데 여기서 Job 과정 중 ‘set-environment’ Job 이 실행이 완료된 후에만 ‘image-build’ 실행 하도록 구성 하는 역활 입니다.
그 다음에는 ‘matrix’ 기능이 있습니다. 이 기능은 GitHub Actions 페이지에서 더 편한 시각화를 하기 위한 기능입니다. 여기서 ‘set-environment’ 통해 배포 환경
그 다음 Step 영역을 보시면 checkout 기능을 통해 현재 실행되는 브랜치 repository 를 가져오고 AWS Credentials 로그인 할수 있도록 미리
AWS 인증이 완료 된 이후 AWS ECR 로그인을 진행하게 되고 해당 애플리케이션 루트 경로에 미리 준비한 DockerFile 통해 Docker build 진행하고 빌드가 완료 된 이후
여기서 환경 변수 값을 통해 build 및 push 를 진행 하는데 이러한 변수 설정 값은 이후 방법은 안내 하도록 하겠습니다.
Job ‘deploy’ 구성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 deploy:   runs-on:  ubuntu-latest    needs:  [ set-environment , image-build  ]   permissions:      id-token:  write      contents:  read    strategy:      matrix:        environment:  ["${{ needs.set-environment.outputs.environment }} " ]   environment:  ${{  matrix.environment  }}    steps:    -  name:  checkout  the  code      uses:  actions/checkout@v4    -  name:  Configure  AWS  Credentials      id:  credentials      uses:  aws-actions/configure-aws-credentials@v4      with:        aws-region:  ${{  vars.AWS_REGION  }}        role-to-assume:  ${{  secrets.AWS_ROLE_TO_ASSUME  }}    -  name:  setup  kubectl      uses:  azure/setup-kubectl@v3      with:        version:  latest    -  name:  setup  helm      uses:  azure/setup-helm@v3      with:        version:  v3.11.1    -  name:  access  kubernetes      run:  |        aws eks update-kubeconfig --name ${{ vars.CLUSTER_NAME }} -  name:  deploy     id:  status      run:  |        helm upgrade --install spring-boot-app kubernetes/spring-boot-app --create-namespace --namespace spring-boot-${{ vars.SUFFIX }} \       --set image.tag=${{ github.sha }} \       --set image.repository=${{ secrets.REGISTRY }}/${{ vars.REPOSITORY }} -  name:  notify     if:  always()      uses:  slackapi/slack-github-action@v1.24.0      with:        payload:  |          {           "text": "message",           "blocks": [             {               "type": "section",               "text": {                 "type": "mrkdwn",                 "text": "Environment : ${{ matrix.environment }}, Deploy Result : ${{ steps.status.outcome }}, Repository : ${{ github.repository }}."               }             }           ]         } env:       SLACK_WEBHOOK_URL:  ${{  secrets.SLACK_WEBHOOK_URL  }}        SLACK_WEBHOOK_TYPE:  INCOMING_WEBHOOK  
그 다음은 Job 조건에서 ‘deploy’ 입니다. CD 진행 할때 진행되는 Job 입니다. 앞써 실행된 ‘image-build’ 에서 최종적으로 만들어진 docker image
동일하게 checkout 진행 하고 인증을 위해 AWS Credentials 실행 하도록 합니다. 그 다음은 ‘kubectl’ 하고 ‘helm’ 액션을 이용하는데 kubernetes 하고 helm
kubernetes 접근 하기 위해 
1 aws eks update-kubeconfig --name ${{ vars.CLUSTER_NAME }} 
명령어를 사용 합니다. 완료되면 지정된 cluster 에 접근이 가능해집니다. 그 다음 ‘deploy’ Step 에서는 helm 커멘드를 이용해서 접근한 kubernetes Cluster 에 배포 하도록 합니다.
그 다음 ‘notify’ step 일 경우 if 조건을 always() 사용 한다는 것을 볼수 있습니다. ‘deploy’ 작업이 성공은 물론 실패 하더라도 slack 에 메시지를
Job ‘create-pr-develop’ 구성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 create-pr-develop:   if:  needs.set-environment.outputs.environment  ==  'develop'  &&  github.ref_type  ==  'tag'    runs-on:  ubuntu-latest    needs:  [set-environment ]   steps:    -  name:  checkout      uses:  actions/checkout@v4    -  name:  gh  auth  login      run:  |        echo ${{ secrets.PERSONAL_ACCESS_TOKEN }} | gh auth login --with-token -  name:  create  branch     run:  |        git checkout -b release/${{ github.ref_name }}       git push origin release/${{ github.ref_name }} -  name:  create  pr     run:  |        gh  pr  create  --base  develop  --head  release/${{  github.ref_name  }}  --title  "release/${{ github.ref_name }}  -> develop"  --body  "release pr"  
if 조건을 보면 ‘set-environment’ Job 통해 설정한 배포 환경 값이 ‘develop’ 이고 push 조건인 ‘tag’ 일 경우에만 발동 하도록 되어 있습니다.
needs 경우 ‘set-environment’ job 이 완료해야 실행 가능하도록 되어 있습니다.
1 2 3 -  name:  gh  auth  login   run:  |     echo  ${{  secrets.PERSONAL_ACCESS_TOKEN  }}  |  gh  auth  login  --with-token  
step 에서 github auth login 하기 위한 명령어 입니다. github 홈페이지에서 생성한 PERSONAL_ACCESS_TOKEN 을 이용해서 인증 처리 하게 됩니다.
Job ‘create-pr-prod’ 구성 1 2 3 4 5 6 7 8 9 10 11 12 13 create-pr-prod:   if:  needs.set-environment.outputs.environment  ==  'develop'  &&  github.event.pull_request.merged  ==  true    runs-on:  ubuntu-latest    needs:  [set-environment ]   steps:    -  name:  checkout      uses:  actions/checkout@v4    -  name:  gh  auth  login      run:  |        echo ${{ secrets.PERSONAL_ACCESS_TOKEN }} | gh auth login --with-token -  name:  create  pr     run:  |        gh  pr  create  --base  release-prod  --head  ${{  github.ref_name  }}  --title  "${{ github.head_ref }}  -> ${{ github.ref_name }}  -> release-prod"  --body  "release pr"  
이전 Job ‘create-pr-develop’ 에서 생성한 ‘release/${tag name}’ 브랜치에서 ‘develop’ 브랜치로 merge 실행시 작동 하게 됩니다.
Job ‘approve’ 구성 1 2 3 4 5 6 7 8 9 approve:   if:  needs.set-environment.outputs.environment  ==  'prod'    runs-on:  ubuntu-latest    environment:  approve-process    needs:  [set-environment , image-build ]   steps:    -  name:  approve      run:  |        echo  "Approve Done"  
브랜치 ‘release-prod’ CD 작업 중 일때
그래서 Approve Process 라는 환경을 구성하고 Protection Rule 을 설정을 한 다음 GitHub Actions Job 에서 Environment 값으로 Approve Process 를
Job ‘prod-deploy’ 구성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 prod-deploy:   runs-on:  ubuntu-latest    needs:  [ approve  ]   permissions:      id-token:  write      contents:  read    strategy:      matrix:        environment:  ["prod" ]   environment:  ${{  matrix.environment  }}    steps:    -  name:  checkout  the  code      uses:  actions/checkout@v4    -  name:  Configure  AWS  Credentials      id:  credentials      uses:  aws-actions/configure-aws-credentials@v4      with:        aws-region:  ${{  vars.AWS_REGION  }}        role-to-assume:  ${{  secrets.AWS_ROLE_TO_ASSUME  }}    -  name:  setup  kubectl      uses:  azure/setup-kubectl@v3      with:        version:  latest    -  name:  setup  helm      uses:  azure/setup-helm@v3      with:        version:  v3.11.1    -  name:  access  kubernetes      run:  |        aws eks update-kubeconfig --name ${{ vars.CLUSTER_NAME }} -  name:  deploy     id:  status      run:  |        helm upgrade --install spring-boot-app kubernetes/spring-boot-app --create-namespace --namespace spring-boot-${{ vars.SUFFIX }} \       --set image.tag=${{ github.sha }} \       --set image.repository=${{ secrets.REGISTRY }}/${{ vars.REPOSITORY }} -  name:  notify     if:  always()      uses:  slackapi/slack-github-action@v1.24.0      with:        payload:  |          {           "text": "message",           "blocks": [             {               "type": "section",               "text": {                 "type": "mrkdwn",                 "text": "Environment : ${{ matrix.environment }}, Deploy Result : ${{ steps.status.outcome }}, Repository : ${{ github.repository }}."               }             }           ]         } env:       SLACK_WEBHOOK_URL:  ${{  secrets.SLACK_WEBHOOK_URL  }}        SLACK_WEBHOOK_TYPE:  INCOMING_WEBHOOK  
Job ‘approve’ 최종 승인을 받고 실행되는 deploy Job 입니다. 기존 ‘deploy’ Job 을 재활용 하기가 어려워서 동일한 ‘deploy’ Job 인
      
        Copyright 201- syh8088. 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.