이전 과정에서 jenkins안에서 호스트의 docker 데몬의 접근할 수 있도록 하여 빌드가 정상적으로 진행되는 것까지 확인했다.
이번 과정에서는 이미지로 빌드하고 docker run을 통해 컨테이너화 시켜서 정상적으로 마이크로 서비스를 운영해보자
pipeline {
agent any
stages {
stage('Repository clone') {
steps {
sh 'pwd'
git branch: 'notification', credentialsId: 'qkrtprjs', url: 'https://lab.ssafy.com/s11-fintech-finance-sub1/S11P21A604.git'
}
post {
failure {
echo 'Repository clone failure !'
}
success {
echo 'Repository clone success !'
}
}
}
stage('Build image') {
steps {
dir('notification') {
sh 'chmod +x ./gradlew'
sh './gradlew build'
sh 'pwd'
//qkrtprjs은 Docker Repository 이름 , notification은 도커 컨테이너 이름을 의미
sh 'docker build -t qkrtprjs/notification .'
}
echo 'Build image...'
}
post {
failure {
echo 'Build image failure !'
}
success {
echo 'Build image success !'
}
}
}
stage('Remove Previous image') {
steps {
script {
try {
sh 'docker stop notification'
sh 'docker rm notification'
} catch (e) {
echo 'fail to stop and remove container'
}
}
}
post {
failure {
echo 'Remove Previous image failure !'
}
success {
echo 'Remove Previous image success !'
}
}
}
stage('Run New image') {
steps {
sh 'docker run --name notification -d -p 8083:8083 qkrtprjs/notification'
echo 'Run New member image'
}
post {
failure {
echo 'Run New image failure !'
}
success {
echo 'Run New image success !'
}
}
}
}
}
이미지가 jenkins 컨테이너에 정상적으로 만들어졌는지 확인하기 위해서 컨테이너에 접근
docker exec -it jenkins sh
정상적으로 접근
이미지를 빌드한 후에 정상적으로 이미지가 생성되었는지 확인
docker images
로 확인
정상적으로 notification 이미지 실행중 확인
해당 브랜치로 push 날렸을때 콘솔확인
정상적으로 이미지가 실행되었다는 문구 확인
현재 마이크로서비스가 컨테이너로 실행되고 있는지 확인
docker ps
jenkins이외에도 notification이라는 이름을 갖는 컨테이너가 실행중인 것을 확인
테스트를 위해 컨트롤러에 작성해놓은 url로 확인
정상적인 응답 확인
현재 MySQL 설정은 localhost의 3306포트로 설정되어있는데 프로젝트가 정상적으로 작동이 되었다 이 문제를 해결해보자.
아직 DB를 접근하지 않아서 발생한 오류인지 알아보자.
추가적으로 MySQL도 EC2에 띄어서 사용할 수 있도록 지정하자
역시나 로컬의 MySQL에 접근하지 않아서 에러가 발생하지 않았다. 해당 문제를 확인하기 위해서 Repository와 Entity를 생성해주고 연결하려는 시도를 진행했다.
NotificationApplicationTests > contextLoads() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1806
Caused by: jakarta.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:421
Caused by: org.hibernate.exception.JDBCConnectionException at SQLStateConversionDelegate.java:100
Caused by: com.mysql.cj.jdbc.exceptions.CommunicationsException at SQLError.java:174
Caused by: com.mysql.cj.exceptions.CJCommunicationsException at null:-1
Caused by: java.net.ConnectException at null:-2
위와 같이 MySQL에 접근할 수 없다는 에러가 발생했다.
마이크로서비스들이 따로 DB를 사용하는 것이 일반적이라고 학습했지만, 서버의 개수가 작고 크기고 작기때문에 여러개의 마이크로서비스들이 사용할 MySQL을 '하나' 열기로했다.
version: '3.8' # Docker Compose 파일 버전
services:
mysql:
# image: mysql:latest 최신 MySQL 이미지
# 프로젝트의 버전과 맞추기 위해 하단 버전으로 진행
image: mysql:8.0
container_name: mysql-container # 컨테이너 이름
environment:
MYSQL_ROOT_PASSWORD: ${root의 비밀번호} # root 비밀번호 설정
MYSQL_DATABASE: ${데이터베이스 이름} # 기본 데이터베이스 생성
ports:
- "3306:3306" # 호스트와 컨테이너 간 포트 매핑
volumes:
- /home/ubuntu/mysql-data:/var/lib/mysql # 데이터 영속성을 위한 볼륨
위처럼 작성한 mysql을 위한 docker-compose.yml 파일을 생성했지만 이전에 jenkins를 실행시킬때의 docker-compose.yml도 존재하기 때문에 네이밍으로 차별화두자
docker-compose -f mysql-docker-compose.yml up -d
정상적으로 jenkins, 마이크로서비스, MySQL 컨테이너가 실행중인것을 확인
MySQL 이미지를 :lates를 사용해서 빌드하게 되면 9버전의 MySQL을 다운하게 되는데 프로젝트에서 사용하는 버전은 8버전으로 8.0으로 이미지 빌드를 했지만 실행이 되지 않는 에러 발생
spring:
datasource:
url: jdbc:mysql://j11a604.p.ssafy.io:3306/trabean?useSSL=false&serverTimezone=UTC
DB설정 수정해주고 다시 한번 연결 확인
프로젝트에서 Repository 설정도 완료해주었지만 에러없이 정상적으로 서버가 구동되는 것을 확인
CREATE SCHEMA IF NOT EXISTS trabean;
USE trabean;
CREATE TABLE `users` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`user_key` VARCHAR(40) UNIQUE NOT NULL,
`email` VARCHAR(100) UNIQUE NOT NULL,
`password` VARCHAR(255) NOT NULL,
`name` VARCHAR(10) NOT NULL,
`payment_account_id` bigint NULL,
`main_account_id` bigint UNIQUE NULL,
PRIMARY KEY (`user_id`)
);
...
MySQL에서 제공하는 Enum 자료형을 사용해서 데이터를 저장하려고했지만 enum 사용관련해서 좋지 않다는 피드백을 확인
일단은 Varchar 자료형을 사용해서 문자열로 받고 백엔드단에서 유효성을 점검하는 방식으로 진행
하지만, 저장된 데이터를 조회하는 과정에서 Enum부분에서 에러 발생, 데이터베이스에서 받아온 값과 enum을 연결해주지 못해서 발생한 에러
private NotificationType type;
Entity 필드를 위처럼 정의하였는데 받아온 값과 Enum을 연결해주기 위해서 JPA에서 제공해주는 어노테이션이 존재
시도 1) @Enumerated(EnumType.STRING) 어노테이션 적용
Hibernate에서는 enum을 데이터베이스에 저장하기 위해 @Enumerated 어노테이션을 사용할 수 있습니다. 이때 EnumType.STRING이나 EnumType.ORDINAL을 선택할 수 있습니다. ORDINAL은 정수형으로 저장하고, STRING은 문자열로 저장합니다.
본인은 문자열로 데이터를 관리하고자 하여 STRING으로 진행
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long notificationId;
private Long senderId;
private Long receiverId;
private Long accountId;
@Enumerated(EnumType.STRING)
private NotificationType type;
private boolean isRead;
private Long amount;
private Timestamp createTime;
각각의 마이크로서비스들의 CI/CD 결과를 Mattermost를 통해서 알려줄 수 있도록 연동해보자
이 채널로 고정 클릭
이때 중요한점은 제목과 채널명은 영어로 생성하길 바란다. /기호와 한글을 사용해서 진행했을때는 실패했다는 알림을 받았다.
여기서 웹훅 URL을 저장해놓는다
두 플랫폼을 웹훅을 통해 연결을 설정했다면 Pipeline을 통해서 알림을 보낼 수 있는 script를 작성한다.
stage('Build image') {
steps {
dir('notification') {
sh 'chmod +x ./gradlew'
sh './gradlew build'
sh 'pwd'
sh 'docker build -t qkrtprjs/notification .'
}
echo 'Build image...'
}
post {
failure {
echo 'Build image failure !'
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()
mattermostSend (color: 'danger',
message: "도커 이미지 빌드 실패: ${env.JOB_NAME} #${env.BUILD_NUMBER} by ${Author_ID}(${Author_Name})\n(<${env.BUILD_URL}|Details>)",
endpoint: 'https://meeting.ssafy.com/hooks/bb6j17ansjnambc9cjddf8gw7o',
channel: 'CICD'
)
}
}
success {
echo 'Build image success !'
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()
mattermostSend (color: 'good',
message: "도커 이미지 빌드 성공: ${env.JOB_NAME} #${env.BUILD_NUMBER} by ${Author_ID}(${Author_Name})\n(<${env.BUILD_URL}|Details>)",
endpoint: 'https://meeting.ssafy.com/hooks/bb6j17ansjnambc9cjddf8gw7o',
channel: 'CICD'
)
}
}
}
}
해당 script를 작성하게 되면 누가 push를 진행했는지 성공했는지 실패했는지, 어떤 마이크로서비스인지를 알림을 통해 알려주게된다.
프로젝트에서 중요한 설정을 관리하는 application.yml 파일이 Gitlab에 노출되어있는데 이 문제를 어떻게 해결할까?