작성 기준: SCP 공식 기술 가이드 (DevOps Service Configuration Guide v1.1, July 2023)
환경 전제 조건: SKE(Kubernetes Engine) ✅ · SCR(Container Registry) ✅ · Jenkins(K8S Apps) ✅ · GitHub Enterprise ✅ · Helm Chart ✅
[수동 실행: Jenkins "Build Now"]
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Stage 1: Checkout │
│ scp.sample.com/project/processing → main 브랜치 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Stage 2: Image Build │
│ docker build -t <SCR>/<PROJECT>/processing:<BUILD_NO> . │
│ └─ Dockerfile (repo root) │
│ COPY app /opt/app │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Stage 3: Image Push │
│ docker push → SCP Container Registry (SCR) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Stage 4: Helm Upgrade (Pod 재시작 포함) │
│ helm upgrade <release> <chart> │
│ --set image.tag=<BUILD_NO> ← 이미지 갱신 │
│ --set podAnnotations.restartedAt=<timestamp> │
│ ← Pod 강제 재시작 트리거 │
└─────────────────────────────────────────────────────────────┘
중요:
kubectl명령 대신helm upgrade를 사용하여 이미지 갱신 및 Pod 재시작을 처리합니다.
image.tag값이 변경되면 Kubernetes가 자동으로 Rolling Update를 수행합니다.
파이프라인 생성 전 아래 정보를 미리 수집합니다.
| 항목 | 확인 방법 | 예시 |
|---|---|---|
| SCR 엔드포인트 | SCP Console → Container → Container Registry → 레지스트리 선택 → 엔드포인트 확인 | registry.samsungsdscloud.com |
| SCR 프로젝트명 | Container Registry 생성 시 지정한 이름 | myproject |
| SCR AccessKey / SecretKey | SCP Console → IAM → 액세스 키 관리 | AKID... / SECRET... |
| Jenkins 도메인 | SCP Console → Container → Kubernetes Apps → Jenkins 상세 → 도메인 확인 | jenkins.devops-edu.net |
| GitHub Enterprise URL | SCP Console → DevOps Tools → GitHub Enterprise | scp.sample.com |
| GitHub Token | GitHub Enterprise → Settings → Developer settings → Personal Access Tokens | ghp_xxx... |
| Helm Release 이름 | 기 배포된 Helm release 이름 | processing |
| Helm Chart 이름 | 업로드된 Chart 이름 | processing-chart |
| K8S Namespace | 애플리케이션이 배포된 Namespace | processing-ns |
| SKE kubeconfig (Helm 실행용) | SCP Console → Container → Kubernetes Engine → 클러스터 → kubeconfig 다운로드 | YAML 파일 |
Jenkins에서 DevOps Console과 연동하기 위한 API Token을 발급합니다.
브라우저에서 Jenkins 도메인 접속:
http://jenkins.devops-edu.net (실제 Jenkins 도메인으로 변경)
Jenkins 생성 시 설정한 admin 계정과 비밀번호로 로그인합니다.
우측 상단 [admin 계정명] 클릭
→ Configure (또는 Settings)
→ API Token 섹션
→ [Add new Token] 버튼 클릭
→ Token 이름 입력 (예: devops-console-token)
→ [Generate] 클릭
→ 생성된 Token 값 복사하여 보관
⚠️ 주의: Token은 생성 직후 한 번만 표시됩니다. 반드시 별도로 저장하세요.
Jenkins Pipeline에서 사용할 인증 정보를 사전 등록합니다.
Jenkins 대시보드 → Manage Jenkins → Credentials
→ System → Global credentials (unrestricted)
→ [Add Credentials] 클릭
| 필드 | 값 |
|---|---|
| Kind | Username with password |
| Username | GitHub Enterprise 계정 |
| Password | GitHub Enterprise Personal Access Token |
| ID | ghe-credential |
| Description | SCP GitHub Enterprise |
| 필드 | 값 |
|---|---|
| Kind | Username with password |
| Username | SCR AccessKey |
| Password | SCR SecretKey |
| ID | scr-auth-credential |
| Description | SCP Container Registry 인증키 |
Helm 명령 실행을 위해 SKE kubeconfig가 필요합니다.
SCP Console → Container → Kubernetes Engine
→ 클러스터 선택 → [kubeconfig 다운로드] 버튼 클릭
다운로드한 파일을 Jenkins Credential에 등록:
| 필드 | 값 |
|---|---|
| Kind | Secret file |
| File | 다운로드한 kubeconfig YAML 파일 업로드 |
| ID | kubeconfig-ske |
| Description | SKE Cluster kubeconfig |
SCP Console (https://cloud.samsungsds.com/serviceportal)
→ 좌측 메뉴: DevOps Tools
→ DevOps Service
→ [DevOps Console 이동] 또는 [DevOps Console 접속] 클릭
⚠️ DevOps Service를 신청하지 않은 경우 → [DevOps Service 신청] 먼저 진행
DevOps Console 좌측 메뉴 → 도구 관리(Tool Management) → CICD 도구 탭
[도구 등록] 클릭
→ 도구 유형: Jenkins
→ 도구 이름: jenkins-processing (임의 지정)
→ Jenkins URL: http://jenkins.devops-edu.net
→ API Token: (STEP 1에서 발급한 Token)
→ [저장] 클릭
DevOps Console → 도구 관리 → SCM 도구 탭
[도구 등록] 클릭
→ 도구 유형: GitHub Enterprise
→ 도구 이름: ghe-processing
→ GitHub Enterprise URL: https://scp.sample.com
→ 인증 정보: Username / Personal Access Token 입력
→ [저장] 클릭
DevOps Console 좌측 → 테넌트 관리 → [테넌트 생성]
테넌트 이름: processing-tenant
설명: Processing 서비스 CI/CD
[생성] 클릭
테넌트 선택 → [프로젝트 그룹 생성]
그룹 이름: processing-group
[생성] 클릭
프로젝트 그룹 선택 → [새 프로젝트 생성]
| 항목 | 값 |
|---|---|
| 프로젝트 이름 | processing-cicd |
| 설명 | Processing Image Build & Deploy |
| 배포 대상 | Kubernetes |
| 클러스터 | (등록된 SKE 클러스터 선택) |
⚠️ 배포 대상을 Kubernetes로 반드시 선택해야 이후 단계에서 K8S 배포 옵션이 활성화됩니다.
클러스터가 없는 경우 → 클러스터 관리 (우측 상단 9점 아이콘) → 클러스터 등록
Application Templates 목록에서
→ 적합한 템플릿 선택 (Python 없을 경우 → Custom 또는 Generic 선택)
→ [다음] 클릭
| 항목 | 값 |
|---|---|
| SCM 도구 | ghe-processing (STEP 3에서 등록) |
| Repository URL | https://scp.sample.com/project/processing |
| 브랜치 | main |
| 항목 | 값 |
|---|---|
| Registry 유형 | SCP Container Registry |
| Registry | (생성된 SCR 레지스트리 선택) |
| AccessKey | SCR AccessKey |
| SecretKey | SCR SecretKey |
| 항목 | 값 |
|---|---|
| CICD 도구 | jenkins-processing (STEP 3에서 등록) |
| Jenkins 도메인 | jenkins.devops-edu.net |
프로젝트 요약 정보 확인
→ Code Repository, Image Registry, Build Pipeline 설정 확인
→ [프로젝트 생성] 클릭
DevOps Console에서 프로젝트가 생성되면 Jenkins에 연동 설정을 합니다.
브라우저 → http://jenkins.devops-edu.net
Jenkins 대시보드에서 DevOps Console 프로젝트와 연결된 폴더가 생성되어 있는지 확인합니다.
Jenkins 대시보드 → [새로운 Item] 클릭
→ Item 이름 입력: processing-deploy
→ [Pipeline] 선택
→ [OK] 클릭
Pipeline 설정 화면에서 하단 Pipeline 섹션으로 이동:
| 항목 | 설정값 |
|---|---|
| Definition | Pipeline script from SCM |
| SCM | Git |
| Repository URL | https://scp.sample.com/project/processing |
| Credentials | ghe-credential |
| Branch | */main |
| Script Path | Jenkinsfile |
[저장] 클릭
GitHub Enterprise Repository root에 아래 Jenkinsfile을 생성하여 저장합니다.
아래 Jenkinsfile에서 < > 로 표시된 항목을 실제 값으로 변경하세요.
| 변수 | 설명 | 예시 |
|---|---|---|
REGISTRY |
SCR 엔드포인트 | registry.samsungsdscloud.com |
SCR_PROJECT |
SCR 프로젝트명 | myproject |
HELM_RELEASE |
Helm Release 이름 | processing |
HELM_CHART |
Helm Chart 이름 | processing-chart |
HELM_NAMESPACE |
K8S Namespace | processing-ns |
pipeline {
agent any
// ✅ Trigger 없음 → 수동 실행 전용
// triggers {} 블록 미포함
environment {
// ─── Container Registry ───────────────────────────
REGISTRY = "<SCR_ENDPOINT>" // 예: registry.samsungsdscloud.com
SCR_PROJECT = "<SCR_PROJECT_NAME>" // SCR 내 프로젝트명
IMAGE_NAME = "processing"
IMAGE_TAG = "${BUILD_NUMBER}" // 빌드번호를 이미지 태그로 사용
FULL_IMAGE = "${REGISTRY}/${SCR_PROJECT}/${IMAGE_NAME}:${IMAGE_TAG}"
// ─── Helm ─────────────────────────────────────────
HELM_RELEASE = "<HELM_RELEASE_NAME>" // 기 배포된 Helm release 이름
HELM_CHART = "<HELM_CHART_NAME>" // 업로드된 Chart 이름
HELM_NAMESPACE = "<K8S_NAMESPACE>" // 배포 대상 Namespace
// ─── Jenkins Credential ID ─────────────────────────
SCR_CREDENTIAL = "scr-auth-credential"
GHE_CREDENTIAL = "ghe-credential"
KUBECONFIG_CRED = "kubeconfig-ske"
}
stages {
// ── Stage 1: 소스 체크아웃 ──────────────────────────
stage('Checkout') {
steps {
git(
url: 'https://scp.sample.com/project/processing',
branch: 'main',
credentialsId: "${GHE_CREDENTIAL}"
)
}
}
// ── Stage 2: 이미지 빌드 ────────────────────────────
// Dockerfile 위치: repo root (.)
// 핵심 명령: COPY app /opt/app
stage('Image Build') {
steps {
sh """
echo "=== Image Build Start ==="
echo "Image: ${FULL_IMAGE}"
docker build \\
-t ${FULL_IMAGE} \\
-f Dockerfile \\
.
echo "=== Image Build Complete ==="
"""
}
}
// ── Stage 3: 이미지 푸시 ────────────────────────────
stage('Image Push') {
steps {
withCredentials([
usernamePassword(
credentialsId: "${SCR_CREDENTIAL}",
usernameVariable: 'SCR_USER',
passwordVariable: 'SCR_PASS'
)
]) {
sh """
echo "=== Registry Login ==="
docker login ${REGISTRY} \\
-u \${SCR_USER} \\
-p \${SCR_PASS}
echo "=== Image Push ==="
docker push ${FULL_IMAGE}
docker logout ${REGISTRY}
echo "=== Push Complete ==="
"""
}
}
}
// ── Stage 4: Helm Upgrade (Pod 재시작) ───────────────
// kubectl 미사용 → helm upgrade로 이미지 갱신 및 Pod 재시작 처리
// image.tag 변경 → K8S Rolling Update 자동 수행
// podAnnotations.restartedAt 변경 → 동일 태그라도 강제 재시작 보장
stage('Helm Upgrade') {
steps {
withCredentials([
file(
credentialsId: "${KUBECONFIG_CRED}",
variable: 'KUBECONFIG'
)
]) {
sh """
echo "=== Helm Upgrade Start ==="
echo "Release: ${HELM_RELEASE}"
echo "Image: ${FULL_IMAGE}"
RESTART_TIME=\$(date +%s)
helm upgrade ${HELM_RELEASE} ${HELM_CHART} \\
--namespace ${HELM_NAMESPACE} \\
--reuse-values \\
--set image.repository="${REGISTRY}/${SCR_PROJECT}/${IMAGE_NAME}" \\
--set image.tag="${IMAGE_TAG}" \\
--set "podAnnotations.restartedAt=\${RESTART_TIME}" \\
--kubeconfig \${KUBECONFIG} \\
--wait \\
--timeout 5m
echo "=== Helm Upgrade Complete ==="
echo "=== New Image Applied: ${FULL_IMAGE} ==="
"""
}
}
}
}
post {
success {
echo "✅ Pipeline SUCCESS"
echo "Image: ${FULL_IMAGE}"
}
failure {
echo "❌ Pipeline FAILED — Build #${BUILD_NUMBER}"
}
}
}
# 로컬 또는 GitHub Enterprise 웹 UI에서 저장
git add Jenkinsfile
git commit -m "chore: add CI/CD pipeline for processing image build and deploy"
git push origin main
Jenkins 대시보드
→ processing-deploy (Pipeline Item) 선택
→ 좌측 메뉴 [지금 빌드 (Build Now)] 클릭
빌드 히스토리에서 실행 중인 빌드 번호 클릭
→ [Console Output] 클릭하여 실시간 로그 확인
정상 실행 시 로그 예시:
=== Image Build Start ===
Image: registry.samsungsdscloud.com/myproject/processing:42
...
Successfully built abc123def456
Successfully tagged registry.samsungsdscloud.com/myproject/processing:42
=== Image Build Complete ===
=== Registry Login ===
Login Succeeded
=== Image Push ===
The push refers to repository [registry.samsungsdscloud.com/myproject/processing]
42: digest: sha256:... size: ...
=== Push Complete ===
=== Helm Upgrade Start ===
Release: processing
Image: registry.samsungsdscloud.com/myproject/processing:42
Release "processing" has been upgraded. Happy Helming!
=== Helm Upgrade Complete ===
=== New Image Applied: registry.samsungsdscloud.com/myproject/processing:42 ===
Jenkins Pipeline 화면에서 Stage View로 각 단계 성공 여부를 시각적으로 확인할 수 있습니다:
[Checkout] → [Image Build] → [Image Push] → [Helm Upgrade]
✅ ✅ ✅ ✅
helm upgrade에서 Pod 재시작이 발생하는 두 가지 경우:
| 방법 | 원리 | 설명 |
|---|---|---|
image.tag 변경 |
Deployment spec 변경 → Rolling Update | 매 빌드마다 BUILD_NUMBER가 태그 → 자동 재시작 |
podAnnotations 변경 |
Pod template spec 변경 → Rolling Update | 동일 태그라도 강제 재시작 보장 |
업로드된 Helm Chart의 values.yaml에 아래 항목이 있는지 확인하고, 없으면 추가합니다.
# values.yaml
image:
repository: registry.samsungsdscloud.com/myproject/processing
tag: latest # 파이프라인 실행 시 --set image.tag=<BUILD_NUMBER>로 덮어씀
pullPolicy: Always # 항상 최신 이미지 Pull
# Pod 재시작 어노테이션 (파이프라인에서 --set으로 갱신)
podAnnotations:
restartedAt: "0"
Chart의 templates/deployment.yaml에서 image 및 annotations 참조 확인:
# templates/deployment.yaml 핵심 부분
metadata:
annotations:
{{- toYaml .Values.podAnnotations | nindent 8 }} # ← 이 줄 필요
spec:
template:
metadata:
annotations:
{{- toYaml .Values.podAnnotations | nindent 8 }} # ← Pod template에도 필요
spec:
containers:
- name: processing
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" # ← 이 줄 필요
imagePullPolicy: {{ .Values.image.pullPolicy }}
⚠️
podAnnotations가 Pod template metadata에 적용되어야 Pod 재시작이 발생합니다.
Deployment metadata에만 있으면 재시작되지 않습니다.
증상: cannot connect to the Docker daemon
원인 및 조치:
증상: unauthorized: authentication required
조치:
scr-auth-credential의 AccessKey/SecretKey 재확인증상: Error: Kubernetes cluster unreachable
조치:
kubeconfig-ske 등록 여부 확인증상: Error: chart "processing-chart" not found
조치:
HELM_CHART 변수값 확인 — 업로드된 Chart 이름과 정확히 일치해야 함증상: Helm upgrade는 성공했지만 Pod의 이미지가 갱신되지 않음
체크리스트:
values.yaml에 podAnnotations 항목 존재 여부templates/deployment.yaml의 Pod template metadata에 annotations 참조 여부imagePullPolicy: Always 설정 여부--reuse-values 옵션으로 이전 image.tag가 유지되는 경우 → --set image.tag가 정상 전달되는지 확인| 항목 | 출처 |
|---|---|
| SCP DevOps Service Configuration Guide v1.1 | cloud.samsungsds.com (공식 PDF, July 2023) |
| SCP Kubernetes Engine kubeconfig 다운로드 | cloud.samsungsds.com/serviceportal/knowledge/tutorials_detail/container/connect_k8sApiSvr.html |
| GitHub Enterprise Webhook 연동 | docs.github.com/en/enterprise-server (공식 문서) |
| Helm upgrade 공식 레퍼런스 | helm.sh/docs/helm/helm_upgrade |