CI란?
CI는 Contious Integration으로 지속적인 통합이라 할 수 있다. 개발팀이 정기적으로 코드 변경사항을 구현하고 테스트 한 후, 공유 버전 관리 레포지토리에 병합하는 방식을 말한다. 자동화 된 빌드에 의해 이런 `체크인`이 인증되므로 코드와 관련된 모든 문제를 신속하게 파악하고 해결 할 수 있다. CI를 사용하면 개발자 팀 사이에 충돌 없이 동일한 앱을 동시에 작업 할 수있다.
사용 툴
- Github
- Docker
- spring boot
차례
- spring boot 프로젝트 구조
- Github actions 스크립트 파일
- Dockerfile 파일
- Gitlab CI 확인
Spring Boot 프로젝트 구조
메이븐을 통한 멀티 모듈 구조로 프로젝트 구성을 만들었다.
- web-api: spring boot 메인 프로젝트로 MVC에서 컨트롤러, 서비스 로직을 담당하는 부분을 맡고 있는 모듈이다.
- web-core: core 프로젝트로 독립적으로 사용가능하게 만든 모듈로 주로 jpa, entity, utils exception 정도를 넣어둔 모듈이다.
- web-dao: MVC에 모델 파트를 맡은 부분으로 만든 모듈로 데이터베이스에 데이터를 가져오는 모듈로 사용하고있다.
- web-middleware: 주로 필터, wrapper 등을 사용하는 모듈로 만들어 두었다.
위 처럼 만든 모듈을 통하여 web-api 밑에 jar파일을 통하여 프로젝트를 실행 할 수있게 구조를 만들었다.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<parent>
<groupId>cm.kr.project</groupId>
<artifactId>project-anme</artifactId>
<version>0.0.1</version>
</parent>
<groupId>com.kr.project</groupId>
<artifactId>web-api</artifactId>
<version>0.0.1</version>
<name>web-api</name>
<description>web-api</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.kr.project</groupId>
<artifactId>web-core</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.kr.project</groupId>
<artifactId>web-dao</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.kr.project</groupId>
<artifactId>web-middleware</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
위 처럼 parent pom.xml에 묶어 다른 모듈들을 불러서 사용하고 있다.
Github actions 스크립트 파일
Github배포 yml 파일을 작성했다.
name: CI-CD
on:
push:
branches:
- master
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
env:
DATASOURCE_KEY: ${{ secrets.DATASOURCE_KEY }}
DATASOURCE_URL: ${{ secrets.DATASOURCE_URL }}
DATASOURCE_USERNAME: ${{ secrets.DATASOURCE_USERNAME }}
DATASOURCE_PASSWORD: ${{ secrets.DATASOURCE_PASSWORD }}
DOCKER_HUB_REPO: ${{ secrets.DOCKER_HUB_REPO }}
DOCKER_HUB_NAME: ${{ secrets.DOCKER_HUB_NAME }}
DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }}
DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }}
steps:
- name: Checkout
uses: actions/checkout@v2
# Cache Maven
- name: Cache Maven packages
uses: actions/cache@v2
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
# Maven Package
- name: Build with Maven
run: mvn -Dmaven.test.skip=true -B package --file ./pom.xml
# Docker Image Build
- name: Docker Build Image
run: |
docker build -t ${{ env.DOCKER_HUB_REPO }} \
--build-arg DATASOURCE_KEY="${{ env.DATASOURCE_KEY }}" \
--build-arg DATASOURCE_URL="${{ env.DATASOURCE_URL }}" \
--build-arg DATASOURCE_USERNAME="${{ env.DATASOURCE_USERNAME }}" \
--build-arg DATASOURCE_PASSWORD="${{ env.DATASOURCE_PASSWORD }}" .
# Docker Hub Login
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ env.DOCKER_HUB_USER }}
password: ${{ env.DOCKER_HUB_PASSWORD }}
# Docker Hub 이미지 push
- name: Build and Release to DockerHub
env:
NAME: ${{ env.DOCKER_HUB_NAME }}
REPO: ${{ env.DOCKER_HUB_REPO }}
run : |
docker tag $REPO:latest $NAME/$REPO:latest
docker push $NAME/$REPO:latest
- 도커, DB의 정보는 Github secert으로 env처리후 불러왔다. ( db정보 경우 이전 포스팅했던 jasypt 해시 처리도 진행했다)
- maven 빌드 경우 동일할 경우 캐시처리로 빌드 속도를 향상시켰다.
- maven 패키징을 진행했고 테스트는 스킵처리로 진행했다.
- Dockerfile 이미지를 빌드했고 db정보를 argumenet로 전달을 진했다.
- Docker Hub에 로그인 했다.
- 4단계에서 만들어진 이미지 파일을 Docker Hub로 push를 진행했다.
내가 만든 CI 스크립트로 멀티 모듈을 하나의 jar로 패키징한 후 Docker 이미지화 시킨후 허브에 올려두었다.
다양한 방식이 있겠지만 필자는 이후에 도커 허브의 이미지로 CD를 구축하는 법을 찾아볼 예정이다.
Dockerfile 파일
FROM openjdk:8-alpine
WORKDIR /app
ARG JAR_FILE_PATH=/web-api/target/*.jar
ARG DATASOURCE_KEY
ARG DATASOURCE_URL
ARG DATASOURCE_USERNAME
ARG DATASOURCE_PASSWORD
ENV ACTIVE_PROFILE="local" \
DATASOURCE_KEY=${DATASOURCE_KEY} \
DATASOURCE_URL=${DATASOURCE_URL} \
DATASOURCE_USERNAME=${DATASOURCE_USERNAME} \
DATASOURCE_PASSWORD=${DATASOURCE_PASSWORD}
COPY /${JAR_FILE_PATH} ROOT.jar
EXPOSE 12001
ENTRYPOINT ["java", "-jar", "-Xincgc", "-Xmx1024m", "-Dspring.profiles.active=${ACTIVE_PROFILE}", "-Dencryptor.key=${DATASOURCE_KEY}", "-Dspring.datasource.url=${DATASOURCE_URL}", "-Dspring.datasource.username=${DATASOURCE_USERNAME}", "-Dspring.datasource.password=${DATASOURCE_PASSWORD}", "-Duser.timezone=Asia/Seoul", "ROOT.jar"]
도커 파일을 만들어주었고 디스크 공간 소모를 아끼기위해 openjdk 경량화를 사용하였다. (web-api/target 밑에 생긴 jar를 사용하게 만들었다)
이후 여러 argument를 세팅한 후 기본 포트를 설정하고 jar를 실행시키는 명령어를 넣어준 도커 파일을 만들었다.
Gitlab CI 확인
github action을 살펴보면 정상적으로 구동되는것을 확인 할 수있다.
위 이미지 처럼 도커 허브에 내가 올린 이미지가 정상적으로 올라가는것을 볼 수있다. 이 이미지를 이용해서 이제 배포를 진행 할 거다
아직은 CD에 대해서 정확히 공부를 하지 않은 상태로 배포 스크립트를 작성해서 배포해보는 연습을 진행할 예정이다.
'Devops' 카테고리의 다른 글
gitHub & Jenkins CI/CD 적용 (4/4) (1) | 2024.06.06 |
---|---|
gitHub & Jenkins CI/CD 적용 (3/4) (0) | 2024.06.02 |
gitHub & Jenkins CI/CD 적용 (2/4) (0) | 2024.06.01 |
gitHub & Jenkins CI/CD 적용 (1/4) (0) | 2024.06.01 |
Docker Hub Image 배포 스크립트 (0) | 2024.04.11 |