<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Eundms</title>
    <link>https://eundms.tistory.com/</link>
    <description>LogDEVLife</description>
    <language>ko</language>
    <pubDate>Thu, 25 Jun 2026 02:18:02 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>:해피래빗 </managingEditor>
    <image>
      <title>Eundms</title>
      <url>https://tistory1.daumcdn.net/tistory/4620854/attach/79c77f821c704b208d104a0bcca05378</url>
      <link>https://eundms.tistory.com</link>
    </image>
    <item>
      <title>[Kubernetes] ServiceAccount, Role, RoleBinding 관계</title>
      <link>https://eundms.tistory.com/1006</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;누가 무엇을 연결(누가 무엇을 한다)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ServiceAccount : 권한을 사용할 주체&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Role : 어떤 리소스에 어떤 행동을 할 수 있는지 정의&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- RoleBinding: ServiceAccount와 Role을 연결&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1779620678622&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  namespace: dev&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1779620690607&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev
  name: pod-reader

rules:
- apiGroups: [&quot;&quot;]
  resources: [&quot;pods&quot;]
  verbs: [&quot;get&quot;, &quot;list&quot;, &quot;watch&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1779620714103&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: dev

subjects:
- kind: ServiceAccount
  name: app-sa
  namespace: dev

roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Role vs ClusterRole&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Role : 특정 namespace 범위, 특정 namespace 안에서만 동작&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ClusterRole: Node 조회, 모든 namespace pod 조회&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;RoleBinding vs ClusterRoleBinding&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RoleBinding&lt;/td&gt;
&lt;td&gt;namespace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ClusterRoleBinding&lt;/td&gt;
&lt;td&gt;cluster 전체&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  지식 in Action/☁️  ️</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/1006</guid>
      <comments>https://eundms.tistory.com/1006#entry1006comment</comments>
      <pubDate>Sun, 24 May 2026 20:06:36 +0900</pubDate>
    </item>
    <item>
      <title>[Kubernetes] Secret</title>
      <link>https://eundms.tistory.com/1005</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;시크릿의 특성과 사용이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kubernetes Secret은 단순 Base64 인코딩이다 (암호화가 아니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;etcd에 평문으로 저장되며 API (access)접근 권한이 있는 모든 사용자 또는 etcd에 접근할 수 있는 모든 사용자는 시크릿을 조회하거나 수정할 수 있다. 네임스페이스에서 파드를 생성할 권한이 있는 사람은 누구나 해당 네임스페이스의 모든 시크릿을 읽을 수 있다 .&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, kubectl get secrets -o yaml 로 보면 쉽게 복원 가능하다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 Secret을 쓰는 이유는 운영 레벨에서 안전성을 높이는 구조가 있기 때문이다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 노드 단위로 제한하여 전달할 수 있다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Secret은 필요한 Pod가 있는 Node에만 전달된다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 전체 클러스터에 퍼지지 않으므로 공격 표면적(?)이 감소한다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 디스크가 아니라 메모리(tmpfs)에 저장된다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 디스크 탈취 공격을 방지할 수 있다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) Pod 삭제시 Secret도 같이 삭제된다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Pod가 사라지면 Kubelet이 Secret도 정리한다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 따라서, 잔존 데이터 리스크가 감소한다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4) Git에 안 올리면 최소한의 사고 방지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Secret YAML을 repo에 안 올리는 것만으로도 사람의 실수로 유출되는 사고를 방지할 수 있다&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;934&quot; data-start=&quot;899&quot; data-ke-size=&quot;size23&quot;&gt;시크릿을 안전하게 사용하려면&amp;nbsp;&lt;/h3&gt;
&lt;p data-end=&quot;934&quot; data-start=&quot;899&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/security/secrets-good-practices/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/ko/docs/concepts/security/secrets-good-practices/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;934&quot; data-start=&quot;899&quot; data-ke-size=&quot;size18&quot;&gt;etcd Encryption at Rest 활성화&lt;a href=&quot;https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;957&quot; data-start=&quot;935&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;957&quot; data-start=&quot;935&quot; data-section-id=&quot;1sf6zbn&quot;&gt;etcd에 저장될 때 실제로 암호화됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1006&quot; data-start=&quot;986&quot; data-ke-size=&quot;size18&quot;&gt;RBAC으로 접근 제한 &lt;a href=&quot;https://kubernetes.io/ko/docs/reference/access-authn-authz/authorization/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/ko/docs/reference/access-authn-authz/authorization/&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1030&quot; data-start=&quot;1007&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1030&quot; data-start=&quot;1007&quot; data-section-id=&quot;16jfm1j&quot;&gt;Secret 읽을 수 있는 권한 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;External Secret 관리 도구 사용&lt;a href=&quot;https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#provider-for-the-secrets-store-csi-driver&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://secrets-store-csi-driver.sigs.k8s.io/concepts.html#provider-for-the-secrets-store-csi-driver&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  지식 in Action/☁️  ️</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/1005</guid>
      <comments>https://eundms.tistory.com/1005#entry1005comment</comments>
      <pubDate>Tue, 21 Apr 2026 08:29:19 +0900</pubDate>
    </item>
    <item>
      <title>AI시대에 개발자에게 가장 필요한 역량이 무엇일까 (지극히 개인적인 생각)</title>
      <link>https://eundms.tistory.com/1004</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;AI 시대에 개발자에게 가장 필요한 역량은 '고유한 관점'이라고 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; 생성형 AI는 확률에 기반하여 문제를 정의하고 해결하지만&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;같은 기술을 사용하더라도 문제를 바라보는 시각에 따라 전혀 다른 해결 방식이 나올 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 엘리베이터 속도가 느리다는 문제에 대해 어떤 이는 속도를 개선하려 했고, 다른 이는 거울을 설치해 사용자의 체감 시간을 줄이는 방식으로 접근했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발에서도 마찬가지라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능 개선, 시스템 구조 단순화, 운영 안정성 확보 등 어떤 관점에서 문제를 정의하느냐에 따라 해결 방향은 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 중요한 것은 문제의 본질적인 맥락을 이해하고, 상황에 맞는 해결책을 설계하는 사고력이라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이미 알려진 방식에 머무르기보다 다양한 관점에서 시도하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 과정과 생각을 팀과 공유하며 설득하는 과정이 앞으로 더욱 중요해질 것이라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px; color: #dddddd;&quot;&gt;이러한 관점에서 오픈소스 활동은 좋은 환경이라고 생각한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> Insight</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/1004</guid>
      <comments>https://eundms.tistory.com/1004#entry1004comment</comments>
      <pubDate>Wed, 15 Apr 2026 21:23:39 +0900</pubDate>
    </item>
    <item>
      <title>[Kubernetes] 서비스 : NodePort, ClusterIP, Load Balancer</title>
      <link>https://eundms.tistory.com/1002</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;서비스&lt;/h3&gt;
&lt;pre id=&quot;code_1775360755062&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;kubectl service {서비스이름} --url&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/service/#publishing-services-service-types&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/ko/docs/concepts/services-networking/service/#publishing-services-service-types&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1775361424807&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;서비스&quot; data-og-description=&quot;외부와 접하는 단일 엔드포인트 뒤에 있는 클러스터에서 실행되는 애플리케이션을 노출시키며, 이는 워크로드가 여러 백엔드로 나뉘어 있는 경우에도 가능하다.&quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/service/#publishing-services-service-types&quot; data-og-url=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/service/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ukRgx/dJMb87f62wD/o7f3M1g54bWAkBq9Ix5bbk/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/service/#publishing-services-service-types&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/service/#publishing-services-service-types&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ukRgx/dJMb87f62wD/o7f3M1g54bWAkBq9Ix5bbk/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;서비스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;외부와 접하는 단일 엔드포인트 뒤에 있는 클러스터에서 실행되는 애플리케이션을 노출시키며, 이는 워크로드가 여러 백엔드로 나뉘어 있는 경우에도 가능하다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod 정의가 아래와 같다고 하자&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775360190742&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# pod-definition.yml

apiVersion: v1
kind: Pod

metadata:
  name: myapp-pod
  labels:
    app: myapp
    type: front-end
  spec:
    containers:
    - name: nginx-container
      image: nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/service/#type-nodeport&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NodePort&lt;/a&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service 관점에서 내 포트(port), 노드에 달린 Port(노드포트), 타겟 포트(포트를 노출하고 싶은 컨테이너의 포트)&lt;/p&gt;
&lt;pre id=&quot;code_1775359791206&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# service-definition.yml

apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  type: NodePort
  ports:
    - targetPort: 80   # 1. 타겟 포트 (default, 2와 동일)
      port: 80         # 2. 서비스 오브젝트의 포트값 (필수)
      nodePort: 30008  # 3. 노드 포트 (default, 자동)
  selector:  # pod-definition.yml의 레이블 selector (모든 일치하는 레이블 찾아서 진행함) 
    app: myapp
    type: front-end&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 서비스는 모든 노드에 걸쳐서 동일한 레이블에 해당하는 파드에 대해 적용되고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;이때 service 는 로드밸런서 역할을 하게 됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLUhza/dJMcaax4sK1/xSgM1kXgxWDRidsiGqjfXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLUhza/dJMcaax4sK1/xSgM1kXgxWDRidsiGqjfXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLUhza/dJMcaax4sK1/xSgM1kXgxWDRidsiGqjfXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLUhza%2FdJMcaax4sK1%2FxSgM1kXgxWDRidsiGqjfXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;546&quot; height=&quot;315&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ClusterIp&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시: frontend backend redis 각각 끼리 통신하기 위한 IP&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/service/#%EB%8F%99%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/ko/docs/concepts/services-networking/service/#%EB%8F%99%EA%B8%B0&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775361030866&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# clusterIP for Backend

apiVersion: v1
kind: Service
metadata:
  name: back-end
spec:
  type: ClusterIP
  ports:
    - targetPort: 80
      port: 80
  selector: # pod-definition.yml의 lables.*의 내용 적기
    app: myapp
    type: backend&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lNdkC/dJMcadVN76Z/Z4G29ukVsNvRb6cqxjdvIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lNdkC/dJMcadVN76Z/Z4G29ukVsNvRb6cqxjdvIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lNdkC/dJMcadVN76Z/Z4G29ukVsNvRb6cqxjdvIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlNdkC%2FdJMcadVN76Z%2FZ4G29ukVsNvRb6cqxjdvIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;448&quot; height=&quot;353&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/service/#loadbalancer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Load Balancer&lt;/a&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HAProxy, Nginx등을 설치해서 LoadBalancer가 /voting 은 voting app으로 /dashboard는 dashboard app으로 가게 할 수 있다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS, GCP 등이 제공하는 LoadBalancer 서비스를 사용하기 위한 타입이다&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775361839740&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  type: LoadBalancer
  ports:
    - targetPort: 80
      port: 80
      nodePort: 30008&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  지식 in Action/☁️  ️</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/1002</guid>
      <comments>https://eundms.tistory.com/1002#entry1002comment</comments>
      <pubDate>Sun, 5 Apr 2026 13:07:49 +0900</pubDate>
    </item>
    <item>
      <title>GC 튜닝 기본</title>
      <link>https://eundms.tistory.com/1001</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1) JVM의 주요 default 설정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 서버용 머신 : G1GC가 사용, 그 외 : Serial Collector 사용&lt;/p&gt;
&lt;pre id=&quot;code_1775051621363&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2. Initial heap size (JVM이 시작할 때 바로 확보하는 heap 크기) : RAM의 1/64

3. maximum heap size (JVM heap의 최대 크기) : RAM의 1/4

4. minimum heap size (JVM heap의 최소 크기) : 디폴트 값 설정이 약간 복잡하게 결정됨&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 서버 애플리케이션의 경우 이 세가지 값을 동일하게 맞춤&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775051639756&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;5. 최대 GC thread 수 : heap size와 이용 가능한 CPU resources에 의해 결정됨

6. JIT 컴파일러 : C1과 C2를 사용하는 tiered compiler 사용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 중인 자바 프로세스의 JVM 기본 옵션 보기&amp;nbsp;&lt;/h3&gt;
&lt;pre id=&quot;code_1775050943946&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;jps -l # 현재 실행중인 자바 프로세스 ID 리스트&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgGRKu/dJMcah4ZdQ3/YfWxdkaktKOEs8Y7i4Eapk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgGRKu/dJMcah4ZdQ3/YfWxdkaktKOEs8Y7i4Eapk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgGRKu/dJMcah4ZdQ3/YfWxdkaktKOEs8Y7i4Eapk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgGRKu%2FdJMcah4ZdQ3%2FYfWxdkaktKOEs8Y7i4Eapk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;556&quot; height=&quot;88&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;88&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1775050943946&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;jcmd 프로세스아이디 VM.flags # 기본적으로 설정된 VM Option&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2) 튜닝 대상&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최대 일시 중지 시간(Maximum Pause-Time Goal) : &lt;i&gt;&lt;b&gt;-XX:MaxGCPauseMillis=밀리초&lt;/b&gt;&lt;/i&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 일시 중지 시간 : &amp;nbsp;가비지 컬렉터가 애플리케이션을 중지하고 더 이상 사용되지 않는 공간을 회수하는 데 걸리는 시간&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775050870967&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- pause time이 아무리 길어도 `maximum pause-time goal`보다는 적어야 한다 
- GC는 pause time에 대한 가중평균과 분산을 계산해서 이 둘의 합을 maximum pause-time 으로 설정
- maximum pause-time goal의 디폴트 값은 collector마다 다름&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; heap size나 gc 관련 여러 파라미터들을 조정하여 pause time을 nnn milliseconds보다 작게 유지하려고 시도&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;Q. 일시 중지 시간을 줄이고 싶어+힙 관점에서는 어떻게 조절해야 하는가&lt;/b&gt; &lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙 사이즈 줄이기 (탐색해야하는 힙내 데이터가 줄어들음)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;처리량 목표(Throughput Goal)&amp;nbsp; :&lt;i&gt;&lt;b&gt; -XX:GCTimeRatio=nnn&lt;/b&gt;&lt;/i&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- GC time과 application time을 비교해서 특정 비율을 맞춘다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- `-XX:GCTimeRatio=nnn`로 지정. `GC Time Ratio = 1/(1+nnn)`로 목표를 설정한다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;Q. throughput goal이 충족되지 않음&lt;/b&gt; &lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙 사이즈 늘이기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;풋프린트 (&lt;b&gt;Minimum Footprint Goal&lt;/b&gt;)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 처리량 및 최대 일시 중지 시간 목표가 충족되면, 두 목표 중 하나(대기 처리량 목표)를 더 이상 충족할 수 없을 때까지 힙 크기를 줄인다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(불필요하게 점유하는 메모리를 줄여서 다른 프로세스들도 메모리를 사용할 수 있게 해준다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 가비지 컬렉터가 사용할 수 있는 최소 및 최대 힙 크기는 다음을 사용하여 설정할 수 있다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-Xms=&amp;lt;nnn&amp;gt;&amp;nbsp; : 최소 힙 크기&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-Xmx=&amp;lt;mmm&amp;gt; : 최대 힙 크기&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;Q. 서버 애플리케이션은 최소 힙 = 최대 힙 . 왜 ?&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;런타임 중 힙 크기 변화를 막아서 GC 안정성과 성능을 확보하기 위해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;419&quot; data-start=&quot;371&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;382&quot; data-start=&quot;371&quot; data-section-id=&quot;yllmot&quot;&gt;항상 트래픽 있음&lt;/li&gt;
&lt;li data-end=&quot;404&quot; data-start=&quot;383&quot; data-section-id=&quot;13zyh50&quot;&gt;latency 민감 (특히 API)&lt;/li&gt;
&lt;li data-end=&quot;419&quot; data-start=&quot;405&quot; data-section-id=&quot;19z4bc9&quot;&gt;예측 가능한 성능 중요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;432&quot; data-start=&quot;421&quot; data-ke-size=&quot;size16&quot;&gt;  힙이 늘어나면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;489&quot; data-start=&quot;434&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;450&quot; data-start=&quot;434&quot; data-section-id=&quot;s4lmt7&quot;&gt;GC pause 시간 증가&lt;/li&gt;
&lt;li data-end=&quot;461&quot; data-start=&quot;451&quot; data-section-id=&quot;17dqyao&quot;&gt;요청 지연 발생&lt;/li&gt;
&lt;li data-end=&quot;489&quot; data-start=&quot;462&quot; data-section-id=&quot;10qeo2t&quot;&gt;tail latency 튐 (이게 제일 위험)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3) 힙 사이즈 튜닝을 어떻게 해야 하는가&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;throughput goal을 잡고 max heap size를 잡는다 (swap 없이)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 목표를 달성하지 못하면 RAM 이 이 throughput 을 감당하지 못하는 것이다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;달성했는데 pause time이 너무 길면 maximum pause-time goal 을 지정한다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(단, throughput goal과 maximum pause-time goal은 트레이드 오프 관계이기 때문에 적당한 타협이 필요하다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 애플리케이션은 동일하게 설정한다&amp;nbsp;&lt;/p&gt;</description>
      <category>  지식 in Action/Java &amp;amp; Kotlin</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/1001</guid>
      <comments>https://eundms.tistory.com/1001#entry1001comment</comments>
      <pubDate>Wed, 1 Apr 2026 23:42:38 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] AWS Certified Cloud Practitioner 취득 후기</title>
      <link>https://eundms.tistory.com/999</link>
      <description>&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;시험 개요&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #232b37; text-align: start;&quot;&gt;AWS Certified Cloud Practitioner를 취득하면 AWS 클라우드의 서비스 및 용어에 대한 기초 지식을 습득&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;시간&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;90분 &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;가격&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;100USD (환율...)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;할인 방법&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;1) 여러 방법&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.reddit.com/r/AWSCertifications/comments/1q0vu4p/2026_aws_vouchers_exam_discounts_coupons_other/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.reddit.com/r/AWSCertifications/comments/1q0vu4p/2026_aws_vouchers_exam_discounts_coupons_other/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 100% 할인 - 포인트 교환 : 언제 열릴지 열리긴 할지 모름&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.awseducate.com/student/s/etc-home&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.awseducate.com/student/s/etc-home&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1773065452702&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Sign In&quot; data-og-description=&quot;Functional cookies help us provide useful site features, remember your preferences, and display relevant content. Approved third parties may set these cookies to provide certain site features. If you do not allow these cookies, then some or all of these se&quot; data-og-host=&quot;www.awseducate.com&quot; data-og-source-url=&quot;https://www.awseducate.com/student/s/etc-home&quot; data-og-url=&quot;https://www.awseducate.com/student/s/etc-home&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.awseducate.com/student/s/etc-home&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.awseducate.com/student/s/etc-home&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Sign In&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Functional cookies help us provide useful site features, remember your preferences, and display relevant content. Approved third parties may set these cookies to provide certain site features. If you do not allow these cookies, then some or all of these se&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.awseducate.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0a0a0a; text-align: start;&quot; data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQAA&quot; data-sfc-cb=&quot;&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;Requirements:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;4,500 points for Foundational, 5,200 points for Associate level.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQAQ&quot; data-sfc-cb=&quot;&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;Actions:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Complete surveys, training courses, and labs in the ETC.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQAg&quot; data-sfc-cb=&quot;&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;Process:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;After accumulating enough points, redeem them in the &quot;Rewards&quot; tab of the ETC.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQAw&quot; data-sfc-cb=&quot;&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;Limitations:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Once an associate voucher is received, you cannot request another one immediately, but you can still earn points for a foundational voucher.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-processed=&quot;true&quot; data-hveid=&quot;CAMQBA&quot; data-sfc-cb=&quot;&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-sfc-cp=&quot;&quot;&gt;&lt;b&gt;Validation:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;It may take up to three business days for reward requests to be reviewed.&lt;/span&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-wiz-uids=&quot;A5hsJc_16,A5hsJc_17&quot;&gt;&lt;span data-processed=&quot;true&quot; data-sfc-cb=&quot;&quot; data-wiz-uids=&quot;A5hsJc_16,A5hsJc_17&quot;&gt;&lt;span data-processed=&quot;true&quot; data-wiz-attrbind=&quot;class=A5hsJc_15/TKHnVd&quot; data-animation-atomic=&quot;&quot;&gt;&lt;span data-processed=&quot;true&quot; aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;div data-processed=&quot;true&quot; data-ved=&quot;2ahUKEwiIzIvq_5KTAxWMslYBHVEBBv4Q3s0SegQIAxAG&quot; data-sfc-cb=&quot;&quot; data-animation-skip=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;해당 시험을 본 이유&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이후 &lt;b&gt;AWS Certified Solutions Architect - Associate &lt;/b&gt;취득을 위한&lt;br /&gt;1. &lt;b&gt;50퍼센트 할인 쿠폰&lt;/b&gt;을 얻기 위해&lt;br /&gt;2. &lt;b&gt;다양한 AWS 클라우드 서비스의 역할을 익히기&lt;/b&gt; 위해 (기초 지식 쌓기 위한 목적)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;준비기간&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;9시간 + 알파 (= 3시간 + 6시간 + 시험 직전)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;준비 방법&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;1. AWS Skill Builder의 &lt;br /&gt;AWS Cloud Practitioner Essentials 강의 &lt;br /&gt;&lt;a href=&quot;https://skillbuilder.aws&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;https://skillbuilder.aws&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;AWS Skill Builder&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;&quot; data-og-host=&quot;skillbuilder.aws&quot; data-og-source-url=&quot;https://skillbuilder.aws&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bihj6u/dJMb85WRl6U/c0yDiqCxk22i53sErD4gf1/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300&quot; data-og-url=&quot;https://skillbuilder.aws&quot;&gt;&lt;a href=&quot;https://skillbuilder.aws&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://skillbuilder.aws&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bihj6u/dJMb85WRl6U/c0yDiqCxk22i53sErD4gf1/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AWS Skill Builder&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;skillbuilder.aws&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;2. 어떤 블로그에 담겨 있는 기출 문제 정리 (이건 효과가 그렇게 있지 않았다)&lt;br /&gt;&lt;br /&gt;오히려 개념을 이해하고&lt;br /&gt;강의 내에서 제공해주는 기본 문제들을 &lt;br /&gt;개념에 기반하여 풀 수 있는 것이 중요하다&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;시험 준비 팁&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;해당 강의의 주제가 아래와 같은데&lt;br /&gt;이게 출제 기준과 매우 일치하다고 &lt;br /&gt;개인적으로 생각된다 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;AWS 클라우드의 기본 기능 및 &lt;b&gt;이점&lt;/b&gt;&lt;br /&gt;AWS 클라우드에서 가상 &lt;b&gt;컴퓨팅 리소스&lt;/b&gt;를 프로비저닝하고 관리하는 방법&lt;br /&gt;AWS 컴퓨팅 서비스가 &lt;b&gt;확장 가능&lt;/b&gt;한 서버리스 애플리케이션 환경을 지원하는 방법&lt;br /&gt;AWS &lt;b&gt;글로벌 인프라의 기본 구성 요소&lt;/b&gt; 및 &lt;b&gt;이점&lt;/b&gt;&lt;br /&gt;AWS &lt;b&gt;네트워킹 구성 요소 및 서비스&lt;/b&gt;&lt;br /&gt;AWS &lt;b&gt;스토리지 서비스, 스토리지 티어, 데이터 수명 주기 정책&lt;/b&gt;&lt;br /&gt;AWS 데이터베이스 서비스 및 &lt;b&gt;마이그레이션&lt;/b&gt; 도구&lt;br /&gt;AWS AI/ML 서비스, &lt;b&gt;AWS 생성형 AI &lt;/b&gt;서비스, &lt;b&gt;AWS ETL 데이터 파이프라인&lt;/b&gt;의 이점 및 목적&lt;br /&gt;&lt;b&gt;AWS 보안 서비스&lt;/b&gt;가 네트워크 공격으로부터 보호하고, 데이터를 보호하며, 보안 사고를 탐지하고 대응하도록 지원하는 방법&lt;br /&gt;AWS &lt;b&gt;모니터링&lt;/b&gt;, &lt;b&gt;규정 준수&lt;/b&gt;, &lt;b&gt;거버넌스 서비스&lt;/b&gt;&lt;br /&gt;&lt;b&gt;AWS 요금&lt;/b&gt; 및 &lt;b&gt;AWS Support&lt;/b&gt;의 기본 개념, 서비스, 기능&lt;br /&gt;&lt;b&gt;AWS 마이그레이션 전략&lt;/b&gt; 및 서비스&lt;br /&gt;전문 AWS 서비스 및 &lt;b&gt;AWS Well-Architected Framework의 6가지 핵심 요소&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;다음 글에서 아직도 헷갈리는 서비스들을 정리해보겠다.. (네트워크, 스토리지, 데이터처리, 마이그레이션, 모니터링)&lt;/p&gt;</description>
      <category> Insight/회고-연간_프로젝트_특별한일</category>
      <category>aws</category>
      <category>AWS Certified Cloud Practitioner</category>
      <category>시험후기</category>
      <category>준비 방법</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/999</guid>
      <comments>https://eundms.tistory.com/999#entry999comment</comments>
      <pubDate>Mon, 9 Mar 2026 09:39:40 +0900</pubDate>
    </item>
    <item>
      <title>[쿠버네티스] 쿠버네티스 리소스 구조 이해하기 - kind, metadata, spec</title>
      <link>https://eundms.tistory.com/998</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;모든 쿠버네티스 리소스는 4가지 최상위 필드를 가진다&amp;nbsp;&lt;/h3&gt;
&lt;pre id=&quot;code_1771891488953&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;apiVersion:
kind:
metadata:
spec:&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/#required-fields&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/docs/concepts/overview/working-with-objects/#required-fields&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1771892828823&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Objects In Kubernetes&quot; data-og-description=&quot;Kubernetes objects are persistent entities in the Kubernetes system. Kubernetes uses these entities to represent the state of your cluster. Learn about the Kubernetes object model and how to work with these objects.&quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/#required-fields&quot; data-og-url=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fq3or/dJMb84XVGCo/32l1l56x4RTbNkHR9UkVE1/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/#required-fields&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/#required-fields&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fq3or/dJMb84XVGCo/32l1l56x4RTbNkHR9UkVE1/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Objects In Kubernetes&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Kubernetes objects are persistent entities in the Kubernetes system. Kubernetes uses these entities to represent the state of your cluster. Learn about the Kubernetes object model and how to work with these objects.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spec은 리소스의 원하는 상태를 정의하는데 이 부분이 Kind마다 다르다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/#object-spec-and-status&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/docs/concepts/overview/working-with-objects/#object-spec-and-status&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1771892860664&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Objects In Kubernetes&quot; data-og-description=&quot;Kubernetes objects are persistent entities in the Kubernetes system. Kubernetes uses these entities to represent the state of your cluster. Learn about the Kubernetes object model and how to work with these objects.&quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/#object-spec-and-status&quot; data-og-url=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/brVojq/dJMb82Mz04o/pHtVSVhgK0bY59MjnuTvA0/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/#object-spec-and-status&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/#object-spec-and-status&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/brVojq/dJMb82Mz04o/pHtVSVhgK0bY59MjnuTvA0/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Objects In Kubernetes&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Kubernetes objects are persistent entities in the Kubernetes system. Kubernetes uses these entities to represent the state of your cluster. Learn about the Kubernetes object model and how to work with these objects.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Kind 종류&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Wokrload 관련 (앱 실행)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pod&lt;/b&gt; : 컨테이너 실행의 최소 단위 (지금 사용 중)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Deployment&lt;/b&gt;: Pod를 여러 개 생성/업데이트/롤백 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ReplicaSet&lt;/b&gt;: Pod 복제본 수 유지 (보통 Deployment가 자동 관리)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;StatefulSet&lt;/b&gt;: 상태가 있는 앱(DB 등) - 순서 보장, 고정 이름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DaemonSet&lt;/b&gt;: 모든 노드에 Pod 1개씩 실행 (로그 수집, 모니터링 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Job&lt;/b&gt; : 한 번 실행하고 끝나는 작업&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CronJob&lt;/b&gt; : 스케줄에 따라 반복 실행하는 Job&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Network (접근/통신)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Service&lt;/b&gt;: Pod에 안정적인 네트워크 접점 제공 (지금 사용중)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ingress&lt;/b&gt;: 외부 HTTP 트래픽을 Service로 라우팅 (도메인/경로 기반)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NetworkPolicy&lt;/b&gt;: Pod간 네트워크 트래픽 제어 (방화벽)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Configration (설정/저장)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ConfigMap&lt;/b&gt; : 설정값 저장 (환경변수, 설정 파일)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Secret&lt;/b&gt;: 민감한 데이터 저장 (비밀번호, 토큰)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PersistentVolume&lt;/b&gt; (PV) : 물리 스토리지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PersistentVolumeClaim&lt;/b&gt; (PVC) : PV 요청 (Pod가 스토리지 사용 시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Cluster Administration (클러스터 관리)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Namespace&lt;/b&gt; : 리소스를 논리적으로 분리&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ServiceAccount&lt;/b&gt; : Pod의 인증 ID&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Role/ClusterRole&lt;/b&gt; : 권한 정의&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RoleBinding/ClusterRoleBinding&lt;/b&gt; : 권한을 SA/사용자에 부여&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주요 Spec의 의미&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod의&amp;nbsp;spec&amp;nbsp;&amp;rarr;&amp;nbsp;&quot;어떤&amp;nbsp;컨테이너를&amp;nbsp;실행할&amp;nbsp;것인가&quot;&lt;/p&gt;
&lt;pre id=&quot;code_1771891382315&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  spec:
    containers:
    - name: redis
      image: redis:alpine
      ports:
      - containerPort: 6379&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;Service의&amp;nbsp;spec&amp;nbsp;&amp;rarr;&amp;nbsp;&quot;어떤&amp;nbsp;Pod에&amp;nbsp;어떻게&amp;nbsp;네트워크를&amp;nbsp;연결할&amp;nbsp;것인가&quot;&lt;/p&gt;
&lt;pre id=&quot;code_1771891408291&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  spec:
    type: NodePort
    ports:
    - port: 8080         # 클러스터 내부에서 서비스 접근 포트 
      targetPort: 80     # Pod의 어느 포트로 보낼지 
      nodePort: 31000    # 외부에서 접근하는 포트
    selector:            # label이 일치하는 Pod를 찾아 연결
      app: redis&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;Deployment의&amp;nbsp;spec&amp;nbsp;&amp;rarr;&amp;nbsp;&quot;Pod를&amp;nbsp;몇&amp;nbsp;개,&amp;nbsp;어떻게&amp;nbsp;관리할&amp;nbsp;것인가&quot;&lt;/p&gt;
&lt;pre id=&quot;code_1771891418956&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  spec:
    replicas: 3
    selector:
      matchLabels:
        app: redis
    template:            # Pod 템플릿 (안에 또 metadata + spec)
      metadata:
        labels:
          app: redis
      spec:
        containers:
        - name: redis
          image: redis:alpine&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Service -&amp;gt; Pod 연결 흐름&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service의 spec.selector.{key} : {value} == Pod의 metadata.labels.{key} : {value}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1771892886569&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Service&quot; data-og-description=&quot;Expose an application running in your cluster behind a single outward-facing endpoint, even when the workload is split across multiple backends.&quot; data-og-host=&quot;kubernetes.io&quot; data-og-source-url=&quot;https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service&quot; data-og-url=&quot;https://kubernetes.io/docs/concepts/services-networking/service/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0JDl5/dJMb9hCYfes/hmWkCuFLkoThbYqbccQxak/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0JDl5/dJMb9hCYfes/hmWkCuFLkoThbYqbccQxak/img.png?width=1727&amp;amp;height=373&amp;amp;face=0_0_1727_373');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Service&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Expose an application running in your cluster behind a single outward-facing endpoint, even when the workload is split across multiple backends.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  지식 in Action/☁️  ️</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/998</guid>
      <comments>https://eundms.tistory.com/998#entry998comment</comments>
      <pubDate>Tue, 24 Feb 2026 09:25:51 +0900</pubDate>
    </item>
    <item>
      <title>[테스트] 통합 테스트에서 테스트 간 DB 상태가 공유되는 문제 : @Transactional, 사용하면 안되는 상황, 그외 방식</title>
      <link>https://eundms.tistory.com/994</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 아래 테스트 코드를 실행 시켰다&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1770635251519&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootTest
@Import(SplearnTestConfiguration.class)
public class MemberRegisterTest {
  @Autowired
  private MemberRegister memberRegister;

  @Test
  void register(){
    Member member = memberRegister.register(MemberFixture.createRegisterRequest());

    assertThat(member.getId()).isNotNull();
    assertThat(member.getStatus()).isEqualTo(MemberStatus.PENDING);
  }

  @Test
  void duplicateEmailFail(){
    Member member = memberRegister.register(MemberFixture.createRegisterRequest());

    assertThatThrownBy(
        () -&amp;gt; memberRegister.register(MemberFixture.createRegisterRequest())
    ).isInstanceOf(DuplicateEmailException.class);

  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;현상&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;duplicateEmailFail의 첫번째 register에서 예외가 발생했다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원인&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통합 테스트에서 테스트 간 DB 상태가 공유되는 것이 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, @Transactional 으로 테스트 메서드마다 실행 후 자동 롤백되도록 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;@Transactional 으로 롤백이 안되는 경우는 없을까?&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 스프링 테스트가 아닐 때&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Test의 TransactionalTestExecutionListener가 @Transactional의 테스트 후 자동 롤백을 해준다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. HTTP 레벨 테스트&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@SpringBootTest(webEnvironment=RANDOM_PORT) + RestTemplate/WebTestClient로 테스트하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 별도 스레드에서 별도 트랜잭션을 사용하므로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트의 롤백이 서버 쪽 DB 변경에 영향을 못 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. DB가 원격이거나 분리된 경우&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트의 애플리케이션이 서로 다른 DB 커넥션/트랜잭션을 사용하면 롤백이 불가능하다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;테스트 코드와 애플리케이션 코드가 같은 트랜잭션을 공유하면 안되는 경우가 있을까?&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;@Transactional 테스트가 버그를 숨기는 경우&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) Lazy Loading 문제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테스트에 @Transactional이 있으면 영속성 컨텍스트가 테스트 끝까지 열려있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 서비스에서 지연 로딩(LAZY)을 호출해도 테스트에선 정상 동작&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하지만 실제 운영에선 서비스 메서드가 끝나면 트랜잭션이 닫히므로 LazyInitializationException 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테스트는 통과했는데 운영에서 터지는 상황&lt;/p&gt;
&lt;pre id=&quot;code_1770640438426&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Member 엔티티
@Entity
public class Member {
  @OneToMany(fetch = FetchType.LAZY)
  private List&amp;lt;Order&amp;gt; orders;  // 지연 로딩
}

// 서비스
@Service
public class MemberService {
  @Transactional
  public Member findMember(Long id) {
    return memberRepository.findById(id).orElseThrow();
    // 여기서 트랜잭션 끝 &amp;rarr; 영속성 컨텍스트 닫힘
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1770640458169&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 테스트에 @Transactional이 있으면
@Test
@Transactional
void test() {
  Member member = memberService.findMember(1L);
  member.getOrders().size(); // 테스트 트랜잭션이 아직 열려있어서 &amp;rarr; 성공!
}

// 운영에서는
Member member = memberService.findMember(1L);
member.getOrders().size(); // 서비스 트랜잭션이 이미 닫혔으므로 &amp;rarr; LazyInitializationException!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;운영&amp;nbsp;환경&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;컨트롤러&amp;nbsp;호출&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;서비스&amp;nbsp;@Transactional&amp;nbsp;시작&amp;nbsp;&amp;rarr;&amp;nbsp;영속성&amp;nbsp;컨텍스트&amp;nbsp;열림&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;memberRepository.findById(1L)&amp;nbsp;&amp;nbsp;--&amp;nbsp;Member&amp;nbsp;로딩&amp;nbsp;(orders는&amp;nbsp;LAZY라&amp;nbsp;프록시)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;서비스&amp;nbsp;@Transactional&amp;nbsp;끝&amp;nbsp;&amp;rarr;&amp;nbsp;영속성&amp;nbsp;컨텍스트&amp;nbsp;닫힘&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;member.getOrders().size()&amp;nbsp;&amp;nbsp;--&amp;nbsp;영속성&amp;nbsp;컨텍스트&amp;nbsp;이미&amp;nbsp;닫힘&amp;nbsp;&amp;rarr;&amp;nbsp;LazyInitializationException!&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;테스트&amp;nbsp;환경&amp;nbsp;(@Transactional&amp;nbsp;있을&amp;nbsp;때)&lt;br /&gt;&amp;nbsp;&amp;nbsp;테스트&amp;nbsp;@Transactional&amp;nbsp;시작&amp;nbsp;&amp;rarr;&amp;nbsp;영속성&amp;nbsp;컨텍스트&amp;nbsp;열림&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;서비스&amp;nbsp;@Transactional&amp;nbsp;(테스트&amp;nbsp;트랜잭션에&amp;nbsp;합류,&amp;nbsp;새로&amp;nbsp;안&amp;nbsp;만듦)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;memberRepository.findById(1L)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;서비스&amp;nbsp;메서드&amp;nbsp;끝&amp;nbsp;(하지만&amp;nbsp;트랜잭션은&amp;nbsp;테스트&amp;nbsp;것이라&amp;nbsp;안&amp;nbsp;닫힘)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;member.getOrders().size()&amp;nbsp;&amp;nbsp;--&amp;nbsp;테스트&amp;nbsp;트랜잭션이&amp;nbsp;아직&amp;nbsp;열려있음&amp;nbsp;&amp;rarr;&amp;nbsp;성공!&lt;br /&gt;&amp;nbsp;&amp;nbsp;테스트&amp;nbsp;@Transactional&amp;nbsp;끝&amp;nbsp;&amp;rarr;&amp;nbsp;롤백&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;핵심은&amp;nbsp;서비스의&amp;nbsp;@Transactional이&amp;nbsp;독립&amp;nbsp;트랜잭션을&amp;nbsp;안&amp;nbsp;만들고&amp;nbsp;테스트&amp;nbsp;트랜잭션에&amp;nbsp;합류(기본&amp;nbsp;전파&amp;nbsp;=&lt;br /&gt;&amp;nbsp;&amp;nbsp;REQUIRED)하기 때문에, 서비스 메서드가 끝나도 영속성 컨텍스트가 살아있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영에서는 서비스 트랜잭션이 진짜 끝나니까 터진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2) Flush 타이밍 문제 (ID 생성 전략에 따라 다름)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 롤백할 거니까 JPA가 DB에 flush를 안 할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; GenerationType.IDENTITY는 save()시 즉시 INSERT 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; GenerationType.SEQUENCE는 save()시 INSERT를 커밋 시점까지 미룰 수 있음 -&amp;gt; 이때 flush 생략 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- unique 제약 조건 위반 같은 DB 레벨 에러가 테스트에서 안 터짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테스트는 통과, 운영에서 실패&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 아래처럼 @Id의 @GeneratedValue(GenerationType.SEQUENCE)인 엔티티가 있고&lt;/p&gt;
&lt;pre id=&quot;code_1770640483818&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
	@Id
  	@GeneratedValue(strategy = GenerationType.SEQUENCE) // 확인!
  	private Long id;
    
    // Member 엔티티에 unique 제약
	@Column(unique = true)
	private String email;
    
    //중략..
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 @DataJpaTest 테스트 코드를 작성한다고 하자&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1770640501519&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@DataJpaTest
class MemberRepositoryTest {
  @Autowired
  MemberRepository memberRepository;
  
  // @Transactional - @DataJpaTest을 사용하게 되면 @Transactional이 이미 포함되어 있음
  @Test
  void duplicateEmailFail(){
    Member member = Member.register(createRegisterRequest(), createPasswordEncoder());
    memberRepository.save(member);

    Member member2 = Member.register(createRegisterRequest(), createPasswordEncoder());
    assertThatThrownBy(() -&amp;gt; memberRepository.save(member2))
        .isInstanceOf(DataIntegrityViolationException.class);

  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번째 save에서 예외가 났어야 했지만,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 살펴보면, SEQUENCE 전략은 시퀀스에서 id만 미리 받아오고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 INSERT는 flush/커밋 시점까지 미루기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;unique 제약 위반이 발생하지 않음을 알 수 있다. (IDENTITY는 flush되서 예외 발생함)&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hibernate: create sequence member_seq start with 1 increment by 50&lt;br /&gt;Hibernate:&amp;nbsp;create&amp;nbsp;table&amp;nbsp;member&amp;nbsp;(id&amp;nbsp;bigint&amp;nbsp;not&amp;nbsp;null,&amp;nbsp;address&amp;nbsp;varchar(255),&amp;nbsp;nick_name&amp;nbsp;varchar(255),&amp;nbsp;password_hash&amp;nbsp;varchar(255),&amp;nbsp;status&amp;nbsp;enum&amp;nbsp;('ACTIVE','DEACTIVATED','PENDING'),&amp;nbsp;primary&amp;nbsp;key&amp;nbsp;(id),&amp;nbsp;unique&amp;nbsp;(address))&lt;br /&gt;2026-02-09T21:44:16.147+09:00&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;10145&amp;nbsp;---&amp;nbsp;[splearn]&amp;nbsp;[&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Test&amp;nbsp;worker]&amp;nbsp;j.LocalContainerEntityManagerFactoryBean&amp;nbsp;:&amp;nbsp;Initialized&amp;nbsp;JPA&amp;nbsp;EntityManagerFactory&amp;nbsp;for&amp;nbsp;persistence&amp;nbsp;unit&amp;nbsp;'default'&lt;br /&gt;2026-02-09T21:44:16.276+09:00&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;10145&amp;nbsp;---&amp;nbsp;[splearn]&amp;nbsp;[&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Test&amp;nbsp;worker]&amp;nbsp;t.s.a.required.MemberRepositoryTest&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;Started&amp;nbsp;MemberRepositoryTest&amp;nbsp;in&amp;nbsp;0.878&amp;nbsp;seconds&amp;nbsp;(process&amp;nbsp;running&amp;nbsp;for&amp;nbsp;1.221)&lt;br /&gt;Mockito&amp;nbsp;is&amp;nbsp;currently&amp;nbsp;self-attaching&amp;nbsp;to&amp;nbsp;enable&amp;nbsp;the&amp;nbsp;inline-mock-maker.&amp;nbsp;This&amp;nbsp;will&amp;nbsp;no&amp;nbsp;longer&amp;nbsp;work&amp;nbsp;in&amp;nbsp;future&amp;nbsp;releases&amp;nbsp;of&amp;nbsp;the&amp;nbsp;JDK.&amp;nbsp;Please&amp;nbsp;add&amp;nbsp;Mockito&amp;nbsp;as&amp;nbsp;an&amp;nbsp;agent&amp;nbsp;to&amp;nbsp;your&amp;nbsp;build&amp;nbsp;what&amp;nbsp;is&amp;nbsp;described&amp;nbsp;in&amp;nbsp;Mockito's&amp;nbsp;documentation:&amp;nbsp;&lt;a href=&quot;https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.3&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.3&lt;/a&gt;&lt;br /&gt;WARNING:&amp;nbsp;A&amp;nbsp;Java&amp;nbsp;agent&amp;nbsp;has&amp;nbsp;been&amp;nbsp;loaded&amp;nbsp;dynamically&amp;nbsp;(/Users/eundms/.gradle/caches/modules-2/files-2.1/net.bytebuddy/byte-buddy-agent/1.15.11/a38b16385e867f59a641330f0362ebe742788ed8/byte-buddy-agent-1.15.11.jar)&lt;br /&gt;WARNING:&amp;nbsp;If&amp;nbsp;a&amp;nbsp;serviceability&amp;nbsp;tool&amp;nbsp;is&amp;nbsp;in&amp;nbsp;use,&amp;nbsp;please&amp;nbsp;run&amp;nbsp;with&amp;nbsp;-XX:+EnableDynamicAgentLoading&amp;nbsp;to&amp;nbsp;hide&amp;nbsp;this&amp;nbsp;warning&lt;br /&gt;WARNING:&amp;nbsp;If&amp;nbsp;a&amp;nbsp;serviceability&amp;nbsp;tool&amp;nbsp;is&amp;nbsp;not&amp;nbsp;in&amp;nbsp;use,&amp;nbsp;please&amp;nbsp;run&amp;nbsp;with&amp;nbsp;-Djdk.instrument.traceUsage&amp;nbsp;for&amp;nbsp;more&amp;nbsp;information&lt;br /&gt;WARNING:&amp;nbsp;Dynamic&amp;nbsp;loading&amp;nbsp;of&amp;nbsp;agents&amp;nbsp;will&amp;nbsp;be&amp;nbsp;disallowed&amp;nbsp;by&amp;nbsp;default&amp;nbsp;in&amp;nbsp;a&amp;nbsp;future&amp;nbsp;release&lt;br /&gt;&lt;b&gt;Hibernate: select next value for member_seq &lt;span style=&quot;color: #ee2323;&quot;&gt;// 첫&amp;nbsp;번째&amp;nbsp;save:&amp;nbsp;시퀀스&amp;nbsp;값만&amp;nbsp;가져옴&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Hibernate:&amp;nbsp;select&amp;nbsp;next&amp;nbsp;value&amp;nbsp;for&amp;nbsp;member_seq&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;nbsp;//&amp;nbsp;두&amp;nbsp;번째 save: 시퀀스 값만 가져옴&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Expecting&amp;nbsp;code&amp;nbsp;to&amp;nbsp;raise&amp;nbsp;a&amp;nbsp;throwable.&lt;br /&gt;java.lang.AssertionError:&amp;nbsp;&lt;br /&gt;Expecting&amp;nbsp;code&amp;nbsp;to&amp;nbsp;raise&amp;nbsp;a&amp;nbsp;throwable.&lt;br /&gt;at&amp;nbsp;tobyspring.splearn.application.required.MemberRepositoryTest.duplicateEmailFail(MemberRepositoryTest.java:38)&lt;br /&gt;at&amp;nbsp;java.base/java.lang.reflect.Method.invoke(Method.java:580)&lt;br /&gt;at&amp;nbsp;java.base/java.util.ArrayList.forEach(ArrayList.java:1596)&lt;br /&gt;at&amp;nbsp;java.base/java.util.ArrayList.forEach(ArrayList.java:1596)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Hibernate: insert into member (address,nick_name,password_hash,status,id) values (?,?,?,?,?) &lt;span style=&quot;color: #ee2323;&quot;&gt;// &amp;nbsp;실제 INSERT는 flush/커밋 시점까지 미룸&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 운영에서 동일한 이메일을 두 번 입력하는 코드는 트랜잭션 커밋 시점에 flush 되어 예외가 발생한다&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1770641686256&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 운영에서는
memberRepository.save(new Member(&quot;a@b.com&quot;));
memberRepository.save(new Member(&quot;a@b.com&quot;));
// 트랜잭션 커밋 시점에 flush &amp;rarr; DB에서 unique constraint violation!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;즉, 다시 설명하자면,&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;운영&amp;nbsp;환경&amp;nbsp;(트랜잭션&amp;nbsp;분리)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;서비스&amp;nbsp;@Transactional&amp;nbsp;시작&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;save(member1)&amp;nbsp;&amp;nbsp;&amp;nbsp;--&amp;nbsp;시퀀스&amp;nbsp;조회&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;save(member2)&amp;nbsp;&amp;nbsp;&amp;nbsp;--&amp;nbsp;시퀀스&amp;nbsp;조회&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;트랜잭션&amp;nbsp;커밋&amp;nbsp;&amp;rarr;&amp;nbsp;flush&amp;nbsp;&amp;rarr;&amp;nbsp;INSERT&amp;nbsp;2건&amp;nbsp;&amp;rarr;&amp;nbsp;unique&amp;nbsp;위반&amp;nbsp;터짐!&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;테스트&amp;nbsp;환경&amp;nbsp;(트랜잭션&amp;nbsp;공유)&lt;br /&gt;&amp;nbsp;&amp;nbsp;테스트&amp;nbsp;@Transactional&amp;nbsp;시작&amp;nbsp;(=&amp;nbsp;서비스도&amp;nbsp;이&amp;nbsp;트랜잭션에&amp;nbsp;참여)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;save(member1)&amp;nbsp;&amp;nbsp;&amp;nbsp;--&amp;nbsp;시퀀스&amp;nbsp;조회&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;save(member2)&amp;nbsp;&amp;nbsp;&amp;nbsp;--&amp;nbsp;시퀀스&amp;nbsp;조회&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;테스트&amp;nbsp;끝&amp;nbsp;&amp;rarr;&amp;nbsp;롤백&amp;nbsp;&amp;rarr;&amp;nbsp;flush&amp;nbsp;안&amp;nbsp;함&amp;nbsp;&amp;rarr;&amp;nbsp;unique&amp;nbsp;위반&amp;nbsp;안&amp;nbsp;터짐!&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;테스트가&amp;nbsp;트랜잭션을&amp;nbsp;감싸고&amp;nbsp;있으니까,&amp;nbsp;서비스의&amp;nbsp;@Transactional이&amp;nbsp;새&amp;nbsp;트랜잭션을&amp;nbsp;안&amp;nbsp;만들고&amp;nbsp;테스트&lt;br /&gt;&amp;nbsp;&amp;nbsp;트랜잭션에 합류한다. 그러면 커밋이 영원히 안 일어나고(롤백이니까), flush도 생략될 수 있어서&lt;br /&gt;&amp;nbsp;&amp;nbsp;운영에서만 터지는 버그를 숨기게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;// 참고로 SEQUENCE 를 예외 터지게 하려면 명시적으로 Flush 해줘야 함&lt;/p&gt;
&lt;pre id=&quot;code_1770642082546&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  @Test
  void duplicateEmailFail(){
      Member member = Member.register(createRegisterRequest(), createPasswordEncoder());
      memberRepository.save(member);

      Member member2 = Member.register(createRegisterRequest(), createPasswordEncoder());
      memberRepository.save(member2);

      assertThatThrownBy(() -&amp;gt; entityManager.flush())  // 여기서 실제 INSERT 발생 &amp;rarr; 예외
          .isInstanceOf(DataIntegrityViolationException.class);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;gt;&amp;gt;&amp;gt; 실제 운영 환경과 동일한 트랜잭션 경계로 테스트하고 싶을 때는 @Transactional을 빼고 테스트를 진행하자&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그렇다면, 테스트 간&amp;nbsp; 데이터를 격리시키는 다른 방법에는 무엇이 있을까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 각 테스트 마다 다른 데이터 사용하기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 각 테스트 실행전에 데이터 초기화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;언제 해야 할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 테스트 시작 전 : @BeforeEach에서 정리&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떻게 초기화해야 할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- @Sql / 로직 호출로 각 테스트에 적합한 데이터 입력&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 메타 데이터에서 전체 테이블 목록을 자동으로 조회해서 TRUNCATE하는 클래스를 만들어두고 호출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  지식 in Action/ </category>
      <category>테스트</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/994</guid>
      <comments>https://eundms.tistory.com/994#entry994comment</comments>
      <pubDate>Mon, 9 Feb 2026 22:10:52 +0900</pubDate>
    </item>
    <item>
      <title>[테스트]  No qualifying bean of type 'tobyspring.splearn.application.required.EmailSender' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}</title>
      <link>https://eundms.tistory.com/993</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;에러 메시지 일부&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Caused&amp;nbsp;by:&amp;nbsp;org.springframework.beans.factory.UnsatisfiedDependencyException:&amp;nbsp;Error&amp;nbsp;creating&amp;nbsp;bean&amp;nbsp;with&amp;nbsp;name&amp;nbsp;'memberService'&amp;nbsp;defined&amp;nbsp;in&amp;nbsp;file&amp;nbsp;[/Users/eundms/IdeaProjects/splearn/build/classes/java/main/tobyspring/splearn/application/MemberService.class]:&amp;nbsp;Unsatisfied&amp;nbsp;dependency&amp;nbsp;expressed&amp;nbsp;through&amp;nbsp;constructor&amp;nbsp;parameter&amp;nbsp;1:&amp;nbsp;No&amp;nbsp;qualifying&amp;nbsp;bean&amp;nbsp;of&amp;nbsp;type&amp;nbsp;'tobyspring.splearn.application.required.EmailSender'&amp;nbsp;available:&amp;nbsp;expected&amp;nbsp;at&amp;nbsp;least&amp;nbsp;1&amp;nbsp;bean&amp;nbsp;which&amp;nbsp;qualifies&amp;nbsp;as&amp;nbsp;autowire&amp;nbsp;candidate.&amp;nbsp;Dependency&amp;nbsp;annotations:&amp;nbsp;{}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;b&gt;@SpringBootTest&lt;/b&gt;를 활용한 테스트를 작성중이다&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1770631499975&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootTest
public class MemberRegisterManualTest {
  @Autowired
  private MemberRegister memberRegister;

  @Test
  void register(){
    Member member = memberRegister.register(MemberFixture.createRegisterRequest());

    assertThat(member.getId()).isNotNull();
    assertThat(member.getStatus()).isEqualTo(MemberStatus.PENDING);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 &lt;b&gt;MemberService&lt;/b&gt;가 작성되어 있다&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1770631419896&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class MemberService implements MemberRegister {
  private final MemberRepository memberRepository;
  private final EmailSender emailSender;
  private final PasswordEncoder passwordEncoder;

  @Override
  public Member register(MemberRegisterRequest registerRequest) {
    Member member = Member.register(registerRequest, passwordEncoder);
    memberRepository.save(member);
    emailSender.send(member.getEmail(), &quot;등록을 완료해주세요&quot;, &quot;아래 링크를 클릭해서 등록을 완료해주세요&quot;);
    return member;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;에러 메시지 해석&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Spring Context&lt;/b&gt;에 등록되어 있는 &lt;b&gt;MemberRegister&lt;/b&gt;을 가져오는 데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 안에서 사용되는 &lt;b&gt;EmailSender&lt;/b&gt;, &lt;b&gt;PasswordEncoder&lt;/b&gt;가 스프링 빈으로 등록되어 있지 않다 (구현체 없는 인터페이스임)&lt;/p&gt;
&lt;pre id=&quot;code_1770632031921&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface PasswordEncoder {
    String encode(String password);
    boolean matches(String password, String passwordHash);
}

public interface EmailSender {
  void send(Email email, String subject, String body);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결 시도&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- @Bean으로 emailSender, passwordEncoder를 Bean으로 등록한다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그리고 MemberTestConfiguration 은 독립된 파일로 존재한다&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1770631873096&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  @TestConfiguration
  class MemberTestConfiguration {
    @Bean
    public EmailSender emailSender(){
      return (email, subject, body) -&amp;gt; System.out.println(&quot;sending email&quot; + email);
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
      return MemberFixture.createPasswordEncoder();
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그럼에도 동일한 에러가 난다&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜? @SpringBootTest 가 붙은 MemberRegisterManualTest가 MemberTestConfiguration 을 사용해야 함을 모르기 때문이다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;따라서, @Import 로 사용함을 명시한다&lt;/h3&gt;
&lt;pre id=&quot;code_1770633388810&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootTest
@Import(MemberTestConfiguration.class)
public class MemberRegisterManualTest {
  @Autowired
  private MemberRegister memberRegister;

  @Test
  void register(){
    Member member = memberRegister.register(MemberFixture.createRegisterRequest());

    assertThat(member.getId()).isNotNull();
    assertThat(member.getStatus()).isEqualTo(MemberStatus.PENDING);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;임시로 구현한 DummyEmailSender 와 @TestConfiguration으로 등록한 emailSender 중에 무엇이 우선시 될까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/community/questions/1645701/testconfiguration-%EA%B4%80%EB%A0%A8-%EC%84%A4%EB%AA%85%EA%B3%BC-%EC%8B%A4%EC%A0%9C-%EB%8F%99%EC%9E%91%EC%9D%B4-%EB%8B%A4%EB%A5%B8-%EB%B6%80%EB%B6%84%EC%9D%B4-%EC%9E%88%EB%8A%94-%EA%B2%83-%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4?_gl=1%2A1fsppw%2A_gcl_au%2AMjA1ODQxMTM2MS4xNzY0MDc3MDkxLjEyMjk2NzM3NjAuMTc2OTA4OTY5My4xNzY5MDkwMDYw%2A_ga%2AMjA5MTY0NzUxOC4xNzU1MjIxODA5%2A_ga_85V6SRKGJV%2AczE3NzA2MjkwNjQkbzUxJGcxJHQxNzcwNjQ0ODg2JGo1NSRsMCRoMA..&amp;amp;referrer=inflearn&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.inflearn.com/community/questions/1645701/testconfiguration-%EA%B4%80%EB%A0%A8-%EC%84%A4%EB%AA%85%EA%B3%BC-%EC%8B%A4%EC%A0%9C-%EB%8F%99%EC%9E%91%EC%9D%B4-%EB%8B%A4%EB%A5%B8-%EB%B6%80%EB%B6%84%EC%9D%B4-%EC%9E%88%EB%8A%94-%EA%B2%83-%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4?_gl=1%2A1fsppw%2A_gcl_au%2AMjA1ODQxMTM2MS4xNzY0MDc3MDkxLjEyMjk2NzM3NjAuMTc2OTA4OTY5My4xNzY5MDkwMDYw%2A_ga%2AMjA5MTY0NzUxOC4xNzU1MjIxODA5%2A_ga_85V6SRKGJV%2AczE3NzA2MjkwNjQkbzUxJGcxJHQxNzcwNjQ0ODg2JGo1NSRsMCRoMA..&amp;amp;referrer=inflearn&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1770645163289&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;@TestConfiguration 관련 설명과 실제 동작이 다른 ... - 인프런 | 커뮤니티 질문&amp;amp;답변&quot; data-og-description=&quot;누구나 함께하는 인프런 커뮤니티. 모르면 묻고, 해답을 찾아보세요.&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://www.inflearn.com/community/questions/1645701/testconfiguration-%EA%B4%80%EB%A0%A8-%EC%84%A4%EB%AA%85%EA%B3%BC-%EC%8B%A4%EC%A0%9C-%EB%8F%99%EC%9E%91%EC%9D%B4-%EB%8B%A4%EB%A5%B8-%EB%B6%80%EB%B6%84%EC%9D%B4-%EC%9E%88%EB%8A%94-%EA%B2%83-%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4?_gl=1%2A1fsppw%2A_gcl_au%2AMjA1ODQxMTM2MS4xNzY0MDc3MDkxLjEyMjk2NzM3NjAuMTc2OTA4OTY5My4xNzY5MDkwMDYw%2A_ga%2AMjA5MTY0NzUxOC4xNzU1MjIxODA5%2A_ga_85V6SRKGJV%2AczE3NzA2MjkwNjQkbzUxJGcxJHQxNzcwNjQ0ODg2JGo1NSRsMCRoMA..&amp;amp;referrer=inflearn&quot; data-og-url=&quot;https://www.inflearn.com/community/questions/1645701/testconfiguration-%EA%B4%80%EB%A0%A8-%EC%84%A4%EB%AA%85%EA%B3%BC-%EC%8B%A4%EC%A0%9C-%EB%8F%99%EC%9E%91%EC%9D%B4-%EB%8B%A4%EB%A5%B8-%EB%B6%80%EB%B6%84%EC%9D%B4-%EC%9E%88%EB%8A%94-%EA%B2%83-%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4?_gl=1*1fsppw*_gcl_au*MjA1ODQxMTM2MS4xNzY0MDc3MDkxLjEyMjk2NzM3NjAuMTc2OTA4OTY5My4xNzY5MDkwMDYw*_ga*MjA5MTY0NzUxOC4xNzU1MjIxODA5*_ga_85V6SRKGJV*czE3NzA2MjkwNjQkbzUxJGcxJHQxNzcwNjQ0ODg2JGo1NSRsMCRoMA..&amp;amp;referrer=inflearn&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/NIVQ4/dJMb8TB5lES/enP6qpZG6h01MV3tUx5KZk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/b3M45T/dJMb8VNq7s1/Mw0hNRWyYdavZhX3syadck/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cL9Ag5/dJMb8ZvxdcF/lZ19NsjNOcqYeAu0bedYLK/img.png?width=2846&amp;amp;height=1028&amp;amp;face=0_0_2846_1028&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/community/questions/1645701/testconfiguration-%EA%B4%80%EB%A0%A8-%EC%84%A4%EB%AA%85%EA%B3%BC-%EC%8B%A4%EC%A0%9C-%EB%8F%99%EC%9E%91%EC%9D%B4-%EB%8B%A4%EB%A5%B8-%EB%B6%80%EB%B6%84%EC%9D%B4-%EC%9E%88%EB%8A%94-%EA%B2%83-%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4?_gl=1%2A1fsppw%2A_gcl_au%2AMjA1ODQxMTM2MS4xNzY0MDc3MDkxLjEyMjk2NzM3NjAuMTc2OTA4OTY5My4xNzY5MDkwMDYw%2A_ga%2AMjA5MTY0NzUxOC4xNzU1MjIxODA5%2A_ga_85V6SRKGJV%2AczE3NzA2MjkwNjQkbzUxJGcxJHQxNzcwNjQ0ODg2JGo1NSRsMCRoMA..&amp;amp;referrer=inflearn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.inflearn.com/community/questions/1645701/testconfiguration-%EA%B4%80%EB%A0%A8-%EC%84%A4%EB%AA%85%EA%B3%BC-%EC%8B%A4%EC%A0%9C-%EB%8F%99%EC%9E%91%EC%9D%B4-%EB%8B%A4%EB%A5%B8-%EB%B6%80%EB%B6%84%EC%9D%B4-%EC%9E%88%EB%8A%94-%EA%B2%83-%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4?_gl=1%2A1fsppw%2A_gcl_au%2AMjA1ODQxMTM2MS4xNzY0MDc3MDkxLjEyMjk2NzM3NjAuMTc2OTA4OTY5My4xNzY5MDkwMDYw%2A_ga%2AMjA5MTY0NzUxOC4xNzU1MjIxODA5%2A_ga_85V6SRKGJV%2AczE3NzA2MjkwNjQkbzUxJGcxJHQxNzcwNjQ0ODg2JGo1NSRsMCRoMA..&amp;amp;referrer=inflearn&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/NIVQ4/dJMb8TB5lES/enP6qpZG6h01MV3tUx5KZk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/b3M45T/dJMb8VNq7s1/Mw0hNRWyYdavZhX3syadck/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cL9Ag5/dJMb8ZvxdcF/lZ19NsjNOcqYeAu0bedYLK/img.png?width=2846&amp;amp;height=1028&amp;amp;face=0_0_2846_1028');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;@TestConfiguration 관련 설명과 실제 동작이 다른 ... - 인프런 | 커뮤니티 질문&amp;amp;답변&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;누구나 함께하는 인프런 커뮤니티. 모르면 묻고, 해답을 찾아보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  지식 in Action/ </category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/993</guid>
      <comments>https://eundms.tistory.com/993#entry993comment</comments>
      <pubDate>Mon, 9 Feb 2026 19:36:32 +0900</pubDate>
    </item>
    <item>
      <title>히스토리 잘 남기기 : 커밋메시지, 지라, 회의</title>
      <link>https://eundms.tistory.com/992</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;커밋 메시지에 남겨야 할 것들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 변경이 왜 필요했고, 무엇을 바꿨고, 어떤 맥락(Story/Bug)에서 나왔는가&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 왜 이 변경이 필요했는지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 무엇이 달라졌는지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;버그 Fix 커밋 예시&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[지라번호] 현상 명시&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기대 : 재처리 시 정상 처리된 상품 상태는 유지되어야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 실제 : 재처리 시 모든 상품이 PENDING으로 초기화됨&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 원인 : 처리 이력 초기 생성 로직이 전체 상품을 덮어씀&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지라에 남겨야 할 것들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 요구사항이 바뀐 순간 : AC 변경&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 성공/실패 기준 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- QA 판단이 개입된 순간&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Bug triage 결과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 재현 안됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 우선순위 낮춤&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 운영 영향 없음으로 판단&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 지금은 안 한다는 결정 : 나중에 한다, 다음 버전, 범위 제외&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;회의에서 남겨야 할 것들 (결정 로그)&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 80.2326%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.9875%;&quot;&gt;&lt;b&gt;결정(Decision)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.1288%;&quot;&gt;이렇게 하기로 했다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.9875%;&quot;&gt;&lt;b&gt;변경(Change)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.1288%;&quot;&gt;기존 결정에서 바뀐 점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.9875%;&quot;&gt;&lt;b&gt;보류(Deferred)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.1288%;&quot;&gt;지금은 안 하기로 했다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 30.9875%;&quot;&gt;&lt;b&gt;리스크(Risk)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.1288%;&quot;&gt;나중에 문제 될 수 있는 점&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장애 발생&lt;br /&gt;&amp;nbsp;&amp;darr;&lt;br /&gt;최근&amp;nbsp;배포&amp;nbsp;커밋&amp;nbsp;확인&lt;br /&gt;&amp;nbsp;&amp;darr;&lt;br /&gt;커밋&amp;nbsp;&amp;rarr;&amp;nbsp;연결된&amp;nbsp;Bug&amp;nbsp;/&amp;nbsp;Story&amp;nbsp;확인&lt;br /&gt;&amp;nbsp;&amp;darr;&lt;br /&gt;Story&amp;nbsp;&amp;rarr;&amp;nbsp;AC&amp;nbsp;/&amp;nbsp;회의&amp;nbsp;결정&amp;nbsp;로그&amp;nbsp;확인&lt;br /&gt;&amp;nbsp;&amp;darr;&lt;br /&gt;&amp;ldquo;아,&amp;nbsp;이&amp;nbsp;결정&amp;nbsp;때문에&amp;nbsp;여기서&amp;nbsp;터졌구나&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  지식 in Action/Git, Jira  ️</category>
      <author>:해피래빗 </author>
      <guid isPermaLink="true">https://eundms.tistory.com/992</guid>
      <comments>https://eundms.tistory.com/992#entry992comment</comments>
      <pubDate>Wed, 4 Feb 2026 21:04:58 +0900</pubDate>
    </item>
  </channel>
</rss>