[CI/CD] Jenkins를 사용한 CI/CD 구축(SpringBoot, Docker)

ichubtou·2024년 1월 15일
3

다음 환경에서 진행되었다.

  • Spring boot 2.7.9 - Gradle

EC2 Ubuntu서버에서 Docker와 Docker compose를 사용하여 Spring Boot(Gradle)의 CI-CD 구축을 위하여 작성된 글이다.


해당 글에서 프로젝트는 Dockerfile과 Docker-compose를 기반으로 구성되어 있다.


배포할 프로젝트에 Dockerfile과 docker-compose는 이미 작성된 상태이고 나는 deploy폴더에 넣어 뒀다.


사전에 작성된 Dockerfile과 docker-compose.yml


Dockerfile

FROM openjdk:11-jre
COPY build/libs/spring-0.0.1-SNAPSHOT.jar spring.jar
EXPOSE 8080
ENTRYPOINT exec java -jar -Duser.timezone=Asia/Seoul spring.jar

docker-compose.yml

version: "3.7"
services:
  redis:
    container_name: redis
    image: redis:alpine
    ports:
      - 6379:6379
    volumes:
      - ~/Desktop/redis/data/:/data
  spring:
    container_name: spring
    image: [Username]/[이미지 이름] (DockerHub)
    ports:
      - 8080:8080
    volumes:
      - /var/log/:/logs/
    depends_on:
      - redis
  • Username/이미지 이름 (DockerHub) 해당 부분에 본인에게 해당하는 값을 넣어준다.
  • 지금 설정하지 않아도 뒤에 설명이 나오니 일단은 넘어가자.

먼저 그림을 보면서 대략적인 구조를 살펴보자


내 Spring Boot 서버에 Redis가 포함되므로 이 CI/CD 파이프라인에 Redis를 통합했다.



CI/CD 파이프라인 다이어그램


  1. 먼저 개발자는 GitHub에 Push를 한다
  2. Jenkins와 GitHub은 Hook으로 연결되어있어 Jenkins에 설정한 대로 작동한다.
  3. Jenkins는 DockerHub에 해당 프로젝트의 Dockerfile을 이미지로 만들어 DockerHub에 Push한다.
  4. Jenkins는 docker-compose.yml파일을 EC2(Server)에 복사하고 실행한다.
  5. docker-compose.yml이 실행되면서 내부에 있는 이미지를 Pull한다.

다음과 같이 흘러가게 된다.



EC2(Jenkins, Server) - Docker, docker-compose 설치


[Docker] EC2에 Docker 설치(Ubuntu, Docker-compose)


위의 글을 참고하여 두개의 서버에 모두 Docker, Docker-compose를 설치해 준다.



EC2(Jenkins) - Jenkins Container 설치


애플리케이션들의 관리는 Docker로 관리하는 것이 편하다고 생각하기 때문에 Jenkins를 사용할때 Container를 이용할 것이다.


docker-compose를 사용하여 만들어 줄 것이며, Image는 jenkins/jenkins:lts를 사용할 것이다.


Jenkins docker-compose.yml 작성


해당 디렉토리에 docker-compose.yml 파일을 만든다.

vi docker-compose.yml

  • docker-compose.yml
    • image : jenkins/jenkins:lts 이미지 사용
    • containerName : jenkins (본인이 하고 싶은 컨테이너명 작성)
    • volumes
      • /var/run/docker.sock:/var/run/docker.sock : jenkins container 내부에서 docker 명령어를 사용하기 위해 서버에 설치된 docker.sock을 사용할 것이다.
    • ports: 동일하게 8080포트 매핑
      • 포트는 변경 가능하다.<호스트 포트>:<컨테이너 포트>


version: '3'

services:
    jenkins:
        image: jenkins/jenkins:lts
        container_name: jenkins_cicd
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
        ports:
            - "8080:8080"


EC2(Jenkins) - Jenkins Container 실행


다음 명령어로 Jenkins Container 실행

docker-compose up -d

이미지의 다운로드가 끝나고 정상적으로 실행되면 [server ip]:8080 에 접속하면 다음과 같은 화면을 볼 수 있다.



해당 비밀번호는 컨테이너의 로그에서 확인할 수 있다.

docker logs jenkins

or

docker-compose logs

확인한 비밀번호를 사이트에 입력한 후 Continue 를 클릭한다.

그럼 플러그인 설치에 관한 내용이 나오는데, 왼쪽 Install suggested plugins 버튼을 누른다

그럼 젠킨스에서 제안하는 플러그인들을 설치한다. 5분 정도 소요된다.

진짜 가끔씩 플러그인 설치가 실패할 때가 있는데 이때는 답이 없다.


시간차를 두고 계속 시도하는 방법 뿐…

이 문제의 이유를 찾아보았지만 뚜렷한 이유가 없다.

그냥 어느정도 시간이 흐르면 해결 될 뿐.


다음과 같이 설치가 진행된다.

다 설치되면 관리자 계정을 생성할 수 있다. 계정명에는 로그인 시 사용할 ID를 입력해야한다.

정보 입력 후, Save and Continue 버튼을 누른다.

입력 후, 젠킨스 접속 URL을 확인해준다.

다음과 같이 [server 공인 ip]:8080 가 나온다.

확인 후 Save and Finish 버튼을 누른다.

이제 젠킨스를 사용할 준비가 다 되었다.

Start using Jenkins 버튼을 눌러준다



EC2(Jenkins) - Jenkins Job 설정


프로젝트의 CI/CD를 위한Jenkins Job 설정을 시작한다.



Jenkins Job 생성


메인화면 좌측에서 새로운 Item 버튼을 누른다.

원하는 이름을 입력 후 Freestyle project 를 선택해서 job을 생성한다.

CI/CD를 위해서 Repository의 연결이 필요하다.


Jenkins & Github 연결


Public 설정인 Repository는 그냥 url만 넣어주면 된다.

Repository가 Private일 경우에만 다음의 과정을 추가해준다.


Jenkins Add Credentials 설정 - Github Repsotiory(Private)


Repository가 Private일 경우 계정 정보를 포함해야 한다.

Jenkins 버튼을 누른다.

Username with password 항목을 선택해준다.


  • Username: 본인 깃허브 아이디
  • Password: 본인 Github Token 값
  • ID: 해당 Credential 식별 아이디

계정 정보가 틀리다면 Failed to connect to repository 이 문구가 뜬다.


아무 문구가 뜨지 않으면 인증 성공.


그 다음 CI/CD를 진행할 브랜치를 설정해준다.

나는 main branch를 설정해 주었다.

github에 hook을 걸기 위해 다음 항목 선택

이 상태에서 해당 브랜치에 Push를 하게 되면 다음과 같이 성공하게 된다.

이후 해당 프로젝트의 Dockerfile을 기반으로 이미지를 만들어 DockerHub에 등록해야한다.

DockerHub Repository 생성


Docker Hub Container Image Library | App Containerization

도커 허브 사이트에 들어가서 회원가입, 로그인 후 Repository를 만들어 준다.

Create repository 버튼을 눌러준다.

Repository Name과 저장소의 Public, Private 여부를 체크하고 Create 버튼을 누른다.

Repository가 Private일 경우에만 다음의 과정을 추가해준다.


Docker Hub Token 발급 - Docker Repository(Private)


Docker Hub 홈페이지 - 우측 상단 프로필 - My Account - Security - New Access Token

위의 경로를 따라서 Token을 발급한다.



Jenkins Container 내부 접속 후 docker-cli 설치


먼저 해당 프로젝트의 Dockerfile을 기반으로 이미지를 만들어야한다.


Container 내부에서 도커를 사용하는 방법에는 크게 두가지가 있다.

  • DinD 방식
  • Dood 방식

이번에는 Dood방식을 사용한다.

- /var/run/docker.sock:/var/run/docker.sock

아까 작성한 jenkins docker-compose.yml에서 이미 설정을 완료하였다.


Jenkins Container로 접속

docker exec -u root -it jenkins bash

그리고 Docker Cli를 설치한다.

apt-get update
apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
apt-get install docker-ce-cli

해당 명령어는 순서대로

  • 패키지 리스트 업데이트
  • 필요한 패키지 설치
  • 도커의 공식 GPG 키 추가
  • 도커 저장소 설정
  • 도커 클라이언트 설치

이다.


중간중간 Y/n를 묻는데 모두 Y를 선택하면 된다.


그리고 docker ps를 입력하면 컨테이너 외부에 존재하는 도커 호스트의 기능을 빌려서 사용하는 방식이기 때문에 컨테이너 내부에서도 jenkins가 실행되는 모습을 볼 수 있다.

