본 시리즈는 작성자의 이해와 경험을 바탕으로 실습 위주의 설명을 기반으로 작성되었습니다.
실습 위주의 이해를 목표로 하기 때문에 다소 과장이 많고 생략된 부분이 많을 수 있습니다.
따라서, 이론적으로 미흡한 부분이 있을 수 있는 점에 대해 유의하시기 바랍니다.
또한, 본 시리즈는 ChatGPT의 도움을 받아 작성되었습니다.
수 차례의 질문을 통해 도출된 여러가지 다양한 방식의 코드를 종합하여
작성자의 이해와 경험을 바탕으로 가장 정석으로 생각되는 코드를 재정립하였습니다.
NodeJS
, GitLab
플러그인 설치/frontend
에 Dockerfile
작성# Node.js 공식 이미지 사용. 버전 20.11.1, 경량화된 Alpine Linux 기반
FROM node:20.11.1-alpine
# 작업 디렉토리 설정. 컨테이너 내 앱의 기본 경로
WORKDIR /home/app
# 현재 디렉토리의 package.json과 package-lock.json 파일이 존재한다면
# 컨테이너의 작업 디렉토리로 package.json과 package-lock.json 복사
COPY package*.json ./
# package.json에 명시된 애플리케이션 의존성 설치
# package-lock.json이 있을 경우 더 빠르게 설치 가능
RUN npm install
# 현재 디렉토리의 모든 파일을 컨테이너의 작업 디렉토리로 복사
COPY . .
# React 애플리케이션 빌드
RUN npm run build
/backend
에 Dockerfile
작성# OpenJDK 17을 포함하는 경량화된 Alpine Linux 베이스 이미지 사용
FROM openjdk:17-jdk-alpine
# 컨테이너 내부의 작업 디렉토리를 /home/app로 설정
WORKDIR /home/app
# 호스트 시스템의 SpringBoot 애플리케이션 JAR 파일을 컨테이너 내부 작업 디렉토리로 복사
COPY build/libs/*.jar app.jar
# 컨테이너가 시작될 때 실행될 명령어 정의, 작업 디렉토리 /home/app/app.jar 파일 실행
ENTRYPOINT ["java","-jar","./app.jar"]
# 컨테이너의 8080 포트를 외부로 노출
EXPOSE 8080
초록색 박스로 표시된
GitLab webhook URL
을 잘 기록해둔다.
초록색 박스로 표시된 고급 탭에서Generate
한Secret token
을 잘 기록해둔다.
git branch: 'master', credentialsId: 'YOUR_CREDENTIAL', url: 'https://<Your Git Repository URL>'
pipeline {
agent any
tools {
nodejs 'nodejs-20.11.1'
}
// 필요한 변수 설정
environment {
PROJECT_DIR = 'your_project_directory_name'
DOCKER_REGISTRY = 'your_docker_registry_url'
BACKEND_IMAGE_NAME = 'server/backend'
FRONTEND_IMAGE_NAME = 'server/frontend'
BACKEND_CONTAINER_NAME = 'server-backend'
FRONTEND_CONTAINER_NAME = 'server-frontend'
}
stages {
stage('Checkout') {
steps {
echo 'Starting Repository Checkout'
git url: 'https://<Your Git Repository URL>',
credentialsId: 'YOUR_CREDENTIAL', branch: 'master'
echo 'Repository Checkout Completed'
}
}
stage('Build Frontend') {
steps {
echo 'Starting Frontend Build Process'
dir('frontend') {
sh 'docker ps -aqf "name=${FRONTEND_CONTAINER_NAME}" && docker stop ${FRONTEND_CONTAINER_NAME} && docker rm ${FRONTEND_CONTAINER_NAME}'
sh 'docker images -q ${FRONTEND_IMAGE_NAME} && docker rmi ${FRONTEND_IMAGE_NAME}'
sh 'docker build -t ${FRONTEND_IMAGE_NAME} .'
}
echo 'Frontend Build Completed Successfully'
}
post {
success {
script {
echo 'Build Frontend Success'
}
}
failure {
script {
echo 'Build Frontend Failed'
}
}
}
}
stage('Test Frontend') {
steps {
echo 'Starting Frontend Tests'
dir('frontend') {
sh 'npm test'
}
echo 'Frontend Tests Completed'
}
post {
success {
script {
echo 'Test Frontend Success'
}
}
failure {
script {
echo 'Test Frontend Failed'
}
}
}
}
stage('Deploy Frontend') {
steps {
echo 'Deploying Frontend'
sh "docker run -d -p 3000:3000 --name ${FRONTEND_CONTAINER_NAME} ${FRONTEND_IMAGE_NAME}"
echo 'Frontend Deployed Successfully'
}
post {
success {
script {
echo 'Deploy Frontend Success'
}
}
failure {
script {
echo 'Deploy Frontend Failed'
}
}
}
}
stage('Build Backend') {
steps {
echo 'Starting Backend Build Process'
dir('backend') {
sh 'chmod +x ./gradlew'
sh './gradlew clean build'
sh 'docker ps -aqf "name=${BACKEND_CONTAINER_NAME}" && docker stop ${BACKEND_CONTAINER_NAME} && docker rm ${BACKEND_CONTAINER_NAME}'
sh 'docker images -q ${BACKEND_IMAGE_NAME} && docker rmi ${BACKEND_IMAGE_NAME}'
sh 'docker build -t ${BACKEND_IMAGE_NAME} .'
}
echo 'Backend Build Completed Successfully'
}
post {
success {
script {
echo 'Build Backend Success'
}
}
failure {
script {
echo 'Build Backend Failed'
}
}
}
}
stage('Test Backend') {
steps {
echo 'Starting Backend Tests'
dir('backend') {
sh './gradlew test'
}
echo 'Backend Tests Completed'
}
post {
success {
script {
echo 'Test Backend Success'
}
}
failure {
script {
echo 'Test Backend Failed'
}
}
}
}
stage('Deploy Backend') {
steps {
echo 'Deploying Backend'
sh "docker run -d -p 8080:8080 --name ${BACKEND_CONTAINER_NAME} ${BACKEND_IMAGE_NAME}"
echo 'Backend Deployed Successfully'
}
post {
success {
script {
echo 'Deploy Backend Success'
}
}
failure {
script {
echo 'Deploy Backend Failed'
}
}
}
}
}
post {
always {
echo 'Pipeline Execution Complete.'
}
success {
echo 'Pipeline Execution Success.'
script {
echo '빌드/배포 Success'
}
}
failure {
echo 'Pipeline Execution Failed.'
script {
echo '빌드/배포 Failed'
}
}
}
}
URL
: 위에서 기록해둔GitLab webhook URL
Secret token
: 위에서 기록해둔Secret token
Endpoint
: Incoming Webhook URLChannel
: Incoming Webhook을 추가할 때 선택했던 채널 이름 (초록색 박스 안의 주소)Build Server URL
: Jenkins URL (자동으로 입력되어 있을 것이다.)
// 공통 함수 정의
def sendMattermostNotification(String stage, String status) {
script {
def AUTHOR_ID = sh(script: "git show -s --pretty=%an", returnStdout: true).trim()
def AUTHOR_NAME = sh(script: "git show -s --pretty=%ae", returnStdout: true).trim()
def color = (status == 'Success') ? 'good' : 'danger'
def message = "${stage} ${status}: ${env.JOB_NAME} #${env.BUILD_NUMBER} by ${AUTHOR_ID}(${AUTHOR_NAME})\n(<${env.BUILD_URL}|Details>)"
def endpoint = 'https://your_notification_service_endpoint'
def channel = 'your_notification_service_channel'
mattermostSend (
color: color,
message: message,
endpoint: endpoint,
channel: channel,
)
}
}
pipeline {
agent any
...
}
// 공통 함수 정의
def sendMattermostNotification(String stage, String status) {
script {
def AUTHOR_ID = sh(script: "git show -s --pretty=%an", returnStdout: true).trim()
def AUTHOR_NAME = sh(script: "git show -s --pretty=%ae", returnStdout: true).trim()
def color = (status == 'Success') ? 'good' : 'danger'
def message = "${stage} ${status}: ${env.JOB_NAME} #${env.BUILD_NUMBER} by ${AUTHOR_ID}(${AUTHOR_NAME})\n(<${env.BUILD_URL}|Details>)"
def endpoint = 'https://your_notification_service_endpoint'
def channel = 'your_notification_service_channel'
mattermostSend (
color: color,
message: message,
endpoint: endpoint,
channel: channel,
)
}
}
pipeline {
agent any
tools {
nodejs 'nodejs-20.11.1'
}
// 필요한 변수 설정
environment {
PROJECT_DIR = 'your_project_directory_name'
DOCKER_REGISTRY = 'your_docker_registry_url'
BACKEND_IMAGE_NAME = 'server/backend'
FRONTEND_IMAGE_NAME = 'server/frontend'
BACKEND_CONTAINER_NAME = 'server-backend'
FRONTEND_CONTAINER_NAME = 'server-frontend'
}
stages {
stage('Checkout') {
steps {
echo 'Starting Repository Checkout'
git url: 'https://<Your Git Repository URL>',
credentialsId: 'YOUR_CREDENTIAL', branch: 'master'
echo 'Repository Checkout Completed'
}
}
stage('Build Frontend') {
steps {
echo 'Starting Frontend Build Process'
dir('frontend') {
sh 'docker ps -aqf "name=${FRONTEND_CONTAINER_NAME}" && docker stop ${FRONTEND_CONTAINER_NAME} && docker rm ${FRONTEND_CONTAINER_NAME}'
sh 'docker images -q ${FRONTEND_IMAGE_NAME} && docker rmi ${FRONTEND_IMAGE_NAME}'
sh 'docker build -t ${FRONTEND_IMAGE_NAME} .'
}
echo 'Frontend Build Completed Successfully'
}
post {
success {
script {
sendMattermostNotification('Build Frontend', 'Success')
}
}
failure {
script {
sendMattermostNotification('Build Frontend', 'Failed')
}
}
}
}
stage('Test Frontend') {
steps {
echo 'Starting Frontend Tests'
dir('frontend') {
sh 'npm test'
}
echo 'Frontend Tests Completed'
}
post {
success {
script {
sendMattermostNotification('Test Frontend', 'Success')
}
}
failure {
script {
sendMattermostNotification('Test Frontend', 'Failed')
}
}
}
}
stage('Deploy Frontend') {
steps {
echo 'Deploying Frontend'
sh "docker run -d -p 3000:3000 --name ${FRONTEND_CONTAINER_NAME} ${FRONTEND_IMAGE_NAME}"
echo 'Frontend Deployed Successfully'
}
post {
success {
script {
sendMattermostNotification('Deploy Frontend', 'Success')
}
}
failure {
script {
sendMattermostNotification('Deploy Frontend', 'Failed')
}
}
}
}
stage('Build Backend') {
steps {
echo 'Starting Backend Build Process'
dir('backend') {
sh 'chmod +x ./gradlew'
sh './gradlew clean build'
sh 'docker ps -aqf "name=${BACKEND_CONTAINER_NAME}" && docker stop ${BACKEND_CONTAINER_NAME} && docker rm ${BACKEND_CONTAINER_NAME}'
sh 'docker images -q ${BACKEND_IMAGE_NAME} && docker rmi ${BACKEND_IMAGE_NAME}'
sh 'docker build -t ${BACKEND_IMAGE_NAME} .'
}
echo 'Backend Build Completed Successfully'
}
post {
success {
script {
sendMattermostNotification('Build Backend', 'Success')
}
}
failure {
script {
sendMattermostNotification('Build Backend', 'Failed')
}
}
}
}
stage('Test Backend') {
steps {
echo 'Starting Backend Tests'
dir('backend') {
sh './gradlew test'
}
echo 'Backend Tests Completed'
}
post {
success {
script {
sendMattermostNotification('Test Backend', 'Success')
}
}
failure {
script {
sendMattermostNotification('Test Backend', 'Failed')
}
}
}
}
stage('Deploy Backend') {
steps {
echo 'Deploying Backend'
sh "docker run -d -p 8080:8080 --name ${BACKEND_CONTAINER_NAME} ${BACKEND_IMAGE_NAME}"
echo 'Backend Deployed Successfully'
}
post {
success {
script {
sendMattermostNotification('Deploy Backend', 'Success')
}
}
failure {
script {
sendMattermostNotification('Deploy Backend', 'Failed')
}
}
}
}
}
post {
always {
echo 'Pipeline Execution Complete.'
}
success {
echo 'Pipeline Execution Success.'
script {
sendMattermostNotification('빌드/배포', 'Success')
}
}
failure {
echo 'Pipeline Execution Failed.'
script {
sendMattermostNotification('빌드/배포', 'Failed')
}
}
}
}