<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ux on ICE-ICE-BEAR-BLOG</title><link>https://ice-ice-bear.github.io/ko/tags/ux/</link><description>Recent content in Ux on ICE-ICE-BEAR-BLOG</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Wed, 08 Apr 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://ice-ice-bear.github.io/ko/tags/ux/index.xml" rel="self" type="application/rss+xml"/><item><title>Hybrid Image Search 개발기 #11 — Tone/Angle 인젝션 UX 개선과 EC2 배포</title><link>https://ice-ice-bear.github.io/ko/posts/2026-04-08-hybrid-search-dev11/</link><pubDate>Wed, 08 Apr 2026 00:00:00 +0900</pubDate><guid>https://ice-ice-bear.github.io/ko/posts/2026-04-08-hybrid-search-dev11/</guid><description>&lt;img src="https://ice-ice-bear.github.io/" alt="Featured image of post Hybrid Image Search 개발기 #11 — Tone/Angle 인젝션 UX 개선과 EC2 배포" /&gt;&lt;p&gt;&lt;a class="link" href="https://ice-ice-bear.github.io/ko/posts/2026-04-07-hybrid-search-dev10/" &gt;이전 글: Hybrid Image Search 개발기 #10&lt;/a&gt;에서 OTel 메트릭 대시보드를 구축하고 파이프라인 성능을 최적화했다. 이번에는 tone/angle 인젝션 기능의 UX를 대폭 개선하고, EC2 인스턴스를 스케일업한 뒤 배포 자동화 스크립트까지 작성했다.&lt;/p&gt;
&lt;h2 id="이번-회차-커밋-로그"&gt;이번 회차 커밋 로그
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: center"&gt;순서&lt;/th&gt;
 &lt;th style="text-align: center"&gt;유형&lt;/th&gt;
 &lt;th&gt;내용&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;1&lt;/td&gt;
 &lt;td style="text-align: center"&gt;chore&lt;/td&gt;
 &lt;td&gt;Gemini API 타임아웃을 2분에서 3분으로 증가&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;2&lt;/td&gt;
 &lt;td style="text-align: center"&gt;fix&lt;/td&gt;
 &lt;td&gt;로컬 환경에서 OTel 익스포터 비활성화하여 연결 에러 해소&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;3&lt;/td&gt;
 &lt;td style="text-align: center"&gt;feat&lt;/td&gt;
 &lt;td&gt;tone/angle 인젝션 재생성 시 카테고리 변경 허용&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;4&lt;/td&gt;
 &lt;td style="text-align: center"&gt;fix&lt;/td&gt;
 &lt;td&gt;EC2 인스턴스 타입을 t3.medium에서 m7g.2xlarge로 변경&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;5&lt;/td&gt;
 &lt;td style="text-align: center"&gt;feat&lt;/td&gt;
 &lt;td&gt;tone/angle 자동 인젝션 활성화/비활성화 토글 추가&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;6&lt;/td&gt;
 &lt;td style="text-align: center"&gt;feat&lt;/td&gt;
 &lt;td&gt;재생성 시 원본의 인젝션 토글 상태를 자동 반영&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;7&lt;/td&gt;
 &lt;td style="text-align: center"&gt;feat&lt;/td&gt;
 &lt;td&gt;인젝션 없는 이미지에 인젝션 추가 시 비율 컨트롤 표시&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;8&lt;/td&gt;
 &lt;td style="text-align: center"&gt;feat&lt;/td&gt;
 &lt;td&gt;EC2 셋업 및 배포 스크립트 추가&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="배경-프로덕션을-향한-두-갈래-작업"&gt;배경: 프로덕션을 향한 두 갈래 작업
