{"id":12003,"date":"2026-10-05T11:54:42","date_gmt":"2026-10-05T02:54:42","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12003"},"modified":"2026-10-06T14:32:21","modified_gmt":"2026-10-06T05:32:21","slug":"kubernetes-spring-boot-hello-world-%ec%99%80-%ec%a0%95%ec%a0%81-%eb%a6%ac%ec%86%8c%ec%8a%a4-%ed%94%84%eb%a1%9c%ec%a0%9d%ed%8a%b8-%eb%b0%b0%ed%8f%ac%ed%95%98%ea%b8%b0","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12003","title":{"rendered":"Kubernetes \u2013 Spring Boot Hello World \uc640 \uc815\uc801 \ub9ac\uc18c\uc2a4 \ud504\ub85c\uc81d\ud2b8 \ubc30\ud3ec\ud558\uae30"},"content":{"rendered":"<h1>Kubernetes \u2013 Spring Boot Hello World \uc640 \uc815\uc801 \ub9ac\uc18c\uc2a4 \ud504\ub85c\uc81d\ud2b8 \ubc30\ud3ec\ud558\uae30<\/h1>\n<blockquote>\n<p>\uc774 \uae00\uc740 <a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=11993\">Kubernetes \u2013 ArgoCD + Helm \uc73c\ub85c Native Helm + GitOps Values \ud328\ud134 \uad6c\uc131\ud558\uae30<\/a> \uc758 \ud6c4\uc18d\ud3b8\uc785\ub2c8\ub2e4. 2\ud3b8\uc5d0\uc11c \ub9cc\ub4e0 \ub2e8\uc77c \ub178\ub4dc \ud074\ub7ec\uc2a4\ud130(Debian 13 \/ Raspberry Pi, <code>192.168.20.206<\/code>)\uc640 <code>k8s-gitops<\/code> \uc800\uc7a5\uc18c\ub97c \uadf8\ub300\ub85c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<h2>0. \ubaa9\ud45c<\/h2>\n<p>\uc774\ubc88 \uae00\uc5d0\uc11c\ub294 <strong>\uc9c1\uc811 \ub9cc\ub4e0 \uc560\ud50c\ub9ac\ucf00\uc774\uc158 2\uac1c<\/strong>\ub97c 2\ud3b8\uacfc \uac19\uc740 Native Helm + GitOps Values \ud328\ud134\uc73c\ub85c \ubc30\ud3ec\ud569\ub2c8\ub2e4.<\/p>\n<ul>\n<li><strong>spring-hello<\/strong> : Spring Boot \ub85c \ub9cc\ub4e0 Hello World \uc6f9 \uc560\ud50c\ub9ac\ucf00\uc774\uc158 (Thymeleaf \ud398\uc774\uc9c0 1\uc7a5 + JSON API 1\uac1c)<\/li>\n<li><strong>static-web<\/strong> : \uc774\ubbf8\uc9c0, CSS \uac19\uc740 \uc815\uc801 \ub9ac\uc18c\uc2a4\ub9cc \uc11c\ube59\ud558\ub294 nginx \ucee8\ud14c\uc774\ub108<\/li>\n<\/ul>\n<p>spring-hello \uc758 HTML \ud398\uc774\uc9c0\ub294 CSS \uc640 \uc774\ubbf8\uc9c0\ub97c <strong>static-web \uc5d0\uc11c \ubd88\ub7ec\uc635\ub2c8\ub2e4.<\/strong> \uc2e4\uc81c \uc11c\ube44\uc2a4\uc5d0\uc11c WAS \uc640 \uc815\uc801 \ub9ac\uc18c\uc2a4 \uc11c\ubc84(\ub610\ub294 CDN)\ub97c \ubd84\ub9ac\ud558\ub294 \uad6c\uc870\ub97c \ud648\ub7a9\uc5d0\uc11c \uadf8\ub300\ub85c \uc5f0\uc2b5\ud558\ub294 \uac83\uc774 \ubaa9\uc801\uc785\ub2c8\ub2e4.<\/p>\n<p>2\ud3b8\uacfc \ub2ec\ub77c\uc9c0\ub294 \uc810\uc740 \ud558\ub098\uc785\ub2c8\ub2e4. nginx \uacf5\uc2dd \uc774\ubbf8\uc9c0 \ub300\uc2e0 <strong>\ub0b4\uac00 \ube4c\ub4dc\ud55c \uc774\ubbf8\uc9c0<\/strong>\ub97c \uc368\uc57c \ud558\ubbc0\ub85c, \uc774\ubbf8\uc9c0\ub97c \ube4c\ub4dc\ud574\uc11c \ub808\uc9c0\uc2a4\ud2b8\ub9ac\uc5d0 \uc62c\ub9ac\ub294 \ub2e8\uacc4(CI)\uac00 \ucd94\uac00\ub429\ub2c8\ub2e4.<\/p>\n<h2>1. \uc804\uccb4 \uad6c\uc870<\/h2>\n<p>\uc800\uc7a5\uc18c\ub294 3\uac1c\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. \uc571 \uc800\uc7a5\uc18c 2\uac1c(<code>spring-hello<\/code>, <code>static-web<\/code>)\ub294 \uc774\ubbf8\uc9c0\ub97c \ub9cc\ub4e4\uace0, 2\ud3b8\uc758 <code>k8s-gitops<\/code> \ub294 \uadf8 \uc774\ubbf8\uc9c0\uc758 <strong>\uc5b4\ub290 \ud0dc\uadf8\ub97c \ubc30\ud3ec\ud560\uc9c0<\/strong>\ub9cc \uacb0\uc815\ud569\ub2c8\ub2e4.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.skyer9.pe.kr\/wordpress\/wp-content\/uploads\/2026\/10\/image-1791255497040.png\" alt=\"file\" \/><\/p>\n<p>\uc717\uc904\uc740 \uc571 \uc800\uc7a5\uc18c\uc5d0 push \ud560 \ub54c\ub9c8\ub2e4 \uc790\ub3d9\uc73c\ub85c \ub3cc\uace0, \uc544\ub7ab\uc904\uc740 values \uc758 <code>image.tag<\/code> \ub97c \ubc14\uafd4 push \ud560 \ub54c\ub9cc \ub3d5\ub2c8\ub2e4. \ube0c\ub77c\uc6b0\uc800\ub294 spring-hello \uc5d0\uc11c HTML \uc744, static-web \uc5d0\uc11c CSS\u00b7\uc774\ubbf8\uc9c0\ub97c \uac01\uac01 \ubc1b\uc2b5\ub2c8\ub2e4.<\/p>\n<h2>2. Spring Boot Hello World \ud504\ub85c\uc81d\ud2b8 (spring-hello)<\/h2>\n<p>Spring Boot \ub294 2026\ub144 6\uc6d4 GA \ub41c <strong>4.1.x<\/strong>, Java \ub294 LTS \uc778 <strong>25<\/strong> \ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. <a href=\"https:\/\/start.spring.io\">start.spring.io<\/a> \uc5d0\uc11c \uc544\ub798\ucc98\ub7fc \ub9cc\ub4e4\uba74 \ub429\ub2c8\ub2e4.<\/p>\n<ul>\n<li>Project: Gradle &#8211; Groovy \/ Language: Java \/ Spring Boot: 4.1.x \/ Java: 25<\/li>\n<li>Group: <code>com.example<\/code> \/ Artifact: <code>spring-hello<\/code><\/li>\n<li>Dependencies: <strong>Spring Web<\/strong>, <strong>Thymeleaf<\/strong>, <strong>Spring Boot Actuator<\/strong><\/li>\n<\/ul>\n<pre><code class=\"language-text\">spring-hello\/\n\u251c\u2500\u2500 .github\/workflows\/build.yml      # 4\uc7a5\n\u251c\u2500\u2500 Dockerfile\n\u251c\u2500\u2500 build.gradle\n\u2514\u2500\u2500 src\/main\/\n    \u251c\u2500\u2500 java\/com\/example\/hello\/\n    \u2502   \u251c\u2500\u2500 SpringHelloApplication.java\n    \u2502   \u2514\u2500\u2500 HelloController.java\n    \u2514\u2500\u2500 resources\/\n        \u251c\u2500\u2500 application.yaml\n        \u2514\u2500\u2500 templates\/index.html<\/code><\/pre>\n<h3>2.1 build.gradle<\/h3>\n<p>start.spring.io \uac00 \ub9cc\ub4e4\uc5b4 \uc900 \ud30c\uc77c\uc5d0\uc11c <strong>jar \ud30c\uc77c \uc774\ub984 \uace0\uc815<\/strong>\uacfc <strong>plain jar \ube44\ud65c\uc131\ud654<\/strong> \ub450 \uac00\uc9c0\ub9cc \ucd94\uac00\ud569\ub2c8\ub2e4. Dockerfile \uc5d0\uc11c <code>build\/libs\/app.jar<\/code> \ud558\ub098\ub9cc \ubcf5\uc0ac\ud558\uae30 \uc704\ud574\uc11c\uc785\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-groovy\">plugins {\n    id &#039;java&#039;\n    id &#039;org.springframework.boot&#039; version &#039;4.1.0&#039;   \/\/ start.spring.io \uac00 \ub123\uc5b4 \uc900 \ucd5c\uc2e0 \ud328\uce58 \uadf8\ub300\ub85c\n    id &#039;io.spring.dependency-management&#039; version &#039;1.1.7&#039;\n}\n\ngroup = &#039;com.example&#039;\nversion = &#039;0.0.1&#039;\n\njava {\n    toolchain {\n        languageVersion = JavaLanguageVersion.of(25)\n    }\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation &#039;org.springframework.boot:spring-boot-starter-webmvc&#039;\n    implementation &#039;org.springframework.boot:spring-boot-starter-thymeleaf&#039;\n    implementation &#039;org.springframework.boot:spring-boot-starter-actuator&#039;\n    testImplementation &#039;org.springframework.boot:spring-boot-starter-test&#039;\n}\n\n\/\/ \u2605 \ucd94\uac00\nbootJar {\n    archiveFileName = &#039;app.jar&#039;\n}\njar {\n    enabled = false\n}<\/code><\/pre>\n<blockquote>\n<p>Spring Boot 4 \ubd80\ud130 <code>spring-boot-starter-web<\/code> \uc740 <code>spring-boot-starter-webmvc<\/code> \ub85c \uc774\ub984\uc774 \ubc14\ub00c\uc5c8\uc2b5\ub2c8\ub2e4. \uc608\uc804 \uc774\ub984\ub3c4 \ub3d9\uc791\ud558\uc9c0\ub9cc deprecated \uc785\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<h3>2.2 HelloController.java<\/h3>\n<p>\ud398\uc774\uc9c0 1\uc7a5(<code>\/<\/code>)\uacfc JSON API 1\uac1c(<code>\/api\/hello<\/code>)\ub97c \ub9cc\ub4ed\ub2c8\ub2e4. \uc751\ub2f5\uc5d0 <strong>\ud30c\ub4dc \uc774\ub984(HOSTNAME)<\/strong> \uc744 \ub123\uc5b4 \ub450\uba74 \ub808\ud50c\ub9ac\uce74 2\uac1c\uc5d0 \uc694\uccad\uc774 \ub098\ub258\ub294 \uac83\uc744 \ub208\uc73c\ub85c \ud655\uc778\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-java\">package com.example.hello;\n\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n@Controller\npublic class HelloController {\n\n    @Value(&quot;${app.static-base-url}&quot;)\n    private String staticBaseUrl;\n\n    @Value(&quot;${app.version}&quot;)\n    private String version;\n\n    private final String hostname = System.getenv().getOrDefault(&quot;HOSTNAME&quot;, &quot;local&quot;);\n\n    @GetMapping(&quot;\/&quot;)\n    public String index(Model model) {\n        model.addAttribute(&quot;staticBaseUrl&quot;, staticBaseUrl);\n        model.addAttribute(&quot;version&quot;, version);\n        model.addAttribute(&quot;hostname&quot;, hostname);\n        return &quot;index&quot;;\n    }\n\n    @GetMapping(&quot;\/api\/hello&quot;)\n    @ResponseBody\n    public Map&lt;String, String&gt; hello() {\n        return Map.of(\n                &quot;message&quot;, &quot;Hello, World!&quot;,\n                &quot;version&quot;, version,\n                &quot;pod&quot;, hostname);\n    }\n}<\/code><\/pre>\n<h3>2.3 application.yaml<\/h3>\n<p>\uc815\uc801 \ub9ac\uc18c\uc2a4 \uc11c\ubc84 \uc8fc\uc18c\ub294 <strong>\ucf54\ub4dc\uc5d0 \ud558\ub4dc\ucf54\ub529\ud558\uc9c0 \uc54a\uace0 \uc124\uc815\uac12<\/strong>\uc73c\ub85c \ub461\ub2c8\ub2e4. \ucfe0\ubc84\ub124\ud2f0\uc2a4\uc5d0\uc11c\ub294 \ud658\uacbd\ubcc0\uc218 <code>APP_STATIC_BASE_URL<\/code> \ub85c \ub36e\uc5b4\uc501\ub2c8\ub2e4(Spring \uc758 relaxed binding).<\/p>\n<pre><code class=\"language-yaml\">app:\n  static-base-url: http:\/\/localhost:8081   # \ub85c\uceec \uac1c\ubc1c\uc6a9 \uae30\ubcf8\uac12\n  version: local\n\nmanagement:\n  endpoints:\n    web:\n      exposure:\n        include: health,info\n  endpoint:\n    health:\n      probes:\n        enabled: true        # \/actuator\/health\/liveness, \/readiness \ud65c\uc131\ud654<\/code><\/pre>\n<h3>2.4 templates\/index.html<\/h3>\n<p>CSS \uc640 \uc774\ubbf8\uc9c0\ub294 <code>staticBaseUrl<\/code> \uc744 \uc55e\uc5d0 \ubd99\uc5ec\uc11c <strong>static-web \uc5d0\uc11c<\/strong> \uac00\uc838\uc635\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;html xmlns:th=&quot;http:\/\/www.thymeleaf.org&quot; lang=&quot;ko&quot;&gt;\n&lt;head&gt;\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\n    &lt;title&gt;Spring Hello&lt;\/title&gt;\n    &lt;link rel=&quot;stylesheet&quot; th:href=&quot;${staticBaseUrl + &#039;\/css\/style.css&#039;}&quot;&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;main class=&quot;card&quot;&gt;\n    &lt;img th:src=&quot;${staticBaseUrl + &#039;\/img\/logo.png&#039;}&quot; alt=&quot;logo&quot; class=&quot;logo&quot;&gt;\n    &lt;h1&gt;Hello, World!&lt;\/h1&gt;\n    &lt;p&gt;version : &lt;span th:text=&quot;${version}&quot;&gt;local&lt;\/span&gt;&lt;\/p&gt;\n    &lt;p&gt;pod : &lt;span th:text=&quot;${hostname}&quot;&gt;local&lt;\/span&gt;&lt;\/p&gt;\n&lt;\/main&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n<h3>2.5 Dockerfile<\/h3>\n<p>jar \ub294 GitHub Actions \ub7ec\ub108\uc5d0\uc11c \ubbf8\ub9ac \ube4c\ub4dc\ud558\uace0(4\uc7a5), Dockerfile \uc740 <strong>\ubcf5\uc0ac\ub9cc<\/strong> \ud569\ub2c8\ub2e4. <code>RUN<\/code> \uba85\ub839\uc774 \uc5c6\uc73c\ubbc0\ub85c arm64 \uc774\ubbf8\uc9c0\ub97c \ub9cc\ub4e4 \ub54c QEMU \uc5d0\ubbac\ub808\uc774\uc158\uc774 \ud544\uc694 \uc5c6\uace0 \ube4c\ub4dc\uac00 \ube60\ub985\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-dockerfile\">FROM eclipse-temurin:25-jre\n\nWORKDIR \/app\nCOPY build\/libs\/app.jar app.jar\n\n# \ucee8\ud14c\uc774\ub108 \uba54\ubaa8\ub9ac limit \uc758 75% \ub97c \ud799\uc73c\ub85c \uc0ac\uc6a9\nENV JAVA_TOOL_OPTIONS=&quot;-XX:MaxRAMPercentage=75&quot;\n\n# root \ub85c \uc2e4\ud589\ud558\uc9c0 \uc54a\uc74c (\uc22b\uc790 UID \ub294 RUN useradd \uc5c6\uc774\ub3c4 \uc0ac\uc6a9 \uac00\ub2a5)\nUSER 1000:1000\n\nEXPOSE 8080\nENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;\/app\/app.jar&quot;]<\/code><\/pre>\n<p>\ub85c\uceec \ud655\uc778<\/p>\n<pre><code class=\"language-bash\">.\/gradlew bootRun\ncurl http:\/\/localhost:8080\/api\/hello<\/code><\/pre>\n<h2>3. \uc815\uc801 \ub9ac\uc18c\uc2a4 \ud504\ub85c\uc81d\ud2b8 (static-web)<\/h2>\n<p>\uc815\uc801 \ub9ac\uc18c\uc2a4\ub294 \ubcc4\ub3c4 \uc800\uc7a5\uc18c\ub85c \ubd84\ub9ac\ud558\uace0, <strong>\ud30c\uc77c\uc744 nginx \uc774\ubbf8\uc9c0 \uc548\uc5d0 \ub123\uc5b4\uc11c<\/strong> \ubc30\ud3ec\ud569\ub2c8\ub2e4. \ub514\uc790\uc774\ub108\ub098 \ud504\ub860\ud2b8\uc5d4\ub4dc \ub2f4\ub2f9\uc774 CSS\u00b7\uc774\ubbf8\uc9c0\ub9cc \uace0\uccd0\uc11c push \ud574\ub3c4 WAS \ub97c \ub2e4\uc2dc \ube4c\ub4dc\ud560 \ud544\uc694\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-text\">static-web\/\n\u251c\u2500\u2500 .github\/workflows\/build.yml      # 4\uc7a5\n\u251c\u2500\u2500 Dockerfile\n\u251c\u2500\u2500 nginx\/\n\u2502   \u2514\u2500\u2500 default.conf\n\u2514\u2500\u2500 html\/\n    \u251c\u2500\u2500 index.html                   # \uc815\uc801 \uc11c\ubc84 \uc790\uccb4 \ud655\uc778\uc6a9\n    \u251c\u2500\u2500 css\/\n    \u2502   \u2514\u2500\u2500 style.css\n    \u2514\u2500\u2500 img\/\n        \u2514\u2500\u2500 logo.jpg                 # \uc544\ubb34 PNG \ud30c\uc77c<\/code><\/pre>\n<h3>3.1 html\/css\/style.css<\/h3>\n<pre><code class=\"language-css\">body {\n    margin: 0;\n    min-height: 100vh;\n    display: grid;\n    place-items: center;\n    font-family: system-ui, sans-serif;\n    background: #f2f4f7;\n}\n\n.card {\n    padding: 40px 56px;\n    border-radius: 12px;\n    background: #fff;\n    box-shadow: 0 2px 12px rgba(0, 0, 0, .08);\n    text-align: center;\n}\n\n.logo {\n    width: 96px;\n}<\/code><\/pre>\n<p><code>html\/index.html<\/code> \uc740 \uc815\uc801 \uc11c\ubc84\ub9cc \ub2e8\ub3c5\uc73c\ub85c \uc5f4\uc5c8\uc744 \ub54c \ud655\uc778\uc6a9\uc785\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;html lang=&quot;ko&quot;&gt;\n&lt;head&gt;\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\n    &lt;title&gt;static-web&lt;\/title&gt;\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;\/css\/style.css&quot;&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;main class=&quot;card&quot;&gt;\n    &lt;img src=&quot;\/img\/logo.png&quot; alt=&quot;logo&quot; class=&quot;logo&quot;&gt;\n    &lt;h1&gt;static-web OK&lt;\/h1&gt;\n&lt;\/main&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n<h3>3.2 nginx\/default.conf<\/h3>\n<p>\uc774\ubbf8\uc9c0 \uae30\ubcf8 \uc124\uc815\uc744 \ub36e\uc5b4\uc368\uc11c <strong>\uc815\uc801 \ud30c\uc77c \uce90\uc2dc \ud5e4\ub354<\/strong>\uc640 <strong>\ud5ec\uc2a4\uccb4\ud06c \uacbd\ub85c<\/strong>\ub97c \ucd94\uac00\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-nginx\">server {\n    listen       80;\n    server_name  _;\n    root         \/usr\/share\/nginx\/html;\n\n    location \/ {\n        try_files $uri $uri\/ =404;\n    }\n\n    # \uc815\uc801 \ud30c\uc77c: \ube0c\ub77c\uc6b0\uc800 \uce90\uc2dc 1\uc2dc\uac04\n    location ~* \\.(css|js|png|jpe?g|gif|svg|webp|ico|woff2?)$ {\n        expires 1h;\n        access_log off;\n        # \ub2e4\ub978 \ud3ec\ud2b8(=\ub2e4\ub978 origin)\uc758 spring-hello \ud398\uc774\uc9c0\uc5d0\uc11c \ud3f0\ud2b8\u00b7fetch \ub85c \uc77d\uc744 \ub54c \ud544\uc694\n        add_header Access-Control-Allow-Origin &quot;*&quot;;\n    }\n\n    # k8s probe \uc6a9\n    location = \/healthz {\n        access_log off;\n        default_type text\/plain;\n        return 200 &quot;ok&quot;;\n    }\n}<\/code><\/pre>\n<blockquote>\n<p><code>&lt;link rel=&quot;stylesheet&quot;&gt;<\/code> \uc640 <code>&lt;img&gt;<\/code> \ub294 \ub2e4\ub978 origin \uc5d0\uc11c \ubd88\ub7ec\uc640\ub3c4 CORS \ud5e4\ub354\uac00 \ud544\uc694 \uc5c6\uc2b5\ub2c8\ub2e4. \ub098\uc911\uc5d0 \uc6f9\ud3f0\ud2b8(<code>@font-face<\/code>)\ub098 JS \uc758 <code>fetch()<\/code> \ub85c \uc77d\ub294 \ud30c\uc77c\uc774 \uc0dd\uae30\uba74 \uadf8\ub54c \uc704 <code>Access-Control-Allow-Origin<\/code> \uc774 \ud544\uc694\ud569\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<h3>3.3 Dockerfile<\/h3>\n<pre><code class=\"language-dockerfile\"># \uc6b4\uc601\uc5d0\uc11c\ub294 nginx:1.xx-alpine \ucc98\ub7fc \ubc84\uc804\uc744 \uace0\uc815\ud558\uc138\uc694\nFROM nginx:stable-alpine\n\nCOPY nginx\/default.conf \/etc\/nginx\/conf.d\/default.conf\nCOPY html\/ \/usr\/share\/nginx\/html\/<\/code><\/pre>\n<p>\uc774 Dockerfile \ub3c4 <code>RUN<\/code> \uc774 \uc5c6\uc5b4\uc11c arm64 \uc774\ubbf8\uc9c0\ub97c \uc5d0\ubbac\ub808\uc774\uc158 \uc5c6\uc774 \ubc14\ub85c \ub9cc\ub4e4 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ub85c\uceec \ud655\uc778 (2.3 \uc758 \uae30\ubcf8\uac12 <code>http:\/\/localhost:8081<\/code> \uacfc \ud3ec\ud2b8\ub97c \ub9de\ucda5\ub2c8\ub2e4)<\/p>\n<pre><code class=\"language-bash\">docker build -t static-web .\ndocker run --rm -p 8081:80 static-web\n\n# \ub2e4\ub978 \ud130\ubbf8\ub110\uc5d0\uc11c spring-hello \ub97c bootRun \ud55c \ub4a4\n# http:\/\/localhost:8080\/ \uc811\uc18d \u2192 \uc2a4\ud0c0\uc77c\uacfc \ub85c\uace0\uac00 \ubcf4\uc774\uba74 \uc131\uacf5<\/code><\/pre>\n<h2>4. GitHub Actions \ub85c \uc774\ubbf8\uc9c0 \ube4c\ub4dc \u2192 ghcr.io push<\/h2>\n<p>\ub77c\uc988\ubca0\ub9ac \ud30c\uc774\uc5d0\uc11c \uc9c1\uc811 <code>docker build<\/code> \ud574\ub3c4 \ub418\uc9c0\ub9cc, \ud074\ub7ec\uc2a4\ud130 \ub178\ub4dc\uc5d0\uc11c \ube4c\ub4dc\ud558\ub294 \uac83\uc740 GitOps \ud750\ub984\uacfc \ub9de\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. \uc774\ubbf8\uc9c0\ub294 <strong>GitHub Actions \uac00 \ube4c\ub4dc\ud574\uc11c GitHub Container Registry(ghcr.io)<\/strong> \uc5d0 \uc62c\ub9ac\uace0, \ud074\ub7ec\uc2a4\ud130\ub294 \ubc1b\uc544 \uac00\uae30\ub9cc \ud569\ub2c8\ub2e4.<\/p>\n<ul>\n<li><code>linux\/arm64<\/code> (\ub77c\uc988\ubca0\ub9ac \ud30c\uc774)\uc640 <code>linux\/amd64<\/code> (\uac1c\ubc1c PC) \uc774\ubbf8\uc9c0\ub97c <strong>\ud568\uaed8<\/strong> \ub9cc\ub4ed\ub2c8\ub2e4<\/li>\n<li>\ud0dc\uadf8\ub294 \ucee4\ubc0b \ud574\uc2dc \uae30\ubc18 <code>sha-xxxxxxx<\/code> \uc640 <code>latest<\/code> \ub97c \ubd99\uc774\uace0, <strong>\ud074\ub7ec\uc2a4\ud130\uc5d0\uc11c\ub294 <code>sha-<\/code> \ud0dc\uadf8\ub9cc<\/strong> \uc0ac\uc6a9\ud569\ub2c8\ub2e4 (7\uc7a5)<\/li>\n<li>\uc778\uc99d\uc740 Actions \uae30\ubcf8 \uc81c\uacf5 <code>GITHUB_TOKEN<\/code> \uc744 \uc0ac\uc6a9\ud558\ubbc0\ub85c \ubcc4\ub3c4 \ud1a0\ud070\uc774 \ud544\uc694 \uc5c6\uc2b5\ub2c8\ub2e4<\/li>\n<\/ul>\n<h3>4.1 spring-hello\/.github\/workflows\/build.yml<\/h3>\n<pre><code class=\"language-yaml\">name: build\n\non:\n  push:\n    branches: [ main ]\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  packages: write          # ghcr.io push \uad8c\ud55c\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v5\n\n      - uses: actions\/setup-java@v5\n        with:\n          distribution: temurin\n          java-version: &#039;25&#039;\n          cache: gradle\n\n      - name: Build jar\n        run: .\/gradlew bootJar --no-daemon\n\n      - uses: docker\/setup-buildx-action@v3\n\n      - uses: docker\/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - id: meta\n        uses: docker\/metadata-action@v5\n        with:\n          images: ghcr.io\/${{ github.repository_owner }}\/spring-hello\n          tags: |\n            type=sha,prefix=sha-\n            type=raw,value=latest\n\n      - uses: docker\/build-push-action@v7\n        with:\n          context: .\n          platforms: linux\/amd64,linux\/arm64\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n          labels: ${{ steps.meta.outputs.labels }}<\/code><\/pre>\n<h3>4.2 static-web\/.github\/workflows\/build.yml<\/h3>\n<p>Java \ube4c\ub4dc \ub2e8\uacc4\ub9cc \ube60\uc9c0\uace0 \ub098\uba38\uc9c0\ub294 \uac19\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-yaml\">name: build\n\non:\n  push:\n    branches: [ main ]\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  packages: write\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v5\n      - uses: docker\/setup-buildx-action@v3\n      - uses: docker\/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n      - id: meta\n        uses: docker\/metadata-action@v5\n        with:\n          images: ghcr.io\/${{ github.repository_owner }}\/static-web\n          tags: |\n            type=sha,prefix=sha-\n            type=raw,value=latest\n      - uses: docker\/build-push-action@v7\n        with:\n          context: .\n          platforms: linux\/amd64,linux\/arm64\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n          labels: ${{ steps.meta.outputs.labels }}<\/code><\/pre>\n<blockquote>\n<p>\uc561\uc158\uc758 \uba54\uc774\uc800 \ubc84\uc804(<code>@v5<\/code>, <code>@v7<\/code> \ub4f1)\uc740 \uc791\uc131 \uc2dc\uc810 \uae30\uc900\uc785\ub2c8\ub2e4. \uac01 \uc561\uc158 \uc800\uc7a5\uc18c\uc758 Releases \uc5d0\uc11c \ucd5c\uc2e0 \uba54\uc774\uc800 \ubc84\uc804\uc744 \ud655\uc778\ud558\uc138\uc694.<\/p>\n<\/blockquote>\n<h3>4.3 \ud328\ud0a4\uc9c0\ub97c Public \uc73c\ub85c \ubcc0\uacbd<\/h3>\n<p>\ucc98\uc74c push \ub41c ghcr.io \ud328\ud0a4\uc9c0\ub294 <strong>Private<\/strong> \uc785\ub2c8\ub2e4. \ud648\ub7a9\uc5d0\uc11c\ub294 Public \uc73c\ub85c \ubc14\uafb8\ub294 \uac83\uc774 \uac00\uc7a5 \uac04\ub2e8\ud569\ub2c8\ub2e4.<\/p>\n<ol>\n<li>GitHub \ud504\ub85c\ud544 \u2192 <strong>Packages<\/strong> \u2192 <code>spring-hello<\/code><\/li>\n<li><strong>Package settings<\/strong> \u2192 Danger Zone \u2192 <strong>Change visibility<\/strong> \u2192 Public<\/li>\n<li><code>static-web<\/code> \ub3c4 \ub3d9\uc77c\ud558\uac8c<\/li>\n<\/ol>\n<p>\ud074\ub7ec\uc2a4\ud130 \ub178\ub4dc\uc5d0\uc11c \ubc1b\uc544\uc9c0\ub294\uc9c0 \ud655\uc778\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\"># sudo crictl pull ghcr.io\/&lt;YOUR_ID&gt;\/spring-hello:latest\n# sudo crictl pull ghcr.io\/&lt;YOUR_ID&gt;\/static-web:latest\n\nsudo ctr -n k8s.io images pull --platform linux\/arm64 ghcr.io\/&lt;YOUR_ID&gt;\/spring-hello:latest\nsudo ctr -n k8s.io images pull --platform linux\/arm64 ghcr.io\/&lt;YOUR_ID&gt;\/static-web:latest\n\nsudo ctr -n k8s.io images ls | grep &lt;YOUR_ID&gt;<\/code><\/pre>\n<blockquote>\n<p>ghcr.io \uc774\ubbf8\uc9c0 \uacbd\ub85c\ub294 <strong>\uc18c\ubb38\uc790\ub9cc<\/strong> \ud5c8\uc6a9\ub429\ub2c8\ub2e4. GitHub ID \uc5d0 \ub300\ubb38\uc790\uac00 \uc788\ub2e4\uba74 values \uc5d0\uc11c\ub294 \uc18c\ubb38\uc790\ub85c \uc801\uc5b4\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<p>push \uac00 \ub05d\ub098\uba74 Actions \ub85c\uadf8 \ub610\ub294 \ud328\ud0a4\uc9c0 \ud398\uc774\uc9c0\uc5d0\uc11c <strong><code>sha-<\/code> \ub85c \uc2dc\uc791\ud558\ub294 \ud0dc\uadf8<\/strong>(\uc608: <code>sha-1a2b3c4<\/code>)\ub97c \ud655\uc778\ud574 \ub461\ub2c8\ub2e4. \ub2e4\uc74c \uc7a5\uc5d0\uc11c values \uc5d0 \uc801\uc744 \uac12\uc785\ub2c8\ub2e4.<\/p>\n<h2>5. k8s-gitops \uc800\uc7a5\uc18c\uc5d0 \ucd94\uac00<\/h2>\n<p>2\ud3b8\uc758 \uaddc\uce59(<code>apps\/<\/code> = \ubb34\uc5c7\uc744\u00b7\uc5b4\ub290 \ubc84\uc804\uc73c\ub85c, <code>values\/<\/code> = \uc5b4\ub5bb\uac8c)\uc744 \uadf8\ub300\ub85c \ub530\ub985\ub2c8\ub2e4. \ucd94\uac00\ub418\ub294 \ud30c\uc77c\uc740 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-text\">k8s-gitops\/\n\u251c\u2500\u2500 apps\/\n\u2502   \u251c\u2500\u2500 spring-hello.yaml            # \u2605 \ucd94\uac00\n\u2502   \u2514\u2500\u2500 static-web.yaml              # \u2605 \ucd94\uac00\n\u251c\u2500\u2500 values\/\n\u2502   \u251c\u2500\u2500 spring-hello\/values.yaml     # \u2605 \ucd94\uac00\n\u2502   \u2514\u2500\u2500 static-web\/values.yaml       # \u2605 \ucd94\uac00\n\u2514\u2500\u2500 charts\/\n    \u251c\u2500\u2500 nginx\/                       # 2\ud3b8 \ucc28\ud2b8 \u2192 static-web \uc5d0 \uc7ac\uc0ac\uc6a9\n    \u2514\u2500\u2500 spring-boot\/                 # \u2605 \ucd94\uac00 (Spring Boot \uc571 \uacf5\uc6a9 \ucc28\ud2b8)\n        \u251c\u2500\u2500 Chart.yaml\n        \u251c\u2500\u2500 values.yaml\n        \u2514\u2500\u2500 templates\/\n            \u251c\u2500\u2500 deployment.yaml\n            \u2514\u2500\u2500 service.yaml<\/code><\/pre>\n<ul>\n<li><strong>static-web<\/strong> \uc740 \uacb0\uad6d nginx \uc774\ubbf8\uc9c0\uc774\ubbc0\ub85c 2\ud3b8\uc758 <code>charts\/nginx<\/code> \ub97c <strong>\uadf8\ub300\ub85c \uc7ac\uc0ac\uc6a9<\/strong>\ud558\uace0, values \uc5d0\uc11c \uc774\ubbf8\uc9c0\ub9cc \ubc14\uafc9\ub2c8\ub2e4.<\/li>\n<li><strong>spring-hello<\/strong> \ub294 \ud3ec\ud2b8(8080), \ud5ec\uc2a4\uccb4\ud06c(actuator), JVM \uba54\ubaa8\ub9ac \uc124\uc815\uc774 \ud544\uc694\ud558\ubbc0\ub85c <code>charts\/spring-boot<\/code> \ub97c \uc0c8\ub85c \ub9cc\ub4ed\ub2c8\ub2e4. \uc571 \uc774\ub984\uc744 Release \uc774\ub984\uc73c\ub85c \uc4f0\uae30 \ub54c\ubb38\uc5d0, \uc774\ud6c4 \ub9cc\ub4dc\ub294 Spring Boot \uc571\ub3c4 values \ud30c\uc77c \ud558\ub098\ub9cc \ucd94\uac00\ud558\uba74 \ub429\ub2c8\ub2e4.<\/li>\n<\/ul>\n<h3>5.1 charts\/spring-boot<\/h3>\n<p><code>charts\/spring-boot\/Chart.yaml<\/code><\/p>\n<pre><code class=\"language-yaml\">apiVersion: v2\nname: spring-boot\ndescription: Spring Boot \uc571 \uacf5\uc6a9 \ucc28\ud2b8\ntype: application\nversion: 0.1.0<\/code><\/pre>\n<p><code>charts\/spring-boot\/values.yaml<\/code> (\ucc28\ud2b8 \uae30\ubcf8\uac12)<\/p>\n<pre><code class=\"language-yaml\">replicaCount: 1\n\nimage:\n  repository: &quot;&quot;\n  tag: &quot;&quot;\n\nimagePullSecrets: []        # private \ub808\uc9c0\uc2a4\ud2b8\ub9ac\uc77c \ub54c\ub9cc \uc0ac\uc6a9 (8\uc7a5)\n\ncontainerPort: 8080\n\n# \ud658\uacbd\ubcc0\uc218 (KEY: value)\nenv: {}\n\nservice:\n  type: ClusterIP\n  port: 80\n  nodePort: null\n\nresources:\n  requests: { cpu: 100m, memory: 256Mi }\n  limits:   { memory: 512Mi }<\/code><\/pre>\n<p><code>charts\/spring-boot\/templates\/deployment.yaml<\/code><\/p>\n<pre><code class=\"language-yaml\">apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: {{ .Release.Name }}\n  labels:\n    app: {{ .Release.Name }}\nspec:\n  replicas: {{ .Values.replicaCount }}\n  selector:\n    matchLabels:\n      app: {{ .Release.Name }}\n  template:\n    metadata:\n      labels:\n        app: {{ .Release.Name }}\n    spec:\n      {{- with .Values.imagePullSecrets }}\n      imagePullSecrets:\n        {{- toYaml . | nindent 8 }}\n      {{- end }}\n      containers:\n        - name: app\n          image: &quot;{{ .Values.image.repository }}:{{ .Values.image.tag }}&quot;\n          ports:\n            - name: http\n              containerPort: {{ .Values.containerPort }}\n          env:\n            - name: APP_VERSION                 # \ud654\uba74\uc5d0 \ud45c\uc2dc\ud560 \ubc84\uc804 = \uc774\ubbf8\uc9c0 \ud0dc\uadf8\n              value: {{ .Values.image.tag | quote }}\n            {{- range $key, $value := .Values.env }}\n            - name: {{ $key }}\n              value: {{ $value | quote }}\n            {{- end }}\n          # \ub77c\uc988\ubca0\ub9ac \ud30c\uc774\uc5d0\uc11c\ub294 \uae30\ub3d9\uc5d0 \uc218\uc2ed \ucd08 \uac78\ub9bc \u2192 \ucd5c\ub300 180\ucd08 \uae30\ub2e4\ub9bc\n          startupProbe:\n            httpGet: { path: \/actuator\/health\/liveness, port: http }\n            periodSeconds: 5\n            failureThreshold: 36\n          livenessProbe:\n            httpGet: { path: \/actuator\/health\/liveness, port: http }\n            periodSeconds: 10\n          readinessProbe:\n            httpGet: { path: \/actuator\/health\/readiness, port: http }\n            periodSeconds: 5\n          resources:\n            {{- toYaml .Values.resources | nindent 12 }}<\/code><\/pre>\n<p><code>charts\/spring-boot\/templates\/service.yaml<\/code><\/p>\n<pre><code class=\"language-yaml\">apiVersion: v1\nkind: Service\nmetadata:\n  name: {{ .Release.Name }}\nspec:\n  type: {{ .Values.service.type }}\n  selector:\n    app: {{ .Release.Name }}\n  ports:\n    - port: {{ .Values.service.port }}\n      targetPort: http\n      {{- if and (eq .Values.service.type &quot;NodePort&quot;) .Values.service.nodePort }}\n      nodePort: {{ .Values.service.nodePort }}\n      {{- end }}<\/code><\/pre>\n<h3>5.2 values (\uc774 \ud074\ub7ec\uc2a4\ud130\uc758 \uc2e4\uc81c \uc124\uc815)<\/h3>\n<p>\ud3ec\ud2b8\ub294 2\ud3b8 nginx(31405) \ub2e4\uc74c \ubc88\ud638\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<\/p>\n<table>\n<thead>\n<tr>\n<th>\uc571<\/th>\n<th>NodePort<\/th>\n<th>\uc811\uc18d \uc8fc\uc18c<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>spring-hello<\/td>\n<td>31406<\/td>\n<td><code>http:\/\/192.168.20.206:31406\/<\/code><\/td>\n<\/tr>\n<tr>\n<td>static-web<\/td>\n<td>31407<\/td>\n<td><code>http:\/\/192.168.20.206:31407\/<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><code>values\/spring-hello\/values.yaml<\/code><\/p>\n<pre><code class=\"language-yaml\">replicaCount: 2\n\nimage:\n  repository: ghcr.io\/&lt;YOUR_ID&gt;\/spring-hello\n  tag: sha-1a2b3c4               # 4\uc7a5\uc5d0\uc11c \ud655\uc778\ud55c \ud0dc\uadf8\n\nenv:\n  # \ube0c\ub77c\uc6b0\uc800\uac00 CSS\u00b7\uc774\ubbf8\uc9c0\ub97c \ubc1b\uc544 \uac08 \uc8fc\uc18c \u2192 \ub178\ub4dc IP + static-web NodePort\n  APP_STATIC_BASE_URL: http:\/\/192.168.20.206:31407\n\nservice:\n  type: NodePort\n  nodePort: 31406<\/code><\/pre>\n<p><code>values\/static-web\/values.yaml<\/code> (2\ud3b8 <code>charts\/nginx<\/code> \uc758 \uac12 \uad6c\uc870 \uadf8\ub300\ub85c)<\/p>\n<pre><code class=\"language-yaml\">replicaCount: 1\n\nimage:\n  repository: ghcr.io\/&lt;YOUR_ID&gt;\/static-web\n  tag: sha-5d6e7f8               # 4\uc7a5\uc5d0\uc11c \ud655\uc778\ud55c \ud0dc\uadf8\n\nservice:\n  type: NodePort\n  nodePort: 31407<\/code><\/pre>\n<blockquote>\n<p><code>APP_STATIC_BASE_URL<\/code> \uc5d0 \ucfe0\ubc84\ub124\ud2f0\uc2a4 \ub0b4\ubd80 \uc8fc\uc18c(<code>http:\/\/static-web<\/code>)\ub97c \uc4f0\uba74 \uc548 \ub429\ub2c8\ub2e4. CSS\u00b7\uc774\ubbf8\uc9c0\ub97c \uc694\uccad\ud558\ub294 \uac83\uc740 \ud30c\ub4dc\uac00 \uc544\ub2c8\ub77c <strong>\uc0ac\uc6a9\uc790\uc758 \ube0c\ub77c\uc6b0\uc800<\/strong>\uc774\uae30 \ub54c\ubb38\uc5d0, \ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c \uc811\uadfc \uac00\ub2a5\ud55c \uc8fc\uc18c\uc5ec\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<h3>5.3 apps (Application \uc815\uc758)<\/h3>\n<p>2\ud3b8 3.3 \uc758 nginx \uc640 \uac19\uc740 \ud615\ud0dc\uc785\ub2c8\ub2e4. \ucc28\ud2b8\ub3c4 values \ub3c4 \uac19\uc740 \uc800\uc7a5\uc18c\uc5d0 \uc788\uc9c0\ub9cc multi-source \ud615\ud0dc\ub97c \uc720\uc9c0\ud569\ub2c8\ub2e4.<\/p>\n<p><code>apps\/spring-hello.yaml<\/code><\/p>\n<pre><code class=\"language-yaml\">apiVersion: argoproj.io\/v1alpha1\nkind: Application\nmetadata:\n  name: spring-hello\n  namespace: argocd\n  finalizers:\n    - resources-finalizer.argocd.argoproj.io\nspec:\n  project: default\n  sources:\n    - repoURL: https:\/\/github.com\/&lt;YOUR_ID&gt;\/k8s-gitops.git\n      targetRevision: main\n      path: charts\/spring-boot\n      helm:\n        releaseName: spring-hello\n        valueFiles:\n          - $values\/values\/spring-hello\/values.yaml\n    - repoURL: https:\/\/github.com\/&lt;YOUR_ID&gt;\/k8s-gitops.git\n      targetRevision: main\n      ref: values\n  destination:\n    server: https:\/\/kubernetes.default.svc\n    namespace: hello\n  syncPolicy:\n    automated: { prune: true, selfHeal: true }\n    syncOptions:\n      - CreateNamespace=true<\/code><\/pre>\n<p><code>apps\/static-web.yaml<\/code><\/p>\n<pre><code class=\"language-yaml\">apiVersion: argoproj.io\/v1alpha1\nkind: Application\nmetadata:\n  name: static-web\n  namespace: argocd\n  finalizers:\n    - resources-finalizer.argocd.argoproj.io\nspec:\n  project: default\n  sources:\n    - repoURL: https:\/\/github.com\/&lt;YOUR_ID&gt;\/k8s-gitops.git\n      targetRevision: main\n      path: charts\/nginx                 # 2\ud3b8 \ucc28\ud2b8 \uc7ac\uc0ac\uc6a9\n      helm:\n        releaseName: static-web\n        valueFiles:\n          - $values\/values\/static-web\/values.yaml\n    - repoURL: https:\/\/github.com\/&lt;YOUR_ID&gt;\/k8s-gitops.git\n      targetRevision: main\n      ref: values\n  destination:\n    server: https:\/\/kubernetes.default.svc\n    namespace: hello\n  syncPolicy:\n    automated: { prune: true, selfHeal: true }\n    syncOptions:\n      - CreateNamespace=true<\/code><\/pre>\n<p>\ub450 \uc571\uc740 <code>hello<\/code> \ub124\uc784\uc2a4\ud398\uc774\uc2a4\uc5d0 \ud568\uaed8 \ubc30\ud3ec\ud569\ub2c8\ub2e4. 2\ud3b8\uc758 nginx(default \ub124\uc784\uc2a4\ud398\uc774\uc2a4)\uc640 \uc11e\uc774\uc9c0 \uc54a\uac8c \ud558\uae30 \uc704\ud574\uc11c\uc785\ub2c8\ub2e4.<\/p>\n<p>push \uc804\uc5d0 \ub80c\ub354\ub9c1 \uacb0\uacfc\ub97c \ubbf8\ub9ac \ud655\uc778\ud569\ub2c8\ub2e4. (2\ud3b8 5.3 \uacfc \uac19\uc740 \ubc29\ubc95)<\/p>\n<pre><code class=\"language-bash\">helm template spring-hello charts\/spring-boot -n hello \\\n  -f values\/spring-hello\/values.yaml | less\n\nhelm template static-web charts\/nginx -n hello \\\n  -f values\/static-web\/values.yaml | less<\/code><\/pre>\n<h2>6. \uc801\uc6a9 \ubc0f \ud655\uc778<\/h2>\n<p>2\ud3b8\uc5d0\uc11c root Application \uc774 <code>apps\/<\/code> \ub514\ub809\ud130\ub9ac\ub97c \ubcf4\uace0 \uc788\uc73c\ubbc0\ub85c, <strong>push \ub9cc \ud558\uba74<\/strong> \uc0c8 Application 2\uac1c\uac00 \uc790\ub3d9\uc73c\ub85c \uc0dd\uc131\ub429\ub2c8\ub2e4. kubectl apply \ub294 \ud544\uc694 \uc5c6\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">git add .\ngit commit -m &quot;add spring-hello, static-web&quot;\ngit push origin main\n\n# \ubc14\ub85c \ubc18\uc601\ud558\ub824\uba74 (\uae30\ub2e4\ub9ac\uba74 \ucd5c\ub300 3\ubd84)\nargocd login 192.168.20.206:30443 --username admin --insecure\nargocd app get root --refresh<\/code><\/pre>\n<pre><code class=\"language-bash\">kubectl -n argocd get applications\n------------------------------------\nNAME             SYNC STATUS   HEALTH STATUS\nargocd           Synced        Healthy\nheadlamp         Synced        Healthy\nmetrics-server   Synced        Healthy\nnginx            Synced        Healthy\nroot             Synced        Healthy\nspring-hello     Synced        Healthy\nstatic-web       Synced        Healthy<\/code><\/pre>\n<pre><code class=\"language-bash\">kubectl -n hello get pods,svc\n------------------------------------\nNAME                                READY   STATUS    RESTARTS   AGE\npod\/spring-hello-7c9d8b6f5d-4kq2x   1\/1     Running   0          2m\npod\/spring-hello-7c9d8b6f5d-p8m7z   1\/1     Running   0          2m\npod\/static-web-6b8f7d9c4-x2n5w      1\/1     Running   0          2m\n\nNAME                   TYPE       CLUSTER-IP      PORT(S)        AGE\nservice\/spring-hello   NodePort   10.96.112.45    80:31406\/TCP   2m\nservice\/static-web     NodePort   10.96.201.13    80:31407\/TCP   2m<\/code><\/pre>\n<blockquote>\n<p>spring-hello \ud30c\ub4dc\ub294 \ub77c\uc988\ubca0\ub9ac \ud30c\uc774\uc5d0\uc11c <code>READY 1\/1<\/code> \uc774 \ub418\uae30\uae4c\uc9c0 30\ucd08\\~1\ubd84 \uc815\ub3c4 \uac78\ub9bd\ub2c8\ub2e4. \uadf8\ub3d9\uc548\uc740 startupProbe \uac00 \uae30\ub2e4\ub824 \uc8fc\ubbc0\ub85c \uc7ac\uc2dc\uc791\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<h3>6.1 \uc815\uc801 \ub9ac\uc18c\uc2a4 \ud655\uc778<\/h3>\n<pre><code class=\"language-bash\">curl -I http:\/\/192.168.20.206:31407\/css\/style.css\n# HTTP\/1.1 200 OK\n# Content-Type: text\/css\n# Expires: ...\n# Cache-Control: max-age=3600\n# Access-Control-Allow-Origin: *<\/code><\/pre>\n<h3>6.2 Spring Boot \ud655\uc778<\/h3>\n<pre><code class=\"language-bash\"># \uc5ec\ub7ec \ubc88 \ud638\ucd9c\ud558\uba74 pod \uac12\uc774 \ub450 \ud30c\ub4dc \uc0ac\uc774\uc5d0\uc11c \ubc14\ub01c\nfor i in $(seq 1 6); do curl -s http:\/\/192.168.20.206:31406\/api\/hello; echo; done\n# {&quot;message&quot;:&quot;Hello, World!&quot;,&quot;version&quot;:&quot;sha-1a2b3c4&quot;,&quot;pod&quot;:&quot;spring-hello-7c9d8b6f5d-4kq2x&quot;}\n# {&quot;message&quot;:&quot;Hello, World!&quot;,&quot;version&quot;:&quot;sha-1a2b3c4&quot;,&quot;pod&quot;:&quot;spring-hello-7c9d8b6f5d-p8m7z&quot;}<\/code><\/pre>\n<p>\ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c <code>http:\/\/192.168.20.206:31406\/<\/code> \uc5d0 \uc811\uc18d\ud574 <strong>\uce74\ub4dc \uc2a4\ud0c0\uc77c\uacfc \ub85c\uace0 \uc774\ubbf8\uc9c0\uac00 \ubcf4\uc774\uba74<\/strong> \ub450 \uc571\uc774 \uc5f0\uacb0\ub41c \uac83\uc785\ub2c8\ub2e4. \uac1c\ubc1c\uc790 \ub3c4\uad6c Network \ud0ed\uc5d0\uc11c <code>style.css<\/code>, <code>logo.png<\/code> \uac00 <code>:31407<\/code> \uc5d0\uc11c \ubc1b\uc544\uc9c4 \uac83\uc744 \ud655\uc778\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<ul>\n<li>spring-hello : <code>http:\/\/192.168.20.206:31406\/<\/code><\/li>\n<li>static-web : <code>http:\/\/192.168.20.206:31407\/<\/code><\/li>\n<li>ArgoCD : <code>https:\/\/192.168.20.206:30443\/<\/code> (Application 2\uac1c \ucd94\uac00 \ud655\uc778)<\/li>\n<\/ul>\n<h2>7. \uc0c8 \ubc84\uc804 \ubc30\ud3ec: \uc571 push \u2192 \ud0dc\uadf8 1\uc904 \ubcc0\uacbd<\/h2>\n<p>\ucf54\ub4dc\ub97c \uace0\uce5c \ub4a4\uc758 \ubc30\ud3ec\ub294 <strong>\ub450 \ubc88\uc758 push<\/strong> \uc785\ub2c8\ub2e4. \uc571 \uc800\uc7a5\uc18c push \ub85c \uc774\ubbf8\uc9c0\uac00 \ub9cc\ub4e4\uc5b4\uc9c0\uace0, k8s-gitops \uc800\uc7a5\uc18c push \ub85c \ubc30\ud3ec\ub429\ub2c8\ub2e4.<\/p>\n<ol>\n<li>\uc571 \uc800\uc7a5\uc18c(spring-hello \ub610\ub294 static-web)\uc5d0\uc11c \ucf54\ub4dc\ub97c \uc218\uc815\ud558\uace0 push<\/li>\n<li>GitHub Actions \uac00 \uc0c8 \uc774\ubbf8\uc9c0 <code>sha-9f8e7d6<\/code> \uc744 ghcr.io \uc5d0 push<\/li>\n<li>k8s-gitops \uc5d0\uc11c values \uc758 <code>image.tag<\/code> \ud55c \uc904\ub9cc \ubcc0\uacbd \ud6c4 push<\/li>\n<\/ol>\n<pre><code class=\"language-bash\">cd k8s-gitops\nvi values\/spring-hello\/values.yaml     # tag: sha-9f8e7d6\ngit commit -am &quot;spring-hello sha-9f8e7d6&quot;\ngit push<\/code><\/pre>\n<p>ArgoCD \uac00 Deployment \uc758 image \uac00 \ubc14\ub010 \uac83\uc744 \uac10\uc9c0\ud574 <strong>\ub864\ub9c1 \uc5c5\ub370\uc774\ud2b8<\/strong>\ud569\ub2c8\ub2e4. readinessProbe \uac00 \ud1b5\uacfc\ud55c \uc0c8 \ud30c\ub4dc\ub9cc \ud2b8\ub798\ud53d\uc744 \ubc1b\uc73c\ubbc0\ub85c, 6.2 \uc758 curl \ubc18\ubcf5 \ud638\ucd9c\uc744 \ucf1c \ub454 \ucc44\ub85c \ubc30\ud3ec\ud574\ub3c4 \uc751\ub2f5\uc774 \ub04a\uae30\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">kubectl -n hello rollout status deployment\/spring-hello<\/code><\/pre>\n<h3>7.1 \uc65c <code>latest<\/code> \ub97c \uc4f0\uc9c0 \uc54a\ub294\uac00<\/h3>\n<p>values \uc5d0 <code>tag: latest<\/code> \ub97c \uc801\uc73c\uba74 \uc0c8 \uc774\ubbf8\uc9c0\uac00 \uc62c\ub77c\uc640\ub3c4 <strong>Git \uc5d0\ub294 \uc544\ubb34 \ubcc0\ud654\uac00 \uc5c6\uc73c\ubbc0\ub85c<\/strong> ArgoCD \uac00 \ubc30\ud3ec\ud560 \uc774\uc720\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. \ub610 \uc9c0\uae08 \uc5b4\ub5a4 \ucf54\ub4dc\uac00 \ub3cc\uace0 \uc788\ub294\uc9c0 Git \ub9cc \ubcf4\uace0\ub294 \uc54c \uc218 \uc5c6\uac8c \ub429\ub2c8\ub2e4.<\/p>\n<p><code>sha-<\/code> \ud0dc\uadf8\ub97c \uc4f0\uba74 \ub2e4\uc74c\uc774 \ubaa8\ub450 Git \uc73c\ub85c \ud574\uacb0\ub429\ub2c8\ub2e4.<\/p>\n<ul>\n<li>\ud604\uc7ac \ubc30\ud3ec \ubc84\uc804 = values \uc758 \ud0dc\uadf8 = \uc571 \uc800\uc7a5\uc18c\uc758 \ucee4\ubc0b<\/li>\n<li>\ub864\ubc31 = <code>git revert<\/code> \ud6c4 push (2\ud3b8 6.1 \uacfc \ub3d9\uc77c)<\/li>\n<li>\ubc30\ud3ec \uc774\ub825 = k8s-gitops \uc758 \ucee4\ubc0b \ub85c\uadf8<\/li>\n<\/ul>\n<h3>7.2 \ud0dc\uadf8 \ubcc0\uacbd\uc744 \uc790\ub3d9\ud654\ud558\ub824\uba74<\/h3>\n<p>\ud0dc\uadf8 \uc218\uc815\uc774 \ubc88\uac70\ub85c\uc6cc\uc9c0\uba74 \ub2e4\uc74c \ub450 \uac00\uc9c0 \ubc29\ubc95\uc774 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<ul>\n<li><strong>\uc571 \uc800\uc7a5\uc18c Actions \uc5d0\uc11c k8s-gitops \uc5d0 \ucee4\ubc0b<\/strong> : \ube4c\ub4dc \ub9c8\uc9c0\ub9c9 \ub2e8\uacc4\uc5d0\uc11c values \uc758 \ud0dc\uadf8\ub97c <code>sed<\/code> \ub85c \ubc14\uafb8\uace0 push. k8s-gitops \uc4f0\uae30 \uad8c\ud55c\uc774 \uc788\ub294 \ud1a0\ud070\uc744 \uc571 \uc800\uc7a5\uc18c Secret \uc73c\ub85c \ub4f1\ub85d\ud574\uc57c \ud569\ub2c8\ub2e4.<\/li>\n<li><strong>Argo CD Image Updater<\/strong> : \ub808\uc9c0\uc2a4\ud2b8\ub9ac\ub97c \uac10\uc2dc\ud558\ub2e4\uac00 \uc0c8 \ud0dc\uadf8\uac00 \uc0dd\uae30\uba74 Git \uc5d0 \uc790\ub3d9 \ucee4\ubc0b. \ubcc4\ub3c4 \ucef4\ud3ec\ub10c\ud2b8\ub97c \uc124\uce58\ud574\uc57c \ud569\ub2c8\ub2e4.<\/li>\n<\/ul>\n<p>\ub450 \ubc29\ubc95 \ubaa8\ub450 \uacb0\uad6d <strong>Git \uc758 \ud0dc\uadf8\uac00 \ubc14\ub00c\uc5b4\uc11c \ubc30\ud3ec\ub41c\ub2e4<\/strong>\ub294 \uc6d0\uce59\uc740 \uac19\uc2b5\ub2c8\ub2e4. \uc774 \uae00\uc5d0\uc11c\ub294 \ud750\ub984\uc774 \uc798 \ubcf4\uc774\ub3c4\ub85d \uc218\ub3d9\uc73c\ub85c \ub461\ub2c8\ub2e4.<\/p>\n<h2>8. \uc8fc\uc758\uc0ac\ud56d\uacfc \ubb38\uc81c \ud574\uacb0<\/h2>\n<h3>8.1 <code>exec format error<\/code> \ub85c \ud30c\ub4dc\uac00 \ubc14\ub85c \uc8fd\uc744 \ub54c<\/h3>\n<p>\uc774\ubbf8\uc9c0\uc5d0 arm64 \uac00 \uc5c6\ub294 \uacbd\uc6b0\uc785\ub2c8\ub2e4. 4\uc7a5 workflow \uc758 <code>platforms<\/code> \uc5d0 <code>linux\/arm64<\/code> \uac00 \uc788\ub294\uc9c0, \uadf8\ub9ac\uace0 \uc774\ubbf8\uc9c0\uc5d0 \ub450 \uc544\ud0a4\ud14d\ucc98\uac00 \ubaa8\ub450 \ub4e4\uc5b4\uac14\ub294\uc9c0 \ud655\uc778\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">docker buildx imagetools inspect ghcr.io\/&lt;YOUR_ID&gt;\/spring-hello:sha-1a2b3c4\n# Platform: linux\/amd64\n# Platform: linux\/arm64   \u2190 \uc774 \uc904\uc774 \uc788\uc5b4\uc57c \ud568<\/code><\/pre>\n<h3>8.2 <code>ImagePullBackOff<\/code><\/h3>\n<p>\ub300\ubd80\ubd84 \ud328\ud0a4\uc9c0\uac00 \uc544\uc9c1 Private \uc774\uac70\ub098, \uc774\ubbf8\uc9c0 \uacbd\ub85c\uc5d0 \ub300\ubb38\uc790\uac00 \uc11e\uc778 \uacbd\uc6b0\uc785\ub2c8\ub2e4. Private \uc73c\ub85c \uc720\uc9c0\ud558\uace0 \uc2f6\ub2e4\uba74 <code>read:packages<\/code> \uad8c\ud55c \ud1a0\ud070\uc73c\ub85c pull Secret \uc744 \ub9cc\ub4e4\uace0 values \uc5d0\uc11c \ucc38\uc870\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-bash\">kubectl create namespace hello\nkubectl -n hello create secret docker-registry ghcr-pull \\\n  --docker-server=ghcr.io \\\n  --docker-username=&lt;YOUR_ID&gt; \\\n  --docker-password=&lt;GITHUB_TOKEN&gt;<\/code><\/pre>\n<pre><code class=\"language-yaml\"># values\/spring-hello\/values.yaml \uc5d0 \ucd94\uac00\nimagePullSecrets:\n  - name: ghcr-pull<\/code><\/pre>\n<blockquote>\n<p>2\ud3b8 6.3 \uacfc \ub9c8\ucc2c\uac00\uc9c0\ub85c \uc774 Secret \uc740 <strong>Git \uc5d0 \ucee4\ubc0b\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.<\/strong> \ub610 2\ud3b8\uc758 <code>charts\/nginx<\/code> \uc5d0\ub294 <code>imagePullSecrets<\/code> \uac00 \uc5c6\uc73c\ubbc0\ub85c, static-web \ub3c4 Private \uc73c\ub85c \uc4f0\ub824\uba74 5.1 \uc758 deployment.yaml \ucc98\ub7fc <code>with .Values.imagePullSecrets<\/code> \ube14\ub85d\uc744 \ucd94\uac00\ud574\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<\/blockquote>\n<h3>8.3 \uba54\ubaa8\ub9ac: OOMKilled \uc640 \ub290\ub9b0 \uae30\ub3d9<\/h3>\n<ul>\n<li>JVM \uc740 \ucee8\ud14c\uc774\ub108 limit \ub97c \uae30\uc900\uc73c\ub85c \ud799\uc744 \uc7a1\uc2b5\ub2c8\ub2e4(<code>MaxRAMPercentage=75<\/code> \u2192 limit 512Mi \uc911 \uc57d 384Mi). <code>OOMKilled<\/code> \uac00 \ubcf4\uc774\uba74 <code>values\/spring-hello\/values.yaml<\/code> \uc5d0\uc11c <code>resources.limits.memory<\/code> \ub97c \uc62c\ub9bd\ub2c8\ub2e4.<\/li>\n<li>\ub77c\uc988\ubca0\ub9ac \ud30c\uc774 4GB \uc5d0\uc11c\ub294 2\ud3b8\uc758 ArgoCD + Headlamp + \uc774\ubc88 spring-hello 2\uac1c(\ucd5c\ub300 1Gi)\uac00 \ud568\uaed8 \uc62c\ub77c\uac11\ub2c8\ub2e4. <code>kubectl top pods -A<\/code> \ub85c \uc5ec\uc720\ub97c \ud655\uc778\ud558\uace0, \ubd80\uc871\ud558\uba74 <code>replicaCount: 1<\/code> \ub85c \uc904\uc785\ub2c8\ub2e4.<\/li>\n<li>\uae30\ub3d9\uc774 180\ucd08\ub97c \ub118\uaca8 \uc7ac\uc2dc\uc791\uc774 \ubc18\ubcf5\ub418\uba74 \ucc28\ud2b8\uc758 <code>startupProbe.failureThreshold<\/code> \ub97c \ub298\ub9bd\ub2c8\ub2e4.<\/li>\n<\/ul>\n<h3>8.4 static-web \ud5ec\uc2a4\uccb4\ud06c<\/h3>\n<p>3.2 \uc5d0\uc11c \ub9cc\ub4e0 <code>\/healthz<\/code> \ub294 2\ud3b8 <code>charts\/nginx<\/code> \uc5d0 probe \uac00 \uc5c6\uc5b4\uc11c \uc544\uc9c1 \uc4f0\uc774\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. \ud544\uc694\ud558\uba74 <code>charts\/nginx\/templates\/deployment.yaml<\/code> \uc758 \ucee8\ud14c\uc774\ub108\uc5d0 \ub2e4\uc74c\uc744 \ucd94\uac00\ud569\ub2c8\ub2e4. (2\ud3b8 nginx \uacf5\uc2dd \uc774\ubbf8\uc9c0\uc5d0\ub294 <code>\/healthz<\/code> \uac00 \uc5c6\uc73c\ubbc0\ub85c <code>path: \/<\/code> \ub97c \uc4f0\ub294 \ud3b8\uc774 \ub450 \uc571 \ubaa8\ub450\uc5d0 \uc548\uc804\ud569\ub2c8\ub2e4.)<\/p>\n<pre><code class=\"language-yaml\">          readinessProbe:\n            httpGet: { path: \/, port: 80 }\n            periodSeconds: 5<\/code><\/pre>\n<h3>8.5 CSS \ub97c \uace0\ucce4\ub294\ub370 \ud654\uba74\uc774 \uadf8\ub300\ub85c\uc77c \ub54c<\/h3>\n<p>static-web \uc740 1\uc2dc\uac04 \ube0c\ub77c\uc6b0\uc800 \uce90\uc2dc\ub97c \uc8fc\uae30 \ub54c\ubb38\uc5d0, \ud30c\uc77c \uc774\ub984\uc774 \uac19\uc73c\uba74 \uc774\uc804 CSS \uac00 \ubcf4\uc77c \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uac15\ub825 \uc0c8\ub85c\uace0\uce68(Ctrl+Shift+R)\uc73c\ub85c \ud655\uc778\ud558\uace0, \uc6b4\uc601\uc5d0\uc11c\ub294 <code>style.css?v=\ubc84\uc804<\/code> \ucc98\ub7fc \ucffc\ub9ac \ubb38\uc790\uc5f4\uc774\ub098 \ud30c\uc77c\uba85\uc5d0 \ubc84\uc804\uc744 \ubd99\uc5ec \uce90\uc2dc\ub97c \ubb34\ud6a8\ud654\ud569\ub2c8\ub2e4.<\/p>\n<h3>8.6 HTTPS \ub85c \ubc14\uafc0 \ub54c<\/h3>\n<p>\ub098\uc911\uc5d0 spring-hello \ub97c HTTPS \ub85c \uc11c\ube44\uc2a4\ud558\uba74\uc11c <code>APP_STATIC_BASE_URL<\/code> \uc774 <code>http:\/\/<\/code> \ub85c \ub0a8\uc544 \uc788\uc73c\uba74, \ube0c\ub77c\uc6b0\uc800\uac00 <strong>\ud63c\ud569 \ucf58\ud150\uce20(Mixed Content)<\/strong> \ub85c CSS\u00b7\uc774\ubbf8\uc9c0\ub97c \ucc28\ub2e8\ud569\ub2c8\ub2e4. \ub450 \uc571\uc744 Ingress \ub4a4\uc5d0 \uac19\uc740 \ub3c4\uba54\uc778\uc73c\ub85c \ubb36\uc744 \ub54c \ud568\uaed8 \ubc14\uafd4\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<h2>9. \uc815\ub9ac<\/h2>\n<p>2\ud3b8 \u2192 3\ud3b8 \ubcc0\uacbd \uc694\uc57d<\/p>\n<table>\n<thead>\n<tr>\n<th>\ud56d\ubaa9<\/th>\n<th>2\ud3b8<\/th>\n<th>3\ud3b8<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\ubc30\ud3ec \ub300\uc0c1<\/td>\n<td>\uacf5\uc2dd \uc774\ubbf8\uc9c0(nginx, metrics-server \ub4f1)<\/td>\n<td><strong>\uc9c1\uc811 \ube4c\ub4dc\ud55c \uc774\ubbf8\uc9c0<\/strong> 2\uac1c<\/td>\n<\/tr>\n<tr>\n<td>\uc774\ubbf8\uc9c0 \ube4c\ub4dc<\/td>\n<td>\uc5c6\uc74c<\/td>\n<td>GitHub Actions (amd64 + arm64)<\/td>\n<\/tr>\n<tr>\n<td>\ub808\uc9c0\uc2a4\ud2b8\ub9ac<\/td>\n<td>Docker Hub \ub4f1 \uacf5\uac1c \ub808\uc9c0\uc2a4\ud2b8\ub9ac<\/td>\n<td>ghcr.io (<code>sha-<\/code> \ud0dc\uadf8)<\/td>\n<\/tr>\n<tr>\n<td>\ucc28\ud2b8<\/td>\n<td><code>charts\/nginx<\/code><\/td>\n<td><code>charts\/spring-boot<\/code> \ucd94\uac00, <code>charts\/nginx<\/code> \ub294 static-web \uc5d0 \uc7ac\uc0ac\uc6a9<\/td>\n<\/tr>\n<tr>\n<td>\uc571 \uad6c\uc131<\/td>\n<td>\ub2e8\uc77c nginx<\/td>\n<td>WAS(spring-hello) + \uc815\uc801 \ub9ac\uc18c\uc2a4 \uc11c\ubc84(static-web) \ubd84\ub9ac<\/td>\n<\/tr>\n<tr>\n<td>\ubc30\ud3ec \ud2b8\ub9ac\uac70<\/td>\n<td>values \/ targetRevision \ubcc0\uacbd<\/td>\n<td>values \uc758 <code>image.tag<\/code> \ubcc0\uacbd<\/td>\n<\/tr>\n<tr>\n<td>\uc218\ub3d9 \uc791\uc5c5<\/td>\n<td>\ucd5c\ucd08 1\ud68c<\/td>\n<td>\uc571 push \ud6c4 \ud0dc\uadf8 1\uc904 \uc218\uc815 (7.2 \ub85c \uc790\ub3d9\ud654 \uac00\ub2a5)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\uc800\uc7a5\uc18c\ub294 \uc138 \uac1c\uac00 \ub418\uc5c8\uc9c0\ub9cc \uc5ed\ud560\uc740 \uba85\ud655\ud569\ub2c8\ub2e4. <strong>\uc571 \uc800\uc7a5\uc18c\ub294 \uc774\ubbf8\uc9c0\ub97c \ub9cc\ub4e4\uace0, k8s-gitops \ub294 \ubb34\uc5c7\uc744 \ubc30\ud3ec\ud560\uc9c0 \uacb0\uc815\ud558\uace0, ArgoCD \ub294 \uadf8\ub300\ub85c \ubc18\uc601\ud569\ub2c8\ub2e4.<\/strong><\/p>\n<h2>\ucc38\uace0<\/h2>\n<ul>\n<li><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=11993\">Kubernetes \u2013 ArgoCD + Helm \uc73c\ub85c Native Helm + GitOps Values \ud328\ud134 \uad6c\uc131\ud558\uae30<\/a> (2\ud3b8)<\/li>\n<li><a href=\"https:\/\/spring.io\/blog\/2026\/06\/10\/spring-boot-4\/\">Spring Boot 4.1.0 available now<\/a> \u2013 spring.io<\/li>\n<li><a href=\"https:\/\/github.com\/Spring-projects\/Spring-boot\/wiki\/Spring-Boot-4.1-Release-Notes\">Spring Boot 4.1 Release Notes<\/a> \u2013 GitHub wiki<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Kubernetes \u2013 Spring Boot Hello World \uc640 \uc815\uc801 \ub9ac\uc18c\uc2a4 \ud504\ub85c\uc81d\ud2b8 \ubc30\ud3ec\ud558\uae30 \uc774 \uae00\uc740 Kubernetes \u2013 ArgoCD + Helm \uc73c\ub85c Native Helm + GitOps Values \ud328\ud134 \uad6c\uc131\ud558\uae30 \uc758 \ud6c4\uc18d\ud3b8\uc785\ub2c8\ub2e4. 2\ud3b8\uc5d0\uc11c \ub9cc\ub4e0 \ub2e8\uc77c \ub178\ub4dc \ud074\ub7ec\uc2a4\ud130(Debian 13 \/ Raspberry Pi, 192.168.20.206)\uc640 k8s-gitops \uc800\uc7a5\uc18c\ub97c \uadf8\ub300\ub85c \uc0ac\uc6a9\ud569\ub2c8\ub2e4. 0. \ubaa9\ud45c \uc774\ubc88 \uae00\uc5d0\uc11c\ub294 \uc9c1\uc811 \ub9cc\ub4e0 \uc560\ud50c\ub9ac\ucf00\uc774\uc158 2\uac1c\ub97c 2\ud3b8\uacfc \uac19\uc740 Native Helm +\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12003\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[],"class_list":["post-12003","post","type-post","status-publish","format-standard","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12003","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12003"}],"version-history":[{"count":4,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12003\/revisions"}],"predecessor-version":[{"id":12008,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12003\/revisions\/12008"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12003"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12003"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12003"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}