@Heebeom Kim

Spring Boot CI/CD (with Docker & Jenkins)

흐름 따라 CI/CD 구성하기

GitHub + Jenkins + AWS EC2 (+ Docker Hub)

spring boot ci cd 1

  • Hello Application (Local)

    • Code -> Push -> GitHub(GitLab, BitBucket, …)
  • GitHub

    • Webhook -> Jenkins (Master)
  • Jenkins (Master, AWS EC2 Container #1)

    • Master -> Agent
  • Hello App (Jenkins Agent / AWS EC2 Container #2)

    • Fetch Code <- GitHub
    • Build with Pipeline
    • Tests (Unit Test, Integration Test, …)
    • Build JAR
    • Build Docker Image
    • (Docker Image -> Push -> Docker Hub)
    • Run Spring Boot Docker Container (from Docker Image)

준비 사항

  • Spring Boot Application
  • GitHub 계정
  • AWS 계정 (or IAM 계정)

AWS EC2 준비

  • Create Container - 2개 생성

    • Jenkins
    • Ubuntu 20.04
    • t3.small
    • tag → Name: {프로젝트명}-jenkins
    • Hello App
    • Ubuntu 20.04
    • t3.small
    • tag → Name: {프로젝트명}-hello
  • Security Group, Inbound Rules

    • 22 (SSH 접속)
    • 8080 (Spring Boot)
    • 50000 (Jenkins Agent)
  • SSH

    • key 권한 변경

      $ sudo chmod 400 jayce.pem
    • .ssh/config

      Host jenkins
        User ubuntu
        HostName {Host IP}
        IdentityFile ~/.ssh/jayce.pem
        ­
      Host hello
        User ubuntu
        HostName {Host IP}
        IdentityFile ~/.ssh/jayce.pem
    • EC2 - Jenkins 접속

      $ ssh jenkins

[EC2 - Jenkins]

Set up Docker repository

$ sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker Engine

$ sudo apt-get update && sudo apt-get install -y docker-ce docker-ce-cli containerd.io

Install Docker Compose

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

Install Jenkins with Docker

  • create folder

    $ mkdir jenkins
    $ cd jenkins
  • docker-compose.yml

    services:
      jenkins-docker:
        container_name: jenkins-docker
        image: docker:dind
        privileged: true
        networks:
          jenkins:
            aliases:
              - docker
        environment:
          - DOCKER_TLS_CERTDIR=/certs
        volumes:
          - jenkins-docker-certs:/certs/client
          - jenkins-data:/var/jenkins_home
        ports:
          - "2376:2376"
      jenkins-blueocean:
        container_name: jenkins-blueocean
        image: jenkinsci/blueocean
        networks:
          - jenkins
        environment:
          - DOCKER_HOST=tcp://docker:2376
          - DOCKER_CERT_PATH=/certs/client
          - DOCKER_TLS_VERIFY=1
        volumes:
          - jenkins-docker-certs:/certs/client:ro
          - jenkins-data:/var/jenkins_home
        ports:
          - "8080:8080"
          - "50000:50000"
    networks:
      jenkins:
        name: jenkins
    volumes:
      jenkins-docker-certs:
        name: jenkins-docker-certs
      jenkins-data:
        name: jenkins-data
  • Run Docker Compose

    $ sudo docker-compose up -d

Jenkins 접속

  • http://{Jenkins Host IP}:8080
  • Unlock Jenkins spring boot ci cd 2
  • Jenkins가 실행된 인스턴스에서 아래 명령어 실행하여 Administrator password 획득

    $ sudo docker exec jenkins-blueocean cat /var/jenkins_home/secrets/initialAdminPassword

Jenkins 설정

  1. Plugins
  2. Docker Pipeline
  3. (Optional) AdoptOpenJDK installer

    • build 시, 별도의 jdk를 사용하고 싶은 경우 설치하여 사용
  4. Global Tool Configuration
  5. (Optional) Add JDK

    • Name jdk-11
    • Version jdk-11.0.11+9

Jenkins New Pipeline

  • New Item

    • hello + Pipeline
  • Configuration

    • Build Triggers
    • GitHub hook trigger for GITScm polling
    • Pipeline Definition
    • Pipeline script from SCM
    • SCM -> Git

      • Repository URL 설정 https://github.com/{username}/hello.git
      • Credentials 설정 (Private Repo일 경우)
      • Branches to build -> Branch Specifier (blank for ‘any’)
      • default branch로 작성 */main

Hello Application 준비 [Local]

  • Spring Boot Simple Application

build.gradle

  • plain jar 파일을 생성하지 않기 위하여 아래 내용 추가

    jar {
      enabled = false
    }

Dockerfile

FROM openjdk:11-jdk-slim
ARG JAR_FILE=build/libs/\*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

Jenkinsfile

pipeline {
  environment {
    imageName = 'hello'
    containerName = 'hello'
  }
  agent { 
    label 'hello'
  }
  stages {
    stage('Build Jar') {
      steps {
        sh './gradlew clean build'
      }
    }

    stage('Build Docker Image') {
      steps {
        script {
          docker.build(imageName)
        }
      }
    }
    
    stage('Docker Run') {
      steps {
        sh """
          docker stop ${containerName} && docker rm ${containerName}
          docker run -d --name ${containerName} -p 8080:8080 ${imageName}
        """
      }
    }
  }
}

[GitHub]

  • Create Repository -> hello
  • Local Code -> Push
  • Add Webhook

    • http://{Jenkins Host IP}:8080/github-webhook/
    • 마지막에 /로 끝나도록 작성할 것! 주의!

[EC2 - Hello]

Set up Docker repository

$ sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker Engine

$ sudo apt-get update && sudo apt-get install -y docker-ce docker-ce-cli containerd.io

Java 설치

$ sudo apt update && sudo apt install -y openjdk-8-jdk

working directory로 사용할 jenkins 폴더 생성

$ mkdir jenkins

[EC2 - Jenkins]

  • Jenkins 관리 -> 노드 관리 -> 신규 노드

    • Labels을 통해 특정 노드에서 빌드 작업 수행 지정 가능
    • Remote root directory
    • /home/ubuntu/jenkins spring boot ci cd 3

[EC2 - Hello]

  • Jenkins Master로 부터 agent.jar 받아오기

    cd jenkins
    wget http://{Jenkins Host IP}:8080/jnlpJars/agent.jar 
  • Jenkins Master의 worker 설정에서 아래 명령어 복사 & 실행 → agent 실행

    ⚠️ sudo 필요 spring boot ci cd 4

[EC2 - Jenkins]

  • worker1 활성화 확인 spring boot ci cd 5

Run

[Local]

  • Git Push를 통해 Code의 변경 사항이 발생하면, Webhook -> Jenkins -> Build -> Deploy 흐름으로 잘 진행 되는지 확인.
  • 추가적으로 Docker Hub에 Image를 Push 하려면?

Docker Swarm(or AWS ECS)

spring boot ci cd 6


Written by@Heebeom Kim
iOS Engineer. Interested in Architecture, Automation. Work for CPNG

GitHubLinkedIn