2024-03-25

GithubAction으로 오라클 클라우드 CI/CD 구축하기

Github Action을 사용해서 저번에 구축한 오라클 클라우드 쿠버네티스 환경에 애플리케이션을 배포하는 방법에 대해서 공부하면서 작성한 포스팅이다.
CI/CD를 구축해두지 않았다면 쿠버네티스 배포의 단계는 아래와 같을 것이다.
  1. 작성한 소스 코드를 빌드한다.
  1. 소스 코드를 Docker Image로 빌드한다.
    위 1, 2 단계는 Docker 파일의 설정으로 충분히 한 단계로 압축할 수 있다.
  1. 빌드한 Docker Image를 Docker hub 또는 Docker Image Registry에 push한다.
  1. 서버에 접속하여 서버에서 Kubernetes에 접속한다.
    위 단계 또한 본인 PC에 KubeConfig를 잘 설정해두면 서버에 접속 없이 Kubernetes에 접속이 가능하다.
  1. Deployment 파일을 push한 이미지로 변경 후 Apply 한다.
매번 배포 때 마다 이런 절차를 거쳐가는게 정말 불편하고 번거롭기 때문에 커밋하면 자동으로 배포까지 진행이 되도록 구축을 할 것이다.

Github Actions


Github Actions란?

빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD 플랫폼으로, 리포지토리에 대한 모든 풀 요청을 빌드 및 테스트하거나 병합된 풀 요청을 프로덕션에 배포하는 워크플로를 생성할 수 있다.
Github Actions를 활용하여 DevOps 이상의 기능을 구현하고, 저장소에서 다양한 이벤트가 발생할 때 워크플로를 실행할 수 있게 하기 때문에 다양하게 응용하여 사용할 수 있다.
Ex. develop branch로 push할 경우 개발서버에 배포하기. prodduct branch로 merge할 경우 운영서버에 배포하기.

CI/CD 구상하기


스텝 계획하기

위에서 작성한 순서를 기반으로 스텝을 줄여 보도록 하겠다.
  1. 소스코드를 도커 빌드 시에 빌드하며 이미지 생성 시 push하도록 구성
  1. 배포한 이미지의 버전으로 kubernetes의 deployment.yml을 수정 및 반영
위와 같이 2번에 걸쳐 가능하도록 스텝을 압축시켰다.

스텝 구현하기

.Docker 파일 작성하기

NextJS로 만든 홈페이지를 배포하기 위해서 NextJS에서 예제로 제공하는 Dockerfile을 약간 수정해서 사용하기로 했다.
FROM node:20-alpine AS base

FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json yarn.lock* ./
RUN yarn --frozen-lockfile;


FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN yarn build;
RUN yarn install --frozen-lockfile --production
RUN rm -rf ./.next/cache

FROM base AS runner
WORKDIR /app

ENV NODE_ENV production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

RUN mkdir .next
RUN chown nextjs:nodejs .next

COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD HOSTNAME="0.0.0.0" node server.js

Github Action Workflow 작성하기

수정된 deployment.yml 파일을 적용하기 위해서 kubectl을 실행 시킬 필요가 있었다.
그래서 actions-hub/kubectl를 사용해서 명령어를 실행시키도록 구현했다.
간단하게 deployment.yml에서 이미지를 새롭게 푸쉬한 도커 이미지로 버전을 바꾸고 apply하면 됐다.
아래와 같이 workflow를 작성했다.
name: Deploy my Server
on:
  push:
    branches: [main]
jobs:
  build-deploy:
    name: Build & Deploy
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Create env
        run: |-
          echo "${{ secrets.NOTION_API_KEY }}" >> .env

      - name: Docker login
        uses: docker/login-action@v3
        with:
          registry: yny.ocir.io
          username: ${{ secrets.OCI_REGISTRY_USERNAME }}
          password: ${{ secrets.OCI_REGISTRY_PASSWORD }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: build and push the Docker image
        run: |-
          docker buildx build \
          --push \
          --platform linux/arm64 \
          --tag "${{ secrets.OCI_REGISTRY_URL }}/hbnation-app:$GITHUB_SHA" \
          .

      - name: set Deployment
        run: |-
          sed -i "s|hbnation-app:latest|${{ secrets.OCI_REGISTRY_URL }}/hbnation-app:$GITHUB_SHA|" ./deploy/deployment.yml

      - name: Deploy
        uses: actions-hub/kubectl@master
        env:
          KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
        with:
          args: apply -f ./deploy/deployment.yml
이렇게 작성해서 hbnation-app:latest라는 이미지명을 오라클 컨테이너 레지스트리에 푸쉬한 이미지로 변경해서 apply할 수 있게 만들어주었다.

마치며

배포 때마다 번거롭게 이미지를 빌드해서 레지스트리에 푸쉬하고 deployment.yml를 수정해서 반영하는 절차를 커밋하나로 축약하게 되었다.
이제 더 빠른 배포가 가능하니 차근차근 홈페이지를 더 좋게 만들어볼 예정이다.