GROWTH LOG STORIES

함께 만든 성장을,
기록으로 연결합니다.

AI와 함께 배우고, 직접 만들고, 서로 나눈
그로스로그 멤버들의 생생한 성장 기록을 만나보세요.

성장 기록
5기+이어진 커뮤니티
HEALTHIO
PROJECT

사진 한 장으로 시작하는 건강 루틴, Health IO

대표 이야기 읽기

ALL STORIES

성장의 순간을
한곳에서 만나보세요.

프로젝트의 시작부터 모임에서 나눈 인사이트까지,
그로스로그가 함께 만든 기록을 모았습니다.
개의 성장 기록

성장일지

[GL 3기 7회차 ③] 직접 하지 않게 만들기 — 쿠버네티스 GitOps, Flutter 리빌드 줄이기, S3 Presigned URL 🌱

GROWTH LOG🌱 2026. 8. 9. 06:56

안녕하세요! 그로스로그 입니다!😊 🌱

Git에 올리면 배포가 알아서 따라오는 구조, 다시 그리지 않아도 되는 화면을 골라내는 법, 그리고 서버를 거치지 않고 파일을 내려받게 하는 방법. 3기 7회차 세 편입니다.

3기 7회차, 2025년 6월 말입니다. 이번 회차에는 사람이나 서버가 직접 하지 않게 만드는 이야기 세 편이 모였어요.

 

01

⛵ 쿠버네티스 GitOps

이지은 님

이지은 님 원문에 실린 이미지
이런 내용이에요
쿠버네티스 스터디의 마지막 구간을 통째로 정리한 실습 기록입니다. 화면 캡처가 마흔 장 넘어요.
세 단계로 갑니다. Probe(상태 진단) → Manifest 관리(Kustomize·Helm) → GitOps(ArgoCD)요.
각 단계마다 개념 정리 → 명령어 → 실행 결과 캡처가 붙습니다.
Mac과 Windows 설치 명령을 나란히 적어둔 것도 눈에 띕니다.

조금 더 들어가 보면

🩺 살아 있는 것과 준비된 것

첫 단계가 Probe인데, 세 종류를 역할로 갈랐습니다.

livenessProbe — 컨테이너가 동작 중인지 체크. 동작 체크 실패 시 kubelet이 해당 컨테이너를 terminate하고 새 container 가동
readinessProbe — 컨테이너가 요청을 처리할 준비가 되었는지 여부 체크. 실패 시 엔드포인트 컨트롤러가 pod에 연관된 모든 서비스 엔드포인트에서 pod의 IP 주소 제거

둘의 차이가 실패했을 때 하는 일에 있습니다.

liveness가 실패하면 컨테이너를 죽이고 새로 띄웁니다. readiness가 실패하면 죽이지 않고 트래픽만 끊어요. 그리고 다시 준비되면 자동으로 다시 붙습니다.

왜 나눠놨을까요. 앱이 잠깐 바쁠 때를 생각하면 됩니다. 캐시를 새로 채우는 중이라 응답이 느린 상태에서 liveness가 실패하면 멀쩡한 앱을 죽이는 셈이에요. 그런데 그동안 요청을 받으면 사용자가 오래 기다리고요.

"트래픽은 끊되 죽이지는 않는" 상태가 필요한데, 그게 readiness입니다.

그래서 이런 줄이 붙었습니다.

운영환경에서는 liveness probe와 readiness probe를 함께 사용

세 번째 startupProbe의 설명도 정확합니다.

시작이 느린 SpringBoot, Actuator로 체크
startup probe가 주어진 경우, 성공할 때까지 다른 나머지 프로브는 활성화되지 않음 (성공 후 다른 프로브로 전환)

시작이 오래 걸리는 앱을 위한 유예 기간입니다. 이게 없으면 liveness의 initialDelaySeconds를 넉넉히 잡아야 하는데, 그러면 평소 장애 감지도 그만큼 늦어져요. startupProbe로 시작 구간을 따로 떼면 둘 다 챙길 수 있습니다.

체크 방식 네 가지도 정리했습니다. exec, httpGet, grpc, tcpSocket이요. 그중 exec의 판정 기준이 명확합니다.

지정된 명령 실행 (상태 코드 0으로 종료 시 진단 성공)

🧱 같은 것을 환경마다 다르게

두 번째 단계가 Manifest 관리인데, 왜 필요한지부터 적었습니다.

개발, 검증, 운영 환경별로 구성과 설정이 다른 경우에도 일관성 확보 (누락, 오타, 오류의 가능성 높아 기본 구성에 overlay하는 방식 적용)

"누락, 오타, 오류"가 문제의 실체입니다.

환경이 셋이면 YAML을 세 벌 들고 있게 되는데, 대부분이 똑같고 몇 줄만 다릅니다. 그런데 공통 부분을 고칠 때 세 파일을 다 고쳐야 하고, 하나를 빠뜨리면 운영에서만 다르게 도는 상황이 생겨요.

Kustomize가 그걸 base와 overlay로 나눕니다.

Base — Kustomize를 통해 변경할 yaml이 저장된 디렉터리. 재사용 가능한 기본 yaml
Overlay — Base에 적용할 kustomization.yaml이 저장된 디렉터리. 환경별
리소스를 변경하지 않고 필드를 재정의하여 새로운 쿠버네티스 리소스를 생성

원본을 안 건드린다는 게 핵심입니다. 개발용 overlay는 "이미지 태그만 dev로", 운영용은 "복제본 수만 3으로" 같은 차이만 적어두면 돼요.

Helm은 성격이 다릅니다.

보편적으로 사용되는 Manifest 도구 (Kubernetes의 package manager)
Template 기반 manifest 생성, 버전관리/업그레이드/롤백, 재사용 가능(차트)

패키지 매니저라는 점이 다릅니다. Kustomize는 내 YAML을 겹쳐 쓰는 도구인데, Helm은 남이 만든 차트를 받아 쓰는 것까지 포함해요. 실습에서도 Bitnami 저장소를 등록해 nginx를 설치합니다.

그리고 롤백이 목록에 있습니다. Helm은 릴리스를 버전으로 관리해서 이전 상태로 되돌릴 수 있거든요.

🔄 Git이 정답이 되는 구조

마지막이 ArgoCD입니다. 실습 순서가 이렇게 끝나요.

본인 Repository 클론 → Helm Chart 생성 → Git Push → values 파일 변경 → Git push

배포 명령이 없습니다.

이게 GitOps의 요점입니다. kubectl applyhelm upgrade를 사람이 치지 않아요. Git 저장소의 내용이 곧 클러스터가 있어야 할 상태이고, ArgoCD가 그걸 계속 확인해서 맞춰줍니다.

3기 3회차 큐레이션에서 소개해드린 이혜원 님의 노트에 이런 문장이 있었죠.

서버에게 직접 동작을 명령하지 않고 내가 원하는 상태를 "선언"하는 명령어

GitOps는 그 선언을 Git에 두는 것입니다. 쿠버네티스가 "선언된 상태를 유지"한다면, ArgoCD는 "그 선언이 어디 적혀 있는지"를 Git으로 옮긴 셈이에요.

그래서 얻는 게 몇 가지 있습니다. 누가 언제 무엇을 바꿨는지가 커밋 로그에 남고, 되돌리려면 커밋을 되돌리면 됩니다. 그리고 클러스터에 직접 손댈 권한을 사람에게 주지 않아도 되고요.

📝 원문에서는 이렇게 씁니다

이 기록의 형식이 일정합니다. 개념 → 명령어 블록 → 캡처 → 확인 결과요.

그리고 명령어에 운영체제별 대안이 붙어 있습니다.

Binary 설치 / MacOS / Chocolatey (Window)
Mac Homebrew 설치 / Windows Chocolatey

스터디를 여러 사람이 함께 하니 환경이 갈리거든요. 어느 쪽이든 따라올 수 있게 둘 다 적어둔 겁니다.

확인 명령도 매번 붙습니다.

# Pod 확인
watch kubectl get pod -o wide

# Pod 상세 정보
kubectl describe pod liveness-http

