mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 05:36:23 +00:00
add ci/cd
This commit is contained in:
parent
9adcab2048
commit
ead263d1d2
File diff suppressed because one or more lines are too long
82
claude/build-image-back.md
Normal file
82
claude/build-image-back.md
Normal file
@ -0,0 +1,82 @@
|
||||
# 백엔드 컨테이너이미지 작성가이드
|
||||
|
||||
[요청사항]
|
||||
- 백엔드 각 서비스를의 컨테이너 이미지 생성
|
||||
- 실제 빌드 수행 및 검증까지 완료
|
||||
- '[결과파일]'에 수행한 명령어를 포함하여 컨테이너 이미지 작성 과정 생성
|
||||
|
||||
[작업순서]
|
||||
- 서비스명 확인
|
||||
서비스명은 settings.gradle에서 확인
|
||||
|
||||
예시) include 'common'하위의 4개가 서비스명임.
|
||||
```
|
||||
rootProject.name = 'tripgen'
|
||||
|
||||
include 'common'
|
||||
include 'user-service'
|
||||
include 'location-service'
|
||||
include 'ai-service'
|
||||
include 'trip-service'
|
||||
```
|
||||
|
||||
- 실행Jar 파일 설정
|
||||
실행Jar 파일명을 서비스명과 일치하도록 build.gradle에 설정 합니다.
|
||||
```
|
||||
bootJar {
|
||||
archiveFileName = '{서비스명}.jar'
|
||||
}
|
||||
```
|
||||
|
||||
- Dockerfile 생성
|
||||
아래 내용으로 deployment/container/Dockerfile-backend 생성
|
||||
```
|
||||
# Build stage
|
||||
FROM openjdk:23-oraclelinux8 AS builder
|
||||
ARG BUILD_LIB_DIR
|
||||
ARG ARTIFACTORY_FILE
|
||||
COPY ${BUILD_LIB_DIR}/${ARTIFACTORY_FILE} app.jar
|
||||
|
||||
# Run stage
|
||||
FROM openjdk:23-slim
|
||||
ENV USERNAME=k8s
|
||||
ENV ARTIFACTORY_HOME=/home/${USERNAME}
|
||||
ENV JAVA_OPTS=""
|
||||
|
||||
# Add a non-root user
|
||||
RUN adduser --system --group ${USERNAME} && \
|
||||
mkdir -p ${ARTIFACTORY_HOME} && \
|
||||
chown ${USERNAME}:${USERNAME} ${ARTIFACTORY_HOME}
|
||||
|
||||
WORKDIR ${ARTIFACTORY_HOME}
|
||||
COPY --from=builder app.jar app.jar
|
||||
RUN chown ${USERNAME}:${USERNAME} app.jar
|
||||
|
||||
USER ${USERNAME}
|
||||
|
||||
ENTRYPOINT [ "sh", "-c" ]
|
||||
CMD ["java ${JAVA_OPTS} -jar app.jar"]
|
||||
```
|
||||
|
||||
- 컨테이너 이미지 생성
|
||||
아래 명령으로 각 서비스 빌드. shell 파일을 생성하지 말고 command로 수행.
|
||||
서브에이젼트를 생성하여 병렬로 수행.
|
||||
```
|
||||
DOCKER_FILE=deployment/container/Dockerfile-backend
|
||||
service={서비스명}
|
||||
|
||||
docker build \
|
||||
--platform linux/amd64 \
|
||||
--build-arg BUILD_LIB_DIR="${서비스명}/build/libs" \
|
||||
--build-arg ARTIFACTORY_FILE="${서비스명}.jar" \
|
||||
-f ${DOCKER_FILE} \
|
||||
-t ${서비스명}:latest .
|
||||
```
|
||||
- 생성된 이미지 확인
|
||||
아래 명령으로 모든 서비스의 이미지가 빌드되었는지 확인
|
||||
```
|
||||
docker images | grep {서비스명}
|
||||
```
|
||||
|
||||
[결과파일]
|
||||
deployment/container/build-image.md
|
||||
770
claude/deploy-actions-cicd-back.md
Normal file
770
claude/deploy-actions-cicd-back.md
Normal file
@ -0,0 +1,770 @@
|
||||
# 백엔드 GitHub Actions 파이프라인 작성 가이드
|
||||
|
||||
[요청사항]
|
||||
- GitHub Actions 기반 CI/CD 파이프라인 구축 가이드 작성
|
||||
- 환경별(dev/staging/prod) Kustomize 매니페스트 관리 및 자동 배포 구현
|
||||
- SonarQube 코드 품질 분석과 Quality Gate 포함
|
||||
- Kustomize 매니페스트 생성부터 배포까지 전체 과정 안내
|
||||
- '[결과파일]'에 구축 방법 및 파이프라인 작성 가이드 생성
|
||||
- 아래 작업은 실제 수행하여 파일 생성
|
||||
- Kustomize 디렉토리 구조 생성
|
||||
- Base Kustomization 작성
|
||||
- 환경별 Overlay 작성
|
||||
- 환경별 Patch 파일 생성
|
||||
- GitHub Actions 워크플로우 파일 작성
|
||||
- 환경별 배포 변수 파일 작성
|
||||
- 수동 배포 스크립트 작성
|
||||
|
||||
[작업순서]
|
||||
- 사전 준비사항 확인
|
||||
프롬프트의 '[실행정보]'섹션에서 아래정보를 확인
|
||||
- {ACR_NAME}: Azure Container Registry 이름
|
||||
- {RESOURCE_GROUP}: Azure 리소스 그룹명
|
||||
- {AKS_CLUSTER}: AKS 클러스터명
|
||||
- {NAMESPACE}: Namespace명
|
||||
예시)
|
||||
```
|
||||
[실행정보]
|
||||
- ACR_NAME: acrdigitalgarage01
|
||||
- RESOURCE_GROUP: rg-digitalgarage-01
|
||||
- AKS_CLUSTER: aks-digitalgarage-01
|
||||
- NAMESPACE: phonebill-dg0500
|
||||
```
|
||||
|
||||
- 시스템명과 서비스명 확인
|
||||
settings.gradle에서 확인.
|
||||
- {SYSTEM_NAME}: rootProject.name
|
||||
- {SERVICE_NAMES}: include 'common'하위의 include문 뒤의 값임
|
||||
|
||||
예시) include 'common'하위의 서비스명들.
|
||||
```
|
||||
rootProject.name = 'phonebill'
|
||||
|
||||
include 'common'
|
||||
include 'api-gateway'
|
||||
include 'user-service'
|
||||
include 'order-service'
|
||||
include 'payment-service'
|
||||
```
|
||||
|
||||
- JDK버전 확인
|
||||
루트 build.gradle에서 JDK 버전 확인.
|
||||
{JDK_VERSION}: 'java' 섹션에서 JDK 버전 확인. 아래 예에서는 21임.
|
||||
```
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- GitHub 저장소 환경 구성 안내
|
||||
- GitHub Repository Secrets 설정
|
||||
- Azure 접근 인증정보 설정
|
||||
```
|
||||
# Azure Service Principal
|
||||
Repository Settings > Secrets and variables > Actions > Repository secrets에 등록
|
||||
|
||||
AZURE_CREDENTIALS:
|
||||
{
|
||||
"clientId": "{클라이언트ID}",
|
||||
"clientSecret": "{클라이언트시크릿}",
|
||||
"subscriptionId": "{구독ID}",
|
||||
"tenantId": "{테넌트ID}"
|
||||
}
|
||||
예시)
|
||||
{
|
||||
"clientId": "5e4b5b41-7208-48b7-b821-d6d5acf50ecf",
|
||||
"clientSecret": "ldu8Q~GQEzFYU.dJX7_QsahR7n7C2xqkIM6hqbV8",
|
||||
"subscriptionId": "2513dd36-7978-48e3-9a7c-b221d4874f66",
|
||||
"tenantId": "4f0a3bfd-1156-4cce-8dc2-a049a13dba23",
|
||||
}
|
||||
```
|
||||
|
||||
- ACR Credentials
|
||||
Credential 구하는 방법 안내
|
||||
az acr credential show --name {acr 이름}
|
||||
예) az acr credential show --name acrdigitalgarage01
|
||||
```
|
||||
ACR_USERNAME: {ACR_NAME}
|
||||
ACR_PASSWORD: {ACR패스워드}
|
||||
```
|
||||
- SonarQube URL과 인증 토큰
|
||||
SONAR_HOST_URL 구하는 방법과 SONAR_TOKEN 작성법 안내
|
||||
SONAR_HOST_URL: 아래 명령 수행 후 http://{External IP}를 지정
|
||||
k get svc -n sonarqube
|
||||
예) http://20.249.187.69
|
||||
|
||||
SONAR_TOKEN 값은 아래와 같이 작성
|
||||
- SonarQube 로그인 후 우측 상단 'Administrator' > My Account 클릭
|
||||
- Security 탭 선택 후 토큰 생성
|
||||
|
||||
```
|
||||
SONAR_TOKEN: {SonarQube토큰}
|
||||
SONAR_HOST_URL: {SonarQube서버URL}
|
||||
```
|
||||
|
||||
- Docker Hub (Rate Limit 해결용)
|
||||
Docker Hub 패스워드 작성 방법 안내
|
||||
- DockerHub(https://hub.docker.com)에 로그인
|
||||
- 우측 상단 프로필 아이콘 클릭 후 Account Settings를 선택
|
||||
- 좌측메뉴에서 'Personal Access Tokens' 클릭하여 생성
|
||||
```
|
||||
DOCKERHUB_USERNAME: {Docker Hub 사용자명}
|
||||
DOCKERHUB_PASSWORD: {Docker Hub 패스워드}
|
||||
```
|
||||
|
||||
- GitHub Repository Variables 설정
|
||||
```
|
||||
# Workflow 제어 변수
|
||||
Repository Settings > Secrets and variables > Actions > Variables > Repository variables에 등록
|
||||
|
||||
ENVIRONMENT: dev (기본값, 수동실행시 선택 가능: dev/staging/prod)
|
||||
SKIP_SONARQUBE: true (기본값, 수동실행시 선택 가능: true/false)
|
||||
```
|
||||
|
||||
**사용 방법:**
|
||||
- **자동 실행**: Push/PR 시 기본값 사용 (ENVIRONMENT=dev, SKIP_SONARQUBE=true)
|
||||
- **수동 실행**: Actions 탭 > "Backend Services CI/CD" > "Run workflow" 버튼 클릭
|
||||
- Environment: dev/staging/prod 선택
|
||||
- Skip SonarQube Analysis: true/false 선택
|
||||
|
||||
- Kustomize 디렉토리 구조 생성
|
||||
- GitHub Actions 전용 Kustomize 디렉토리 생성
|
||||
```bash
|
||||
mkdir -p .github/kustomize/{base,overlays/{dev,staging,prod}}
|
||||
mkdir -p .github/kustomize/base/{common,{서비스명1},{서비스명2},...}
|
||||
mkdir -p .github/{config,scripts}
|
||||
```
|
||||
- 기존 k8s 매니페스트를 base로 복사
|
||||
```bash
|
||||
# 기존 deployment/k8s/* 파일들을 base로 복사
|
||||
cp deployment/k8s/common/* .github/kustomize/base/common/
|
||||
cp deployment/k8s/{서비스명}/* .github/kustomize/base/{서비스명}/
|
||||
|
||||
# 네임스페이스 하드코딩 제거
|
||||
find .github/kustomize/base -name "*.yaml" -exec sed -i 's/namespace: .*//' {} \;
|
||||
```
|
||||
|
||||
- Base Kustomization 작성
|
||||
`.github/kustomize/base/kustomization.yaml` 파일 생성
|
||||
```yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
metadata:
|
||||
name: {SYSTEM_NAME}-base
|
||||
|
||||
resources:
|
||||
# Common resources
|
||||
- common/configmap-common.yaml
|
||||
- common/secret-common.yaml
|
||||
- common/secret-imagepull.yaml
|
||||
- common/ingress.yaml
|
||||
|
||||
# 각 서비스별 리소스
|
||||
- {SERVICE_NAME}/deployment.yaml
|
||||
- {SERVICE_NAME}/service.yaml
|
||||
- {SERVICE_NAME}/configmap.yaml
|
||||
- {SERVICE_NAME}/secret.yaml
|
||||
|
||||
images:
|
||||
- name: {ACR_NAME}.azurecr.io/{SYSTEM_NAME}/{SERVICE_NAME}
|
||||
newTag: latest
|
||||
```
|
||||
|
||||
- 환경별 Patch 파일 생성
|
||||
각 환경별로 필요한 patch 파일들을 생성합니다.
|
||||
**중요원칙**:
|
||||
- **base 매니페스트에 없는 항목은 추가 안함**
|
||||
- **base 매니페스트와 항목이 일치해야 함**
|
||||
- Secret 매니페스트에 'data'가 아닌 'stringData'사용
|
||||
|
||||
**1. ConfigMap Common Patch 파일 생성**
|
||||
`.github/kustomize/overlays/{ENVIRONMENT}/cm-common-patch.yaml`
|
||||
|
||||
- base 매니페스트를 환경별로 복사
|
||||
```
|
||||
cp .github/kustomize/base/common/cm-common.yaml .github/kustomize/overlays/{ENVIRONMENT}/cm-common-patch.yaml
|
||||
```
|
||||
|
||||
- SPRING_PROFILES_ACTIVE를 환경에 맞게 설정 (dev/staging/prod)
|
||||
- DDL_AUTO 설정: dev는 "update", staging/prod는 "validate"
|
||||
- JWT 토큰 유효시간은 prod에서 보안을 위해 짧게 설정
|
||||
|
||||
**2. Secret Common Patch 파일 생성**
|
||||
`.github/kustomize/overlays/{ENVIRONMENT}/secret-common-patch.yaml`
|
||||
|
||||
- base 매니페스트를 환경별로 복사
|
||||
```
|
||||
cp .github/kustomize/base/common/secret-common.yaml .github/kustomize/overlays/{ENVIRONMENT}/secret-common-patch.yaml
|
||||
```
|
||||
|
||||
**3. Ingress Patch 파일 생성**
|
||||
`.github/kustomize/overlays/{ENVIRONMENT}/ingress-patch.yaml`
|
||||
- base의 ingress.yaml을 환경별로 오버라이드
|
||||
- **⚠️ 중요**: 개발환경 Ingress Host의 기본값은 base의 ingress.yaml과 **정확히 동일하게** 함
|
||||
- base에서 `host: {SYSTEM_NAME}-api.20.214.196.128.nip.io` 이면
|
||||
- dev에서도 `host: {SYSTEM_NAME}-api.20.214.196.128.nip.io` 로 동일하게 설정
|
||||
- **절대** `{SYSTEM_NAME}-dev-api.xxx` 처럼 변경하지 말 것
|
||||
- Staging/Prod 환경별 도메인 설정: {SYSTEM_NAME}.도메인 형식
|
||||
- service name을 '{서비스명}'으로 함.
|
||||
- Staging/prod 환경은 HTTPS 강제 적용 및 SSL 인증서 설정
|
||||
- staging/prod는 nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
- dev는 nginx.ingress.kubernetes.io/ssl-redirect: "false"
|
||||
|
||||
**4. deployment Patch 파일 생성** ⚠️ **중요**
|
||||
각 서비스별로 별도 파일 생성
|
||||
`.github/kustomize/overlays/{ENVIRONMENT}/deployment-{SERVICE_NAME}-patch.yaml`
|
||||
|
||||
**필수 포함 사항:**
|
||||
- ✅ **replicas 설정**: 각 서비스별 Deployment의 replica 수를 환경별로 설정
|
||||
- dev: 모든 서비스 1 replica (리소스 절약)
|
||||
- staging: 모든 서비스 2 replicas
|
||||
- prod: 모든 서비스 3 replicas
|
||||
- ✅ **resources 설정**: 각 서비스별 Deployment의 resources를 환경별로 설정
|
||||
- dev: requests(256m CPU, 256Mi Memory), limits(1024m CPU, 1024Mi Memory)
|
||||
- staging: requests(512m CPU, 512Mi Memory), limits(2048m CPU, 2048Mi Memory)
|
||||
- prod: requests(1024m CPU, 1024Mi Memory), limits(4096m CPU, 4096Mi Memory)
|
||||
|
||||
**5. Secret Service Patch 파일 생성**
|
||||
각 서비스별로 별도 파일 생성
|
||||
`.github/kustomize/overlays/{ENVIRONMENT}/secret-{SERVICE_NAME}-patch.yaml`
|
||||
|
||||
- base 매니페스트를 환경별로 복사
|
||||
```
|
||||
cp .github/kustomize/base/{SERVICE_NAME}/secret-{SERVICE_NAME}.yaml .github/kustomize/overlays/{ENVIRONMENT}/secret-{SERVICE_NAME}-patch.yaml
|
||||
```
|
||||
- 환경별 데이터베이스 연결 정보로 수정
|
||||
- **⚠️ 중요**: 패스워드 등 민감정보는 실제 환경 구축 시 별도 설정
|
||||
|
||||
- 환경별 Overlay 작성
|
||||
각 환경별로 `overlays/{환경}/kustomization.yaml` 생성
|
||||
```yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: {NAMESPACE}
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- path: cm-common-patch.yaml
|
||||
target:
|
||||
kind: ConfigMap
|
||||
name: cm-common
|
||||
- path: deployment-{SERVICE_NAME}-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: {SERVICE_NAME}
|
||||
- path: ingress-patch.yaml
|
||||
target:
|
||||
kind: Ingress
|
||||
name: {SYSTEM_NAME}
|
||||
- path: secret-common-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-common
|
||||
- path: secret-{SERVICE_NAME}-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-{SERVICE_NAME}
|
||||
|
||||
images:
|
||||
- name: {ACR_NAME}.azurecr.io/{SYSTEM_NAME}/{SERVICE_NAME}
|
||||
newTag: {ENVIRONMENT}-latest
|
||||
|
||||
```
|
||||
|
||||
- GitHub Actions 워크플로우 작성
|
||||
`.github/workflows/backend-cicd.yaml` 파일 생성 방법을 안내합니다.
|
||||
|
||||
주요 구성 요소:
|
||||
- **Build & Test**: Gradle 기반 빌드 및 단위 테스트
|
||||
- **SonarQube Analysis**: 코드 품질 분석 및 Quality Gate
|
||||
- **Container Build & Push**: 환경별 이미지 태그로 빌드 및 푸시
|
||||
- **Kustomize Deploy**: 환경별 매니페스트 적용
|
||||
|
||||
```yaml
|
||||
name: Backend Services CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
paths:
|
||||
- '{서비스명1}/**'
|
||||
- '{서비스명2}/**'
|
||||
- '{서비스명3}/**'
|
||||
- '{서비스명N}/**'
|
||||
- 'common/**'
|
||||
- '.github/**'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ENVIRONMENT:
|
||||
description: 'Target environment'
|
||||
required: true
|
||||
default: 'dev'
|
||||
type: choice
|
||||
options:
|
||||
- dev
|
||||
- staging
|
||||
- prod
|
||||
SKIP_SONARQUBE:
|
||||
description: 'Skip SonarQube Analysis'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: choice
|
||||
options:
|
||||
- 'true'
|
||||
- 'false'
|
||||
|
||||
env:
|
||||
REGISTRY: ${{ secrets.REGISTRY }}
|
||||
IMAGE_ORG: ${{ secrets.IMAGE_ORG }}
|
||||
RESOURCE_GROUP: ${{ secrets.RESOURCE_GROUP }}
|
||||
AKS_CLUSTER: ${{ secrets.AKS_CLUSTER }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Test
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
image_tag: ${{ steps.set_outputs.outputs.image_tag }}
|
||||
environment: ${{ steps.set_outputs.outputs.environment }}
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK {버전}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '{JDK버전}'
|
||||
distribution: 'temurin'
|
||||
cache: 'gradle'
|
||||
|
||||
- name: Determine environment
|
||||
id: determine_env
|
||||
run: |
|
||||
# Use input parameter or default to 'dev'
|
||||
ENVIRONMENT="${{ github.event.inputs.ENVIRONMENT || 'dev' }}"
|
||||
echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Load environment variables
|
||||
id: env_vars
|
||||
run: |
|
||||
ENV=${{ steps.determine_env.outputs.environment }}
|
||||
|
||||
# Initialize variables with defaults
|
||||
REGISTRY="{ACR_NAME}.azurecr.io"
|
||||
IMAGE_ORG="{SYSTEM_NAME}"
|
||||
RESOURCE_GROUP="{RESOURCE_GROUP}"
|
||||
AKS_CLUSTER="{AKS_CLUSTER}"
|
||||
NAMESPACE="{NAMESPACE}"
|
||||
|
||||
# Read environment variables from .github/config file
|
||||
if [[ -f ".github/config/deploy_env_vars_${ENV}" ]]; then
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
# Skip comments and empty lines
|
||||
[[ "$line" =~ ^#.*$ ]] && continue
|
||||
[[ -z "$line" ]] && continue
|
||||
|
||||
# Extract key-value pairs
|
||||
key=$(echo "$line" | cut -d '=' -f1)
|
||||
value=$(echo "$line" | cut -d '=' -f2-)
|
||||
|
||||
# Override defaults if found in config
|
||||
case "$key" in
|
||||
"resource_group") RESOURCE_GROUP="$value" ;;
|
||||
"cluster_name") AKS_CLUSTER="$value" ;;
|
||||
esac
|
||||
done < ".github/config/deploy_env_vars_${ENV}"
|
||||
fi
|
||||
|
||||
# Export for other jobs
|
||||
echo "REGISTRY=$REGISTRY" >> $GITHUB_ENV
|
||||
echo "IMAGE_ORG=$IMAGE_ORG" >> $GITHUB_ENV
|
||||
echo "RESOURCE_GROUP=$RESOURCE_GROUP" >> $GITHUB_ENV
|
||||
echo "AKS_CLUSTER=$AKS_CLUSTER" >> $GITHUB_ENV
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Build with Gradle
|
||||
run: |
|
||||
./gradlew build -x test
|
||||
|
||||
- name: SonarQube Analysis & Quality Gate
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
||||
run: |
|
||||
# Check if SonarQube should be skipped
|
||||
SKIP_SONARQUBE="${{ github.event.inputs.SKIP_SONARQUBE || 'true' }}"
|
||||
|
||||
if [[ "$SKIP_SONARQUBE" == "true" ]]; then
|
||||
echo "⏭️ Skipping SonarQube Analysis (SKIP_SONARQUBE=$SKIP_SONARQUBE)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Define services array
|
||||
services=({SERVICE_NAME1} {SERVICE_NAME2} {SERVICE_NAME3} {SERVICE_NAMEN})
|
||||
|
||||
# Run tests, coverage reports, and SonarQube analysis for each service
|
||||
for service in "${services[@]}"; do
|
||||
./gradlew :$service:test :$service:jacocoTestReport :$service:sonar \
|
||||
-Dsonar.projectKey={SYSTEM_NAME}-$service-${{ steps.determine_env.outputs.environment }} \
|
||||
-Dsonar.projectName={SYSTEM_NAME}-$service-${{ steps.determine_env.outputs.environment }} \
|
||||
-Dsonar.host.url=$SONAR_HOST_URL \
|
||||
-Dsonar.token=$SONAR_TOKEN \
|
||||
-Dsonar.java.binaries=build/classes/java/main \
|
||||
-Dsonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml \
|
||||
-Dsonar.exclusions=**/config/**,**/entity/**,**/dto/**,**/*Application.class,**/exception/**
|
||||
done
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: app-builds
|
||||
path: |
|
||||
{SERVICE_NAME1}/build/libs/*.jar
|
||||
{SERVICE_NAME2}/build/libs/*.jar
|
||||
{SERVICE_NAME3}/build/libs/*.jar
|
||||
{SERVICE_NAMEN}/build/libs/*.jar
|
||||
|
||||
- name: Set outputs
|
||||
id: set_outputs
|
||||
run: |
|
||||
# Generate timestamp for image tag
|
||||
IMAGE_TAG=$(date +%Y%m%d%H%M%S)
|
||||
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
|
||||
echo "environment=${{ steps.determine_env.outputs.environment }}" >> $GITHUB_OUTPUT
|
||||
|
||||
release:
|
||||
name: Build and Push Docker Images
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: app-builds
|
||||
|
||||
- name: Set environment variables from build job
|
||||
run: |
|
||||
echo "REGISTRY=${{ needs.build.outputs.registry }}" >> $GITHUB_ENV
|
||||
echo "IMAGE_ORG=${{ needs.build.outputs.image_org }}" >> $GITHUB_ENV
|
||||
echo "ENVIRONMENT=${{ needs.build.outputs.environment }}" >> $GITHUB_ENV
|
||||
echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub (prevent rate limit)
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Login to Azure Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ secrets.ACR_USERNAME }}
|
||||
password: ${{ secrets.ACR_PASSWORD }}
|
||||
|
||||
- name: Build and push Docker images for all services
|
||||
run: |
|
||||
# Define services array
|
||||
services=({SERVICE_NAME1} {SERVICE_NAME2} {SERVICE_NAME3} {SERVICE_NAMEN})
|
||||
|
||||
# Build and push each service image
|
||||
for service in "${services[@]}"; do
|
||||
echo "Building and pushing $service..."
|
||||
docker build \
|
||||
--build-arg BUILD_LIB_DIR="$service/build/libs" \
|
||||
--build-arg ARTIFACTORY_FILE="$service.jar" \
|
||||
-f deployment/container/Dockerfile-backend \
|
||||
-t ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/$service:${{ needs.build.outputs.environment }}-${{ needs.build.outputs.image_tag }} .
|
||||
|
||||
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/$service:${{ needs.build.outputs.environment }}-${{ needs.build.outputs.image_tag }}
|
||||
done
|
||||
|
||||
deploy:
|
||||
name: Deploy to Kubernetes
|
||||
needs: [build, release]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set image tag environment variable
|
||||
run: |
|
||||
echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
|
||||
echo "ENVIRONMENT=${{ needs.build.outputs.environment }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Azure CLI
|
||||
run: |
|
||||
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
|
||||
|
||||
- name: Azure Login
|
||||
uses: azure/login@v1
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_CREDENTIALS }}
|
||||
|
||||
- name: Setup kubectl
|
||||
uses: azure/setup-kubectl@v3
|
||||
|
||||
- name: Get AKS Credentials
|
||||
run: |
|
||||
az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.AKS_CLUSTER }} --overwrite-existing
|
||||
|
||||
- name: Create namespace
|
||||
run: |
|
||||
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
- name: Install Kustomize
|
||||
run: |
|
||||
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
|
||||
sudo mv kustomize /usr/local/bin/
|
||||
|
||||
- name: Update Kustomize images and deploy
|
||||
run: |
|
||||
# 환경별 디렉토리로 이동
|
||||
cd deployment/cicd/kustomize/overlays/${{ env.ENVIRONMENT }}
|
||||
|
||||
# 각 서비스별 이미지 태그 업데이트
|
||||
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/api-gateway:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
|
||||
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/user-service:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
|
||||
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/bill-service:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
|
||||
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/product-service:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
|
||||
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/kos-mock:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
|
||||
|
||||
# 매니페스트 적용
|
||||
kubectl apply -k .
|
||||
|
||||
- name: Wait for deployments to be ready
|
||||
run: |
|
||||
echo "Waiting for deployments to be ready..."
|
||||
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/${{ env.ENVIRONMENT }}-api-gateway --timeout=300s
|
||||
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/${{ env.ENVIRONMENT }}-user-service --timeout=300s
|
||||
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/${{ env.ENVIRONMENT }}-bill-service --timeout=300s
|
||||
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/${{ env.ENVIRONMENT }}-product-service --timeout=300s
|
||||
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/${{ env.ENVIRONMENT }}-kos-mock --timeout=300s
|
||||
|
||||
```
|
||||
|
||||
- GitHub Actions 전용 환경별 설정 파일 작성
|
||||
`.github/config/deploy_env_vars_{환경}` 파일 생성 방법
|
||||
|
||||
**.github/config/deploy_env_vars_dev**
|
||||
```bash
|
||||
# dev Environment Configuration
|
||||
resource_group={RESOURCE_GROUP}
|
||||
cluster_name={AKS_CLUSTER}
|
||||
```
|
||||
|
||||
**.github/config/deploy_env_vars_staging**
|
||||
```bash
|
||||
# staging Environment Configuration
|
||||
resource_group={RESOURCE_GROUP}
|
||||
cluster_name={AKS_CLUSTER}
|
||||
```
|
||||
|
||||
**.github/config/deploy_env_vars_prod**
|
||||
```bash
|
||||
# prod Environment Configuration
|
||||
resource_group={RESOURCE_GROUP}
|
||||
cluster_name={AKS_CLUSTER}
|
||||
```
|
||||
|
||||
**참고**: Kustomize 방식에서는 namespace, replicas, resources 등은 kustomization.yaml과 patch 파일에서 관리됩니다.
|
||||
|
||||
- GitHub Actions 전용 수동 배포 스크립트 작성
|
||||
`.github/scripts/deploy-actions.sh` 파일 생성:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
ENVIRONMENT=${1:-dev}
|
||||
IMAGE_TAG=${2:-latest}
|
||||
|
||||
echo "🚀 Manual deployment starting..."
|
||||
echo "Environment: $ENVIRONMENT"
|
||||
echo "Image Tag: $IMAGE_TAG"
|
||||
|
||||
# Check if kustomize is installed
|
||||
if ! command -v kustomize &> /dev/null; then
|
||||
echo "Installing Kustomize..."
|
||||
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
|
||||
sudo mv kustomize /usr/local/bin/
|
||||
fi
|
||||
|
||||
# Load environment variables from .github/config
|
||||
if [[ -f ".github/config/deploy_env_vars_${ENVIRONMENT}" ]]; then
|
||||
source ".github/config/deploy_env_vars_${ENVIRONMENT}"
|
||||
echo "✅ Environment variables loaded for $ENVIRONMENT"
|
||||
else
|
||||
echo "❌ Environment configuration file not found: .github/config/deploy_env_vars_${ENVIRONMENT}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create namespace
|
||||
echo "📝 Creating namespace {NAMESPACE}..."
|
||||
kubectl create namespace {NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
# 환경별 이미지 태그 업데이트 (.github/kustomize 사용)
|
||||
cd .github/kustomize/overlays/${ENVIRONMENT}
|
||||
|
||||
echo "🔄 Updating image tags..."
|
||||
# 서비스 배열 정의
|
||||
services=({SERVICE_NAME1} {SERVICE_NAME2} {SERVICE_NAME3} {SERVICE_NAMEN})
|
||||
|
||||
# 각 서비스별 이미지 태그 업데이트
|
||||
for service in "${services[@]}"; do
|
||||
kustomize edit set image {ACR_NAME}.azurecr.io/{SYSTEM_NAME}/$service:${ENVIRONMENT}-${IMAGE_TAG}
|
||||
done
|
||||
|
||||
echo "🚀 Deploying to Kubernetes..."
|
||||
# 배포 실행
|
||||
kubectl apply -k .
|
||||
|
||||
echo "⏳ Waiting for deployments to be ready..."
|
||||
# 서비스별 배포 상태 확인
|
||||
for service in "${services[@]}"; do
|
||||
kubectl rollout status deployment/${ENVIRONMENT}-$service -n {NAMESPACE} --timeout=300s
|
||||
done
|
||||
|
||||
echo "🔍 Health check..."
|
||||
# API Gateway Health Check (첫 번째 서비스가 API Gateway라고 가정)
|
||||
GATEWAY_SERVICE=${services[0]}
|
||||
GATEWAY_POD=$(kubectl get pod -n {NAMESPACE} -l app.kubernetes.io/name=${ENVIRONMENT}-$GATEWAY_SERVICE -o jsonpath='{.items[0].metadata.name}')
|
||||
kubectl -n {NAMESPACE} exec $GATEWAY_POD -- curl -f http://localhost:8080/actuator/health || echo "Health check failed, but deployment completed"
|
||||
|
||||
echo "📋 Service Information:"
|
||||
kubectl get pods -n {NAMESPACE}
|
||||
kubectl get services -n {NAMESPACE}
|
||||
kubectl get ingress -n {NAMESPACE}
|
||||
|
||||
echo "✅ GitHub Actions deployment completed successfully!"
|
||||
```
|
||||
|
||||
- SonarQube 프로젝트 설정 방법 작성
|
||||
- SonarQube에서 각 서비스별 프로젝트 생성
|
||||
- Quality Gate 설정:
|
||||
```
|
||||
Coverage: >= 80%
|
||||
Duplicated Lines: <= 3%
|
||||
Maintainability Rating: <= A
|
||||
Reliability Rating: <= A
|
||||
Security Rating: <= A
|
||||
```
|
||||
|
||||
- 롤백 방법 작성
|
||||
- GitHub Actions에서 이전 버전으로 롤백:
|
||||
```bash
|
||||
# 이전 워크플로우 실행으로 롤백
|
||||
1. GitHub > Actions > 성공한 이전 워크플로우 선택
|
||||
2. Re-run all jobs 클릭
|
||||
```
|
||||
- kubectl을 이용한 롤백:
|
||||
```bash
|
||||
# 특정 버전으로 롤백
|
||||
kubectl rollout undo deployment/{환경}-{서비스명} -n {NAMESPACE} --to-revision=2
|
||||
|
||||
# 롤백 상태 확인
|
||||
kubectl rollout status deployment/{환경}-{서비스명} -n {NAMESPACE}
|
||||
```
|
||||
- 수동 스크립트를 이용한 롤백:
|
||||
```bash
|
||||
# 이전 안정 버전 이미지 태그로 배포
|
||||
./deployment/cicd/scripts/deploy-actions.sh {환경} {이전태그}
|
||||
```
|
||||
|
||||
[체크리스트]
|
||||
GitHub Actions CI/CD 파이프라인 구축 작업을 누락 없이 진행하기 위한 체크리스트입니다.
|
||||
|
||||
## 📋 사전 준비 체크리스트
|
||||
- [ ] settings.gradle에서 시스템명과 서비스명 확인 완료
|
||||
- [ ] 실행정보 섹션에서 ACR명, 리소스 그룹, AKS 클러스터명 확인 완료
|
||||
|
||||
## 📂 GitHub Actions 전용 Kustomize 구조 생성 체크리스트
|
||||
- [ ] 디렉토리 구조 생성: `.github/kustomize/{base,overlays/{dev,staging,prod}}`
|
||||
- [ ] 서비스별 base 디렉토리 생성: `.github/kustomize/base/{common,{서비스명들}}`
|
||||
- [ ] 기존 k8s 매니페스트를 base로 복사 완료
|
||||
- [ ] **리소스 누락 방지 검증 완료**:
|
||||
- [ ] `ls .github/kustomize/base/*/` 명령으로 모든 서비스 디렉토리의 파일 확인
|
||||
- [ ] 각 서비스별 필수 파일 존재 확인 (deployment.yaml, service.yaml 필수)
|
||||
- [ ] ConfigMap 파일 존재 시 `cm-{서비스명}.yaml` 명명 규칙 준수 확인
|
||||
- [ ] Secret 파일 존재 시 `secret-{서비스명}.yaml` 명명 규칙 준수 확인
|
||||
- [ ] Base kustomization.yaml 파일 생성 완료
|
||||
- [ ] 모든 서비스의 deployment.yaml, service.yaml 포함 확인
|
||||
- [ ] 존재하는 모든 ConfigMap 파일 포함 확인 (`cm-{서비스명}.yaml`)
|
||||
- [ ] 존재하는 모든 Secret 파일 포함 확인 (`secret-{서비스명}.yaml`)
|
||||
- [ ] **검증 명령어 실행 완료**:
|
||||
- [ ] `kubectl kustomize .github/kustomize/base/` 정상 실행 확인
|
||||
- [ ] 에러 메시지 없이 모든 리소스 출력 확인
|
||||
|
||||
## 🔧 GitHub Actions 전용 환경별 Overlay 구성 체크리스트
|
||||
### 중요 체크 사항
|
||||
- Base Kustomization에서 존재하지 않는 Secret 파일들 제거
|
||||
|
||||
### 공통 체크 사항
|
||||
- **base 매니페스트에 없는 항목을 추가하지 않았는지 체크**
|
||||
- **base 매니페스트와 항목이 일치 하는지 체크**
|
||||
- Secret 매니페스트에 'data'가 아닌 'stringData'사용했는지 체크
|
||||
- **⚠️ Kustomize patch 방법 변경**: `patchesStrategicMerge` → `patches` (target 명시)
|
||||
|
||||
### DEV 환경
|
||||
- [ ] `.github/kustomize/overlays/dev/kustomization.yaml` 생성 완료
|
||||
- [ ] `.github/kustomize/overlays/dev/cm-common-patch.yaml` 생성 완료 (dev 프로파일, update DDL)
|
||||
- [ ] `.github/kustomize/overlays/dev/secret-common-patch.yaml` 생성 완료
|
||||
- [ ] `.github/kustomize/overlays/dev/ingress-patch.yaml` 생성 완료 (**Host 기본값은 base의 ingress.yaml과 동일**)
|
||||
- [ ] `.github/kustomize/overlays/dev/deployment-{서비스명}-patch.yaml` 생성 완료 (replicas, resources 지정)
|
||||
- [ ] 각 서비스별 `.github/kustomize/overlays/dev/secret-{서비스명}-patch.yaml` 생성 완료
|
||||
|
||||
### STAGING 환경
|
||||
- [ ] `.github/kustomize/overlays/staging/kustomization.yaml` 생성 완료
|
||||
- [ ] `.github/kustomize/overlays/staging/cm-common-patch.yaml` 생성 완료 (staging 프로파일, validate DDL)
|
||||
- [ ] `.github/kustomize/overlays/staging/secret-common-patch.yaml` 생성 완료
|
||||
- [ ] `.github/kustomize/overlays/staging/ingress-patch.yaml` 생성 완료 (prod 도메인, HTTPS, SSL 인증서)
|
||||
- [ ] `.github/kustomize/overlays/staging/deployment-{서비스명}-patch.yaml` 생성 완료 (replicas, resources 지정)
|
||||
- [ ] 각 서비스별 `.github/kustomize/overlays/staging/secret-{서비스명}-patch.yaml` 생성 완료
|
||||
|
||||
### PROD 환경
|
||||
- [ ] `.github/kustomize/overlays/prod/kustomization.yaml` 생성 완료
|
||||
- [ ] `.github/kustomize/overlays/prod/cm-common-patch.yaml` 생성 완료 (prod 프로파일, validate DDL, 짧은 JWT)
|
||||
- [ ] `.github/kustomize/overlays/prod/secret-common-patch.yaml` 생성 완료
|
||||
- [ ] `.github/kustomize/overlays/prod/ingress-patch.yaml` 생성 완료 (prod 도메인, HTTPS, SSL 인증서)
|
||||
- [ ] `.github/kustomize/overlays/prod/deployment-{서비스명}-patch.yaml` 생성 완료 (replicas, resources 지정)
|
||||
- [ ] 각 서비스별 `.github/kustomize/overlays/prod/secret-{서비스명}-patch.yaml` 생성 완료
|
||||
|
||||
## ⚙️ GitHub Actions 설정 및 스크립트 체크리스트
|
||||
- [ ] 환경별 설정 파일 생성: `.github/config/deploy_env_vars_{dev,staging,prod}`
|
||||
- [ ] GitHub Actions 워크플로우 파일 `.github/workflows/backend-cicd.yaml` 생성 완료
|
||||
- [ ] 워크플로우 주요 내용 확인
|
||||
- Build, SonarQube, Docker Build & Push, Deploy 단계 포함
|
||||
- JDK 버전 확인: `java-version: '{JDK버전}'`
|
||||
- 변수 참조 문법 확인: `${{ needs.build.outputs.* }}` 사용
|
||||
- 모든 서비스명이 실제 프로젝트 서비스명으로 치환되었는지 확인
|
||||
- **환경 변수 SKIP_SONARQUBE 처리 확인**: 기본값 'true', 조건부 실행
|
||||
- **플레이스홀더 사용 확인**: {ACR_NAME}, {SYSTEM_NAME}, {SERVICE_NAME} 등
|
||||
|
||||
- [ ] 수동 배포 스크립트 `.github/scripts/deploy-actions.sh` 생성 완료
|
||||
- [ ] 스크립트 실행 권한 설정 완료 (`chmod +x .github/scripts/*.sh`)
|
||||
|
||||
[결과파일]
|
||||
- 가이드: .github/actions-pipeline-guide.md
|
||||
- GitHub Actions 워크플로우: .github/workflows/backend-cicd.yaml
|
||||
- GitHub Actions 전용 Kustomize 매니페스트: .github/kustomize/*
|
||||
- GitHub Actions 전용 환경별 설정 파일: .github/config/*
|
||||
- GitHub Actions 전용 수동배포 스크립트: .github/scripts/deploy-actions.sh
|
||||
25
deployment/container/Dockerfile-backend
Normal file
25
deployment/container/Dockerfile-backend
Normal file
@ -0,0 +1,25 @@
|
||||
# Build stage
|
||||
FROM openjdk:23-oraclelinux8 AS builder
|
||||
ARG BUILD_LIB_DIR
|
||||
ARG ARTIFACTORY_FILE
|
||||
COPY ${BUILD_LIB_DIR}/${ARTIFACTORY_FILE} app.jar
|
||||
|
||||
# Run stage
|
||||
FROM openjdk:23-slim
|
||||
ENV USERNAME=k8s
|
||||
ENV ARTIFACTORY_HOME=/home/${USERNAME}
|
||||
ENV JAVA_OPTS=""
|
||||
|
||||
# Add a non-root user
|
||||
RUN adduser --system --group ${USERNAME} && \
|
||||
mkdir -p ${ARTIFACTORY_HOME} && \
|
||||
chown ${USERNAME}:${USERNAME} ${ARTIFACTORY_HOME}
|
||||
|
||||
WORKDIR ${ARTIFACTORY_HOME}
|
||||
COPY --from=builder app.jar app.jar
|
||||
RUN chown ${USERNAME}:${USERNAME} app.jar
|
||||
|
||||
USER ${USERNAME}
|
||||
|
||||
ENTRYPOINT [ "sh", "-c" ]
|
||||
CMD ["java ${JAVA_OPTS} -jar app.jar"]
|
||||
184
deployment/container/build-image.md
Normal file
184
deployment/container/build-image.md
Normal file
@ -0,0 +1,184 @@
|
||||
# 백엔드 컨테이너 이미지 작성 결과
|
||||
|
||||
## 작업 개요
|
||||
- 작업일시: 2025-10-27
|
||||
- 대상 서비스: user, meeting, stt, ai, notification (총 5개)
|
||||
- 작업자: 주영 (DevOps)
|
||||
|
||||
## 작업 진행 상황
|
||||
|
||||
### 1. 서비스명 확인 ✅
|
||||
settings.gradle에서 서비스명 확인 완료:
|
||||
```bash
|
||||
cat settings.gradle
|
||||
```
|
||||
|
||||
확인된 서비스:
|
||||
- common (공통 모듈)
|
||||
- user
|
||||
- meeting
|
||||
- stt
|
||||
- ai
|
||||
- notification
|
||||
|
||||
### 2. bootJar 설정 확인 ✅
|
||||
모든 서비스의 build.gradle에 bootJar 설정이 이미 되어 있음을 확인:
|
||||
|
||||
- user/build.gradle: `archiveFileName = 'user.jar'`
|
||||
- meeting/build.gradle: `archiveFileName = 'meeting.jar'`
|
||||
- stt/build.gradle: `archiveFileName = 'stt.jar'`
|
||||
- ai/build.gradle: `archiveFileName = 'ai.jar'`
|
||||
- notification/build.gradle: `archiveFileName = 'notification.jar'`
|
||||
|
||||
### 3. Dockerfile 생성 ✅
|
||||
deployment/container/Dockerfile-backend 생성 완료:
|
||||
|
||||
```dockerfile
|
||||
# Build stage
|
||||
FROM openjdk:23-oraclelinux8 AS builder
|
||||
ARG BUILD_LIB_DIR
|
||||
ARG ARTIFACTORY_FILE
|
||||
COPY ${BUILD_LIB_DIR}/${ARTIFACTORY_FILE} app.jar
|
||||
|
||||
# Run stage
|
||||
FROM openjdk:23-slim
|
||||
ENV USERNAME=k8s
|
||||
ENV ARTIFACTORY_HOME=/home/${USERNAME}
|
||||
ENV JAVA_OPTS=""
|
||||
|
||||
# Add a non-root user
|
||||
RUN adduser --system --group ${USERNAME} && \
|
||||
mkdir -p ${ARTIFACTORY_HOME} && \
|
||||
chown ${USERNAME}:${USERNAME} ${ARTIFACTORY_HOME}
|
||||
|
||||
WORKDIR ${ARTIFACTORY_HOME}
|
||||
COPY --from=builder app.jar app.jar
|
||||
RUN chown ${USERNAME}:${USERNAME} app.jar
|
||||
|
||||
USER ${USERNAME}
|
||||
|
||||
ENTRYPOINT [ "sh", "-c" ]
|
||||
CMD ["java ${JAVA_OPTS} -jar app.jar"]
|
||||
```
|
||||
|
||||
### 4. Gradle 빌드 수행 ✅
|
||||
모든 서비스의 jar 파일 빌드 완료:
|
||||
|
||||
```bash
|
||||
./gradlew clean bootJar --no-daemon
|
||||
```
|
||||
|
||||
빌드 결과:
|
||||
```
|
||||
BUILD SUCCESSFUL in 17s
|
||||
37 actionable tasks: 34 executed, 3 up-to-date
|
||||
```
|
||||
|
||||
생성된 jar 파일 확인:
|
||||
```bash
|
||||
ls -lh user/build/libs/user.jar meeting/build/libs/meeting.jar stt/build/libs/stt.jar ai/build/libs/ai.jar notification/build/libs/notification.jar
|
||||
```
|
||||
|
||||
결과:
|
||||
- ai.jar: 86M
|
||||
- meeting.jar: 86M
|
||||
- notification.jar: 79M
|
||||
- stt.jar: 92M
|
||||
- user.jar: 77M
|
||||
|
||||
### 5. Docker 이미지 빌드 ⚠️ (대기 중)
|
||||
|
||||
**현재 상태**: Docker 데몬이 실행되지 않아 이미지 빌드를 진행할 수 없습니다.
|
||||
|
||||
**오류 메시지**:
|
||||
```
|
||||
ERROR: Cannot connect to the Docker daemon at unix:///Users/daewoong/.docker/run/docker.sock.
|
||||
Is the docker daemon running?
|
||||
```
|
||||
|
||||
**필요 조치**:
|
||||
1. Docker Desktop 실행
|
||||
2. Docker 데몬 정상 실행 확인:
|
||||
```bash
|
||||
docker ps
|
||||
docker info
|
||||
```
|
||||
|
||||
**준비된 빌드 명령어**:
|
||||
|
||||
각 서비스별 Docker 이미지 빌드 명령어는 다음과 같습니다:
|
||||
|
||||
#### user 서비스
|
||||
```bash
|
||||
docker build \
|
||||
--platform linux/amd64 \
|
||||
--build-arg BUILD_LIB_DIR="user/build/libs" \
|
||||
--build-arg ARTIFACTORY_FILE="user.jar" \
|
||||
-f deployment/container/Dockerfile-backend \
|
||||
-t user:latest .
|
||||
```
|
||||
|
||||
#### meeting 서비스
|
||||
```bash
|
||||
docker build \
|
||||
--platform linux/amd64 \
|
||||
--build-arg BUILD_LIB_DIR="meeting/build/libs" \
|
||||
--build-arg ARTIFACTORY_FILE="meeting.jar" \
|
||||
-f deployment/container/Dockerfile-backend \
|
||||
-t meeting:latest .
|
||||
```
|
||||
|
||||
#### stt 서비스
|
||||
```bash
|
||||
docker build \
|
||||
--platform linux/amd64 \
|
||||
--build-arg BUILD_LIB_DIR="stt/build/libs" \
|
||||
--build-arg ARTIFACTORY_FILE="stt.jar" \
|
||||
-f deployment/container/Dockerfile-backend \
|
||||
-t stt:latest .
|
||||
```
|
||||
|
||||
#### ai 서비스
|
||||
```bash
|
||||
docker build \
|
||||
--platform linux/amd64 \
|
||||
--build-arg BUILD_LIB_DIR="ai/build/libs" \
|
||||
--build-arg ARTIFACTORY_FILE="ai.jar" \
|
||||
-f deployment/container/Dockerfile-backend \
|
||||
-t ai:latest .
|
||||
```
|
||||
|
||||
#### notification 서비스
|
||||
```bash
|
||||
docker build \
|
||||
--platform linux/amd64 \
|
||||
--build-arg BUILD_LIB_DIR="notification/build/libs" \
|
||||
--build-arg ARTIFACTORY_FILE="notification.jar" \
|
||||
-f deployment/container/Dockerfile-backend \
|
||||
-t notification:latest .
|
||||
```
|
||||
|
||||
### 6. 이미지 확인 (대기 중)
|
||||
|
||||
Docker 이미지 빌드 완료 후 다음 명령어로 확인:
|
||||
```bash
|
||||
docker images | grep -E "user|meeting|stt|ai|notification"
|
||||
```
|
||||
|
||||
## 다음 단계
|
||||
|
||||
1. **즉시 수행**: Docker Desktop 실행
|
||||
2. **Docker 확인**: `docker ps` 명령으로 정상 작동 확인
|
||||
3. **이미지 빌드**: 위의 준비된 명령어들을 순차적으로 실행
|
||||
4. **빌드 검증**: 모든 이미지가 정상적으로 생성되었는지 확인
|
||||
5. **결과 업데이트**: 이 문서에 최종 결과 기록
|
||||
|
||||
## 참고사항
|
||||
|
||||
- **플랫폼**: macOS (Darwin 22.1.0)
|
||||
- **Docker 빌드 플랫폼**: linux/amd64 (크로스 플랫폼 빌드)
|
||||
- **베이스 이미지**:
|
||||
- Builder: openjdk:23-oraclelinux8
|
||||
- Runtime: openjdk:23-slim
|
||||
- **보안**: non-root 사용자(k8s)로 컨테이너 실행
|
||||
- **병렬 빌드**: 각 서비스는 독립적으로 빌드 가능 (서브 에이전트 활용)
|
||||
Loading…
x
Reference in New Issue
Block a user