Skip to content

❄️김종원, 김태영, 이은서, 조은희, 홍석민❄️

Notifications You must be signed in to change notification settings

beyond-sw-camp/be08-4th-DQ-OMOS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

be08-4th-DailyQuest-OneMinOneSec

포스터


💫한화시스템 BEYOND SW캠프 4차 프로젝트💫




🛠️ Tech Stack 🛠️

CI/CD

Backend

Frontend

VCS

협업 툴




🍀 프로젝트 소개

OMOS : One Minute One Second

🍀 관리자에게 학생 정보를 보내줄 수 있습니다.

🍀 캘린더를 통해 일정을 확인하고 조율할 수 있습니다.


🔆 프로젝트 개요 및 기대효과

프로젝트 개요

교육 일정 및 휴가 일정을 캘린더를 통해 손쉽게 확인하고 관리할 수 있는 서비스입니다. 매니저가 캘린더를 통해 일정을 한눈에 파악하고 교육, 강의, 프로젝트 일정을 확인할 수 있으며, 개인 휴가 계획 또한 간편한 통합 관리가 가능하도록 도와줍니다.


기대효과

일정 관리의 비효율성을 해결하고, 교육과 휴가, 프로젝트 일정을 통합 관리할 수 있는 도구에 대한 필요성 때문입니다. 많은 교육 기관과 기업에서는 다양한 일정을 관리할 때 개별적으로 시스템을 사용하거나 수작업으로 관리하는 경우가 많습니다. 이러한 방식은 일정 중복, 혼란, 휴가 계획 누락 등의 문제를 야기할 수 있습니다.

특히 매니저는 팀원의 교육, 프로젝트, 휴가 일정을 한눈에 파악하기 어려워 조율에 많은 시간을 할애해야 하고, 구성원들 역시 본인의 교육과 휴가 계획을 쉽게 확인하거나 조정하기 어렵습니다. 이를 해결하기 위해 캘린더를 중심으로 한 통합 일정 관리 시스템을 구축하여, 사용자들이 더 효율적으로 일정을 관리하고, 계획을 원활하게 진행할 수 있도록 돕고자 이 프로젝트를 시작하게 되었습니다.



📑 요구사항 명세서


요구사항 명세서

erd


📋 ERD

ERD


erd


📄 API 명세서


API 명세서

api 명세서



📺 화면 설계서

Figma 보러가기


포스터



📑 시스템 아키텍처


시스템 아키텍처

📑 CI/CD 아키텍처


CI/CD


🩰 CI/CD 명세서


CI/CD 명세서

CI/CD



📜 파이프라인(Jenkinsfile)

auth-service-jenkinsfile
pipeline {
    agent {
        kubernetes {
            yaml '''
            apiVersion: v1
            kind: Pod
            metadata:
              name: jenkins-agent-${env.BUILD_NUMBER}
            spec:
              containers:
              - name: gradle
                image: gradle:7.6.2-jdk17
                command:
                  - cat
                tty: true
              - name: docker
                image: docker:latest
                command:
                - cat
                tty: true
                volumeMounts:
                - mountPath: "/var/run/docker.sock"
                  name: docker-socket
              - name: kubectl
                image: gcr.io/cloud-builders/kubectl
                command:
                - cat
                tty: true
              volumes:
              - name: docker-socket
                hostPath:
                  path: "/var/run/docker.sock"
            '''
        }
    }

    environment {
        DOCKER_CREDENTIALS_ID = 'dockerhub_access'
        DOCKER_IMAGE_NAME = 'jjjwww8802/auth-service'
        DOCKERHUB_URL = 'https://index.docker.io/v1/'
        GITHUB_URL = 'git@github.com:beyond-sw-camp/be08-4th-DQ-OMOS.git'
        GITHUB_CREDENTIALS_ID = 'omos_access_ssh'
    }

    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', credentialsId: "${GITHUB_CREDENTIALS_ID}", url: "${GITHUB_URL}"
            }
        }

        stage('Gradle Build') {
            steps {
                dir('Backend/auth-service') {
                    container('gradle') {
                        sh 'chmod +x ./gradlew'
                        sh './gradlew clean bootJar'
                    }
                }
            }
        }

        stage('Docker Image Build & Push') {
            steps {
                dir('Backend/auth-service') {
                    container('docker') {
                        script {
                            sh 'docker logout'
                            withCredentials([usernamePassword(credentialsId: "${DOCKER_CREDENTIALS_ID}", usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
                                sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
                            }
                            sh "docker build --no-cache -t ${DOCKER_IMAGE_NAME}:latest ."
                            sh "docker push ${DOCKER_IMAGE_NAME}:latest"
                            sh 'docker logout'
                        }
                    }
                }
            }
        }

        stage('Kubernetes Deployment') {
            steps {
                container('kubectl') {
                    script {
                        sh "kubectl set image deploy auth-deploy auth=${DOCKER_IMAGE_NAME}:latest -n default"
                        sh "kubectl rollout restart deploy auth-deploy -n default"
                    }
                }
            }
        }
    }

    post {
        success {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 성공",
                webhookURL: "${DISCORD}"
            }
        }
        failure {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 실패",
                webhookURL: "${DISCORD}"
            }
        }
    }
}