watch를 쓴 게 실습에서 유용합니다. liveness가 실패하면 재시작이 반복되는데, 그게 RESTARTS 숫자가 올라가는 걸로 눈에 보이거든요. 캡처에 붙인 설명도 그 이야기입니다. "계속 restart 진행중"요.

큐레이터 노트

세 단계를 한 흐름으로 묶은 게 이 기록의 값어치입니다.

Probe, Kustomize·Helm, ArgoCD는 따로 배우면 별개의 도구입니다. 그런데 순서대로 놓으면 하나의 이야기가 돼요. 상태를 판정할 수 있어야 → 구성을 선언으로 관리할 수 있고 → 그 선언을 Git에 맡길 수 있습니다.

거꾸로 말하면, Probe 없이 GitOps만 붙이면 배포는 자동인데 뭐가 잘못됐는지 모르는 상태가 됩니다.

이분의 3기 기록을 보면 도커 → 쿠버네티스 1·2주차 → GitOps로 이어집니다. 1회차 큐레이션에서 소개해드린 CJS·ESM 정리, 5회차의 결제 구현과는 결이 또 달라요. 프론트엔드에서 시작해 인프라까지 폭이 넓어진 기록입니다.

원문 읽으러 가기  ↗vapiano.tistory.com/61
 

02

🎨 Flutter 앱 성능 최적화

박상훈 님

이런 내용이에요
Flutter 앱이 느려지는 원인 세 가지를 짚고, 그에 맞는 개선 방법을 정리한 글입니다.
구성이 분명해요. 원인 분석 → 실전 팁 → 구조적 리팩터링 → 결론이요.
그리고 마지막에 조건을 하나 달았습니다. "상태관리 라이브러리를 사용하지 않고 최적화 방법입니다."
5회차에서 소개해드린 유닛 테스트 글과 같은 분의 기록이고, 그 사이에 「디버깅과 성능 분석 도구」가 한 편 더 있습니다.

조금 더 들어가 보면

🔁 다시 그리는 게 문제

원인 첫 번째가 리빌드입니다.

setState()나 상태 관리가 과도하게 build() 호출을 유발
동일한 위젯이 자주 다시 그려짐

그리고 잘못된 예를 붙였어요.

setState(() {
  title = 'New Title'; count++;
});
// 모든 위젯이 rebuild됨

주석 한 줄이 문제를 정확히 짚습니다.

Flutter에서 setState는 그 State가 감싸고 있는 위젯 트리 전체를 다시 만듭니다. 제목 글자 하나 바꾸려고 불렀는데 화면 전체가 다시 그려지는 거예요.

물론 Flutter는 실제 화면을 통째로 다시 칠하지는 않습니다. 새로 만든 위젯 트리와 이전 트리를 비교해서 달라진 부분만 반영해요. 그런데 비교하는 일 자체에 비용이 있습니다. 위젯이 수백 개면 그 비교가 매 프레임 돌아갑니다.

⛔ 다시 그릴 필요가 없다고 알려주기

개선 방법들이 전부 "여기는 안 바뀐다"를 알려주는 방식입니다.

먼저 const입니다.

const MyWidget()불변 → rebuild 방지

const로 만든 위젯은 같은 객체가 재사용됩니다. 비교 단계에서 "같은 인스턴스니까 볼 것도 없다"로 끝나요. 한 글자 붙이는 것치고 효과가 큽니다.

그다음이 RepaintBoundary입니다.

RepaintBoundary(
  child: HeavyWidget(),   // 무거운 위젯
)
특정 영역만 다시 그리도록 분리

이건 리빌드가 아니라 칠하는 단계의 이야기입니다. 화면의 한 부분을 별도 레이어로 떼어놓으면, 옆에서 뭐가 바뀌어도 그 레이어는 다시 칠하지 않아요. 애니메이션 옆에 정적인 그림이 있을 때 특히 효과가 있습니다.

그리고 ListView입니다.

ListView.builder: 지연 렌더링, 성능 우수
ListView: 모든 위젯을 한 번에 build → 메모리 부담

항목 천 개짜리 목록에서 화면에 보이는 건 열 개쯤입니다. builder는 보이는 것만 만들고, 스크롤하면 그때 다음 것을 만들어요.

3기 1회차 큐레이션에서 소개해드린 권순한 님의 배치 최적화와 발상이 같습니다. 다 메모리에 올리지 않고 필요한 만큼만 흘려보내는 것요.

🧵 화면 스레드에서 내보내기

세 번째 원인이 비동기 처리입니다.

Future 작업이 UI 쓰레드에서 블로킹
이미지 로딩, JSON 파싱 등을 메인 쓰레드에서 수행

해법이 이거예요.

compute(parseJson, jsonString);   // 메인 쓰레드 분리

여기서 짚어둘 게 있습니다. async/await를 쓴다고 다른 스레드로 가는 게 아닙니다.

Dart는 기본적으로 한 스레드에서 돕니다. await기다리는 동안 다른 일을 하게 해주는 것이지, 계산을 옮겨주지 않아요. 그래서 큰 JSON을 파싱하는 것처럼 CPU를 계속 쓰는 작업await를 붙여도 화면이 멈춥니다.

compute는 진짜로 다른 isolate에서 실행합니다. 메모리를 공유하지 않는 별도 실행 단위라 화면 스레드가 자유로워져요.

기다리는 일과 계산하는 일을 구분해야 어느 쪽 도구를 쓸지 정할 수 있습니다.

📊 재보고 나서 고치기

프레임 드랍 분석 항목도 있습니다.

flutter run --profile
PerformanceOverlay, DevTools → UI/GC 병목 탐지

--profile 모드를 짚은 게 정확합니다. 개발 모드에서는 성능을 재봐야 의미가 없거든요. 코드를 즉시 반영하려고 최적화를 꺼두기 때문입니다. 릴리스와 같은 조건으로 돌리면서 계측만 켜는 게 --profile이에요.

3기 2회차 큐레이션에서 소개해드린 허해수 님의 언리얼 stat 커맨드와 같은 자리입니다. 고치기 전에 어디가 느린지부터 보는 것요.

이분의 블로그 목록을 보면 이 글 바로 앞에 「디버깅과 성능 분석 도구」가 있습니다. 재는 법을 먼저 쓰고, 그다음에 고치는 법을 쓴 순서예요.

📝 원문에서는 이렇게 닫습니다

결론에 조건이 붙어 있습니다.

Flutter는 성능이 좋지만, 구조와 render 흐름을 이해하지 않으면 리소스를 낭비하기 쉽습니다.
리빌드 범위 통제 / 비동기 작업 분리 / DevTools로 정기 점검
이러한 루틴이 중요합니다.

"루틴"이라는 단어를 썼습니다. 한 번 최적화하고 끝나는 게 아니라 주기적으로 본다는 뜻이에요.

그리고 마지막 한 줄.

상태관리 라이브러리를 사용하지 않고 최적화 방법입니다.

적용 범위를 밝힌 것입니다. 본문에 Selector가 나오긴 하는데, Provider나 Riverpod 같은 걸 전제로 한 최적화는 아니라는 이야기죠.

이런 단서가 있으면 읽는 사람이 판단할 수 있습니다. 다른 상태관리를 쓰고 있다면 그쪽 방식이 따로 있을 수 있다는 걸 알게 되니까요.

큐레이터 노트

원인부터 세 갈래로 나눈 게 이 글을 고른 이유입니다.

"앱이 느리다"는 증상 하나인데 원인은 여러 가지입니다. 리빌드가 많아서일 수도, 목록이 무거워서일 수도, 메인 스레드가 막혀서일 수도 있어요. 원인이 다르면 고치는 방법도 다릅니다.

이 글은 그걸 먼저 갈라놓고 각각에 대응하는 방법을 붙였습니다. 그래서 목록으로만 봐도 내 상황에 맞는 걸 골라 쓸 수 있어요.

5회차 큐레이션에서 소개해드린 이분의 유닛 테스트 글과 이어서 보면 흐름이 보입니다. 테스트로 맞는지 확인하고, 프로파일링으로 빠른지 확인하는 것. 만든 다음에 하는 일 두 가지를 연달아 정리했어요.

원문 읽으러 가기  ↗rcshpark.tistory.com/8
 

03

📥 S3에 업로드된 파일 다운로드

