diff --git a/Dockerfile b/Dockerfile index 60e7ece..91b404a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,13 @@ FROM python:3.12-alpine +ARG OPENAI_API_KEY +ARG GH_TOKEN +ARG HOST +ARG PORT +ENV OPENAI_API_KEY=$OPENAI_API_KEY +ENV GH_TOKEN=$GH_TOKEN +ENV HOST=$HOST +ENV PORT=$PORT # 작업 디렉토리 설정 WORKDIR /app diff --git a/Jenkinsfile b/Jenkinsfile index a405ecb..2d0d1d9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,133 +1,133 @@ -// pipeline { -// agent any -// -// environment { -// // 환경 변수 파일 경로 설정 -// ENV_FILE = '/var/lib/jenkins/environments/.env.ai' -// // Docker 이미지 정보 -// DOCKER_IMAGE = 'aida0/gitfolio_ai:test' -// // AWS 리전 -// AWS_REGION = 'ap-northeast-2' -// } -// -// stages { -// stage('Load Environment Variables') { -// steps { -// script { -// // .env.ai 파일에서 환경 변수 로드 -// def envContent = readFile(ENV_FILE).trim() -// envContent.split('\n').each { line -> -// def (key, value) = line.split('=', 2) -// env."${key}" = value -// } -// } -// } -// } -// -// // Git 저장소 체크아웃 단계 -// stage('Checkout') { -// steps { -// // Git 저장소 URL을 직접 지정하여 체크아웃 -// git branch: 'develop', -// url: 'https://github.com/KTB-Sixmen/gitfolio_AI.git' -// } -// } -// -// stage('Docker Build & Push') { -// steps { -// script { -// // Docker Hub 로그인 -// withCredentials([usernamePassword(credentialsId: 'docker-credentials', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS')]) { -// sh """ -// docker login -u ${DOCKER_USER} -p ${DOCKER_PASS} -// -// # Docker 이미지 빌드 -// docker build \ -// --build-arg OPENAI_API_KEY=${env.OPENAI_API_KEY} \ -// --build-arg GH_TOKEN=${env.GH_TOKEN} \ -// --build-arg HOST=${env.HOST} \ -// --build-arg PORT=${env.PORT} \ -// -t ${DOCKER_IMAGE} . -// -// # Docker 이미지 푸시 -// docker push ${DOCKER_IMAGE} -// """ -// } -// } -// } -// } -// -// stage('Deploy to EC2') { -// steps { -// script { -// withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', -// credentialsId: 'aws-credentials', -// accessKeyVariable: 'AWS_ACCESS_KEY_ID', -// secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) { -// -// // EC2 인스턴스 ID 조회 -// def instanceIds = sh( -// script: """ -// aws ec2 describe-instances \ -// --region ${AWS_REGION} \ -// --filters 'Name=tag:Service,Values=ai' 'Name=instance-state-name,Values=running' \ -// --query 'Reservations[].Instances[].InstanceId' \ -// --output text -// """, -// returnStdout: true -// ).trim() -// -// if (instanceIds) { -// // docker-compose.yaml 파일 인코딩 -// def dockerComposeContent = sh( -// script: "base64 docker-compose.yaml | tr -d '\n'", -// returnStdout: true -// ).trim() -// -// // SSM 명령 실행 - JSON 형식 수정 -// def commandId = sh( -// script: """ -// aws ssm send-command \ -// --instance-ids "${instanceIds}" \ -// --document-name "AWS-RunShellScript" \ -// --comment "Deploying AI Server" \ -// --parameters '{"commands":["cd /home/ec2-user","echo '\\''${dockerComposeContent}'\\'' | base64 -d > docker-compose.yaml","echo '\\''OPENAI_API_KEY=${env.OPENAI_API_KEY}'\\'' > .env","echo '\\''GH_TOKEN=${env.GH_TOKEN}'\\'' >> .env","echo '\\''HOST=${env.HOST}'\\'' >> .env","echo '\\''PORT=${env.PORT}'\\'' >> .env","chmod 600 .env","docker-compose down -v --rmi all","docker-compose pull","docker-compose up -d"]}' \ -// --timeout-seconds 600 \ -// --region ${AWS_REGION} \ -// --output text \ -// --query 'Command.CommandId' -// """, -// returnStdout: true -// ).trim() -// -// // 명령 실행 완료 대기 -// sh """ -// aws ssm wait command-executed \ -// --command-id ${commandId} \ -// --instance-id ${instanceIds} \ -// --region ${AWS_REGION} -// """ -// -// // 실행 결과 확인 -// sh """ -// aws ssm get-command-invocation \ -// --command-id ${commandId} \ -// --instance-id ${instanceIds} \ -// --region ${AWS_REGION} -// """ -// } else { -// error "No running EC2 instances found with the specified tags" -// } -// } -// } -// } -// } -// } -// -// post { -// always { -// // 작업 완료 후 정리 -// cleanWs() -// } -// } -// } \ No newline at end of file +pipeline { + agent any + + environment { + // 환경 변수 파일 경로 설정 + ENV_FILE = '/var/lib/jenkins/environments/.env.ai' + // Docker 이미지 정보 + DOCKER_IMAGE = '727646500036.dkr.ecr.ap-northeast-2.amazonaws.com/gitfolio/ai:dev' + // AWS 리전 + AWS_REGION = 'ap-northeast-2' + } + + stages { + stage('Load Environment Variables') { + steps { + script { + // .env.ai 파일에서 환경 변수 로드 + def envContent = readFile(ENV_FILE).trim() + envContent.split('\n').each { line -> + def (key, value) = line.split('=', 2) + env."${key}" = value + } + } + } + } + + stage('Checkout') { + steps { + // Git 저장소 URL을 직접 지정하여 체크아웃 + git branch: 'develop', + url: 'https://github.com/KTB-Sixmen/gitfolio_AI.git' + } + } + + stage('Docker Build & Push') { + steps { + script { + withCredentials([usernamePassword(credentialsId: 'docker-credentials', + usernameVariable: 'DOCKER_USER', + passwordVariable: 'DOCKER_PASS')]) { + sh ''' + echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin + + # Docker 이미지 빌드 + docker build \ + --build-arg OPENAI_API_KEY="$OPENAI_API_KEY" \ + --build-arg GH_TOKEN="$GH_TOKEN" \ + --build-arg HOST="$HOST" \ + --build-arg PORT="$PORT" \ + -t ${DOCKER_IMAGE} . + + # Docker 이미지 푸시 + docker push ${DOCKER_IMAGE} + ''' + } + } + } + } + + stage('Deploy to EC2') { + steps { + script { + withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', + credentialsId: 'aws-credentials', + accessKeyVariable: 'AWS_ACCESS_KEY_ID', + secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) { + + // EC2 인스턴스 ID 조회 + def instanceIds = sh( + script: """ + aws ec2 describe-instances \ + --region ${AWS_REGION} \ + --filters 'Name=tag:Service,Values=ai' 'Name=instance-state-name,Values=running' \ + --query 'Reservations[].Instances[].InstanceId' \ + --output text + """, + returnStdout: true + ).trim() + + if (instanceIds) { + // docker-compose.yaml 파일 인코딩 + def dockerComposeContent = sh( + script: "base64 docker-compose.yaml | tr -d '\n'", + returnStdout: true + ).trim() + + // SSM 명령 실행 - JSON 형식 수정 + def commandId = sh( + script: """ + aws ssm send-command \ + --instance-ids "${instanceIds}" \ + --document-name "AWS-RunShellScript" \ + --comment "Deploying AI Server" \ + --parameters '{"commands":["cd /home/ec2-user","echo '\\''${dockerComposeContent}'\\'' | base64 -d > docker-compose.yaml","echo '\\''OPENAI_API_KEY=${env.OPENAI_API_KEY}'\\'' > .env","echo '\\''GH_TOKEN=${env.GH_TOKEN}'\\'' >> .env","echo '\\''HOST=${env.HOST}'\\'' >> .env","echo '\\''PORT=${env.PORT}'\\'' >> .env","chmod 600 .env","docker-compose down -v --rmi all","docker-compose pull","docker-compose up -d"]}' \ + --timeout-seconds 600 \ + --region ${AWS_REGION} \ + --output text \ + --query 'Command.CommandId' + """, + returnStdout: true + ).trim() + + // 명령 실행 완료 대기 + sh """ + aws ssm wait command-executed \ + --command-id ${commandId} \ + --instance-id ${instanceIds} \ + --region ${AWS_REGION} + """ + + // 실행 결과 확인 + sh """ + aws ssm get-command-invocation \ + --command-id ${commandId} \ + --instance-id ${instanceIds} \ + --region ${AWS_REGION} + """ + } else { + error "No running EC2 instances found with the specified tags" + } + } + } + } + } + } + + post { + always { + // 작업 완료 후 정리 + cleanWs() + } + } +} \ No newline at end of file diff --git a/Jenkinsfile-prod b/Jenkinsfile-prod new file mode 100644 index 0000000..0933b3b --- /dev/null +++ b/Jenkinsfile-prod @@ -0,0 +1,128 @@ +pipeline { + agent any + + environment { + AWS_REGION = 'ap-northeast-2' + ECR_REGISTRY = credentials('ecr-registry') + DISCORD_CI_WEBHOOK = credentials('ai-dev-discord-ci-webhook') + DOCKER_TAG = 'prod' // dev -> prod로 변경 + ENV_FILE = '/var/lib/jenkins/environments/.env.ai' + } + + stages { + stage('소스코드 체크아웃') { + steps { + script { + deleteDir() + git branch: 'develop', + url: 'https://github.com/KTB-Sixmen/gitfolio_AI.git' + } + } + } + + stage('환경 설정') { + steps { + script { + // 환경 변수 파일 복사 + if (fileExists(ENV_FILE)) { + sh """ + cp ${ENV_FILE} .env + echo '환경 파일 복사 완료: ${ENV_FILE}' + + # .env 파일에서 환경변수를 추출하여 Jenkins 환경에 설정 + export OPENAI_API_KEY=\$(grep OPENAI_API_KEY .env | cut -d '=' -f2) + export GH_TOKEN=\$(grep GH_TOKEN .env | cut -d '=' -f2) + export HOST=\$(grep HOST .env | cut -d '=' -f2) + export PORT=\$(grep PORT .env | cut -d '=' -f2) + + # 환경변수를 Jenkins 환경에 설정 + echo "OPENAI_API_KEY=\${OPENAI_API_KEY}" >> env.properties + echo "GH_TOKEN=\${GH_TOKEN}" >> env.properties + echo "HOST=\${HOST}" >> env.properties + echo "PORT=\${PORT}" >> env.properties + """ + + // env.properties 파일을 Jenkins 환경변수로 로드 + def props = readProperties file: 'env.properties' + env.OPENAI_API_KEY = props.OPENAI_API_KEY + env.GH_TOKEN = props.GH_TOKEN + env.HOST = props.HOST + env.PORT = props.PORT + } else { + error "환경 파일을 찾을 수 없습니다: ${ENV_FILE}" + } + + // ECR 로그인 + withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', + credentialsId: 'aws-credentials', + accessKeyVariable: 'AWS_ACCESS_KEY_ID', + secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) { + sh """ + aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ECR_REGISTRY} + echo 'ECR 로그인 완료' + """ + } + } + } + } + + stage('Docker 이미지 빌드 및 푸시') { + steps { + script { + def imageTag = "${ECR_REGISTRY}/gitfolio/ai:${DOCKER_TAG}" + + sh """ + docker build \ + -f Dockerfile \ + -t ${imageTag} \ + --platform linux/amd64 \ + --build-arg OPENAI_API_KEY=${env.OPENAI_API_KEY} \ + --build-arg GH_TOKEN=${env.GH_TOKEN} \ + --build-arg HOST=${env.HOST} \ + --build-arg PORT=${env.PORT} \ + . + + # 빌드된 이미지의 환경변수 확인 + echo "===== 이미지 환경변수 확인 =====" + docker run --rm ${imageTag} env | grep -E "OPENAI_API_KEY|GH_TOKEN|HOST|PORT" + + docker push ${imageTag} + """ + } + } + } + } + + post { + always { + script { + sh """ + docker builder prune -f --filter until=24h + docker image prune -f + rm -f .env + """ + } + } + success { + discordSend description: "AI 서비스 CI 파이프라인 성공", + footer: "Jenkins Pipeline Success", + link: env.BUILD_URL, + result: currentBuild.currentResult, + title: JOB_NAME, + webhookURL: DISCORD_CI_WEBHOOK + } + + failure { + discordSend description: "AI 서비스 CI 파이프라인 실패", + footer: "Jenkins Pipeline Failed", + link: env.BUILD_URL, + result: currentBuild.currentResult, + title: JOB_NAME, + webhookURL: DISCORD_CI_WEBHOOK + } + + } + + + +} \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 9f37a2a..1c78f43 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,8 +1,15 @@ +version: "3.8" + services: ai: platform: linux/amd64 - image: aida0/gitfolio_ai:test + image: 727646500036.dkr.ecr.ap-northeast-2.amazonaws.com/gitfolio/ai:dev container_name: gitfolio_ai + + # (1) .env 파일로 환경변수 주입 + env_file: + - .env + ports: - target: 8000 published: 80 @@ -10,8 +17,7 @@ services: - target: 8000 published: 443 protocol: tcp - env_file: - - .env # 현재 디렉토리의 .env 파일을 참조 + networks: - ai