DevOps & Cloud발행일 2025. 9. 8.원본 https://blog.naver.com/jword_/224000548491 ↗

Jenkins 3. 컨테이너 배포(OCI, Dockerhub)

Jenkins 3. 컨테이너 배포(OCI, Dockerhub) — #개발자의도구들 #도커이미지 #도커OCI #Spring서버이미지 #OCI이미지제작 #OCI이미지실습 #젠킨...

#DevOps/cloudOps#Naver Blog

#개발자의도구들 #도커이미지 #도커OCI #Spring서버이미지 #OCI이미지제작 #OCI이미지실습 #젠킨스컨테이너 #dockerhub #도커허브

​

AI스쿨 msa기반 java 백엔드 코스 중에 공부한 내용을 작성하였습니다

\* 현재 Spring x 프로젝트를 진행하고 있습니다. 전체 목차를 보시려면 여기를 눌러주세요.

\* Devops stack: 여기

\* 리눅스 기본기: 여기

Before

​

👉 OCI 이미지란 무엇인지

​

https://blog.naver.com/jword\_/223938458112

이미지

[컨테이너 아키텍처와 OCI
#개발자의도구들 #컨테이너아키텍처 AI스쿨 msa기반 java 백엔드 코스 중에 공부한 내용을 작성하였습니...
blog.naver.com](https://blog.naver.com/jword_/223938458112)

👉 Jenkins 파이프라인 수동배포

https://blog.naver.com/jword\_/223996728208

이미지

[Jenkins 2. VM 수동 배포 자동화하기
#개발자의도구들 #ElasticSearch #Logstash AI스쿨 msa기반 java 백엔드 코스 중에 공부한 내용을 작...
blog.naver.com](https://blog.naver.com/jword_/223996728208)

​

​

📌 이전까지 build의 불편한 점

  • 현재 Jenkins를 연결 했으나 여전히 많은 문제들이 존재한다.
  • MSA서버 특성상 배포할 노드를 각각 준비해줘야 한다.
  • 노드마다 각 셋팅을 해줘야 한다.
  • ⚙️1. jvm 다운로드 및 버전 맞추기

​

  • 매우 단순한 일이긴하지만, 매번 셋팅하는 것이 매우 귀찮다.
  • 특정 노드는 다른 버전의 jvm이 필요한 경우도 있을 것이다.
  • 예를들어, ServerA는 jvm 18버전을
  • 내 서버는 현재 jvm 17버전을 사용한다.

​

⚠️ 리눅스의 경우 라이브러리 버전이 전역에 고정 되므로 다른 버전을 사용한다면 배포에 문제가 발생한다.

​

컨테이너 런처 & Docker OCI를 통한 배포

이미지

기존 구조

  • Jar를 실행시키기 위해 JVM이 필요하다.
  • 버전을 맞춰줘야 한다.
  • 👉⚠️ 다를 경우 문제 발생!
  • 개발자가 직접 실행환경을 맞춰야하는 번거로움
  • ⚙️ 원격접속
  • ⚙️ 각 버전에 맞는 jvm 다운로드
  • 😑 번거롭다!

이미지

새로운 구조

기존 배포 구조에 OCI 파일 생성 및 배포로 변경합니다.

-

  • 빌드는 동일하게 하나의 워커 노드에서 진행
  • 빌드된 파일은 OCI 이미지 파일로 제작하여 Dockerhub repository에 push
  • MSA 서버별로 접속하여 dockerhub에서 각 이미지를 Pull하여 docker/podman으로 실행합니다.

OCI 이미지 파일 제작하기

Podman을 사용하여 진행할 것이기 때문에 Containerfile을 제작해야합니다. OCI 파일을 본격적으로 생성하기전 다음과 같은 질문을 생각해봅시다.

​

🤔 언제 OCI가 제작되나요?

  • build 이후 jar 파일이 배포 완료되면

👉 그럼 여기서 jar파일이 해당 노드에 있다고 가정할 수 있습니다.

​

🤔 서버를 실행하기 위해 필요환 환경에 대해 생각해 봅시다.

  • Spring을 돌리기 위해서는 다음과 같은 항목들이 필요합니다.
  • JVM
  • jar파일
  • 실행 명령어

​

필요한 환경을 모두 OCI로 만들어 주면됩니다. 저는 JVM, 배포된 jar파일, 실행 명령어 등을 OCI로 만들었습니다.

​

\* devops 관련 파일들은 따로 repository를 작성하는 것이 좋습니다.

javascript 코드 예제
                                    //  📦 Containerfile 제작

# 사용할 오픈JDK 버전을 명시적으로 지정 (예: 17.0.2)
FROM docker.io/openjdk@sha256:a996cdcc040704ec6badaf5fecf1e144c096e00231a29188596c784bcf858d05

# 작업 디렉터리 설정
WORKDIR /x-front-server

# Jenkins 빌드 결과로 생성된 JAR 파일을 컨테이너로 복사
# (아래 예시 이름을 빌드 산출물의 실제 JAR 이름에 맞게 바꿔주세요)
COPY build/libs/X-FrontServer-0.0.1-SNAPSHOT.jar /x-front-server/front.jar

# 컨테이너가 사용하는 포트 문서화 (예시 8080)
EXPOSE 8080

# 컨테이너 실행 시 JAR 실행
ENTRYPOINT ["java", "-jar", "front.jar"]

⚠️ Anti Pattern

  • ❌ docker.io/openjdk:17-jdk-slim
  • 이런 식으로 지정하면, 버전이 변경되어 이후 호환이 안될 수 있습니다.
  • 👉 JVM은 정확한 태그를 지정해야합니다. (고유식별 가능하도록)

​

  • ❌ ENTRYPOINT \["java", "-jar", "spring-server.jar", "--spring.profiles.active=beta", "--server.port=8090"\] >>> "--server.port=8090" \]
  • 명령어는 최소한을 사용합니다. 해당 이미지 파일은 오직 beta프로필만 사용이 가능합니다.

​

  • ❌ 하나의 빌드에 병렬적으로 build & deploy 진행
  • MSA에서는 각각 다른 pipeline을 구축하여 분리하는 것이 일반적입니다.
  • 내부에서 빌드 순서가 꼬여버릴 수 있고, 언제든 유동적으로 변경되기 때문

​

Deploy 파이프라인 변경 - 도커허브

파이프라인에서 두개의 repository를 참조합니다. 참조 순서는 아래와 같습니다.

1.

  1. x-front
  2. devops전용

​

1번에서 빌드가 완료된 후 생성된 .jar파일과 devops 전용 repository의 Containerfile을 참고하여 OCI 이미지를 생성해야합니다.

​

javascript 코드 예제
                                    pipeline {
  // 📌 reusable env vars
  environment {
    REGISTRY = 'docker.io'
    IMAGE    = 'toolod/x-frontserver'
    VERSION_TAG = "1.0.0-${new Date().format('yyyyMMdd')}-${UUID.randomUUID().toString().take(7)}"
  }

  // -- 중략 --
    stage('Deploy') {
      steps {
        // 1) Use devops repo (has oci/Containerfile)
        dir('devops-management') {
          git url: 'https://github.com/keyveloper/devops-management.git', branch: 'master'

          // 2) Bring the JAR into this repo root
          // 현재 dir = root
          // 📌 $WORKSPACE - worker가 사용하는 루트 dir
          sh '''
mv ${WORKSPACE}/build/libs/X-FrontServer-0.0.1-SNAPSHOT.jar ${WORKSPACE}/devops-management
'''

          // 3) Build & Push OCI image using oci/Containerfile
          withCredentials([string(credentialsId: 'DOCKERHUB_TOKEN', variable: 'DOCKERHUB_TOKEN')]) {
            sh '''
# Docker Hub login (Podman)
podman login docker.io -u toolod -p "$DOCKERHUB_TOKEN"

# Build & push
podman build -f oci/Containerfile -t "${REGISTRY}/${IMAGE}:${VERSION_TAG}" .
podman tag "${REGISTRY}/${IMAGE}:${VERSION_TAG}" "${REGISTRY}/${IMAGE}:latest"

podman push "${REGISTRY}/${IMAGE}:${VERSION_TAG}"
podman push "${REGISTRY}/${IMAGE}:latest"
'''
          }
        }
      }
    }
  }
}
  • 환경변수를 사용하여 최대한 다시 쓸 수 있는 것을 저장해 둡시다.
  • 이미지를 생성할 때는 반드시 고유태그를 붙여야 합니다. (Gitops를 위함)
  • 저의 경우 버전-날짜-UUID 첫 7글자로 사용했습니다.
  • latest 태그는 항상 최신으로 업데이트 되도록 설계하였습니다.