&lt;/h2&gt;&lt;p&gt;#10에서 성능 병목을 잡으면서 두 가지 숙제가 남았다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;UX 문제&lt;/strong&gt; — tone/angle 인젝션 기능이 있지만, 재생성할 때 카테고리를 바꿀 수 없고, 토글도 없어서 사용성이 떨어졌다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;인프라 문제&lt;/strong&gt; — t3.medium으로는 이미지 생성 파이프라인의 리소스 요구를 감당하기 어려웠고, 배포 과정도 수동이었다&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이번 회차는 이 두 가지를 병렬로 해결한 기록이다.&lt;/p&gt;
&lt;h2 id="1단계-gemini-api-타임아웃과-otel-로컬-에러-수정"&gt;1단계: Gemini API 타임아웃과 OTel 로컬 에러 수정
&lt;/h2&gt;&lt;h3 id="타임아웃-2분--3분"&gt;타임아웃 2분 → 3분
&lt;/h3&gt;&lt;p&gt;#10에서 2분 타임아웃을 걸었는데, 실제 운영 중에 Gemini API가 복잡한 이미지 생성 요청에서 2분을 초과하는 경우가 발생했다. 정상적인 처리 중인데 타임아웃으로 잘리는 건 비용 낭비이므로, 3분으로 늘렸다.&lt;/p&gt;
&lt;h3 id="otel-로컬-환경-연결-에러"&gt;OTel 로컬 환경 연결 에러
&lt;/h3&gt;&lt;p&gt;OTel 익스포터가 로컬 개발 환경에서도 Grafana Cloud 엔드포인트에 연결을 시도해서 에러 로그가 쏟아지고 있었다. 로컬에서는 OTel 익스포터를 비활성화하도록 조건 분기를 추가했다.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 Start["앱 시작"] --&gt; EnvCheck{"환경 변수 &amp;lt;br/&amp;gt; OTEL_ENABLED?"}
 EnvCheck --&gt;|true| OTelInit["OTel SDK 초기화 &amp;lt;br/&amp;gt; Traces + Metrics"]
 EnvCheck --&gt;|false| NoOp["OTel 비활성화 &amp;lt;br/&amp;gt; NoOp Exporter"]
 OTelInit --&gt; Grafana["Grafana Cloud"]
 NoOp --&gt; LocalDev["로컬 개발 &amp;lt;br/&amp;gt; 에러 없이 실행"]&lt;/pre&gt;&lt;p&gt;이렇게 하면 환경 변수 하나로 로컬과 프로덕션의 OTel 동작을 깔끔하게 분리할 수 있다.&lt;/p&gt;
