Skip to content

[feat] Dockerfile, docker-compose, Kubernetes 매니페스트 추가#42

Open
dasomel wants to merge 3 commits into
eGovFramework:mainfrom
dasomel-eGovFramework:feat/docker-and-k8s-5.0.x
Open

[feat] Dockerfile, docker-compose, Kubernetes 매니페스트 추가#42
dasomel wants to merge 3 commits into
eGovFramework:mainfrom
dasomel-eGovFramework:feat/docker-and-k8s-5.0.x

Conversation

@dasomel
Copy link
Copy Markdown
Contributor

@dasomel dasomel commented May 20, 2026

변경 사유

boot-sample-java-config에는 컨테이너 이미지/k8s 매니페스트가 없어 로컬에서 Maven 플러그인으로만 실행 가능합니다. 데모와 클러스터 배포 경로를 만들기 위한 최소 산출물을 추가합니다.

변경 내용

  • Dockerfile — multi-stage maven:3.9-eclipse-temurin-17eclipse-temurin:17-jre-alpine, 비루트 사용자, JAVA_OPTS=-XX:MaxRAMPercentage=75 -XX:+ExitOnOutOfMemoryError, HEALTHCHECK Actuator
  • .dockerignoretarget/, k8s/, IDE 파일, README 제외
  • docker-compose.yml — 단일 서비스 (샘플이 HSQLDB in-memory를 사용하므로 DB 사이드카 불필요), ${APP_VERSION:-5.0.0} 변수화
  • k8s/deployment.yaml — 1 replica RollingUpdate, runAsNonRoot, readOnlyRootFilesystem, drop ALL, resource requests/limits, liveness/readiness probe 분리
  • k8s/service.yaml — ClusterIP 8080

영향 범위

  • 애플리케이션 코드, application.properties 변경 없음
  • image: 태그(egovframe-boot-sample-java-config:5.0.0)는 예시 — 운영 환경 레지스트리로 교체 필요

체크리스트

  • 단일 주제(컨테이너화 + k8s 매니페스트)
  • 5.0.x 브랜치 대상
  • 기존 코드/설정 미변경

The boot-sample-java-config repo has no container image definition or
Kubernetes manifests, so the sample can only be run locally via the
Maven Spring Boot plugin. Add a minimal but production-shaped set:

- Dockerfile: multi-stage Maven 3.9 + Temurin 17 -> JRE Alpine, runs as
  a non-root user, exposes 8080, HEALTHCHECK against Actuator.
- .dockerignore: keep build context small.
- docker-compose.yml: single-service compose for quick demo runs, image
  tag parameterised via ${APP_VERSION:-5.0.0}. The sample uses HSQLDB
  in-memory so no DB sidecar is needed.
- k8s/deployment.yaml: replica=1 RollingUpdate, runAsNonRoot,
  readOnlyRootFilesystem, drop ALL, resource requests/limits, separate
  liveness/readiness probes against Actuator.
- k8s/service.yaml: ClusterIP exposing port 8080.

Application code and properties are unchanged.
@dasomel dasomel changed the base branch from 5.0.x to main May 26, 2026 15:53
@dasomel dasomel changed the title [feat][5.0.x] Dockerfile, docker-compose, Kubernetes 매니페스트 추가 [feat] Dockerfile, docker-compose, Kubernetes 매니페스트 추가 May 26, 2026
@eGovFrameSupport
Copy link
Copy Markdown
Contributor

표준프레임워크에 대한 지속적인 참여에 대단히 감사드립니다.
로컬 환경(Windows 11 / Docker Desktop with Kubernetes kubeadm)에서 PR 브랜치(feat/docker-and-k8s-5.0.x)를 받아 그대로 빌드·실행해 본 결과는 다음과 같습니다.

발견 사항 — readiness / liveness probe 및 Dockerfile HEALTHCHECK 경로가 존재하지 않는 엔드포인트를 가리킴