이미지

이미지가 성공적으로 pull 되었습니다.

Docker hub에서 가져오기

현재까지 진행된 순서는 아래와 같습니다.

  • worker node가 build를 진행
  • JAR파일과 Containerfile을 참조하여 Dockerhub에 빌드

​

javascript 코드 예제
                                    stage('RUN') {
      steps {
        sh '''
ssh tod@192.168.0.13 << 'EOF'

# pull from docker hub
podman pull ${REGISTRY}/${IMAGE}:${VERSION_TAG}
podman run -d --name x-front-server-container -p 8080:8080 docker.io/toolod/x-frontserver:latest
EOF
'''
  • SSH 접속해서 podman으로 이미지 pull해서 컨테이너 run하기

​

❌ 에러 발생

javascript 코드 예제
                                    Error: invalid reference format
Error: creating container storage:
 the container name "x-front-server-container"
is already in use by a78d293035b273de6d9c7d7bd8b09049c33109e0e20d80b640f11953a92ef99d.

You have to remove that container to be able to reuse that name:
    that name is already in use, or use --replace to instruct Podman to do so.
  • 이미 작동중인 컨테이너이기 때문에 BUILD에 실패합니다!
  • 👉 보통 작동중인 서버를 새 서버로 한번에 교체하진 않습니다.
  • 하지만 지금은 실습이 중요하니, 컨테이너를 제거하고 다시 띄우는 전략을 취할 수 있습니다.
javascript 코드 예제
                                    podman rm -f x-front-server-container || true
  • 아래 명령어를 파이프라인에 추가 해줄 수 있습니다.

빌드과정 단축 업데이트

javascript 코드 예제
                                    도입 이전: 각 서버 명령어 입력 8회 x n개의 서버 + n개의 서버 셋팅

수동배포 자동화: 빌드 명령어 8회 고정(파이프라인 내에) + n개의 서버 셋팅

컨테이너 자동화 배포: 클릭 한번으로 전 과정 자동화

​