이효원 님

이런 내용이에요
S3에 올려둔 파일을 사용자가 내려받게 만드는 구현 기록입니다.
프런트의 버튼 코드부터 서버의 URL 생성 함수까지 양쪽을 다 올렸어요.
핵심은 Presigned URL입니다. AWS 자격 증명 없이도 정해진 시간 동안만 파일에 접근할 수 있게 하는 방식이요.
코드 아래에 파라미터 하나하나의 역할을 풀어 적었습니다.

조금 더 들어가 보면

🎫 서버가 파일을 나르지 않는다

버튼을 누르면 일어나는 일이 이렇습니다.

fetch('/successcase/download?objectKey=' + encodeURIComponent(objectKey)
      + '&fileName=' + encodeURIComponent(fileName))
  .then(response => response.text())      // Presigned URL이 문자열로 리턴됨
  .then(presignedUrl => {
    window.open(presignedUrl, '_blank');  // 새창에서 다운로드 진행
  })

서버에서 받는 게 파일이 아니라 주소입니다.

이게 이 방식의 요점이에요. 서버는 "이 주소로 가면 받을 수 있다"는 쪽지 한 장만 만들어주고, 실제 파일은 브라우저가 S3에서 직접 받아옵니다.

파일이 서버를 거치는 방식과 비교해보면 차이가 큽니다. 100MB 파일을 열 명이 동시에 받으면, 서버를 거칠 때는 서버가 1GB를 읽어서 1GB를 내보내야 해요. 그동안 다른 요청 처리도 느려지고요.

Presigned URL이면 서버는 짧은 문자열 열 개만 만들면 됩니다. 무거운 일은 S3가 하고요.

그리고 encodeURIComponent를 양쪽 값에 다 씌운 것도 짚어둘 만합니다. 파일명에 한글이나 공백, &가 들어가면 그냥 붙였을 때 주소가 깨지거든요.

⏳ 1분짜리 열쇠

서버 쪽 함수의 핵심이 만료 시간입니다.

Date expiration = new Date();
long expTimeMillis = expiration.getTime();
expTimeMillis += 1000 * 60;   // 1분
expiration.setTime(expTimeMillis);

그리고 이 URL의 성격을 이렇게 적었습니다.

이 URL은 AWS 자격 증명 없이도 특정 시간 동안 파일에 접근할 수 있도록 허용합니다.

"특정 시간 동안"이 안전장치입니다.

Presigned URL은 그 자체로 열쇠라서, 주소를 아는 사람은 누구나 받을 수 있어요. 링크를 복사해서 남에게 주면 그 사람도 받습니다. 그래서 유효 기간이 중요합니다.

1분은 꽤 짧게 잡은 편입니다. 다운로드가 시작되기만 하면 되고, 진행 중인 다운로드가 중간에 끊기지는 않으니까요. 주소가 새어도 1분 뒤에는 못 쓰는 상태가 됩니다.

버킷 자체를 공개로 열어두는 방식과 비교하면 차이가 분명합니다. 공개 버킷은 한 번 주소가 알려지면 계속 열려 있어요. Presigned URL은 매번 새로 만들어야 하고 금방 닫힙니다.

📎 브라우저에 열지 말고 받으라고 하기

작은 대목인데 실무에서 꼭 걸리는 부분이 있습니다.

// 4. 반드시 다운로드 헤더 추가!
generatePresignedUrlRequest.addRequestParameter(
    "response-content-disposition", "attachment; filename=\"" + fileName + "\""
);

주석에 "반드시"라고 붙어 있습니다.

이게 없으면 어떻게 될까요. 브라우저가 파일 형식을 보고 열 수 있는 건 그냥 열어버립니다. PDF나 이미지가 새 탭에 표시되고 말죠. 다운로드가 안 됩니다.

Content-Disposition: attachment"열지 말고 저장하라"는 지시입니다. 그리고 filename=에 이름을 넣으면 S3에 저장된 키가 아니라 원래 파일명으로 저장돼요.

S3의 objectKey는 보통 uploads/2025/06/a3f9c1.jpg 같은 형태라, 이게 없으면 사용자가 a3f9c1.jpg를 받게 됩니다. 저장 이름과 보여줄 이름을 분리한 것이죠.

