- 이슈 관리 : Jira
- 형상 관리 : GitLab, Git
- 커뮤니케이션 : Notion, Mattermost
- CI/CD : Jenkins, Docker, ECS
- 와이어프레임 : Figma
- ERD : ERD Cloud
- 요구사항 정의서 : Google Sheets
- 기능 명세서 : Google Sheets
- 간트차트 : Google Sheets
- Visual Studio Code
- Intellij : 2023.3.2 (Ultimate Edition)
"dependencies": {
"@tanstack/react-query": "^5.28.2",
"axios": "^1.6.7",
"framer-motion": "^11.0.13",
"moment": "^2.30.1",
"next": "14.1.3",
"next-compose-plugins": "^2.2.1",
"react": "^18",
"react-calendar": "^4.8.0",
"react-dom": "^18",
"react-error-boundary": "^4.0.13",
"react-spinners": "^0.13.8",
"sharp": "^0.33.3",
"zustand": "^4.5.2"
},
"devDependencies": {
"@mswjs/http-middleware": "^0.9.2",
"@tanstack/react-query-devtools": "^5.28.6",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"cors": "^2.8.5",
"eslint": "^8",
"eslint-config-next": "14.1.3",
"express": "^4.19.2",
"msw": "^2.2.13",
"sass": "^1.72.0",
"typescript": "^5",
"typescript-plugin-css-modules": "^5.1.0",
"webpack": "^5.90.3"
}
프로그램 | 버전 |
---|---|
jvm | openjdk version "17.0.8.1" 2023-08-24 |
gradle | 8.6 |
spring boot | 3.2.3 |
Spring | 6.1.4 |
spring security | 6.2.1 |
jpa | 6.4.1.FINAL |
querydsl | 5.0.0 |
mysql connector-j | 8.3.0 |
lettuce | 6.3.2.RELEASE |
spring batch | 5.1.0 |
spring cache | 3.2.2 |
jjwt | 0.11.2 |
spring cloud aws | 2.2.6.RELEASE |
nurigo sdk | 4.2.7 |
absl-py==2.1.0
annotated-types==0.6.0
annoy==1.17.3
anyio==4.3.0
astunparse==1.6.3
cachetools==5.3.3
certifi==2024.2.2
charset-normalizer==3.3.2
click==8.1.7
colorama==0.4.6
exceptiongroup==1.2.0
fastapi==0.110.0
filelock==3.13.3
flatbuffers==24.3.25
fsspec==2024.3.1
gast==0.4.0
google-auth==2.29.0
google-auth-oauthlib==0.4.6
google-pasta==0.2.0
greenlet==3.0.3
grpcio==1.62.1
h11==0.14.0
h5py==3.10.0
httptools==0.6.1
huggingface-hub==0.22.1
idna==3.6
importlib_metadata==7.1.0
install==1.3.5
Jinja2==3.1.3
joblib==1.3.2
keras==2.11.0
libclang==18.1.1
Markdown==3.6
MarkupSafe==2.1.5
mpmath==1.3.0
mysql==0.0.3
mysqlclient==2.2.4
networkx==3.2.1
numpy==1.26.4
oauthlib==3.2.2
opt-einsum==3.3.0
packaging==24.0
pillow==10.2.0
protobuf==3.19.6
pyasn1==0.6.0
pyasn1_modules==0.4.0
pydantic==2.6.4
pydantic_core==2.16.3
pykospacing @ git+https://github.com/haven-jeon/PyKoSpacing.git@04aeebcbe26b109486a642e57dc58665c4818cf3
python-dotenv==1.0.1
PyYAML==6.0.1
regex==2023.12.25
requests==2.31.0
requests-oauthlib==2.0.0
rsa==4.9
safetensors==0.4.2
scikit-learn==1.4.1.post1
scipy==1.12.0
sentence-transformers==2.6.1
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.29
starlette==0.36.3
sympy==1.12
tensorboard==2.11.2
tensorboard-data-server==0.6.1
tensorboard-plugin-wit==1.8.1
termcolor==2.4.0
threadpoolctl==3.4.0
tokenizers==0.15.2
torch==2.2.2
tqdm==4.66.2
transformers==4.39.1
typing_extensions==4.10.0
urllib3==2.2.1
uvicorn==0.29.0
watchfiles==0.21.0
websockets==12.0
Werkzeug==3.0.1
wrapt==1.16.0
zipp==3.18.1
프로그램 | 버전 |
---|---|
Amazon Lightsail | CPU : 4vCPUs, RAM : 16GB, OS : Ubuntu |
AWS S3 | S3 Standard |
프로그램 | 버전 |
---|---|
Ubuntu | Ubuntu 20.04.6 LTS |
Docker | 23.0.4 |
Jenkins | 2.440.1 |
MySQL | MySQL Community 8.3.0 |
Redis | Redis 7.2.4 |
Nginx | nginx/1.25.4 |
NEXT_PUBLIC_MODE='local'
NEXT_PUBLIC_URL='https://letter-for.me'
NEXT_PUBLIC_API_URL='https://letter-for.me/api/v1'
- spring boot : application.yml (/src/main/resources에 위치)
server:
port: 8081
spring:
security:
oauth2:
client:
registration: # 카카오 API 사용하기 위한 인증 정보
kakao:
client-id: ${KAKAO_LOGIN_RESTAPI_KEY}
client-secret: ${KAKAO_LOGIN_CLIENT_SECRET}
redirect-uri: ${KAKAO_LOGIN_REDIRECT_URI}
scope: # 카카오 API에서 받아올 정보
- profile_nickname
- profile_image
- account_email
authorization-grant-type: authorization_code
client-authentication-method: client_secret_post
provider:
kakao:
authorization-uri: https://kauth.kakao.com/oauth/authorize
token-uri: https://kauth.kakao.com/oauth/token
user-info-uri: https://kapi.kakao.com/v2/user/me
user-name-attribute: id
provider:
response-uri:
kakao: ${KAKAO_TOKEN_RESPONSE_URI}
datasource: # MySQL 컨테이너 연결 정보
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${MYSQL_URL}
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
jpa:
properties:
hibernate:
jdbc:
time_zone: Asia/Seoul # 시간대 설정
dialect=org:
hibernate:
dialect:
MySQL5Dialect:
transaction:
jta:
platform=org:
hibernate:
service:
jta:
platform:
internal:
JBossStandAloneJtaPlatform:
hibernate:
ddl-auto: none
show-sql: true
data: # Redis 컨테이너 연결 정보
redis:
host: ${REDIS_HOSTNAME}
port: ${REDIS_PORT}
jwt: # JWT 암호화 Key
secret-key: ${JWT_SECRET_KEY}
KAKAO_LOGIN_RESTAPI_KEY=''
KAKAO_LOGIN_CLIENT_SECRET=''
MYSQL_USERNAME='root'
MYSQL_PASSWORD='dltmdgjs'
MYSQL_URL='jdbc:mysql://mysql-container:3306/letterforme'
MYSQL_HOST ='j10a108.p.ssafy.io'
MYSQL_DATABASE ='letterforme'
JWT_SECRET_KEY=''
KAKAO_LOGIN_REDIRECT_URI='{baseUrl}/oauth2/callback/{registrationId}'
KAKAO_TOKEN_RESPONSE_URI='https://localhost:3001/auth/oauth-response'
KAKAO_LOCAL_TOKEN_RESPONSE_URI='https://localhost:3001/auth/oauth-response'
KAKAO_LOCAL_TOKEN=''
COOKIE_DOMAIN='localhost'
OPENAI_MODEL= 'ft:gpt-3.5-turbo-0125:personal::99mAOVqt'
OPENAI_SECRET_KEY=''
REDIS_HOSTNAME='redis-container'
REDIS_PORT='6379'
BACK-END
- spring boot application : 내부 port 8081(port 노출 없이 upstream 연결)
FRONT-END
- next.js : 내부 port 3000(port 노출 없이 upstream 연결)
DATA
- mysql : 3306:3306
- redis : 6379:6379
- fastapi : 8000:8000
DEPLOY
- Nginx : 80:443
- jenkins : 9090:8080
- 서버 세팅
# 서버시간 변경
$ sudo timedatectl set-timezone Asia/Seoul
# 변경한 서버 시간 올바른지 확인o
$ date
Sat Jan 27 18:10:22 KST 2024
# 미러 서버 변경
$ sudo vim /etc/apt/sources.list
# 위에서 열어준 파일의 ~.ubuntu.com(서버경로)를 모두 변경
sudo sed -i 's/ap-northeast-2.ec2.archive.ubuntu.com/mirror.kakao.com/g' /etc/apt/sources.list
# 패키지 업그레이드 및 업데이트
$ sudo apt update
$ sudo apt upgrade
# 가상 메모리 할당
# 현재 메모리 용량 확인(할당전 - swap 영억이 모두 0)
$ free -h
# swap 메모리 할당
$ sudo fallocate -l 8G /swapfile
# 스왑 파일에 대한 읽기 및 쓰기 권한 업데이트
$ sudo chmod 600 /swapfile
# Linux 스왑 영역 설정
$ sudo mkswap /swapfile
# 스왑 공간에 스왑 파일을 추가하여 스왑 파일을 즉시 사용할 수 있도록 만듦
$ sudo swapon /swapfile
# 절차 성공 여부 확인
$ sudo swapon -s
# /etc/fstab 파일을 편집하여 부팅시 스왑 파일을 활성화
$ sudo vi /etc/fstab
# 편집기로 연 파일에 아래 한줄 추가
/swapfile swap swap defaults 0 0
# 할당 후 메모리 확인
$ free -h
- Docker 설치
# Docker Repository 등록 및 docker-ce 패키지 설치
$ sudo apt-get update
$ sudo apt-get install ca-certificates curl
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# docker 버전 확인
$ docker --version
# docker-engine 설치 확인
$ sudo docker run hello-world
# sudo 없이 docker 명령어 사용하기(선택 사항)
# 현재 사용자(ubuntu)를 docker group 에 포함
$ adduser ubuntu
$ sudo usermod -aG docker ubuntu
# 터미널 재실행 후 확인(끝에 docker 가 있는지 확인)
$ id -nG
ubuntu adm dialout cdrom floppy sudo audio dip video plugdev netdev lxd docker
# 네트워크 생성 - 모든 컨테이너의 port를 노출시키지 않으려면 docker 내에서 생성한 네트워크로 컨테이너 간 연결 및 통신해야 한다.
$ docker network create tarot-network
- DB 컨테이너 생성
- MySQL 컨테이너
$ docker run --name mysql-container -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=dltmdgjs -e MYSQL_DATABASE=mydb -d mysql
- Redis 컨테이너
$ docker run --name redis-container -v /home/ubuntu/redis-storage:/data --memory=512m --memory-swap=1g -d --network tarot-network redis
- Jenkins 설정
- jenkins 컨테이너 생성
# jenkins 이미지 받기
$ docker pull jenkins/jenkins:lts
# 확인
$ docker images
# --env JENKINS_OPTS="--prefix=/jenkins" (리버스 프록시 설정한 도메인 뒤에 주소 설정 ex. letter-for.me/jenkins)
# -v /var/run/docker.sock:/var/run/docker.sock (Docker out of docker 설정 - jenkins 컨테이너 내부에서 서버 local의 도커 소켓을 마운트하여 컨테이너 내부에서 서버 로컬 도커를 사용)
$ docker run --name jenkins-container -d -p 9090:8080 -p 50000:50000 --env JENKINS_OPTS="--prefix=/jenkins" -v /home/ubuntu/jenkins:/var/jenkins_home -v /home/ubuntu/.ssh:/root/.ssh -v /var/run/docker.sock:/var/run/docker.sock -u root --network tarot-network jenkins/jenkins:lts
- jenkins 세팅
- jenkins 컨테이너 실행 로그 내 초기 비밀번호
$ docker logs jenkins-container
# Please use the following password to proceed to installation:
# 문장 하단에 초기 비밀번호
-
인터넷에 j10a108.p.ssafy.io:9090/ 접속 → 초기 비밀번호 입력
-
jenkins 초기 설정
- 좌측 버튼(추천 플러그인 설치)과 우측 버튼(선택해서 설치) 중 좌측 버튼(계정명 / 암호 / 이름 / 이메일 입력)
- 추가 플러그인 설치
- GitLab, Generic Webhook Trigger, Post build task, Docker, Docker Commons, Docker Pipeline, Docker API, SSH Agent
- jenkins 컨테이너 내 docker 설치
- 컨테이너를 생성할 때 도커 소켓을 마운트했기 때문에 내부에서 생성된 컨테이너가 서버 로컬에서 생성 및 실행됨
$ docker exec -it jenkins-container bash
# apt-get update
# apt-get install vim
# apt-get install wget
# apt install apt-transport-https ca-certificates curl software-properties-common
# wget -qO- https://get.docker.com/ | sh
# apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
- gitlab과 jenkins 연결
-
gitlab 내 access token 생성
-
jenkins credentials 생성
- credentials > global > add credentials
- credentials 설정
- Kind: GitLab API token
- Scope: Global
- API token: ${위 gitlab에서 생성한 access token}
- ID: gitlabAccessToken
-
연결
- jenkins > system 설정
- Connection name : gitlab
- GitLab host URL : https://lab.ssafy.com/
- Credentials : gitlabAccessToken
- pipeline 생성
-
개발용 FE, 개발용 BE, 배포용(BE + FE) 파이프라인
-
create a job - letterforme - pipeline
-
build triggers의 build when a change ✅
-
시크릿키 받기 → f015e0153ed6c54f465d01a733cb3903
-
create a job - letterforme-frontdev- pipeline
-
build triggers의 build when a change ✅
-
시크릿키 받기 → e4debdbcddb6fea3bc9af53bab06df76
-
create a job - letterforme-backdev - pipeline
-
build triggers의 build when a change ✅
-
시크릿키 받기 → 471fb18e4b58c270c320c26d5d171602
- gitlab webhooks 설정
하단 url은 jenkins pipeline 설정에 있음.
-
url : https://letter-for.me/jenkins/project/letterforme
- pipeline 시크릿키 입력
- push event ✅
- Regular expression - release
-
url : https://letter-for.me/jenkins/project/letterforme-frontdev
- pipeline 시크릿키 입력
- push event ✅
- Regular expression - dev-front
-
url : https://letter-for.me/jenkins/project/letterforme-backdev
- pipeline 시크릿키 입력
- push event ✅
- Regular expression - develop
-
test의 push test
- 자동 배포
-
backend
- develop branch에 push 시 실행
- Dockerfile(devbackDockerfile 경로 최상단에 위치)
# 첫 번째 스테이지: Gradle을 사용하여 Java 애플리케이션을 빌드 FROM gradle:8.7-jdk17-alpine AS BUILD WORKDIR /home/gradle/src/ COPY --chown=gradle:gradle ./back-end . # gradlew 스크립트에 실행 권한 부여 RUN chmod +x ./gradlew # Gradle Wrapper를 사용하여 프로젝트를 clean 후 build, 데몬 사용하지 않는 옵션 RUN ./gradlew clean build --no-daemon # 두 번째 스테이지: 빌드된 JAR 파일을 실행하기 위한 새로운 이미지 FROM eclipse-temurin:17-jdk-alpine # 첫 번째 스테이지(BUILD)에서 빌드된 JAR 파일을 현재 스테이지의 /app.jar로 복사 COPY --from=BUILD /home/gradle/src//build/libs/*.jar /app.jar # 컨테이너 시작 시, 자바 애플리케이션 실행을 위한 ENTRYPOINT 지정 및 /app.jar 실행 ENTRYPOINT ["java","-jar","/app.jar"]
- letterforme-backdev pipeline
pipeline{ agent any environment { KAKAO_LOGIN_RESTAPI_KEY='' KAKAO_LOGIN_CLIENT_SECRET='' MYSQL_USERNAME='root' MYSQL_PASSWORD='dltmdgjs' MYSQL_URL='jdbc:mysql://mysql-container:3306/letterforme' MYSQL_HOST ='j10a108.p.ssafy.io' MYSQL_DATABASE ='letterforme' JWT_SECRET_KEY='' KAKAO_LOGIN_REDIRECT_URI='{baseUrl}/oauth2/callback/{registrationId}' KAKAO_TOKEN_RESPONSE_URI='https://localhost:3001/auth/oauth-response' KAKAO_LOCAL_TOKEN_RESPONSE_URI='https://localhost:3001/auth/oauth-response' KAKAO_LOCAL_TOKEN='' COOKIE_DOMAIN='localhost' OPENAI_MODEL= 'ft:gpt-3.5-turbo-0125:personal::99mAOVqt' OPENAI_SECRET_KEY='' REDIS_HOSTNAME='redis-container' REDIS_PORT='6379' } stages{ stage('Cleaning up'){ agent any steps{ sh 'docker stop devback-container || true' sh 'docker stop fastapi || true' sh 'docker rm devback-container || true' sh 'docker rm fastapi || true' sh 'docker rmi devback-image || true' sh 'docker rmi fastapi || true' sh 'rm -rf /var/jenkins_home/workspace/letterforme-backdev || true' } post{ failure{ error 'Fail Cleaning up' } } } stage('git clone'){ steps { git branch: 'develop', credentialsId: 'gitlab_name', url: 'https://lab.ssafy.com/s10-bigdata-recom-sub2/S10P22A108.git' } } stage('Build recsys : Fast API'){ steps{ dir('recsys/') { sh ''' docker build -t fastapi . docker run -p 8000:8000 -d --name fastapi -e MYSQL_USERNAME=${MYSQL_USERNAME} -e MYSQL_PASSWORD=${MYSQL_PASSWORD} -e MYSQL_HOST=${MYSQL_HOST} -e MYSQL_DATABASE=${MYSQL_DATABASE} fastapi ''' } } post{ failure{ error 'Fail Docker Run' } } } stage('Build back-end : Spring boot'){ steps{ sh''' docker build -f devbackDockerfile -t devback-image . docker run -d -e TZ=Asia/Seoul --name devback-container -e KAKAO_LOGIN_RESTAPI_KEY=${KAKAO_LOGIN_RESTAPI_KEY} -e KAKAO_LOGIN_CLIENT_SECRET=${KAKAO_LOGIN_CLIENT_SECRET} -e MYSQL_USERNAME=${MYSQL_USERNAME} -e MYSQL_PASSWORD=${MYSQL_PASSWORD} -e JWT_SECRET_KEY=${JWT_SECRET_KEY} -e MYSQL_URL=${MYSQL_URL} -e KAKAO_LOGIN_REDIRECT_URI=${KAKAO_LOGIN_REDIRECT_URI} -e KAKAO_TOKEN_RESPONSE_URI=${KAKAO_TOKEN_RESPONSE_URI} -e KAKAO_LOCAL_TOKEN_RESPONSE_URI=${KAKAO_LOCAL_TOKEN_RESPONSE_URI} -e KAKAO_LOCAL_TOKEN=${KAKAO_LOCAL_TOKEN} -e REDIS_HOSTNAME=${REDIS_HOSTNAME} -e REDIS_PORT=${REDIS_PORT} -e OPENAI_SECRET_KEY=${OPENAI_SECRET_KEY} -e COOKIE_DOMAIN=${COOKIE_DOMAIN} -e OPENAI_MODEL=${OPENAI_MODEL} --network tarot-network devback-image ''' } post{ failure{ error 'Fail Docker Run' } } } } post { always { dir("/var/jenkins_home/workspace/letterforme-backdev@tmp") { deleteDir() } dir("/var/jenkins_home/workspace/letterforme-backdev@2") { deleteDir() } dir("/var/jenkins_home/workspace/letterforme-backdev@2@tmp") { deleteDir() } } } }
-
frontend
- dev-front branch에 push 시 실행
- Dockerfile(devfrontDockerfile 경로 최상단에 위치)
FROM node:latest WORKDIR /app COPY ./front-end/package*.json ./ RUN npm install COPY ./front-end . RUN npm run build CMD ["npm", "start"]
- letterforme-frontdev pipeline
pipeline{ agent any environment { NEXT_PUBLIC_MODE='local' NEXT_URL='https://dev.letter-for.me' NEXT_API_URL='https://dev.letter-for.me/api/v1' } stages{ stage('Cleaning up'){ agent any steps{ sh 'docker stop devfront-container || true' sh 'docker rm devfront-container || true' sh 'docker rmi devfront-image || true' sh 'rm -rf /var/jenkins_home/workspace/letterforme-frontdev || true' } post{ failure{ error 'Fail Cleaning up' } } } stage('git clone & build'){ steps { git branch: 'dev-front', credentialsId: 'gitlab_name', url: 'https://lab.ssafy.com/s10-bigdata-recom-sub2/S10P22A108.git' sh 'docker build -f devfrontDockerfile -t devfront-image .' } post{ failure{ error 'Fail Docker Build' } } } stage('Docker Run'){ agent any steps{ sh 'docker run -d --name devfront-container -e NEXT_PUBLIC_MODE=${NEXT_PUBLIC_MODE} -e NEXT_URL=${NEXT_URL} -e NEXT_API_URL=${NEXT_API_URL} --network tarot-network devfront-image' } post{ failure{ error 'Fail Docker Run' } } } } post { always { dir("/var/jenkins_home/workspace/letterforme-frontdev@tmp") { deleteDir() } dir("/var/jenkins_home/workspace/letterforme-frontdev@2") { deleteDir() } dir("/var/jenkins_home/workspace/letterforme-frontdev@2@tmp") { deleteDir() } } } }
-
docker-compose.yaml에서 사용할 환경변수 .env
- sudo vi /home/ubuntu/jenkins/env/.env
KAKAO_LOGIN_RESTAPI_KEY='' KAKAO_LOGIN_CLIENT_SECRET='' MYSQL_USERNAME='root' MYSQL_PASSWORD='dltmdgjs' MYSQL_URL='jdbc:mysql://mysql-container:3306/letterforme' MYSQL_HOST ='j10a108.p.ssafy.io' MYSQL_DATABASE ='letterforme' JWT_SECRET_KEY='' KAKAO_LOGIN_REDIRECT_URI='{baseUrl}/oauth2/callback/{registrationId}' KAKAO_TOKEN_RESPONSE_URI='https://localhost:3001/auth/oauth-response' KAKAO_LOCAL_TOKEN_RESPONSE_URI='https://localhost:3001/auth/oauth-response' KAKAO_LOCAL_TOKEN='' COOKIE_DOMAIN='localhost' OPENAI_MODEL= 'ft:gpt-3.5-turbo-0125:personal::99mAOVqt' OPENAI_SECRET_KEY='' REDIS_HOSTNAME='redis-container' REDIS_PORT='6379' NEXT_PUBLIC_MODE='local' NEXT_PUBLIC_URL='https://letter-for.me' NEXT_PUBLIC_API_URL='https://letter-for.me/api/v1'
-
release
- release branch에 push 시 실행
- Docker-compose.yaml(경로 최상단에 위치)
services: backend: build: context: . dockerfile: devbackDockerfile environment: - KAKAO_LOGIN_RESTAPI_KEY - KAKAO_LOGIN_CLIENT_SECRET - MYSQL_USERNAME - MYSQL_PASSWORD - MYSQL_URL - MYSQL_HOST - MYSQL_DATABASE - JWT_SECRET_KEY - KAKAO_LOGIN_REDIRECT_URI - KAKAO_TOKEN_RESPONSE_URI - KAKAO_LOCAL_TOKEN_RESPONSE_URI - KAKAO_LOCAL_TOKEN - COOKIE_DOMAIN - REDIS_HOSTNAME - REDIS_PORT - OPENAI_MODEL - OPENAI_SECRET_KEY - TZ=Asia/Seoul networks: - tarot-network frontend: build: context: . dockerfile: devfrontDockerfile environment: - NEXT_PUBLIC_MODE - NEXT_PUBLIC_URL - NEXT_PUBLIC_API_URL - TZ=Asia/Seoul networks: - tarot-network networks: tarot-network: driver: bridge external: true
- letterforme pipeline
pipeline{ agent any stages{ stage('Cleaning up'){ agent any steps{ sh 'docker stop letterforme-backend-1 || true' sh 'docker stop letterforme-frontend-1 || true' sh 'docker rm letterforme-backend-1 || true' sh 'docker rm letterforme-frontend-1 || true' sh 'docker rmi letterforme-backend || true' sh 'docker rmi letterforme-frontend || true' sh 'rm -rf /var/jenkins_home/workspace/letterforme|| true' } post{ failure{ error 'Fail Cleaning up' } } } stage('git clone'){ steps { git branch: 'release', credentialsId: 'gitlab_name', url: 'https://lab.ssafy.com/s10-bigdata-recom-sub2/S10P22A108.git' } post{ failure{ error 'Fail git clone' } } } stage('docker-compose up'){ steps { sh 'cp /var/jenkins_home/env/.env .' sh 'docker compose up -d --build' sh 'docker restart nginxc' } post{ failure{ error 'Fail compose up' } } } } post { always { dir("/var/jenkins_home/workspace/letterforme@tmp") { deleteDir() } dir("/var/jenkins_home/workspace/letterforme@2") { deleteDir() } dir("/var/jenkins_home/workspace/letterforme@2@tmp") { deleteDir() } } } }
- Nginx 설정
가비아에서 letter-for.me 도메인을 구매해 사용
-
가비아 설정
- public ip 확인 ->
$ curl ip.ojj.kr
-> 43.202.56.72 - letter-for.me / dev.letter-for.me 설정
letter-for.me -> 배포용 | dev.letter-for.me -> 개발용
- 타입 : A | 호스트 : @ | 값/위치 : 43.202.56.72 | TTL : 3306
- 타입 : A | 호스트 : dev | 값/위치 : 43.202.56.72 | TTL : 3306
- public ip 확인 ->
-
Nginx 컨테이너 생성
# Nginx 이미지 가져오기
$ docker pull nginx
# Nginx 컨테이너 생성
# Nginx 내 default.conf 파일은 수시로 수정해야하므로 반드시 volume 설정
# network 옵션을 통해 기존 jenkins-container 와 연결
$ docker run -d -p 80:80 -p 443:443 -v /home/ubuntu/nginx/default.conf:/etc/nginx/conf.d/default.conf -v /home/ubuntu/nginx/etc/letsencrypt:/etc/letsencrypt --name nginxc --network tarot-network nginx
- SSL 설정
# 컨테이너 접속
$ docker exec -it nginx bash
# apt-get update
# apt-get install certbot python3-certbot-nginx
# apt-get install vim
# certbot --nginx -d letter-for.me -d dev.letter-for.me
- default.conf 파일 설정
- volume 설정 경로의 default.conf 편집
- upstream 설정을 사용하기 위해 dev-front, develop, release 브랜치에 push를 하거나 따로 컨테이너 생성
- 혹은 upstream 설정과 관련 부분 주석 처리
$ sudo vi /home/ubuntu/nginx/default.conf
- default.conf
upstream dev_front {
server devfront-container:3000;
}
upstream dev_back {
server devback-container:8081;
}
upstream frontend {
server letterforme-frontend-1:3000;
}
upstream backend {
server letterforme-backend-1:8081;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
if ($host = dev.letter-for.me) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = letter-for.me) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name letter-for.me dev.letter-for.me;
return 404;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name letter-for.me;
ssl_certificate /etc/letsencrypt/live/letter-for.me/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/letter-for.me/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location /jenkins/ {
proxy_pass http://letter-for.me:9090; # letter-for.me/jenkins 로 jenkins 접속 가능
proxy_redirect default;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_max_temp_file_size 0;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_request_buffering off;
}
location /oauth2/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api/v1 {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://frontend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name dev.letter-for.me;
ssl_certificate /etc/letsencrypt/live/letter-for.me/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/letter-for.me/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location /oauth2/ {
proxy_pass http://dev_back;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api/v1 {
proxy_pass http://dev_back;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://dev_front;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}