calendar-service-jenkinsfile
pipeline {
    agent {
        kubernetes {
            yaml '''
            apiVersion: v1
            kind: Pod
            metadata:
              name: jenkins-agent-${env.BUILD_NUMBER}
            spec:
              containers:
              - name: gradle
                image: gradle:7.6.2-jdk17
                command:
                  - cat
                tty: true
              - name: docker
                image: docker:latest
                command:
                - cat
                tty: true
                volumeMounts:
                - mountPath: "/var/run/docker.sock"
                  name: docker-socket
              - name: kubectl
                image: gcr.io/cloud-builders/kubectl
                command:
                - cat
                tty: true
              volumes:
              - name: docker-socket
                hostPath:
                  path: "/var/run/docker.sock"
            '''
        }
    }

    environment {
        DOCKER_CREDENTIALS_ID = 'dockerhub_access'
        DOCKER_IMAGE_NAME = 'jjjwww8802/calendar-service'
        DOCKERHUB_URL = 'https://index.docker.io/v1/'
        GITHUB_URL = 'git@github.com:beyond-sw-camp/be08-4th-DQ-OMOS.git'
        GITHUB_CREDENTIALS_ID = 'omos_access_ssh'
    }

    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', credentialsId: "${GITHUB_CREDENTIALS_ID}", url: "${GITHUB_URL}"
            }
        }

        stage('Gradle Build') {
            steps {
                dir('Backend/calendar-service') {
                    container('gradle') {
                        sh 'chmod +x ./gradlew'
                        sh './gradlew clean bootJar'
                    }
                }
            }
        }

        stage('Docker Image Build & Push') {
            steps {
                dir('Backend/calendar-service') {
                    container('docker') {
                        script {
                            sh 'docker logout'
                            withCredentials([usernamePassword(credentialsId: "${DOCKER_CREDENTIALS_ID}", usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
                                sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
                            }
                            sh "docker build --no-cache -t ${DOCKER_IMAGE_NAME}:latest ."
                            sh "docker push ${DOCKER_IMAGE_NAME}:latest"
                            sh 'docker logout'
                        }
                    }
                }
            }
        }

        stage('Kubernetes Deployment') {
            steps {
                container('kubectl') {
                    script {
                        sh "kubectl set image deploy calendar-deploy calendar=${DOCKER_IMAGE_NAME}:latest -n default"
                        sh "kubectl rollout restart deploy calendar-deploy -n default"
                    }
                }
            }
        }
    }

    post {
        success {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 성공",
                webhookURL: "${DISCORD}"
            }
        }
        failure {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 실패",
                webhookURL: "${DISCORD}"
            }
        }
    }
}

notice-service-jenkinsfile
pipeline {
    agent {
        kubernetes {
            yaml '''
            apiVersion: v1
            kind: Pod
            metadata:
              name: jenkins-agent-${env.BUILD_NUMBER}
            spec:
              containers:
              - name: gradle
                image: gradle:7.6.2-jdk17
                command:
                  - cat
                tty: true
              - name: docker
                image: docker:latest
                command:
                - cat
                tty: true
                volumeMounts:
                - mountPath: "/var/run/docker.sock"
                  name: docker-socket
              - name: kubectl
                image: gcr.io/cloud-builders/kubectl
                command:
                - cat
                tty: true
              volumes:
              - name: docker-socket
                hostPath:
                  path: "/var/run/docker.sock"
            '''
        }
    }

    environment {
        DOCKER_CREDENTIALS_ID = 'dockerhub_access'
        DOCKER_IMAGE_NAME = 'jjjwww8802/notice-service'
        DOCKERHUB_URL = 'https://index.docker.io/v1/'
        GITHUB_URL = 'git@github.com:beyond-sw-camp/be08-4th-DQ-OMOS.git'
        GITHUB_CREDENTIALS_ID = 'omos_access_ssh'
    }

    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', credentialsId: "${GITHUB_CREDENTIALS_ID}", url: "${GITHUB_URL}"
            }
        }

        stage('Gradle Build') {
            steps {
                dir('Backend/notice-service') {
                    container('gradle') {
                        sh 'chmod +x ./gradlew'
                        sh './gradlew clean bootJar'
                    }
                }
            }
        }

        stage('Docker Image Build & Push') {
            steps {
                dir('Backend/notice-service') {
                    container('docker') {
                        script {
                            sh 'docker logout'
                            withCredentials([usernamePassword(credentialsId: "${DOCKER_CREDENTIALS_ID}", usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
                                sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
                            }
                            sh "docker build --no-cache -t ${DOCKER_IMAGE_NAME}:latest ."
                            sh "docker push ${DOCKER_IMAGE_NAME}:latest"
                            sh 'docker logout'
                        }
                    }
                }
            }
        }

        stage('Kubernetes Deployment') {
            steps {
                container('kubectl') {
                    script {
                        sh "kubectl set image deploy notice-deploy notice=${DOCKER_IMAGE_NAME}:latest -n default"
                        sh "kubectl rollout restart deploy notice-deploy -n default"
                    }
                }
            }
        }
    }

    post {
        success {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 성공",
                webhookURL: "${DISCORD}"
            }
        }
        failure {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 실패",
                webhookURL: "${DISCORD}"
            }
        }
    }
}

notification-service-jenkinsfile
pipeline {
    agent {
        kubernetes {
            yaml '''
            apiVersion: v1
            kind: Pod
            metadata:
              name: jenkins-agent-${env.BUILD_NUMBER}
            spec:
              containers:
              - name: gradle
                image: gradle:7.6.2-jdk17
                command:
                  - cat
                tty: true
              - name: docker
                image: docker:latest
                command:
                - cat
                tty: true
                volumeMounts:
                - mountPath: "/var/run/docker.sock"
                  name: docker-socket
              - name: kubectl
                image: gcr.io/cloud-builders/kubectl
                command:
                - cat
                tty: true
              volumes:
              - name: docker-socket
                hostPath:
                  path: "/var/run/docker.sock"
            '''
        }
    }

    environment {
        DOCKER_CREDENTIALS_ID = 'dockerhub_access'
        DOCKER_IMAGE_NAME = 'jjjwww8802/notification-service'
        DOCKERHUB_URL = 'https://index.docker.io/v1/'
        GITHUB_URL = 'git@github.com:beyond-sw-camp/be08-4th-DQ-OMOS.git'
        GITHUB_CREDENTIALS_ID = 'omos_access_ssh'
    }

    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', credentialsId: "${GITHUB_CREDENTIALS_ID}", url: "${GITHUB_URL}"
            }
        }

        stage('Gradle Build') {
            steps {
                dir('Backend/notification-service') {
                    container('gradle') {
                        sh 'chmod +x ./gradlew'
                        sh './gradlew clean bootJar'
                    }
                }
            }
        }

        stage('Docker Image Build & Push') {
            steps {
                dir('Backend/notification-service') {
                    container('docker') {
                        script {
                            sh 'docker logout'
                            withCredentials([usernamePassword(credentialsId: "${DOCKER_CREDENTIALS_ID}", usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
                                sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
                            }
                            sh "docker build --no-cache -t ${DOCKER_IMAGE_NAME}:latest ."
                            sh "docker push ${DOCKER_IMAGE_NAME}:latest"
                            sh 'docker logout'
                        }
                    }
                }
            }
        }

        stage('Kubernetes Deployment') {
            steps {
                container('kubectl') {
                    script {
                        sh "kubectl set image deploy notification-deploy notification=${DOCKER_IMAGE_NAME}:latest -n default"
                        sh "kubectl rollout restart deploy notification-deploy -n default"
                    }
                }
            }
        }
    }

    post {
        success {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 성공",
                webhookURL: "${DISCORD}"
            }
        }
        failure {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 실패",
                webhookURL: "${DISCORD}"
            }
        }
    }
}