🔑 자격 증명이 파라미터로 들어온다

함수 시그니처를 보면 accessKeysecretKey를 인자로 받습니다. 그리고 글이 여기에 단서를 달았어요.

accessKey (String): AWS 계정의 접근 키입니다. (보안상 민감한 정보이므로 주의하여 관리해야 합니다.)
secretKey (String): AWS 계정의 비밀 키입니다. (보안상 민감한 정보이므로 주의하여 관리해야 합니다.)

두 번 다 같은 경고를 붙였습니다.

파라미터 설명에 이런 주의가 들어가는 게 흔치는 않습니다. 그리고 이건 실제로 중요한 자리예요. 이 값들이 코드에 직접 적히거나 저장소에 올라가면 버킷 전체가 열립니다.

3기 6회차 큐레이션에서 소개해드린 이민경 님의 JWT 정리에도 같은 성격의 이야기가 있었습니다. secret이 새면 토큰을 위조할 수 있다는 것요. 한 개의 값이 전체를 여는 구조가 클라우드와 인증에는 반복해서 나옵니다.

📝 원문에서는 이렇게 씁니다

이 기록은 코드를 먼저 놓고 그다음에 설명합니다.

프런트 코드 → objectKey와 fileName이 뭔지 → 서버 코드 → 파라미터 여섯 개 설명 → 동작 단계별 분석 순서예요.

그리고 동작 설명이 번호로 나뉘어 있습니다.

1. S3 클라이언트 생성 → 2. 만료 시간 설정 → 3. Presigned URL 생성 요청 객체 생성 → 4. 반드시 다운로드 헤더 추가 → 5. Presigned URL 생성

주석 번호와 설명 번호가 같습니다. 코드를 보다가 막히면 아래에서 그 번호를 찾으면 되죠.

프런트와 백엔드를 함께 올린 것도 이 글의 성격을 보여줍니다. Presigned URL 방식은 양쪽이 짝을 맞춰야 돌아가거든요. 서버만 만들어두면 브라우저가 어떻게 받아야 할지 모르고, 프런트만 있으면 줄 주소가 없습니다.

큐레이터 노트

"반드시"라는 주석 하나 때문에 이 글을 골랐습니다.

response-content-disposition을 빠뜨리면 코드는 다 맞는데 다운로드만 안 됩니다. 에러도 안 나요. 파일이 브라우저에 그냥 열리고 맙니다. 그리고 검색해도 잘 안 나오는 부분이고요.

이런 게 구현 기록의 값어치입니다. 문서에 있는 내용을 옮기는 게 아니라, 직접 해보다 걸린 자리를 표시해두는 것요.

그리고 만료 시간을 1분으로 잡은 것. 기본값을 그대로 쓰지 않고 필요한 만큼만 열어둔 판단입니다.

3기 4회차 큐레이션에서 남태식 님의 AWS 실습을 소개해드렸는데, 그쪽이 인프라를 세우는 쪽이라면 이 글은 세워진 것을 애플리케이션에서 쓰는 쪽입니다. 같은 S3를 두 각도에서 다룬 셈이에요.

원문 읽으러 가기  ↗ivory-wrench-4d8.notion.site/S3-21cc8760f513808d974ef71796…

💡 세 편을 겹쳐 읽으며

세 편의 층위가 다릅니다. 클러스터 운영, 앱 화면, 파일 전송이요.

그런데 셋 다 직접 하지 않게 만드는 이야기입니다.

무엇을 안 하게 되었나

이지은 님의 GitOps는 사람이 배포 명령을 치지 않게 만듭니다. Git에 올리면 ArgoCD가 맞춰주니까요.

박상훈 님의 최적화는 앱이 다시 그리지 않게 만듭니다. constRepaintBoundaryListView.builder가 전부 "여기는 안 바뀐다"를 알려주는 장치예요.

이효원 님의 Presigned URL은 서버가 파일을 나르지 않게 만듭니다. 주소만 주고 실제 전송은 S3가 하죠.