&lt;h2 id="2단계-toneangle-인젝션-ux-개선"&gt;2단계: Tone/Angle 인젝션 UX 개선
&lt;/h2&gt;&lt;p&gt;이미지 검색 결과에 tone(색조)과 angle(시점)을 주입해서 새로운 이미지를 생성하는 기능이 있다. 기존에는 한 번 생성하면 수정하기 불편했는데, 세 가지 UX 개선을 진행했다.&lt;/p&gt;
&lt;h3 id="재생성-시-카테고리-변경-허용"&gt;재생성 시 카테고리 변경 허용
&lt;/h3&gt;&lt;p&gt;기존에는 인젝션을 적용해서 이미지를 재생성할 때, 원래 이미지의 카테고리가 고정되어 있었다. 사용자가 &amp;ldquo;이 이미지를 다른 카테고리 스타일로 다시 만들어 보고 싶다&amp;quot;고 할 때 대응할 수 없었다.&lt;/p&gt;
&lt;p&gt;카테고리 선택 드롭다운을 재생성 모드에서도 활성화하여, tone/angle은 유지하면서 카테고리만 바꿔서 재생성할 수 있게 했다.&lt;/p&gt;
&lt;h3 id="인젝션-활성화비활성화-토글"&gt;인젝션 활성화/비활성화 토글
&lt;/h3&gt;&lt;p&gt;tone/angle 인젝션이 항상 자동으로 적용되는 것이 때로는 불편했다. 토글 스위치를 추가해서 사용자가 인젝션 적용 여부를 직접 제어할 수 있게 했다.&lt;/p&gt;
&lt;h3 id="재생성-시-원본-토글-상태-자동-반영"&gt;재생성 시 원본 토글 상태 자동 반영
&lt;/h3&gt;&lt;p&gt;인젝션이 적용된 이미지를 재생성할 때, 토글이 기본값(off)으로 초기화되면 원본과 다른 결과가 나온다. 재생성 시 원본 이미지의 인젝션 토글 상태를 자동으로 복원하도록 했다.&lt;/p&gt;
&lt;h3 id="인젝션-없는-이미지에-인젝션-추가-시"&gt;인젝션 없는 이미지에 인젝션 추가 시
&lt;/h3&gt;&lt;p&gt;인젝션 없이 생성된 이미지에 나중에 인젝션을 추가하려고 할 때, 비율 조절 컨트롤이 표시되지 않는 문제가 있었다. 인젝션 토글을 켜면 비율 슬라이더가 함께 나타나도록 수정했다.&lt;/p&gt;
&lt;h2 id="3단계-ec2-인스턴스-스케일업과-배포-자동화"&gt;3단계: EC2 인스턴스 스케일업과 배포 자동화
&lt;/h2&gt;&lt;h3 id="t3medium--m7g2xlarge"&gt;t3.medium → m7g.2xlarge
&lt;/h3&gt;&lt;p&gt;#10에서 확인한 리소스 사용량 데이터를 바탕으로, 인스턴스 타입을 변경했다.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;항목&lt;/th&gt;
 &lt;th&gt;t3.medium&lt;/th&gt;
 &lt;th&gt;m7g.2xlarge&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;vCPU&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;RAM&lt;/td&gt;
 &lt;td&gt;4 GB&lt;/td&gt;
 &lt;td&gt;32 GB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;아키텍처&lt;/td&gt;
 &lt;td&gt;x86_64&lt;/td&gt;
 &lt;td&gt;ARM (Graviton3)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;비용 효율&lt;/td&gt;
 &lt;td&gt;범용&lt;/td&gt;
 &lt;td&gt;ARM 기반으로 동일 성능 대비 저렴&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Graviton3 기반 m7g는 x86 대비 가격 대비 성능이 좋고, Python 워크로드와의 호환성도 검증되어 있다. 이미지 생성 파이프라인이 CPU/RAM을 많이 쓰는 만큼, 충분한 여유를 확보했다.&lt;/p&gt;
&lt;h3 id="ec2-셋업-및-배포-스크립트"&gt;EC2 셋업 및 배포 스크립트
&lt;/h3&gt;&lt;p&gt;수동으로 SSH 접속해서 환경을 구성하던 과정을 스크립트로 자동화했다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;셋업 스크립트&lt;/strong&gt; — Python, 시스템 패키지 설치, 가상 환경 구성, 환경 변수 설정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;배포 스크립트&lt;/strong&gt; — 최신 코드 pull, 의존성 업데이트, 서비스 재시작&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 스크립트들이 있으면 새 인스턴스를 띄울 때도 빠르게 환경을 복제할 수 있고, 코드 업데이트 배포도 한 줄 명령으로 끝난다.&lt;/p&gt;
&lt;h2 id="정리"&gt;정리
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;주제&lt;/th&gt;
 &lt;th&gt;요약&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Gemini 타임아웃&lt;/td&gt;
 &lt;td&gt;2분 → 3분으로 조정, 정상 처리 중 타임아웃 방지&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;OTel 로컬 에러&lt;/td&gt;
 &lt;td&gt;환경 변수 기반으로 로컬에서 OTel 익스포터 비활성화&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;인젝션 UX&lt;/td&gt;
 &lt;td&gt;카테고리 변경, 토글 추가, 원본 상태 복원, 비율 컨트롤 표시&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;EC2 스케일업&lt;/td&gt;
 &lt;td&gt;t3.medium → m7g.2xlarge (Graviton3, 8 vCPU, 32 GB)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;배포 자동화&lt;/td&gt;
 &lt;td&gt;EC2 셋업 + 배포 스크립트 추가&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;</description></item></channel></rss>