student-service-jenkinsfile
pipeline {
    agent {
        kubernetes {
            yaml '''
            apiVersion: v1
            kind: Pod
            metadata:
              name: jenkins-agent-${env.BUILD_NUMBER}
            spec:
              containers:
              - name: gradle
                image: gradle:7.6.2-jdk17
                command:
                  - cat
                tty: true
              - name: docker
                image: docker:latest
                command:
                - cat
                tty: true
                volumeMounts:
                - mountPath: "/var/run/docker.sock"
                  name: docker-socket
              - name: kubectl
                image: gcr.io/cloud-builders/kubectl
                command:
                - cat
                tty: true
              volumes:
              - name: docker-socket
                hostPath:
                  path: "/var/run/docker.sock"
            '''
        }
    }

    environment {
        DOCKER_CREDENTIALS_ID = 'dockerhub_access'
        DOCKER_IMAGE_NAME = 'jjjwww8802/student-service'
        DOCKERHUB_URL = 'https://index.docker.io/v1/'
        GITHUB_URL = 'git@github.com:beyond-sw-camp/be08-4th-DQ-OMOS.git'
        GITHUB_CREDENTIALS_ID = 'omos_access_ssh'
    }

    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', credentialsId: "${GITHUB_CREDENTIALS_ID}", url: "${GITHUB_URL}"
            }
        }

        stage('Gradle Build') {
            steps {
                dir('Backend/student-service') {
                    container('gradle') {
                        sh 'chmod +x ./gradlew'
                        sh './gradlew clean bootJar'
                    }
                }
            }
        }

        stage('Docker Image Build & Push') {
            steps {
                dir('Backend/student-service') {
                    container('docker') {
                        script {
                            sh 'docker logout'
                            withCredentials([usernamePassword(credentialsId: "${DOCKER_CREDENTIALS_ID}", usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
                                sh 'echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin'
                            }
                            sh "docker build --no-cache -t ${DOCKER_IMAGE_NAME}:latest ."
                            sh "docker push ${DOCKER_IMAGE_NAME}:latest"
                            sh 'docker logout'
                        }
                    }
                }
            }
        }

        stage('Kubernetes Deployment') {
            steps {
                container('kubectl') {
                    script {
                        sh "kubectl set image deploy student-deploy student=${DOCKER_IMAGE_NAME}:latest -n default"
                        sh "kubectl rollout restart deploy student-deploy -n default"
                    }
                }
            }
        }
    }

    post {
        success {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 성공",
                webhookURL: "${DISCORD}"
            }
        }
        failure {
            withCredentials([string(credentialsId: 'discord-webhook', variable: 'DISCORD')]) {
                discordSend description: """
                제목 : ${currentBuild.displayName}
                결과 : ${currentBuild.result}
                실행 시간 : ${currentBuild.duration / 1000}s
                """,
                result: currentBuild.currentResult,
                title: "${env.JOB_NAME} : ${currentBuild.displayName} 실패",
                webhookURL: "${DISCORD}"
            }
        }
    }
}


▶️ CICD 테스트(Jenkinsfile)

IMAGE ALT TEXT HERE

📅 WBS


WBS

wbs


🐻 한줄 회고록

    팀 원     회고
👑김종원
Devops 프로젝트에서 Spring Boot과 Vuejs 애플리케이션의 CI/CD 파이프라인을 구축하며, Jenkins와 Kubernetes 설정 과정에서 Helm을 활용해 효율적으로 환경을 구축해보고, Ngrok을 이용해 깃허브와 웹훅을 연결해 자동화를 하였습니다. Gradle을 통한 빌드 후 Docker 이미지를 생성하고 Docker Hub에 푸시하여 다양한 환경에서 배포 작업을 해보며 잘 몰랐던 CI/CD를 이해할 수 있었습니다. 프로젝트 초기에 기존의 개발방식과 다르게 MSA 방식으로 개발해보고자 제안을 했고 매일 남아서 공부하며 열심히 해준 팀원들에게 고맙습니다!!
 
🍙김태영
처음으로 해보는 CI/CD 프로젝트라서 도커, 쿠버네티스, 젠킨스의 동작 원리를 알 수 있는 소중한 기회였던 것 같습니다.
 
🐶이은서
이번 프로젝트를 프론트엔드부터 백엔드 그리고 CI/CD 파이프라인을 만들어서 배포까지 경험 할 수 있어서 좋았습니다. 배포하는 과정이 어려워 해결하지 못한 부분들을 팀원들 덕분에 배포까지 마무리 할 수 있었던 것 같습니다!!
 
🧁조은희
이번 프로젝트는 프론트엔드부터 배포까지 CI/CD 파이프라인을 직접 경험할 수 있었던 좋은 기회였습니다. 특히 배포 과정에서 노트북 성능이 낮아 빌드와 테스트 속도가 느려지는 문제가 발생하였고, 효율적인 빌드 프로세스와 환경 최적화의 중요성을 깨닫게 되었습니다.
 
🐧홍석민
이번 데브옵스 프로젝트를 진행하면서 기존 모놀리딕 방식이 아닌 msa 방식으로 진행을 해보았는데 중간중간 설계를 바꾸지 않으면 해결하지 못하는 문제들을 마주하면서 설계가 정말 중요하고 신중하게 생각해야 하는 걸 다시 한번 느꼈습니다. 데브옵스도 결코 만만치 않았고 왜 데브옵스 개발자가 따로 있는지 알 수 있는 시간이었습니다.
 

About

❄️김종원, 김태영, 이은서, 조은희, 홍석민❄️

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published