Devops pipline manual » History » Version 1
HAEDONG KANG, 04/15/2026 11:38 PM
| 1 | 1 | HAEDONG KANG | # Devops pipline manual |
|---|---|---|---|
| 2 | |||
| 3 | |
||
| 4 | |||
| 5 | # SCP DevOps Console — Processing 이미지 빌드 및 Kubernetes 배포 파이프라인 매뉴얼 |
||
| 6 | |||
| 7 | **작성 기준:** SCP 공식 기술 가이드 (DevOps Service Configuration Guide v1.1, July 2023) |
||
| 8 | **환경 전제 조건:** SKE(Kubernetes Engine) ✅ · SCR(Container Registry) ✅ · Jenkins(K8S Apps) ✅ · GitHub Enterprise ✅ · Helm Chart ✅ |
||
| 9 | |||
| 10 | --- |
||
| 11 | |||
| 12 | ## 목차 |
||
| 13 | |||
| 14 | 1. [전체 파이프라인 구조](#1-전체-파이프라인-구조) |
||
| 15 | 2. [사전 확인 사항](#2-사전-확인-사항) |
||
| 16 | 3. [STEP 1 — Jenkins API Token 발급](#step-1--jenkins-api-token-발급) |
||
| 17 | 4. [STEP 2 — Jenkins Credential 등록](#step-2--jenkins-credential-등록) |
||
| 18 | 5. [STEP 3 — SCP DevOps Console 진입 및 도구 등록](#step-3--scp-devops-console-진입-및-도구-등록) |
||
| 19 | 6. [STEP 4 — DevOps 프로젝트 생성](#step-4--devops-프로젝트-생성) |
||
| 20 | 7. [STEP 5 — Jenkins Pipeline Item 생성](#step-5--jenkins-pipeline-item-생성) |
||
| 21 | 8. [STEP 6 — Jenkinsfile 작성 및 저장](#step-6--jenkinsfile-작성-및-저장) |
||
| 22 | 9. [STEP 7 — 파이프라인 수동 실행](#step-7--파이프라인-수동-실행) |
||
| 23 | 10. [Helm Chart 설정 — Pod 재시작 로직](#helm-chart-설정--pod-재시작-로직) |
||
| 24 | 11. [트러블슈팅](#트러블슈팅) |
||
| 25 | |||
| 26 | --- |
||
| 27 | |||
| 28 | ## 1. 전체 파이프라인 구조 |
||
| 29 | |||
| 30 | ``` |
||
| 31 | [수동 실행: Jenkins "Build Now"] |
||
| 32 | │ |
||
| 33 | ▼ |
||
| 34 | ┌─────────────────────────────────────────────────────────────┐ |
||
| 35 | │ Stage 1: Checkout │ |
||
| 36 | │ scp.sample.com/project/processing → main 브랜치 │ |
||
| 37 | └─────────────────────────────────────────────────────────────┘ |
||
| 38 | │ |
||
| 39 | ▼ |
||
| 40 | ┌─────────────────────────────────────────────────────────────┐ |
||
| 41 | │ Stage 2: Image Build │ |
||
| 42 | │ docker build -t <SCR>/<PROJECT>/processing:<BUILD_NO> . │ |
||
| 43 | │ └─ Dockerfile (repo root) │ |
||
| 44 | │ COPY app /opt/app │ |
||
| 45 | └─────────────────────────────────────────────────────────────┘ |
||
| 46 | │ |
||
| 47 | ▼ |
||
| 48 | ┌─────────────────────────────────────────────────────────────┐ |
||
| 49 | │ Stage 3: Image Push │ |
||
| 50 | │ docker push → SCP Container Registry (SCR) │ |
||
| 51 | └─────────────────────────────────────────────────────────────┘ |
||
| 52 | │ |
||
| 53 | ▼ |
||
| 54 | ┌─────────────────────────────────────────────────────────────┐ |
||
| 55 | │ Stage 4: Helm Upgrade (Pod 재시작 포함) │ |
||
| 56 | │ helm upgrade <release> <chart> │ |
||
| 57 | │ --set image.tag=<BUILD_NO> ← 이미지 갱신 │ |
||
| 58 | │ --set podAnnotations.restartedAt=<timestamp> │ |
||
| 59 | │ ← Pod 강제 재시작 트리거 │ |
||
| 60 | └─────────────────────────────────────────────────────────────┘ |
||
| 61 | ``` |
||
| 62 | |||
| 63 | > **중요:** `kubectl` 명령 대신 `helm upgrade`를 사용하여 이미지 갱신 및 Pod 재시작을 처리합니다. |
||
| 64 | > `image.tag` 값이 변경되면 Kubernetes가 자동으로 Rolling Update를 수행합니다. |
||
| 65 | |||
| 66 | --- |
||
| 67 | |||
| 68 | ## 2. 사전 확인 사항 |
||
| 69 | |||
| 70 | 파이프라인 생성 전 아래 정보를 미리 수집합니다. |
||
| 71 | |||
| 72 | | 항목 | 확인 방법 | 예시 | |
||
| 73 | |------|-----------|------| |
||
| 74 | | SCR 엔드포인트 | SCP Console → Container → Container Registry → 레지스트리 선택 → 엔드포인트 확인 | `registry.samsungsdscloud.com` | |
||
| 75 | | SCR 프로젝트명 | Container Registry 생성 시 지정한 이름 | `myproject` | |
||
| 76 | | SCR AccessKey / SecretKey | SCP Console → IAM → 액세스 키 관리 | `AKID...` / `SECRET...` | |
||
| 77 | | Jenkins 도메인 | SCP Console → Container → Kubernetes Apps → Jenkins 상세 → 도메인 확인 | `jenkins.devops-edu.net` | |
||
| 78 | | GitHub Enterprise URL | SCP Console → DevOps Tools → GitHub Enterprise | `scp.sample.com` | |
||
| 79 | | GitHub Token | GitHub Enterprise → Settings → Developer settings → Personal Access Tokens | `ghp_xxx...` | |
||
| 80 | | Helm Release 이름 | 기 배포된 Helm release 이름 | `processing` | |
||
| 81 | | Helm Chart 이름 | 업로드된 Chart 이름 | `processing-chart` | |
||
| 82 | | K8S Namespace | 애플리케이션이 배포된 Namespace | `processing-ns` | |
||
| 83 | | SKE kubeconfig (Helm 실행용) | SCP Console → Container → Kubernetes Engine → 클러스터 → kubeconfig 다운로드 | YAML 파일 | |
||
| 84 | |||
| 85 | --- |
||
| 86 | |||
| 87 | ## STEP 1 — Jenkins API Token 발급 |
||
| 88 | |||
| 89 | Jenkins에서 DevOps Console과 연동하기 위한 API Token을 발급합니다. |
||
| 90 | |||
| 91 | ### 1-1. Jenkins 접속 |
||
| 92 | |||
| 93 | 브라우저에서 Jenkins 도메인 접속: |
||
| 94 | ``` |
||
| 95 | http://jenkins.devops-edu.net (실제 Jenkins 도메인으로 변경) |
||
| 96 | ``` |
||
| 97 | |||
| 98 | ### 1-2. 로그인 |
||
| 99 | |||
| 100 | Jenkins 생성 시 설정한 `admin` 계정과 비밀번호로 로그인합니다. |
||
| 101 | |||
| 102 | ### 1-3. API Token 생성 |
||
| 103 | |||
| 104 | ``` |
||
| 105 | 우측 상단 [admin 계정명] 클릭 |
||
| 106 | → Configure (또는 Settings) |
||
| 107 | → API Token 섹션 |
||
| 108 | → [Add new Token] 버튼 클릭 |
||
| 109 | → Token 이름 입력 (예: devops-console-token) |
||
| 110 | → [Generate] 클릭 |
||
| 111 | → 생성된 Token 값 복사하여 보관 |
||
| 112 | ``` |
||
| 113 | |||
| 114 | > ⚠️ **주의:** Token은 생성 직후 한 번만 표시됩니다. 반드시 별도로 저장하세요. |
||
| 115 | |||
| 116 | --- |
||
| 117 | |||
| 118 | ## STEP 2 — Jenkins Credential 등록 |
||
| 119 | |||
| 120 | Jenkins Pipeline에서 사용할 인증 정보를 사전 등록합니다. |
||
| 121 | |||
| 122 | ### 2-1. Jenkins 관리 메뉴 진입 |
||
| 123 | |||
| 124 | ``` |
||
| 125 | Jenkins 대시보드 → Manage Jenkins → Credentials |
||
| 126 | → System → Global credentials (unrestricted) |
||
| 127 | → [Add Credentials] 클릭 |
||
| 128 | ``` |
||
| 129 | |||
| 130 | ### 2-2. GitHub Enterprise Credential 등록 |
||
| 131 | |||
| 132 | | 필드 | 값 | |
||
| 133 | |------|-----| |
||
| 134 | | Kind | **Username with password** | |
||
| 135 | | Username | GitHub Enterprise 계정 | |
||
| 136 | | Password | GitHub Enterprise Personal Access Token | |
||
| 137 | | ID | `ghe-credential` | |
||
| 138 | | Description | SCP GitHub Enterprise | |
||
| 139 | |||
| 140 | ### 2-3. SCP Container Registry Credential 등록 |
||
| 141 | |||
| 142 | | 필드 | 값 | |
||
| 143 | |------|-----| |
||
| 144 | | Kind | **Username with password** | |
||
| 145 | | Username | SCR AccessKey | |
||
| 146 | | Password | SCR SecretKey | |
||
| 147 | | ID | `scr-auth-credential` | |
||
| 148 | | Description | SCP Container Registry 인증키 | |
||
| 149 | |||
| 150 | ### 2-4. kubeconfig Secret File 등록 (Helm 실행용) |
||
| 151 | |||
| 152 | > Helm 명령 실행을 위해 SKE kubeconfig가 필요합니다. |
||
| 153 | |||
| 154 | ``` |
||
| 155 | SCP Console → Container → Kubernetes Engine |
||
| 156 | → 클러스터 선택 → [kubeconfig 다운로드] 버튼 클릭 |
||
| 157 | ``` |
||
| 158 | |||
| 159 | 다운로드한 파일을 Jenkins Credential에 등록: |
||
| 160 | |||
| 161 | | 필드 | 값 | |
||
| 162 | |------|-----| |
||
| 163 | | Kind | **Secret file** | |
||
| 164 | | File | 다운로드한 kubeconfig YAML 파일 업로드 | |
||
| 165 | | ID | `kubeconfig-ske` | |
||
| 166 | | Description | SKE Cluster kubeconfig | |
||
| 167 | |||
| 168 | --- |
||
| 169 | |||
| 170 | ## STEP 3 — SCP DevOps Console 진입 및 도구 등록 |
||
| 171 | |||
| 172 | ### 3-1. DevOps Console 접속 |
||
| 173 | |||
| 174 | ``` |
||
| 175 | SCP Console (https://cloud.samsungsds.com/serviceportal) |
||
| 176 | → 좌측 메뉴: DevOps Tools |
||
| 177 | → DevOps Service |
||
| 178 | → [DevOps Console 이동] 또는 [DevOps Console 접속] 클릭 |
||
| 179 | ``` |
||
| 180 | |||
| 181 | > ⚠️ DevOps Service를 신청하지 않은 경우 → [DevOps Service 신청] 먼저 진행 |
||
| 182 | |||
| 183 | ### 3-2. Jenkins CICD 도구 등록 |
||
| 184 | |||
| 185 | DevOps Console 좌측 메뉴 → **도구 관리(Tool Management)** → **CICD 도구** 탭 |
||
| 186 | |||
| 187 | ``` |
||
| 188 | [도구 등록] 클릭 |
||
| 189 | → 도구 유형: Jenkins |
||
| 190 | → 도구 이름: jenkins-processing (임의 지정) |
||
| 191 | → Jenkins URL: http://jenkins.devops-edu.net |
||
| 192 | → API Token: (STEP 1에서 발급한 Token) |
||
| 193 | → [저장] 클릭 |
||
| 194 | ``` |
||
| 195 | |||
| 196 | ### 3-3. GitHub Enterprise SCM 도구 등록 |
||
| 197 | |||
| 198 | DevOps Console → **도구 관리** → **SCM 도구** 탭 |
||
| 199 | |||
| 200 | ``` |
||
| 201 | [도구 등록] 클릭 |
||
| 202 | → 도구 유형: GitHub Enterprise |
||
| 203 | → 도구 이름: ghe-processing |
||
| 204 | → GitHub Enterprise URL: https://scp.sample.com |
||
| 205 | → 인증 정보: Username / Personal Access Token 입력 |
||
| 206 | → [저장] 클릭 |
||
| 207 | ``` |
||
| 208 | |||
| 209 | --- |
||
| 210 | |||
| 211 | ## STEP 4 — DevOps 프로젝트 생성 |
||
| 212 | |||
| 213 | ### 4-1. Tenant 생성 (최초 1회) |
||
| 214 | |||
| 215 | DevOps Console 좌측 → **테넌트 관리** → **[테넌트 생성]** |
||
| 216 | |||
| 217 | ``` |
||
| 218 | 테넌트 이름: processing-tenant |
||
| 219 | 설명: Processing 서비스 CI/CD |
||
| 220 | [생성] 클릭 |
||
| 221 | ``` |
||
| 222 | |||
| 223 | ### 4-2. Project Group 생성 |
||
| 224 | |||
| 225 | 테넌트 선택 → **[프로젝트 그룹 생성]** |
||
| 226 | |||
| 227 | ``` |
||
| 228 | 그룹 이름: processing-group |
||
| 229 | [생성] 클릭 |
||
| 230 | ``` |
||
| 231 | |||
| 232 | ### 4-3. Project 생성 |
||
| 233 | |||
| 234 | 프로젝트 그룹 선택 → **[새 프로젝트 생성]** |
||
| 235 | |||
| 236 | #### 기본 정보 입력 |
||
| 237 | |||
| 238 | | 항목 | 값 | |
||
| 239 | |------|-----| |
||
| 240 | | 프로젝트 이름 | processing-cicd | |
||
| 241 | | 설명 | Processing Image Build & Deploy | |
||
| 242 | | **배포 대상** | **Kubernetes** | |
||
| 243 | | 클러스터 | (등록된 SKE 클러스터 선택) | |
||
| 244 | |||
| 245 | > ⚠️ **배포 대상을 Kubernetes로 반드시 선택**해야 이후 단계에서 K8S 배포 옵션이 활성화됩니다. |
||
| 246 | |||
| 247 | 클러스터가 없는 경우 → **클러스터 관리** (우측 상단 9점 아이콘) → 클러스터 등록 |
||
| 248 | |||
| 249 | #### App Template 선택 |
||
| 250 | |||
| 251 | ``` |
||
| 252 | Application Templates 목록에서 |
||
| 253 | → 적합한 템플릿 선택 (Python 없을 경우 → Custom 또는 Generic 선택) |
||
| 254 | → [다음] 클릭 |
||
| 255 | ``` |
||
| 256 | |||
| 257 | #### Code Repository 설정 |
||
| 258 | |||
| 259 | | 항목 | 값 | |
||
| 260 | |------|-----| |
||
| 261 | | SCM 도구 | ghe-processing (STEP 3에서 등록) | |
||
| 262 | | Repository URL | `https://scp.sample.com/project/processing` | |
||
| 263 | | 브랜치 | `main` | |
||
| 264 | |||
| 265 | #### Image Registry 설정 |
||
| 266 | |||
| 267 | | 항목 | 값 | |
||
| 268 | |------|-----| |
||
| 269 | | Registry 유형 | **SCP Container Registry** | |
||
| 270 | | Registry | (생성된 SCR 레지스트리 선택) | |
||
| 271 | | AccessKey | SCR AccessKey | |
||
| 272 | | SecretKey | SCR SecretKey | |
||
| 273 | |||
| 274 | #### Build Pipeline 설정 |
||
| 275 | |||
| 276 | | 항목 | 값 | |
||
| 277 | |------|-----| |
||
| 278 | | CICD 도구 | jenkins-processing (STEP 3에서 등록) | |
||
| 279 | | Jenkins 도메인 | jenkins.devops-edu.net | |
||
| 280 | |||
| 281 | #### 최종 확인 및 생성 |
||
| 282 | |||
| 283 | ``` |
||
| 284 | 프로젝트 요약 정보 확인 |
||
| 285 | → Code Repository, Image Registry, Build Pipeline 설정 확인 |
||
| 286 | → [프로젝트 생성] 클릭 |
||
| 287 | ``` |
||
| 288 | |||
| 289 | --- |
||
| 290 | |||
| 291 | ## STEP 5 — Jenkins Pipeline Item 생성 |
||
| 292 | |||
| 293 | DevOps Console에서 프로젝트가 생성되면 Jenkins에 연동 설정을 합니다. |
||
| 294 | |||
| 295 | ### 5-1. Jenkins 대시보드 접속 |
||
| 296 | |||
| 297 | ``` |
||
| 298 | 브라우저 → http://jenkins.devops-edu.net |
||
| 299 | ``` |
||
| 300 | |||
| 301 | ### 5-2. 프로젝트 폴더 확인 |
||
| 302 | |||
| 303 | Jenkins 대시보드에서 DevOps Console 프로젝트와 연결된 폴더가 생성되어 있는지 확인합니다. |
||
| 304 | |||
| 305 | ### 5-3. New Item 생성 |
||
| 306 | |||
| 307 | ``` |
||
| 308 | Jenkins 대시보드 → [새로운 Item] 클릭 |
||
| 309 | → Item 이름 입력: processing-deploy |
||
| 310 | → [Pipeline] 선택 |
||
| 311 | → [OK] 클릭 |
||
| 312 | ``` |
||
| 313 | |||
| 314 | ### 5-4. Pipeline 설정 |
||
| 315 | |||
| 316 | Pipeline 설정 화면에서 하단 **Pipeline** 섹션으로 이동: |
||
| 317 | |||
| 318 | | 항목 | 설정값 | |
||
| 319 | |------|--------| |
||
| 320 | | Definition | **Pipeline script from SCM** | |
||
| 321 | | SCM | **Git** | |
||
| 322 | | Repository URL | `https://scp.sample.com/project/processing` | |
||
| 323 | | Credentials | ghe-credential | |
||
| 324 | | Branch | `*/main` | |
||
| 325 | | Script Path | `Jenkinsfile` | |
||
| 326 | |||
| 327 | ``` |
||
| 328 | [저장] 클릭 |
||
| 329 | ``` |
||
| 330 | |||
| 331 | --- |
||
| 332 | |||
| 333 | ## STEP 6 — Jenkinsfile 작성 및 저장 |
||
| 334 | |||
| 335 | GitHub Enterprise Repository root에 아래 `Jenkinsfile`을 생성하여 저장합니다. |
||
| 336 | |||
| 337 | ### 6-1. 환경변수 값 확인 후 수정 필요 항목 |
||
| 338 | |||
| 339 | 아래 `Jenkinsfile`에서 `<` `>` 로 표시된 항목을 실제 값으로 변경하세요. |
||
| 340 | |||
| 341 | | 변수 | 설명 | 예시 | |
||
| 342 | |------|------|------| |
||
| 343 | | `REGISTRY` | SCR 엔드포인트 | `registry.samsungsdscloud.com` | |
||
| 344 | | `SCR_PROJECT` | SCR 프로젝트명 | `myproject` | |
||
| 345 | | `HELM_RELEASE` | Helm Release 이름 | `processing` | |
||
| 346 | | `HELM_CHART` | Helm Chart 이름 | `processing-chart` | |
||
| 347 | | `HELM_NAMESPACE` | K8S Namespace | `processing-ns` | |
||
| 348 | |||
| 349 | ### 6-2. Jenkinsfile |
||
| 350 | |||
| 351 | ```groovy |
||
| 352 | pipeline { |
||
| 353 | agent any |
||
| 354 | |||
| 355 | // ✅ Trigger 없음 → 수동 실행 전용 |
||
| 356 | // triggers {} 블록 미포함 |
||
| 357 | |||
| 358 | environment { |
||
| 359 | // ─── Container Registry ─────────────────────────── |
||
| 360 | REGISTRY = "<SCR_ENDPOINT>" // 예: registry.samsungsdscloud.com |
||
| 361 | SCR_PROJECT = "<SCR_PROJECT_NAME>" // SCR 내 프로젝트명 |
||
| 362 | IMAGE_NAME = "processing" |
||
| 363 | IMAGE_TAG = "${BUILD_NUMBER}" // 빌드번호를 이미지 태그로 사용 |
||
| 364 | FULL_IMAGE = "${REGISTRY}/${SCR_PROJECT}/${IMAGE_NAME}:${IMAGE_TAG}" |
||
| 365 | |||
| 366 | // ─── Helm ───────────────────────────────────────── |
||
| 367 | HELM_RELEASE = "<HELM_RELEASE_NAME>" // 기 배포된 Helm release 이름 |
||
| 368 | HELM_CHART = "<HELM_CHART_NAME>" // 업로드된 Chart 이름 |
||
| 369 | HELM_NAMESPACE = "<K8S_NAMESPACE>" // 배포 대상 Namespace |
||
| 370 | |||
| 371 | // ─── Jenkins Credential ID ───────────────────────── |
||
| 372 | SCR_CREDENTIAL = "scr-auth-credential" |
||
| 373 | GHE_CREDENTIAL = "ghe-credential" |
||
| 374 | KUBECONFIG_CRED = "kubeconfig-ske" |
||
| 375 | } |
||
| 376 | |||
| 377 | stages { |
||
| 378 | |||
| 379 | // ── Stage 1: 소스 체크아웃 ────────────────────────── |
||
| 380 | stage('Checkout') { |
||
| 381 | steps { |
||
| 382 | git( |
||
| 383 | url: 'https://scp.sample.com/project/processing', |
||
| 384 | branch: 'main', |
||
| 385 | credentialsId: "${GHE_CREDENTIAL}" |
||
| 386 | ) |
||
| 387 | } |
||
| 388 | } |
||
| 389 | |||
| 390 | // ── Stage 2: 이미지 빌드 ──────────────────────────── |
||
| 391 | // Dockerfile 위치: repo root (.) |
||
| 392 | // 핵심 명령: COPY app /opt/app |
||
| 393 | stage('Image Build') { |
||
| 394 | steps { |
||
| 395 | sh """ |
||
| 396 | echo "=== Image Build Start ===" |
||
| 397 | echo "Image: ${FULL_IMAGE}" |
||
| 398 | docker build \\ |
||
| 399 | -t ${FULL_IMAGE} \\ |
||
| 400 | -f Dockerfile \\ |
||
| 401 | . |
||
| 402 | echo "=== Image Build Complete ===" |
||
| 403 | """ |
||
| 404 | } |
||
| 405 | } |
||
| 406 | |||
| 407 | // ── Stage 3: 이미지 푸시 ──────────────────────────── |
||
| 408 | stage('Image Push') { |
||
| 409 | steps { |
||
| 410 | withCredentials([ |
||
| 411 | usernamePassword( |
||
| 412 | credentialsId: "${SCR_CREDENTIAL}", |
||
| 413 | usernameVariable: 'SCR_USER', |
||
| 414 | passwordVariable: 'SCR_PASS' |
||
| 415 | ) |
||
| 416 | ]) { |
||
| 417 | sh """ |
||
| 418 | echo "=== Registry Login ===" |
||
| 419 | docker login ${REGISTRY} \\ |
||
| 420 | -u \${SCR_USER} \\ |
||
| 421 | -p \${SCR_PASS} |
||
| 422 | |||
| 423 | echo "=== Image Push ===" |
||
| 424 | docker push ${FULL_IMAGE} |
||
| 425 | |||
| 426 | docker logout ${REGISTRY} |
||
| 427 | echo "=== Push Complete ===" |
||
| 428 | """ |
||
| 429 | } |
||
| 430 | } |
||
| 431 | } |
||
| 432 | |||
| 433 | // ── Stage 4: Helm Upgrade (Pod 재시작) ─────────────── |
||
| 434 | // kubectl 미사용 → helm upgrade로 이미지 갱신 및 Pod 재시작 처리 |
||
| 435 | // image.tag 변경 → K8S Rolling Update 자동 수행 |
||
| 436 | // podAnnotations.restartedAt 변경 → 동일 태그라도 강제 재시작 보장 |
||
| 437 | stage('Helm Upgrade') { |
||
| 438 | steps { |
||
| 439 | withCredentials([ |
||
| 440 | file( |
||
| 441 | credentialsId: "${KUBECONFIG_CRED}", |
||
| 442 | variable: 'KUBECONFIG' |
||
| 443 | ) |
||
| 444 | ]) { |
||
| 445 | sh """ |
||
| 446 | echo "=== Helm Upgrade Start ===" |
||
| 447 | echo "Release: ${HELM_RELEASE}" |
||
| 448 | echo "Image: ${FULL_IMAGE}" |
||
| 449 | |||
| 450 | RESTART_TIME=\$(date +%s) |
||
| 451 | |||
| 452 | helm upgrade ${HELM_RELEASE} ${HELM_CHART} \\ |
||
| 453 | --namespace ${HELM_NAMESPACE} \\ |
||
| 454 | --reuse-values \\ |
||
| 455 | --set image.repository="${REGISTRY}/${SCR_PROJECT}/${IMAGE_NAME}" \\ |
||
| 456 | --set image.tag="${IMAGE_TAG}" \\ |
||
| 457 | --set "podAnnotations.restartedAt=\${RESTART_TIME}" \\ |
||
| 458 | --kubeconfig \${KUBECONFIG} \\ |
||
| 459 | --wait \\ |
||
| 460 | --timeout 5m |
||
| 461 | |||
| 462 | echo "=== Helm Upgrade Complete ===" |
||
| 463 | echo "=== New Image Applied: ${FULL_IMAGE} ===" |
||
| 464 | """ |
||
| 465 | } |
||
| 466 | } |
||
| 467 | } |
||
| 468 | } |
||
| 469 | |||
| 470 | post { |
||
| 471 | success { |
||
| 472 | echo "✅ Pipeline SUCCESS" |
||
| 473 | echo "Image: ${FULL_IMAGE}" |
||
| 474 | } |
||
| 475 | failure { |
||
| 476 | echo "❌ Pipeline FAILED — Build #${BUILD_NUMBER}" |
||
| 477 | } |
||
| 478 | } |
||
| 479 | } |
||
| 480 | ``` |
||
| 481 | |||
| 482 | ### 6-3. Jenkinsfile Git 저장 |
||
| 483 | |||
| 484 | ```bash |
||
| 485 | # 로컬 또는 GitHub Enterprise 웹 UI에서 저장 |
||
| 486 | git add Jenkinsfile |
||
| 487 | git commit -m "chore: add CI/CD pipeline for processing image build and deploy" |
||
| 488 | git push origin main |
||
| 489 | ``` |
||
| 490 | |||
| 491 | --- |
||
| 492 | |||
| 493 | ## STEP 7 — 파이프라인 수동 실행 |
||
| 494 | |||
| 495 | ### 7-1. Jenkins Pipeline 실행 |
||
| 496 | |||
| 497 | ``` |
||
| 498 | Jenkins 대시보드 |
||
| 499 | → processing-deploy (Pipeline Item) 선택 |
||
| 500 | → 좌측 메뉴 [지금 빌드 (Build Now)] 클릭 |
||
| 501 | ``` |
||
| 502 | |||
| 503 | ### 7-2. 빌드 진행 상태 확인 |
||
| 504 | |||
| 505 | ``` |
||
| 506 | 빌드 히스토리에서 실행 중인 빌드 번호 클릭 |
||
| 507 | → [Console Output] 클릭하여 실시간 로그 확인 |
||
| 508 | ``` |
||
| 509 | |||
| 510 | 정상 실행 시 로그 예시: |
||
| 511 | ``` |
||
| 512 | === Image Build Start === |
||
| 513 | Image: registry.samsungsdscloud.com/myproject/processing:42 |
||
| 514 | ... |
||
| 515 | Successfully built abc123def456 |
||
| 516 | Successfully tagged registry.samsungsdscloud.com/myproject/processing:42 |
||
| 517 | === Image Build Complete === |
||
| 518 | |||
| 519 | === Registry Login === |
||
| 520 | Login Succeeded |
||
| 521 | === Image Push === |
||
| 522 | The push refers to repository [registry.samsungsdscloud.com/myproject/processing] |
||
| 523 | 42: digest: sha256:... size: ... |
||
| 524 | === Push Complete === |
||
| 525 | |||
| 526 | === Helm Upgrade Start === |
||
| 527 | Release: processing |
||
| 528 | Image: registry.samsungsdscloud.com/myproject/processing:42 |
||
| 529 | Release "processing" has been upgraded. Happy Helming! |
||
| 530 | === Helm Upgrade Complete === |
||
| 531 | === New Image Applied: registry.samsungsdscloud.com/myproject/processing:42 === |
||
| 532 | ``` |
||
| 533 | |||
| 534 | ### 7-3. Stage 별 결과 확인 |
||
| 535 | |||
| 536 | Jenkins Pipeline 화면에서 Stage View로 각 단계 성공 여부를 시각적으로 확인할 수 있습니다: |
||
| 537 | |||
| 538 | ``` |
||
| 539 | [Checkout] → [Image Build] → [Image Push] → [Helm Upgrade] |
||
| 540 | ✅ ✅ ✅ ✅ |
||
| 541 | ``` |
||
| 542 | |||
| 543 | --- |
||
| 544 | |||
| 545 | ## Helm Chart 설정 — Pod 재시작 로직 |
||
| 546 | |||
| 547 | ### Pod 재시작 원리 |
||
| 548 | |||
| 549 | `helm upgrade`에서 Pod 재시작이 발생하는 두 가지 경우: |
||
| 550 | |||
| 551 | | 방법 | 원리 | 설명 | |
||
| 552 | |------|------|------| |
||
| 553 | | `image.tag` 변경 | Deployment spec 변경 → Rolling Update | 매 빌드마다 `BUILD_NUMBER`가 태그 → 자동 재시작 | |
||
| 554 | | `podAnnotations` 변경 | Pod template spec 변경 → Rolling Update | 동일 태그라도 강제 재시작 보장 | |
||
| 555 | |||
| 556 | ### Helm Chart values.yaml 확인/수정 |
||
| 557 | |||
| 558 | 업로드된 Helm Chart의 `values.yaml`에 아래 항목이 있는지 확인하고, 없으면 추가합니다. |
||
| 559 | |||
| 560 | ```yaml |
||
| 561 | # values.yaml |
||
| 562 | |||
| 563 | image: |
||
| 564 | repository: registry.samsungsdscloud.com/myproject/processing |
||
| 565 | tag: latest # 파이프라인 실행 시 --set image.tag=<BUILD_NUMBER>로 덮어씀 |
||
| 566 | pullPolicy: Always # 항상 최신 이미지 Pull |
||
| 567 | |||
| 568 | # Pod 재시작 어노테이션 (파이프라인에서 --set으로 갱신) |
||
| 569 | podAnnotations: |
||
| 570 | restartedAt: "0" |
||
| 571 | ``` |
||
| 572 | |||
| 573 | ### Deployment 템플릿 확인 |
||
| 574 | |||
| 575 | Chart의 `templates/deployment.yaml`에서 image 및 annotations 참조 확인: |
||
| 576 | |||
| 577 | ```yaml |
||
| 578 | # templates/deployment.yaml 핵심 부분 |
||
| 579 | |||
| 580 | metadata: |
||
| 581 | annotations: |
||
| 582 | {{- toYaml .Values.podAnnotations | nindent 8 }} # ← 이 줄 필요 |
||
| 583 | |||
| 584 | spec: |
||
| 585 | template: |
||
| 586 | metadata: |
||
| 587 | annotations: |
||
| 588 | {{- toYaml .Values.podAnnotations | nindent 8 }} # ← Pod template에도 필요 |
||
| 589 | spec: |
||
| 590 | containers: |
||
| 591 | - name: processing |
||
| 592 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" # ← 이 줄 필요 |
||
| 593 | imagePullPolicy: {{ .Values.image.pullPolicy }} |
||
| 594 | ``` |
||
| 595 | |||
| 596 | > ⚠️ `podAnnotations`가 **Pod template metadata**에 적용되어야 Pod 재시작이 발생합니다. |
||
| 597 | > Deployment metadata에만 있으면 재시작되지 않습니다. |
||
| 598 | |||
| 599 | --- |
||
| 600 | |||
| 601 | ## 트러블슈팅 |
||
| 602 | |||
| 603 | ### Issue 1: Docker build 실패 |
||
| 604 | |||
| 605 | **증상:** `cannot connect to the Docker daemon` |
||
| 606 | |||
| 607 | **원인 및 조치:** |
||
| 608 | - Jenkins Pod에 Docker daemon 접근 권한 없음 |
||
| 609 | - Jenkins K8S Apps가 Docker socket을 마운트하고 있는지 확인 |
||
| 610 | - SCP Console → K8S Apps → Jenkins 상세 → Volume 설정 확인 |
||
| 611 | |||
| 612 | --- |
||
| 613 | |||
| 614 | ### Issue 2: SCR Push 실패 (unauthorized) |
||
| 615 | |||
| 616 | **증상:** `unauthorized: authentication required` |
||
| 617 | |||
| 618 | **조치:** |
||
| 619 | 1. Jenkins Credential `scr-auth-credential`의 AccessKey/SecretKey 재확인 |
||
| 620 | 2. SCP Console → IAM → 액세스 키 유효 여부 확인 |
||
| 621 | 3. SCR 레지스트리 엔드포인트 정확성 확인 |
||
| 622 | |||
| 623 | --- |
||
| 624 | |||
| 625 | ### Issue 3: Helm upgrade 실패 (kubeconfig) |
||
| 626 | |||
| 627 | **증상:** `Error: Kubernetes cluster unreachable` |
||
| 628 | |||
| 629 | **조치:** |
||
| 630 | 1. Jenkins Credential `kubeconfig-ske` 등록 여부 확인 |
||
| 631 | 2. SCP Console → K8S Engine → 클러스터 → kubeconfig 재다운로드 후 Credential 갱신 |
||
| 632 | |||
| 633 | --- |
||
| 634 | |||
| 635 | ### Issue 4: Helm upgrade 실패 (chart not found) |
||
| 636 | |||
| 637 | **증상:** `Error: chart "processing-chart" not found` |
||
| 638 | |||
| 639 | **조치:** |
||
| 640 | 1. `HELM_CHART` 변수값 확인 — 업로드된 Chart 이름과 정확히 일치해야 함 |
||
| 641 | 2. Helm repo 또는 로컬 Chart 경로 확인 |
||
| 642 | |||
| 643 | --- |
||
| 644 | |||
| 645 | ### Issue 5: Pod가 재시작되지 않음 |
||
| 646 | |||
| 647 | **증상:** Helm upgrade는 성공했지만 Pod의 이미지가 갱신되지 않음 |
||
| 648 | |||
| 649 | **체크리스트:** |
||
| 650 | - [ ] `values.yaml`에 `podAnnotations` 항목 존재 여부 |
||
| 651 | - [ ] `templates/deployment.yaml`의 Pod template metadata에 annotations 참조 여부 |
||
| 652 | - [ ] `imagePullPolicy: Always` 설정 여부 |
||
| 653 | - [ ] `--reuse-values` 옵션으로 이전 image.tag가 유지되는 경우 → `--set image.tag`가 정상 전달되는지 확인 |
||
| 654 | |||
| 655 | --- |
||
| 656 | |||
| 657 | ## 참고 정보 |
||
| 658 | |||
| 659 | | 항목 | 출처 | |
||
| 660 | |------|------| |
||
| 661 | | SCP DevOps Service Configuration Guide v1.1 | cloud.samsungsds.com (공식 PDF, July 2023) | |
||
| 662 | | SCP Kubernetes Engine kubeconfig 다운로드 | cloud.samsungsds.com/serviceportal/knowledge/tutorials_detail/container/connect_k8sApiSvr.html | |
||
| 663 | | GitHub Enterprise Webhook 연동 | docs.github.com/en/enterprise-server (공식 문서) | |
||
| 664 | | Helm upgrade 공식 레퍼런스 | helm.sh/docs/helm/helm_upgrade | |