Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- ESLint #Prettier
- yup
- useState
- redux
- social login #facebook login
- git flow
- 옵셔널 체이닝
- useref
- cafe24
- 쇼핑몰
- social login #kakao login
- react editor #TinyMCE editor
- Material UI
- social login #google login
- social login #Microsoft login
Archives
- Today
- Total
여행가는개발자
Github Action을 활용한 branch 배포 본문
728x90
반응형
워크플로우
- 특정 branch 에 코드가 push 됨
- push 이벤트를 트리거 하여 작성된 워크플로우 실행
- checkout github repository
- docker build and ACR push(auzre 도커 이미지 저장소)
- github 환경 변수에 image tag 와 acr login server 설정
- 설정된 변수로 k8s 매니페스트 임시 파일 생성
- Azure 로그인
- Azure AKS 클러스터와 연결
- 생성된 k8s 임시 파일을 이용하여 애플리케이션 배포
Github Action 구조
- develop-workflow.yml (Github Action 파일)
name: Build and deploy - develop myApp Front
on:
pull_request:
types: [ closed ]
branches:
- develop # 트리거 대상 브랜치 설정
workflow_dispatch:
env:
SLACK_WEBHOOK_URL: ${{ vars.SLACK_WEBHOOK_URL }}
STEP: "Staging"
jobs:
prepare_build:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: 'Send Slack PR Notification'
run: |
curl -X POST --data-urlencode "payload={\"channel\": \"C0566RX1U9H\", \"username\": \"myApp Front - $STEP\", \"text\": \"Merged PR, Start build\", \"icon_emoji\": \":red_car:\"}" $SLACK_WEBHOOK_URL
build:
needs: prepare_build
runs-on: ubuntu-latest
steps:
- name: 'Checkout repository'
uses: actions/checkout@v4
- name: 'Login to ACR'
uses: azure/docker-login@v2
with:
# 환경에 따라 적절한 ACR 서버 설정
login-server: ${{ secrets.DEV_ACR_LOGIN_SERVER }}
username: ${{ secrets.DEV_ACR_USERNAME }}
password: ${{ secrets.DEV_ACR_PASSWORD }}
- name: 'set up docker buildx'
uses: docker/setup-buildx-action@v3
- name: build and push
uses: docker/build-push-action@v6
with:
context: .
dockerfile: Dockerfile
push: true
# Kubernetes 매니페스트와 일치하도록 이미지 이름 설정
tags: ${{ secrets.DEV_ACR_LOGIN_SERVER }}/myApp-front:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
PROFILE=staging
deploy:
needs: [ prepare_build, build ]
runs-on: ubuntu-latest
steps:
- name: 'Checkout repository'
uses: actions/checkout@v4
- name: 'set environment variable'
run: |
echo "IMAGE_TAG=${{ github.sha }}" >> $GITHUB_ENV
echo "ACR_LOGIN_SERVER=${{ secrets.DEV_ACR_LOGIN_SERVER }}" >> $GITHUB_ENV
- name: 'generate k8s manifest'
run: |
# Kubernetes 매니페스트 파일 생성 {실제 파일명} > {임시 파일명}
envsubst < ${{ github.base_ref }}-k8s.yml > ${{ github.base_ref }}-tmp-k8s.yml
shell: bash
- name: 'Azure login'
uses: azure/login@v1.6.1
with:
# Azure 인증 정보 설정
creds: ${{ secrets.DEV_AZURE_CREDENTIALS }}
- name: 'Set AKS context STAGING'
uses: azure/aks-set-context@v3
with:
# Kubernetes 클러스터 정보 설정
cluster-name: ${{ secrets.DEV_CLUSTER_NAME }}
resource-group: ${{ secrets.DEV_CLUSTER_RESOURCE_GROUP }}
- name: 'Setup kubectl STAGING'
uses: azure/setup-kubectl@v3
- name: 'Deploy to AKS front STAGING'
uses: azure/k8s-deploy@v5
with:
namespace: 'default'
manifests: |
# 생성된 Kubernetes 매니페스트 임시 파일 경로 지정
${{ github.base_ref }}-tmp-k8s.yml
- name: 'Send Slack Notification'
if: success() || failure()
run: |
STATUS="완료"
if [ "${{ job.status }}" == "failure" ]; then
STATUS="실패"
fi
curl -X POST --data-urlencode "payload={\"channel\": \"C0566RX1U9H\", \"username\": \"myApp Front - $STEP\", \"text\": \"*$STEP* 배포 *$STATUS! $EMOJI*\", \"icon_emoji\": \":red_car:\"}" $SLACK_WEBHOOK_URL
flowchart TB
classDef blue fill:blue, stroke:black, stroke-width:2px, color:white
classDef yellow fill:yellow, stroke:black, stroke-width:2px, color:black
node(MyBranch)
node --> r1
r1(Github):::yellow
r1-->|action|r2(job)
r2-->r5(deploy)
r2-->r4(build)
r2-->r3(prepare_build)
subgraph deploy
direction LR
r5--->r5.1(Azure login)
r5--->r5.2(kubectl)
r5--->r5.3(Azure Deploy)
r5--->r5.4(Slack PR)
end
subgraph build
direction LR
r4--->r4.1(repository)
r4--->r4.2(Login ACR)
r4--->r4.3(docker)
end
subgraph prepare_build
direction LR
r3--->r3.1(Slack PR)
end
prepare_build
- Slack PR - 슬랙에 ‘Merged PR, Start build’ 문구와 함께 배포를 시작했다는 메세지를 날립니다.
build
- repository - 브랜치에 있는 코드를 체크아웃합니다.
- Login ACR - ACR에 로그인을 합니다.
- docker - 도커 파일을 빌드/푸시합니다
FROM node:20.11.1-slim as base
FROM base as deps
WORKDIR /app
COPY package.json .
RUN yarn install
FROM base as builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
RUN yarn config set depth 0 && yarn cache clean --force
RUN yarn global add env-cmd
ARG PROFILE=staging
COPY . .
RUN env-cmd -f .env.${PROFILE} $(yarn bin)/next build
FROM base as runner
WORKDIR /app
ARG PROFILE=staging
ENV NODE_ENV ${PROFILE}
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]
deploy
- Azure login - 애저에 로그인합니다.
- kubectl - k8s 파일을 푸시/배포합니다.
---
# front deploy
apiVersion: apps/v1
kind: Deployment
metadata:
name: myApp-front
spec:
replicas: 1
selector:
matchLabels:
app: myApp
tier: front
template:
metadata:
labels:
app: myApp
tier: front
spec:
containers:
- name: myApp-front
image: ${ACR_LOGIN_SERVER}/myApp-front:${IMAGE_TAG}
imagePullPolicy: Always
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 15
ports:
- containerPort: 3000
name: myApp-front
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
---
# customer ilb svc
apiVersion: v1
kind: Service
metadata:
name: myApp-svc-front
labels:
app: myApp
spec:
ports:
- port: 80
targetPort: 3000
selector:
app: myApp
tier: front
---
- Azure Deploy - 애저에 배포합니다.
- Slack PR - 슬랙에 빌드 성공 / 실패를 메세지를 남깁니다.
health check 코드 추가
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
const url = request.nextUrl.clone();
if (url.pathname === '/health') {
return new NextResponse(
JSON.stringify({
status: 'ok',
timestamp: new Date().toISOString()
}),
{
status: 200,
headers: {
'Content-Type': 'application/json'
}
}
);
}
return NextResponse.next();
}
export const config = {
matcher: '/health',
};
728x90
반응형
'개발 스터디' 카테고리의 다른 글
구글 스프레드 시트를 활용한 번역 기능 (0) | 2025.03.20 |
---|---|
이펙티브 타입스크립트 (0) | 2025.03.20 |
[FE개발 스터디] 함께 자라기 - 애자일로 가는 길 (29) | 2024.11.15 |