diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..23baf58 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 디폴트 무시된 파일 +/shelf/ +/workspace.xml diff --git a/.idea/lifesub-web.iml b/.idea/lifesub-web.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/lifesub-web.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f03c948 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c65f74c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/container/Dockerfile b/deployment/Dockerfile-lifesub-web similarity index 100% rename from container/Dockerfile rename to deployment/Dockerfile-lifesub-web diff --git a/deployment/Jenkinsfile b/deployment/Jenkinsfile new file mode 100644 index 0000000..53f7808 --- /dev/null +++ b/deployment/Jenkinsfile @@ -0,0 +1,101 @@ +def PIPELINE_ID = "${env.BUILD_NUMBER}" + +def getImageTag() { + def dateFormat = new java.text.SimpleDateFormat('yyyyMMddHHmmss') + def currentDate = new Date() + return dateFormat.format(currentDate) +} + +podTemplate( + label: "${PIPELINE_ID}", + serviceAccount: 'jenkins', + containers: [ + containerTemplate(name: 'node', image: 'node:20-slim', ttyEnabled: true, command: 'cat'), + containerTemplate(name: 'podman', image: "mgoltzsche/podman", ttyEnabled: true, command: 'cat', privileged: true), + containerTemplate(name: 'azure-cli', image: 'hiondal/azure-kubectl:latest', command: 'cat', ttyEnabled: true), + containerTemplate(name: 'envsubst', image: "hiondal/envsubst", command: 'sleep', args: '1h') + ], + volumes: [ + emptyDirVolume(mountPath: '/root/.azure', memory: false) + ] +) { + node(PIPELINE_ID) { + def props + def imageTag = getImageTag() + def manifest = "deploy.yaml" + def namespace + + stage("Get Source") { + checkout scm + props = readProperties file: "deployment/deploy_env_vars" + namespace = "${props.teamid}-${props.root_project}-ns" + } + + stage("Setup AKS") { + container('azure-cli') { + withCredentials([azureServicePrincipal('azure-credentials')]) { + sh """ + az login --service-principal -u \$AZURE_CLIENT_ID -p \$AZURE_CLIENT_SECRET -t \$AZURE_TENANT_ID + az aks get-credentials --resource-group ictcoe-edu --name ${props.teamid}-aks --overwrite-existing + kubectl create namespace ${namespace} --dry-run=client -o yaml | kubectl apply -f - + """ + } + } + } + + stage('Build & Push Image') { + container('podman') { + withCredentials([usernamePassword( + credentialsId: 'acr-credentials', + usernameVariable: 'USERNAME', + passwordVariable: 'PASSWORD' + )]) { + def imagePath = "${props.registry}/${props.image_org}/lifesub-web:${imageTag}" + + sh """ + podman login ${props.registry} --username \$USERNAME --password \$PASSWORD + + podman build \ + --build-arg PROJECT_FOLDER="." \ + --build-arg REACT_APP_MEMBER_URL="${props.react_app_member_url}" \ + --build-arg REACT_APP_MYSUB_URL="${props.react_app_mysub_url}" \ + --build-arg REACT_APP_RECOMMEND_URL="${props.react_app_recommend_url}" \ + --build-arg BUILD_FOLDER="container" \ + --build-arg EXPORT_PORT="${props.export_port}" \ + -f container/Dockerfile-lifesub-web \ + -t ${imagePath} . + + podman push ${imagePath} + """ + } + } + } + + stage('Generate & Apply Manifest') { + container('envsubst') { + sh """ + export namespace=${namespace} + export lifesub_web_image_path=${props.registry}/${props.image_org}/lifesub-web:${imageTag} + export replicas=${props.replicas} + export export_port=${props.export_port} + export resources_requests_cpu=${props.resources_requests_cpu} + export resources_requests_memory=${props.resources_requests_memory} + export resources_limits_cpu=${props.resources_limits_cpu} + export resources_limits_memory=${props.resources_limits_memory} + + envsubst < deployment/${manifest}.template > deployment/${manifest} + cat deployment/${manifest} + """ + } + + container('azure-cli') { + sh """ + kubectl apply -f deployment/${manifest} + + echo "Waiting for deployment to be ready..." + kubectl -n ${namespace} wait --for=condition=available deployment/lifesub-web --timeout=300s + """ + } + } + } +} diff --git a/deployment/deploy.yaml.template b/deployment/deploy.yaml.template new file mode 100644 index 0000000..0ccad5c --- /dev/null +++ b/deployment/deploy.yaml.template @@ -0,0 +1,44 @@ +# Frontend Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lifesub-web + namespace: ${namespace} +spec: + replicas: ${replicas} + selector: + matchLabels: + app: lifesub-web + template: + metadata: + labels: + app: lifesub-web + spec: + containers: + - name: lifesub-web + image: ${lifesub_web_image_path} + imagePullPolicy: Always + ports: + - containerPort: ${export_port} + resources: + requests: + cpu: ${resources_requests_cpu} + memory: ${resources_requests_memory} + limits: + cpu: ${resources_limits_cpu} + memory: ${resources_limits_memory} + +--- +# Frontend Service +apiVersion: v1 +kind: Service +metadata: + name: lifesub-web + namespace: ${namespace} +spec: + selector: + app: lifesub-web + ports: + - port: 80 + targetPort: ${export_port} + type: LoadBalancer \ No newline at end of file diff --git a/deployment/deploy_env_vars b/deployment/deploy_env_vars new file mode 100644 index 0000000..aa6cb1d --- /dev/null +++ b/deployment/deploy_env_vars @@ -0,0 +1,22 @@ +# Team Settings +teamid=dg0200 +root_project=lifesub-web + +# Container Registry Settings +registry=dg0200cr.azurecr.io +image_org=lifesub + +# Application Settings +replicas=1 +export_port=18080 + +# Backend Service URLs +react_app_member_url=http://20.249.185.127/member +react_app_mysub_url=http://20.249.185.127/mysub +react_app_recommend_url=http://20.249.185.127/recommend + +# Resource Settings +resources_requests_cpu=256m +resources_requests_memory=256Mi +resources_limits_cpu=1024m +resources_limits_memory=1024Mi \ No newline at end of file diff --git a/container/nginx.conf b/deployment/nginx.conf similarity index 100% rename from container/nginx.conf rename to deployment/nginx.conf