EC2(Jenkins) - Docker Image 생성


그리고 이미지를 만들어야 하는데 이미지를 만들기 위해서는 Dockerfile과 빌드된 Jar파일이 필요하다.


프로젝트는 컨테이너 내부의 다음 경로에 있다.

  • 컨테이너 내부에서 권한 문제로 다음 명령어를 작성한다.
sudo chown -R jenkins:jenkins /var/jenkins_home/workspace/spring-ci-cd/.gradle
sudo chmod -R 755 /var/jenkins_home/workspace/spring-ci-cd/.gradle

cd /var/jenkins_home/workspace/spring-ci-cd  (jenkins job 이름)

나는 도커 파일을 다음과 같이 최상단 폴더에 두었다.



Jenkins Configuration 명령어추가


그 후 Jenkins - job - Configuration으로 간 후

Build Steps에서 Execute shell을 선택 후 다음과 같이 입력한다.


cd /var/jenkins_home/workspace/spring-ci-cd 
chmod +x ./gradlew
./gradlew clean build
docker build -t ([Username]/[이미지 이름] (DockerHub)) .
docker push ([Username]/[이미지 이름] (DockerHub))

##예)
docker build -t ichubtou/spring .
docker push ichubtou/spring

경로로 이동 후 권한을 얻고 빌드 해당 파일을 docker hub에 push

이렇게 하면 설정한 dockerhub repository에 등록이 된다.


Docker login - Docker Repository(Private)


나는 docker repository가 Private이기 때문에 로그인을 해야 Push가 가능하다.

exit 로 컨테이너를 나간 후 해당 명령어로 접속 docker exec -it jenkins bash

컨테이너 내부에 접속 후 다음 명령어를 입력한다.

docker login

username과 docker hub token을 입력하면 된다.


Docker Repository가 Private이라면 EC2(Server)에도 해당 작업을 수행한다.


해당 작업을 마친 후 실행하면 docker hub repository에 이미지가 올라간 것을 확인할 수 있다.



EC2(Jenkins) - Publish Over SSH Plugin 설치


Jenkins - DashBoard - 젠킨스 관리 - Plugins - Available plugins

위의 경로에서 Publish Over SSH를 검색하여 설치한다.

EC2(Jenkins) - DockerHub Pull 후 실행


Publish over SSH 설정으로 각 EC2 연결


먼저 Jenkins서버와 Spring서버의 연결을 위한 설정을 한다.

Dashboard-Jenkins 관리-System-Publish over SSH

  • Key: spring서버의 ppk 값 복사 붙여넣기
  • Name: 해당 서버 연결을 구분하기 위한(Jenkins에서) 이름
  • Hostname : 배포 서버의 IP
  • Username : 배포 서버의 Username
    • 보통 우분투 서버로 EC2를 생성하면 기본 사용자명이 ubuntu이다.

Test Configuration을 이용하여 테스트가 가능하다.


Send build artifacts over SSH 설정으로 파일 복사


Jenkins Job으로 이동하여

빌드 후 조치 - Send build artifacts over SSH를 선택한다.

  • Name: 연결할 서버 선택
  • Source files : 배포 서버에 전송할 파일 목록을 적는다.
    • 나는 deploy의 docker-compose.yml를 전달하기 위해 deploy 내부 파일을 전송

      # $JENKINS_HOME/workspace/$JOB_NAME/spring-ci-cd/test 파일 전송
      Source files: test
      
      # $JENKINS_HOME/workspace/$JOB_NAME/spring-ci-cd/deploy/ 폴더 속 모든 파일 전송
      Source files: deploy/**
  • Remove prefix : 전송 시 파일명에서 제외 할 prefix
  • Remote directory : 전송되는 폴더 위치
  • Exec command : 배포서버에서 실행되는 명령어 작성

배포서버에도 docker와 docker-compose를 설치하고 docker login까지 마친 상태여야한다.

cd ~/deploy
docker-compose pull
docker-compose up --build -d

\deploy폴더로 이동 후 docker-compose에 있는 이미지 설치 후 실행

그리고 EC2(Server)에 접속하여 docker ps 명령어를 이용해 확인해 보면 잘 실행되는 것을 확인할 수 있다.


다음과 같은 과정을 모두 마쳤다.

1개의 댓글

comment-user-thumbnail
2025년 4월 7일

좋은 글 감사합니다

답글 달기