Renovate vs Dependabot vs ArgoCD Image Updater — 1년 굴려본 솔직 비교
작년 봄에 회사 표준 의존성 업데이트 도구를 정하자는 얘기가 나왔다. 그때 우리 팀에서 굴리던 게 셋이었다. 일부 레포는 Dependabot, 인프라 모듈 레포는 Renovate, 그리고 멀티클러스터 ArgoCD가 관리하는 매니페스트 레포는 ArgoCD Image Updater. 세 개가 동시에 PR을 쏴대니까 리뷰어들이 짜증을 내기 시작했다. "이거 좀 정리하자"가 출발이었다.
결과부터 말하면 셋 다 남겼다. 다만 역할을 잘랐다. 어떤 기준으로 잘랐는지, 1년 돌려본 입장에서 솔직하게 적어본다.
세 도구가 보는 세계가 다르다
처음에 했던 큰 착각이, 이 셋을 같은 카테고리로 묶을 수 있다고 생각한 거였다. 사실 이건 비교가 좀 무리다. 보는 대상이 다르다.
Dependabot은 GitHub에 박혀 있다. 코드 레포의 manifest(package.json, go.mod, requirements.txt 등)를 읽고, 새 버전이 나오면 PR을 쏜다. 보안 advisory에 대한 자동 대응이 강점이다. 우리 케이스로는, Critical CVE가 npm에 떴을 때 새벽에 알아서 PR이 올라와 있는 경험을 몇 번 했다. 진짜로 자고 일어났더니 풀려 있었던 적도 있고.
Renovate는 좀 더 만물상이다. 같은 manifest를 보긴 하는데, 거기서 끝이 아니라 Helm chart, Terraform module, Docker base image, Kustomize image tag, GitHub Actions 워크플로의 uses: 등등 거의 모든 형태의 버전 문자열을 잡아낸다. 설정 자유도가 높고, presets가 많다. 단점은 한 번 설정을 잘못 잡으면 PR이 폭주한다는 것.
ArgoCD Image Updater는 아예 다른 종이다. 얘는 manifest를 읽는 게 아니라, 컨테이너 레지스트리를 폴링한다. 새 이미지 태그가 올라오면 Application의 image 필드를 업데이트하고, 그 변경을 Git에 write-back한다. CI 파이프라인이 이미지를 빌드해서 푸시까지만 하고 손을 떼는 GitOps 패턴에 딱 맞는다.
이걸 한 줄로 정리하면 이렇게 된다. Dependabot은 "코드 의존성", Renovate는 "리포지토리 안의 모든 버전 문자열", ArgoCD Image Updater는 "런타임 이미지". 겹치는 영역은 있지만, 강점이 명확히 다르다.
Dependabot — 기본기는 단단한데 확장이 약하다
장점부터. 설정이 거의 필요 없다. .github/dependabot.yml에 ecosystem 몇 줄 적으면 끝. GitHub Security Advisory와 직접 연동되니까 CVE 대응 측면에서 가장 빠르다. 그리고 "Dependabot이 보낸 PR"이라는 신뢰감 같은 게 있어서 리뷰어들이 일단 한 번은 본다.
단점도 명확하다. 그루핑이 약하다. 작년 가을쯤에 그루핑 기능이 GA로 풀리긴 했는데 (groups 키), Renovate의 packageRules에 비하면 표현력이 부족하다. 예를 들어 "react 관련 패키지는 묶고, 그 외 minor 업데이트도 묶고, major는 따로" 이런 식의 다층 그루핑이 깔끔하지 않다.
그리고 비-GitHub ecosystem에 대한 지원이 약하다. Terraform AWS provider 정도는 잡지만, Helm chart의 dependencies, Kustomize image, ArgoCD ApplicationSet의 image reference 같은 건 못 본다. 인프라 레포에서 쓰기엔 한계가 분명하다.
또 하나 짚자면, rate limit이 은근히 거슬린다. 큰 모노레포에서 ecosystem 여러 개 켜놓으면 GitHub API 한도에 밀려서 PR 생성이 늦어지는 경우가 있었다. 우리는 Node 패키지 100개짜리 레포 하나에서 이걸 만났는데, 해결법은 결국 그룹을 잘게 쪼개는 것뿐이었다.
Renovate — 강력하지만 학습 곡선이 있다
Renovate의 강점은 한마디로 "다 본다"이다. Helm subchart 버전, Terraform module의 ref 태그, GitHub Actions의 third-party action 버전, Kustomize의 newTag, 심지어 Dockerfile 안의 FROM 이미지 태그까지. 인프라 매니페스트 레포에서 쓰면 그동안 손으로 따라다니던 버전들이 한꺼번에 흐름을 갖기 시작한다.
packageRules의 표현력이 압도적이다. 예를 들면:
{
"packageRules": [
{
"matchManagers": ["helm-values", "kubernetes"],
"matchUpdateTypes": ["minor", "patch"],
"groupName": "k8s manifests minor/patch"
},
{
"matchPackagePatterns": ["^aws/"],
"matchUpdateTypes": ["major"],
"dependencyDashboardApproval": true
}
]
}
이런 룰 한 줄이면 마이너/패치는 자동으로 묶이고, AWS 관련 major는 대시보드에서 수동 승인 후에만 PR이 열린다. 그리고 작년에 들어온 "merge confidence" 기능이 의외로 쓸만했다. 새 버전이 얼마나 많은 다른 레포에서 머지되고 있는지를 신호로 주는 건데, 적어도 "이 버전 우리만 쓰고 있는 거 아닌가" 하는 불안을 줄여준다.
단점. 첫 설정에 시간이 걸린다. preset을 그대로 갖다 쓰면 PR이 100개씩 쏟아진다. 처음 한 주 정도는 dependency dashboard 보면서 룰을 다듬는 시간이 반드시 필요하다. 우리 팀에서는 도입 첫 주에 누군가 self-hosted Renovate runner 메모리가 OOM으로 죽는 사건도 있었다. 큰 monorepo에서 Renovate를 GitHub App이 아닌 self-hosted로 돌릴 때 주의해야 한다.
또 하나, API rate limit은 여기도 적용된다. GitHub App으로 쓰면 그래도 한도가 넉넉한데, GitLab/Bitbucket에서 self-hosted로 돌릴 때는 hostRules로 토큰을 분산시켜야 했다.
ArgoCD Image Updater — GitOps에 끼울 때만 빛난다
Image Updater는 처음 봤을 땐 "이거 굳이 필요한가" 싶었다. CI에서 이미지 빌드한 다음에 그냥 매니페스트 레포에 sed로 태그 바꿔서 PR 열면 되는 거 아닌가. 근데 실제로 해보면 그 sed 스크립트가 점점 더러워진다. 환경별로 분기되고, semver 정렬 처리 들어가고, regex 처리 들어가고. 그러다 보면 결국 Image Updater 같은 게 필요해진다.
장점은 레지스트리 기반이라는 것. Manifest 레포가 아니라 컨테이너 레지스트리를 폴링하니까, 개발팀이 CI에서 이미지를 푸시하기만 하면 그게 운영 클러스터까지 흘러간다. write-back을 git으로 하느냐 ArgoCD에 직접 하느냐 선택할 수 있는데, 우리는 git write-back 모드만 쓴다. 그래야 변경 이력이 남고 ArgoCD가 죽었을 때도 진실의 원천이 git에 있다.
metadata:
annotations:
argocd-image-updater.argoproj.io/image-list: app=registry.example.com/myapp
argocd-image-updater.argoproj.io/app.update-strategy: semver
argocd-image-updater.argoproj.io/app.allow-tags: regexp:^v\d+\.\d+\.\d+$
argocd-image-updater.argoproj.io/write-back-method: git
argocd-image-updater.argoproj.io/write-back-target: kustomization
update-strategy로 semver, latest, digest, newest-build을 줄 수 있다. 우리는 prod에서는 semver, dev에서는 newest-build로 잡았다. 빠른 피드백이 필요한 dev 환경에서는 빌드 즉시 반영되도록.
단점. 레지스트리 폴링 주기가 짧지 않다. 기본 2분, 더 짧게 가능하지만 레지스트리 부하가 올라간다. 그리고 kustomize override나 Helm parameter를 만지는 방식이 좀 거칠다. 매니페스트 구조가 복잡하면 write-back-target을 신경 써야 한다. 처음에 우리 팀은 Helm 차트 안에 image.tag를 직접 박는 구조를 쓰고 있어서, Image Updater가 values 파일을 안 만지고 ConfigMap 같은 데에 override를 쌓아두는 이상한 상태가 됐던 적이 있다. write-back-target을 명시적으로 잡고 나서야 해결됐다.
그래서 우리 팀은 어떻게 잘랐나
1년 굴리고 정리한 결론은 이렇다.
Dependabot은 애플리케이션 코드 레포에만. Node/Go/Python 같은 언어 의존성, 그리고 GitHub Security Advisory 대응. 그 외에는 끈다. 보안 이슈가 떴을 때 가장 빨리 PR을 쏘는 게 얘라서 이 역할만큼은 못 뺀다.
Renovate는 인프라/매니페스트 레포 전담. Helm chart, Terraform module, GitHub Actions, Dockerfile base image. 이쪽은 Dependabot이 잡지 못하는 영역이라 분쟁이 없다.
ArgoCD Image Updater는 매니페스트 레포 안에서 런타임 이미지 태그만. Renovate가 manifest 안의 모든 걸 보긴 하지만, "CI에서 방금 빌드된 이미지의 다음 태그"만큼은 레지스트리를 폴링하는 게 더 깔끔하다. 그래서 Renovate에는 argocd-image-updater가 보는 패턴은 제외하는 ignorePaths를 걸어뒀다.
이 분리 이후로 한 레포에서 두 봇이 같은 줄에 PR 쏘는 충돌이 사라졌다. 리뷰어들 불평도 줄었고. 처음부터 이렇게 잘랐으면 좋았을 거란 생각이 든다.
마무리
솔직히, 처음에는 "셋 다 같은 일을 한다"고 생각했다. 그래서 하나로 통일하려 했고, 그 시도는 실패했다. 각각이 보는 세계가 달라서 한 도구로 다 못 잡는다. 통일이 아니라 분담이 답이었다.
혹시 의존성 봇 도입을 고민 중이시면, 먼저 "내가 잡고 싶은 게 코드 의존성이냐, manifest 안의 모든 버전이냐, 런타임 이미지냐"부터 물어보시면 좋을 것 같다. 그 답이 도구를 골라준다.
다른 팀에서는 어떻게 분담하시는지 궁금하다. 혹시 우리랑 다르게 잘라놓으신 분 있으면 댓글 부탁드립니다.
'IT > CI CD' 카테고리의 다른 글
| 왜 우리 팀은 Argo Rollouts를 선택했나 — Flagger와 1년 비교 후기 (0) | 2026.05.11 |
|---|---|
| ARC on Karpenter, EKS에서 GitHub Actions runner 굴리는 법 (0) | 2026.05.06 |
| ArgoCD ApplicationSet PR Generator로 PR별 preview 환경 만들기 (0) | 2026.05.05 |
| GitHub Actions의 concurrency, 배포 race 막는 한 줄 (1) | 2026.04.29 |
| ARC ephemeral runner로 갈아탔다가 새벽에 깬 이야기 (0) | 2026.04.27 |