세 곳 모두 /actuator/** 경로를 프로브 대상으로 사용 중.

  • Dockerfile: HEALTHCHECK ... wget ... http://127.0.0.1:8080/actuator/health
  • k8s/deployment.yaml: readinessProbe.httpGet.path: /actuator/health/readiness
  • k8s/deployment.yaml: livenessProbe.httpGet.path: /actuator/health/liveness

그러나 본 프로젝트 pom.xml 에는 spring-boot-starter-actuator 의존성이 포함되어 있지 않음

1. 애플리케이션 자체는 정상 — 대조군

$ curl -i http://localhost:8080/
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
...
<title>Default BBS List</title>

2. PR이 가리키는 세 경로는 전부 500

$ curl -i http://localhost:8080/actuator/health
HTTP/1.1 500
...
<span>Error Ocurred!</span>

$ curl -i http://localhost:8080/actuator/health/readiness
HTTP/1.1 500
<span>Error Ocurred!</span>

$ curl -i http://localhost:8080/actuator/health/liveness
HTTP/1.1 500
<span>Error Ocurred!</span>

3. Docker HEALTHCHECK 결과 — 컨테이너 (unhealthy) 고착

$ docker compose ps
NAME               STATUS
egov-boot-sample   Up 5 minutes (unhealthy)

$ docker inspect --format '{{json .State.Health}}' egov-boot-sample
{
  "Status": "unhealthy",
  "FailingStreak": 10,
  "Log": [
    { "ExitCode": 1, "Output": "wget: server returned error: HTTP/1.1 500" },
    { "ExitCode": 1, "Output": "wget: server returned error: HTTP/1.1 500" },
    { "ExitCode": 1, "Output": "wget: server returned error: HTTP/1.1 500" },
    ...
  ]
}

4. Kubernetes — 파드 재시작 무한 반복 (CrashLoop 패턴)

$ kubectl get pods -l app.kubernetes.io/name=egovframe-boot-sample-java-config
NAME                                                 READY   STATUS    RESTARTS      AGE
egovframe-boot-sample-java-config-769b6b86d6-h5spr   0/1     Running   5 (36s ago)   8m56s

$ kubectl describe pod ...
Events:
  Warning  Unhealthy  ... Liveness probe failed: HTTP probe failed with statuscode: 500   (x6  over 10m)
  Warning  Unhealthy  ... Readiness probe failed: HTTP probe failed with statuscode: 500  (x60 over 10m)
  Normal   Killing    ... Container app failed liveness probe, will be restarted          (x6  over 9m28s)
  Normal   Started    ... Started container app                                           (x7  over 11m)
  Normal   Pulled     ... Container image "egovframe-boot-sample-java-config:5.0.0" already present on machine

11분 동안 7회 컨테이너 재시작이 발생하며, 정상 진입(READY 1/1)에 한 번도 도달하지 못합니다.

그 외 보강 요청 — 운영 절차 안내 문서

매니페스트만 추가된 상태로 머지하면 사용자가 "이 PR로 무엇을 어떻게 띄울 수 있는가"를 알기 어렵습니다. 다음 항목을
다루는 안내(k8s/README.md 신설 또는 메인 README.md 섹션 추가)를 같이 부탁드립니다.

  • 사전 요구사항 (Docker Desktop / Kubernetes 활성화)
  • 이미지 빌드: docker build -t egovframe-boot-sample-java-config:5.0.0 .
  • 단독 실행: docker compose up -d / 접속 URL / 종료 명령
  • Kubernetes 배포: kubectl apply -f k8s/ / 포트포워딩으로 http://localhost:8080/ 접근 / 정리 명령
  • 외부 레지스트리 사용 시 이미지 태깅·푸시 방법
  • 알려진 제약 (HSQL 인메모리이므로 재시작 시 데이터 초기화, readOnlyRootFilesystem/tmp 외에는 쓰기 불가, 단일
    레플리카 등)

본 수정사항은 해당 Repository 뿐만이 아닌, 표준프레임워크에서 공개된 전체 Repository에서 확인되므로 검토 및 수정이 필요합니다.

- pom.xml에 spring-boot-starter-actuator 추가
- application.properties에 actuator health 노출 및 readiness/liveness probe 설정
- Dockerfile HEALTHCHECK, k8s readiness/liveness 세 곳 모두 /actuator/health/* 경로 유효화하여 500 → 정상화, CrashLoop 방지
- k8s/README.md 신설: 빌드·배포·접속·헬스체크 확인 절차 안내
@dasomel
Copy link
Copy Markdown
Contributor Author

dasomel commented May 28, 2026

리뷰 의견 반영 완료했습니다.

  • 헬스 프로브가 가리키던 /actuator/health/* 엔드포인트가 actuator 미포함으로 500을 반환하던 문제를 수정했습니다. pom.xmlspring-boot-starter-actuator를 추가하고 application.propertiesmanagement.endpoints.web.exposure.include=health, management.endpoint.health.probes.enabled=true 설정을 추가하여 기존 경로를 그대로 활성화했습니다.
  • Dockerfile HEALTHCHECK, deployment readiness/liveness 세 곳 모두 /actuator/health, /actuator/health/readiness, /actuator/health/liveness 경로를 그대로 유지하면서 정상 200 응답을 반환하도록 일관되게 맞춰 CrashLoop를 해소했습니다.
  • 운영 절차 안내 k8s/README.md를 신설하여 이미지 빌드·Docker Compose 실행·kubectl 배포·포트/NodePort 접속·헬스체크 확인 절차를 정리했습니다.

Comment thread k8s/README.md Outdated
minikube service egovframe-boot-sample-java-config --url
```

일반 클러스터에서는 NodePort 값(기본 30080)으로 접속합니다.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 문구가 service.yaml과 일치하지 않습니다.

@dasomel
Copy link
Copy Markdown
Contributor Author

dasomel commented May 29, 2026

리뷰 반영하여 k8s/README.md 4번 "접속" 섹션을 service.yaml 실제 값에 맞게 수정했습니다.

불일치 내용:

  • README에는 "NodePort (service.yaml 기준)"이라는 제목과 NodePort 포트 30080, minikube service 명령, http://<노드 IP>:30080 접속 안내가 있었습니다.
  • 실제 service.yaml은 type: ClusterIP, port: 8080, targetPort: http 로 NodePort가 아닙니다.

수정 내용:

  • 섹션 제목을 "NodePort" → "ClusterIP"로 변경
  • NodePort 기반 접속 안내(포트 30080, minikube service 명령) 제거
  • ClusterIP 특성에 맞게 클러스터 내부 접근 방식(egovframe-boot-sample-java-config:8080)으로 안내 교체
  • 포트 포워딩 섹션은 service.yaml의 port 8080과 일치하므로 그대로 유지

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants