해외에서 살아가는 입장에서는 현지인에게는 당연한 것들이 외국인의 눈에는 새롭고 낯설게 느껴질 때가 많습니다. 이와 같이 한국을 방문한 많은 외국인들도 같은 경험을 하게 됩니다.
외국인에게 필요한 정보와 경험을 얻는 것은 생각보다 어려운 일입니다. OnionHotSayYo는 외국인으로서 한국에 거주하거나 방문하는 모든 이들이 자신의 경험을 공유하고 소통할 수 있는 공간을 제공하기 위해 만들어졌습니다.
또한 OnionHotSayYo를 통해 한국인들 또한 외국인들에게 한국의 흥미로운 정보 제공과 홍보 그리고 소통의 기회를 얻을 수 있습니다.
이재원 | 장민석 | 조예린 | 지현근 | 최종찬 |
1. 개발자가 로컬 환경에서 코드를 작성 및 테스트한 후 , 변경사항을 github로 push
2. github는 변경 사항에 push 되면 webhook이 이벤트를 감지하고 해당 이벤트를 처리하기 위해서 HTTP 요청
3. webhook에서 HTTP요청을 하게 되면 JENKINS를 통해 Gradle을 사용하여 소스코드를 빌드하고 실행이 가능한 jar 파일로 생성
4. 빌드된 jar 파일은 dockerfile를 사용하여 Docker image로 pakaging.
5. Docker는 image를 DockerHub로 push
6. 쿠버네티스 클러스터는 Docker image를 가져와서 배포하고 백엔드와 프론트엔드는 각각의 파드로 배포됨
7. ubuntu 서버에서 MariaDb를 관리하고 backend와 연동하여 데이터를 저장하고 관리함
8. 사용자가 요청한 번역 작업은 DeepL API로 전송되어 처리되며, 번역된 결과가 반환됨
환경
◽ macOS Sonoma 14.2
도구 | 버전 |
---|---|
JDK | 17 |
Docker | 25.0.3 |
Kubernetes | 1.29.1 |
Jenkins | 2.453 |
빌드 문서
[ Dockerfile ]
- Spring boot Dockerfile
FROM openjdk:17-alpine
COPY build/libs/*.jar app.jar
# ARG로 환경 변수 설정
ARG JASYPT_KEY
ENV JASYPT_KEY=$JASYPT_KEY
ENTRYPOINT ["java", "-jar", "app.jar", "--jasypt.encryptor.password=${JASYPT_KEY}"]
🔑 jasypt복호화 패스워드(JASYPT_KEY)는 Jenkins Credentials를 통해 관리하며, 실행 시 환경 변수로서 입력되어 실행됨.
- Vue Dockerfile
FROM node:lts-alpine
RUN apk add --no-cache curl
WORKDIR /app
COPY . ./
RUN npm install
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
- Jenkins Dockerfile
FROM jenkins/jenkins:jdk17
USER root
RUN apt-get update && \
apt-get install -y apt-transport-https ca-certificates curl software-properties-common && \
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# docker-compose 설치
RUN curl -L "https://github.com/docker/compose/releases/download/1.28.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
chmod +x /usr/local/bin/docker-compose && \
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
- Jenkins docker-compose.yml
version: '3.7'
services:
jenkins:
build:
context: .
dockerfile: Dockerfile
container_name: 'jenkins_docker'
# mac 실리콘 칩의 경우 설정
platform: linux/arm64
restart: always
user: root
ports:
- '8080:8080'
- '50000:50000'
volumes:
- './jenkins_home:/var/jenkins_home'
- '/var/run/docker.sock:/var/run/docker.sock'
docker: not found
오류가 발생할 경우
docker exec -it jenkins_docker /bin/bash : container 접속
curl -fsSL https://get.docker.com -o get-docker.sh : docker 설치
sh get-docker.sh
◽ Jenkins Credentials
-
젠킨스 도커 컨테이너에 접속해 RSA Key 생성 -> Github 접속을 위해 private key 등록
-
Dockerhub 접속을 위한 dockerhub 계정 정보 등록
-
jasypt 복호화에 필요한 password 등록
- Github
Repository Settings에 접근하여 Deploy keys에 public key 등록
- ngrok으로 port를 개방하여 Webhook 연결
ngrok http 8080
- Jenkins Tools에서 Java(OpenJDK 17) , Gradle(8.7) 설정
- 새로운 Item -> Pipeline 생성 -> Build Triggers -> Github hook trigger for GITScm polling 체크
- Jenkins Pipeline Script
pipeline {
agent any
tools {
gradle 'gradle'
jdk 'openJDK17'
}
environment {
DOCKERHUB_USERNAME = 'orlzll'
GITHUB_URL = 'https://github.com/OmokNoonE/OnionHotSayYo-backend.git'
}
stages {
stage('Preparation') {
steps {
script {
sh 'docker --version'
}
}
}
stage('Source Build') {
steps {
// 소스파일 체크아웃
git branch: 'main', url: 'https://github.com/OmokNoonE/OnionHotSayYo-backend.git'
// 소스 빌드
// 755권한 필요 (윈도우에서 Git으로 소스 업로드시 권한은 644)
// JASYPT_KEY Credentials
sh "chmod +x ./gradlew"
withCredentials([string(credentialsId: 'JASYPT_KEY', variable: 'JASYPT_KEY')]) { //set SECRET with the credential content
sh "./gradlew clean build -P jasypt.encryptor.password=${JASYPT_KEY}"
}
}
}
stage('Container Build') {
steps {
// jar 파일 복사
sh "cp ./build/libs/*.jar ."
// 컨테이너 빌드 및 업로드
withCredentials([string(credentialsId: 'JASYPT_KEY', variable: 'JASYPT_KEY')]) { //set SECRET with the credential content
sh "docker build --build-arg JASYPT_KEY=${JASYPT_KEY} -t ${DOCKERHUB_USERNAME}/onion-back2:latest . --platform linux/x86_64"
}
// docker hub로 push
withCredentials([usernamePassword(credentialsId: 'DOCKERHUB_PASSWORD', usernameVariable: 'DOCKERHUB_USER', passwordVariable: 'DOCKERHUB_PASS')]) {
sh "echo $DOCKERHUB_PASS | docker login --username $DOCKERHUB_USER --password-stdin"
sh "docker push ${DOCKERHUB_USERNAME}/onion-back2:latest"
}
}
}
}
}
🔨 최초로 pipeline 구축 후에는 지금 빌드
실행
배포 문서
[!NOTE] 스크립트를 통해 실행하려면 아래 매니페스트 파일들을 하나의 폴더에서 관리
- boot001dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: boot001dep
spec:
selector:
matchLabels:
app: boot001kube
replicas: 1
template:
metadata:
labels:
app: boot001kube
spec:
containers:
- name: boot-container
image: orlzll/onion-back2:latest
imagePullPolicy: Always
ports:
- containerPort: 8888
- boot001ser.yml
apiVersion: v1
kind: Service
metadata:
name: boot001ser
spec:
type: NodePort
ports:
- port: 8888 #서비스포트
targetPort: 8888
protocol: TCP
nodePort: 30001
selector:
app: boot001kube
- vue001dep.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: vue001dep
spec:
selector:
matchLabels:
app: vue001kube
template:
metadata:
labels:
app: vue001kube
spec:
containers:
- name: vue-container
image: orlzll/onion-front2:latest
imagePullPolicy: Always
ports:
- containerPort: 5173
- vue001ser.yml
apiVersion: v1
kind: Service
metadata:
name: vue001ser
spec:
type: NodePort
ports:
- port: 5173
targetPort: 5173
protocol: TCP
nodePort: 30000
selector:
app: vue001kube
# 디렉토리 경로 설정
KUBE_DIR=../../infra
VUE_DIR=../frontend/OnionHotSayYo_frontend # frontend 디렉토리 경로
PASSWORD='0000' # sudo password
# vue project build
cd $VUE_DIR
echo $PASSWORD | sudo -S docker build -t orlzll/onion-front2 .
echo $PASSWORD | sudo -S docker push orlzll/onion-front2
# manifest
cd $KUBE_DIR
kubectl apply -f vue001dep.yml && kubectl apply -f vue001ser.yml
kubectl apply -f boot001dep.yml && kubectl apply -f boot001ser.yml
[!NOTE] 현재 frontend project는 Jenkins를 통한 build 자동화가 되어 있지 않으므로 이 과정에서 build 및 docker hub로 image push 하도록 설정함
[ 이미지 변경 시 디플로이먼트 업데이트 ]
- 백엔드
kubectl rollout restart deployments boot001dep
젠킨스를 통해 dockerhub image가 자동으로 업데이트 되므로 deployments restart
VUE_DIR=../frontend/OnionHotSayYo_frontend # frontend 디렉토리 경로
PASSWORD='0000' # sudo password
# vue project build
cd $VUE_DIR
echo $PASSWORD | sudo -S docker build -t orlzll/onion-front2 .
echo $PASSWORD | sudo -S docker push orlzll/onion-front2
# deployment restart
kubectl rollout restart deployments vue001dep
빌드 -> 도커 허브에 이미지 업로드 -> 재시작됨
[!NOTE] 추후 해당 과정을 ArgoCD를 통해 도커 허브 이미지의 변경을 감지하고 Kubernetes 클러스터 내의 애플리케이션을 자동으로 업데이트하도록 고도화 예정
Redis Pods
Refresh Token 관리를 위해 Redies를 Kubernetes pods로서 배포함
redis-pod.yml
redis-svc.yml
redis-configmap.yml
화면 구성 이미지 보기
팀 원 | 회고록 |
---|---|
이재원 | 이번 프로젝트를 통해 저는 Spring Data JPA를 활용할 기회를 많이 얻었고, 이를 통해 개발 스킬과 데이터 관리 능력을 향상시킬 수 있었습니다. Spring Data JPA는 데이터 접근 계층을 보다 쉽게 구현할 수 있게 도와주었으며, 일반 비즈니스 요구사항을 효과적으로 처리할 수 있었습니다. 기존 팀원들과 지속적으로 새로운 프로젝트를 진행하면서 팀워크의 중요성을 다시 한 번 깨달았습니다. 협업을 통해 각자의 강점을 최대한 활용하고, 서로의 약점을 보완하며, 프로젝트에 기여할 수 있었습니다. 이 과정에서 백엔드 작업을 담당하면서 프론트엔드 개발자와의 원활한 소통을 위해 API 명세서를 작성하는 전략을 채택했습니다. API 명세서는 개발의 시작부터 명확하게 작성되어, 프론트엔드 팀과 백엔드 팀 간의 기대를 명확히 일치시키는 역할을 했습니다. 이 문서는 각 API의 요청과 응답 형식을 정의하고, 예상되는 에러 상황 및 처리 방법을 상세히 기술함으로써, 개발자 간의 오해를 최소화하고 프로젝트 문서화에 기여할 수 있었습니다. 프로그래밍 언어의 기술적, 문법적 연습을 넘어 실제 사용 가능성을 고려하며 설계하는 과정은 매우 도전적이었습니다. 여기서 배운 것은, 단순히 코드를 작성하는 것이 아니라 그 코드가 실제 환경에서 어떻게 기능할지를 예측하고 최적화하는 능력이 중요하다는 것입니다. 이러한 경험들은 저에게 매우 긍정적인 감정과 더 많은 학습에 대한 열정을 가져다주었습니다. 백엔드 개발을 주로 담당하면서도 원활한 소통과 작업 진행을 위해 프론트 및 인프라에 대한 전반적인 이해가 필수적임을 깨달았습니다. 이는 개발자로서 자신의 전문 영역만 공부하는 것에 그치지 않고, 다양한 기술 영역에 대한 지식을 넓혀야 함을 배웠습니다. 마지막으로 함께 해준 팀원분들께 감사하며, 다음 프로젝트도 더 많은 기여를 할 수 있도록 노력하겠습니다. |
장민석 | 이전 프로젝트와 동일한 팀원들과 함께 했다는 점은 정말 좋았어요. 함께 공유하고 배운 Vue 3와 Spring Boot를 다시 복습하고 통합하는 과정에서 서로의 지식을 공유하고 함께 성장할 수 있었습니다. 처음 접한 기술들이었기 때문에 복습을 통해 이전에 배웠던 내용을 확실하게 다시 기억할 수 있었고, 이를 프로젝트에 적용하면서 실전 경험을 쌓을 수 있었습니다. DevOps와의 결합 뿐만 아니라 DevOps와 같은 다른 기술 영역과의 결합도 경험했습니다. Vue 3와 Spring Boot뿐만 아니라 Jenkins, Docker, Kubernetes, Jasypt 등의 DevOps 도구들을 이용하여 프로젝트를 효율적으로 관리하고 배포하는 방법을 배웠습니다. 이를 통해 개발과 운영 사이의 간극을 줄이고, 팀 전체의 업무 효율성을 향상시킬 수 있었습니다. 새로운 팀 협업 경험 이번 프로젝트를 통해 팀원들과의 협업 능력도 크게 향상시켰습니다. 서로 다른 기술 영역을 담당하고 있었기 때문에 서로의 역할과 책임을 이해하고 효율적으로 의사 소통하는 방법을 배웠습니다. 특히 코드 리뷰와 피드백을 통해 서로의 실력을 향상시키는 과정은 매우 유익했습니다. 기술적 지식의 지속적인 보강을 위해, Vue 3와 Spring Boot를 비롯한 기술적 지식을 더욱 확장하고 깊이 있게 이해하기 위해, 프로젝트의 코드를 리팩토링하겠습니다. 이를 통해 코드를 더 깔끔하게 구성하고, 최신 개념 및 모범 사례를 적용하여 효율성을 높일 것입니다. 이전 프로젝트와 동일한 팀원들과 함께한 경험이 매우 유익하고 의미있었습니다. 함께 공유하고 성장한 경험을 바탕으로 앞으로도 지속적인 학습과 개선을 통해 더 나은 결과물을 만들어 나갈 것입니다. Vue 3와 Spring Boot를 복습하고 DevOps와의 결합을 경험한 이번 프로젝트를 통해 많은 것을 배우고 성장할 수 있었습니다. 앞으로도 지속적인 학습과 개선을 통해 더 나은 개발자가 되기 위해 노력할 것이며, 함께하는 팀원들과의 협업을 통해 함께 성장하고 발전해 나가길 기대합니다. |
조예린 | 백엔드와 인프라를 담당하며 CI/CD를 구축하는 과정이 흥미로웠습니다. 기존에 습득한 지식을 되짚으며 부족한 부분을 보완하고, 새로운 기능을 도입하는 과정에서 성취감을 느낄 수 있었습니다. 사용자 경험 개선을 위해 실시간 알림 기능을 도입하는 과정에서 WebSocket과 SSE 중 어떤 방식을 적용할지 고민하고 적절히 적용함으로써 프로젝트의 효율성을 높였습니다. 특히 이번 프로젝트에서는 젠킨스를 활용하여 빌드를 자동화하면서 빌드 프로세스의 편리함을 경험했고, 추후에는 ArgoCD를 도입해 배포까지 자동화하는 환경을 구축하여 소프트웨어 개발 라이프 사이클을 간소화하고 업데이트의 검증 및 릴리즈 시간을 단축하는 지속적인 개선 환경을 만들고자 합니다. 함께 공부하고 경험을 나누며 서로의 역량을 키우고 프로젝트의 성과를 극대화하는 데 기여할 수 있었습니다. 이러한 협력의 과정을 통해 팀원들과의 신뢰와 유대감을 쌓을 수 있었고, 앞으로도 협력을 통해 더 큰 성과를 이루어 나갈 수 있을 것으로 기대합니다. |
지현근 | 이번 프로젝트를 통해 많은 것을 배우고 성장할 수 있는 기회가 되었습니다. 처음부터 프로젝트를 진행하면서 데이터베이스부터 백엔드, 프론트엔드까지의 기술들을 복습할 수 있었습니다. 이를 통해 과거에 학습한 지식을 되새겨 보는 동시에, 새로운 기술들을 습득하고 적용하는 경험을 하게 되어 보람찬 시간이었다고 생각합니다. 다양한 기술을 적용하면서, 기본적인 페이지 구현을 완료하고 최종적인 페이지를 만드는 과정에서 도전과 학습이 있었습니다. 특히, 젠킨스, 도커허브, 그리고 쿠버네티스를 통해 빌드하고 배포하는 과정을 경험했는데 이러한 경험은 실제 프로젝트에서의 배포 및 운영 과정을 이해하고 익히는 데 큰 도움이 되었습니다. 다음 프로젝트에는 더욱 구체적인 설계를 토대로 개발을 진행하고자 합니다. 이번 프로젝트에서는 새로운 기술들을 적용하는 과정에서 다양한 상황에 대처할 필요가 있었습니다. 다음 프로젝트에서는 미리 구체적인 계획을 세우고, 그에 따라 개발을 진행하여 보다 효율적이고 안정적인 결과물을 얻도록 진행하고 싶습니다. 또한 이번 프로젝트를 통해 팀원들과의 협업 능력도 향상되었다고 생각합니다. 서로의 아이디어를 나누고 피드백을 주고받으며 함께 성장하는 경험을 했습니다. 최종 프로젝트에서도 이러한 협업을 통해 더 나은 결과물을 만들어 나가고 싶습니다. |
최종찬 | 프로젝트 기획부터 시작하여 MariaDB와 Ubuntu를 이용한 DB 서버 구축, Java와 Spring Boot를 활용한 백엔드 서버 개발, Vue 3를 활용한 웹 프론트엔드 구현, 그리고 Jenkins, GitHub, Slack을 활용한 지속적인 유지보수, Docker와 Kubernetes를 활용한 베포까지. 이 모든 것을 담은 OnionHotSayYo 프로젝트는 지난 12월부터의 부트캠프 여정을 녹여낸 소중한 프로젝트입니다. 2주라는 비교적 짧은 기간이었지만, 최선을 다해 개발에 몰두하였고, 팀원들과의 협력을 바탕으로 프로젝트를 성공적으로 개발할 수 있었습니다. OnionHotSayYo 프로젝트는 부트캠프에서 경험한 프로젝트 중에서도 가장 열정적으로 참여한 프로젝트였습니다. 이를 통해 개인적으로 지난 학습에서의 부족한 부분을 보완할 수 있는 좋은 기회가 되었으며, 파이널 프로젝트 전, 팀원들과의 협동력을 크게 향상시키며, 결속력을 늘린 귀중한 기회이자 경험이었습니다. 멘토님과 함께 진행할 마지막 프로젝트와 함께, OnionHotSayYo를 더 좋은 퀄리티로 지속적으로 리펙토링해나가면 좋겠습니다. OmokNoonE 화이팅입니다!! |