세 경우 다 일을 없앤 게 아니라 다른 데로 옮겼습니다. ArgoCD에게, 프레임워크에게, S3에게요.

옮기려면 규칙을 정해줘야 한다

그런데 옮기는 데는 대가가 있습니다. 받는 쪽이 판단할 수 있게 규칙을 적어줘야 해요.

ArgoCD가 알아서 맞추려면 Git에 원하는 상태가 정확히 적혀 있어야 합니다. 그래서 Kustomize와 Helm으로 매니페스트를 정리하는 단계가 먼저 나오는 거예요.

Flutter가 다시 안 그리려면 const를 붙여줘야 합니다. 프레임워크가 알아서 판단하지 않아요. 사람이 "이건 불변"이라고 표시해줘야 합니다.

S3가 파일을 내주려면 만료 시간과 다운로드 헤더를 URL에 담아야 합니다. 그냥 주소만으로는 안 되죠.

자동화는 판단을 없애는 게 아니라 앞당깁니다. 실행할 때 하던 판단을 설정할 때 하는 것이고요.

살아 있는지 계속 확인한다

세 편에 공통으로 나오는 게 하나 더 있습니다. 맡겨놓고 안 보는 게 아니라는 것.

이지은 님의 Probe가 그렇습니다. GitOps로 배포를 맡기기 전에 liveness와 readiness로 상태를 계속 재는 장치를 먼저 붙였어요.

박상훈 님의 결론도 그렇습니다. "DevTools로 정기 점검"이 세 항목 중 하나예요. 최적화하고 끝이 아니라 루틴으로 두라는 것이고요.

이효원 님의 1분 만료도 같은 성격입니다. 한 번 열어주고 잊지 않는 구조니까요.

맡기는 것과 방치하는 것의 차이가 여기 있습니다.

이번 회차에서 가져갈 것

1. liveness와 readiness를 함께 걸기.

liveness는 죽이고 다시 띄우고, readiness는 트래픽만 끊습니다. 잠깐 바쁜 앱을 죽이지 않으려면 둘 다 필요합니다.

2. 시작이 느린 앱에는 startupProbe.

initialDelaySeconds를 늘리면 평소 장애 감지도 함께 늦어집니다. 시작 구간만 따로 떼세요.

3. 안 바뀌는 위젯에 const 붙이기.

한 단어인데 리빌드 비교 자체를 건너뜁니다. 목록은 ListView.builder보이는 것만 만드세요.

4. await는 다른 스레드가 아니다.

큰 JSON 파싱처럼 CPU를 쓰는 작업은 await를 붙여도 화면이 멈춥니다. compute로 isolate에 넘기세요.

5. Presigned URL에는 response-content-disposition을 꼭.

없으면 브라우저가 파일을 열어버리고 다운로드가 안 됩니다. 에러도 안 나서 찾기 어렵습니다.


3기 7회차는 2025년 6월 말이었습니다. 1학기가 끝나가던 무렵이에요.

쿠버네티스 스터디와 Flutter 앱과 파일 다운로드 구현이라는 서로 다른 자리에서, 세 분이 나란히 일을 옮기는 방법을 기록했습니다.

성장일지는 멤버들이 2주에 한 번씩 자신의 성장을 기록하는 활동이에요. 지난 기수의 성장일지를 다시 읽으면서, 그때 소개해드리지 못한 글을 하나씩 꺼내고 있습니다.

좋은 글 남겨주신 이지은 님, 박상훈 님, 이효원 님께 감사드립니다. 그리고 3기를 함께 채워주신 모든 멤버분들께도요! 😊

다음 큐레이션으로 다시 찾아오겠습니다! 🌱

- 에디터 · 성장일지 큐레이터 -


※ 본 큐레이션은 각 저자가 공개한 글을 소개하는 것이며, 모든 원문의 저작권은 저자에게 있습니다. 저자 본인의 요청이 있을 경우 즉시 수정 또는 삭제합니다.

WRITE YOUR GROWTH

오늘의 배움을
내일의 성장으로.

기록은 나를 돌아보게 하고, 공유는 우리를 연결합니다.
당신의 다음 성장 이야기도 그로스로그에서 시작해보세요.

커뮤니티 둘러보기