Jenkins/Docker + Github 연동 AWS EC2서버에 SpringBoot gradle (+Mysql) 배포

Jenkins/Docker를 이용하여 AWS EC2 서버에 Gradle로 빌드한 jar 파일을 배포할 것이다.

이는 Spring Boot로 작성한 프로젝트를 Jenkins와 Docker를 활용하여 이미지를 생성하고 그 이미지를 기반으로 EC2에 자동 배포하는 것이다.

jenkins를 이용한 시스템 구성도는 아래와 같다.

# 사용 플랫폼 버전
Springbot 2.6.3
gradle 7.4
AWS EC2 이미지 : Ubuntu 20.04

먼저 만든 SpringBoot 프로젝트를 Docker image로 생성해야 한다.

@RestController
public class TestController {

    @GetMapping("/test")
    public String test() {
        return "jenkins_test";
    }
}

앞서 그 이미지를 사용하기 위한 Dockerfile을 먼저 생성한다.


Docker file (위치: 프로젝트 루트에 있어야 한다.)

FROM openjdk:11-jdk

LABEL maintainer="[email protected]"

EXPOSE 8080

ARG JAR_FILE=build/libs/*.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java","-jar","/app.jar"] 

💥주의
gradle jar 파일 생성이 springboot 2.5버전부터는 java 명령어를 통해 jar 파일이 2개가 생성된다고 한다. 그래서 별도의 설정을 해야JAR_FILE=build/libs/*.jar에 error가 나온다!

build.gradle의 별도 설정

jar {
    enabled = false
}

이제, 로컬에서 별도로 잘되는지 확인하고 Dockerfile을 이용해서 이미지를 만든다.

sudo docker build -t mooh2jj/docker-jenkins-github-test .

그 다음 도커 이미지가 제대로 되있는 확인한다.

sudo docker images

이제 빌드한 네임대로 dockerhub에 이미지를 레포지토리에 등록할 것이다.
이 허브에 이미지를 등록해서 push/pull을 하는 배포 시스템을 만드는 것이다.

이렇게 만들어주자.

그다음 로컬에서 docker 이미지를 저 만든 레포지토리에 push한다.

sudo docker push mooh2jj/docker-jenkins-github-test

이제부터 배포할 서버는 이 레포지터리에 등록된 이미지를 pull 받아서 하는 것이다.


AWS EC2 서버 jenkins, docker 설치

서버설치는 전에 만든 걸 적은 블로그에 참조해두었다.

서버의 종류는 jenkins 인스턴스, 그리고 배포할 서버인 worker 인스턴스 두 개이다.

EC2 서버에는 jenkins + docker를 설치한다.

설치하는 방법은 이 블로그 참조.
jenkins 설치 : https://velog.io/@mooh2jj/Jenkins-AWS-EC2-설치

그리고 worker 인스턴스에는 docker 를 설치해주자.

docker 설치 : https://velog.io/@mooh2jj/AWS-EC2-Docker-설치


Jenkins 인스턴스 배포할 서버 SSH 접속 등록

Jenkins SSH 서버 등록
: https://velog.io/@mooh2jj/젠킨스-자동배포하기

Jenkins 인스턴스 개인키&공개키 생성 > 공개키 SSH서버에 등록 > 젠킨스 개인키 publish-over-ssh 등록 이 순서로 하면 된다.

밑에 Test Configuraion이 Success가 뜨면 젠킨스가 배포서버를 SSH 접속이 성공한 것이다.


Jenkins 프로젝트 생성 및 배포 명령어 등록

Item > Free Style 등록

먼저 이름은 아무렇게 지어도 좋다.

그 다음 프로젝트에 들어가서 구성으로 들어간다.

  • 소스 코드 관리 > Git

Repository URL 에 본인이 만든 프로젝트 Git주소를 적어준다.
프로젝트가 public 으로 되어 있다면 Credentials는 따로 처리할 필요가 없다.

  • Build > Invoke Grade script

Invoke Gradle을 선택할 경우 Jenkins에 Global Toll Configuration에서 Gradle 패키지를 설치해야 사용할 수 있다.

여기서 Use Gradle Wrapper & Make gradlew executable 까지 체크해준다.
jar 파일 자체를 빌드를 해주는 것이다.

Make gradlew executable은 gradlew 권한(chmod) 문제로 실행이 안 되는 상황을 막아 주는 것이다.

그리고

Tasks 안에 clean build를 넣어준다.

그리고

  • Build > Execute shell
sudo docker login -u [도커허브ID] -p [도커허브Password]

sudo docker build -t [도커허브ID]/docker-jenkins-github-test .
sudo docker push [도커허브ID]/docker-jenkins-github-test

를 적어준다.

그러면 젠킨스내부 /var/jenkins_home/workspace/ 안에 git 레포지토리로 등록한 프로젝트가 jenkins-docker-test 가 들어가고 그 프로젝트 안에 /gradlew clean build 가 실행되는 것이다.


💥[도커허브Password] 같은 경우 보안 기밀 상 유출 위험이 있어 DockerHub 내에서 Token을 생성해 기입할 수 있다.


DockerHub > Account Setting > Security > New Access Token

그다음 생성한 암호화된 Token을 [도커허브Password] 자리에 대체하면 된다.


💢 참고로, Invoke Gradle script > Execute shell 이 순서로 진행해주어야 한다. docker 이미지에서 빌드하고 처리하기 때문에 docker push 전에 해야되기 때문이다.


  • 빌드 후 조치 > Send build artifacts over SSH

SSH Server 를 등록해준다.

Name은 알아서 Publish Over를 통해 등록했으면 리스트로 나온 걸 선택해주면 된다.

Transfer Set에 Excute shell 만 적어주면 된다.

sudo docker stop $(sudo docker ps -a -q)
sudo docker rmi -f mooh2jj/docker-jenkins-github-test
sudo nohup docker run -p 8080:8080 mooh2jj/docker-jenkins-github-test > /dev/null 2>&1 &


결과

웹 브라우저에서 잘 확인이 된다.

웹 URL : [등록한 SSH 서버 퍼블릭IP주소]:8080/test

이젠 Jenkins를 통해 Github에 push한 내용이 바로 빌드/배포 하는 과정이 자동화되어진 것이다.
Git + Jenkins + Docker 를 활용해 CI/CD 시스템을 만들면 개발하는 데 정말 편하다는 것을 알 수 있다.


Schedule - Build periodically

Jenkins에서는 Schedule를 짜서 자동으로 배포하는 시스템이 마련되어 있다. 그중 하나가 build periodically 기능이다.

말그대로 주기성을 가지고 빌드/배포한다는 것이다.

# Build every 5 minutes:
H/5 ****

출처 : https://www.baeldung.com/ops/jenkins-job-schedule


MySQL 인스턴스 만들기(추가)

Mysql 도커로 설치및 실행
: 이 블로그 - Mysql 만들기 참조

https://velog.io/@mooh2jj/도커Docker-이미지로-Apache-및-PHP-개발환경-구축하기

추가로 해야할 일

  • jpa, Entity, Controller 만들기
  • mysql post 데이타베이스 만들기

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://{mysql-instacne IP}:9876/post
    username: root
    password: 1234
  jpa:
    open-in-view: true
    hibernate:
      ddl-auto: update
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
      use-new-id-generator-mappings: false
    show-sql: true
    properties:
      hibernate.format_sql: true
      dialect: org.hibernate.dialect.MySQL5InnoDBDialect

logging:
  level:
    root: info
    com.example: debug
    org.hibernate.SQL: debug

@RequiredArgsConstructor
@RestController
public class PostController {

    public final PostRepositroy postRepositroy;

    @PostMapping
    public Post createPost(@RequestBody Post post) {
        return postRepositroy.save(post);
    }

    @GetMapping("/posts")
    public List<Post> getPostList() {
        return postRepositroy.findAll();
    }
}
@Getter
@Setter
@ToString
@Entity
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String content;
}
public interface PostRepositroy extends JpaRepository<Post, Long> {
}

참고

좋은 웹페이지 즐겨찾기