들어가며

쿠버네티스를 이용한 컨테이너 운영 환경이라면 CI/CD는 필수입니다. CI 도구로는 Jenkins, GitHub Actions 등이 널리 사용되고 있으며, CD 분야에서는 ArgoCD가 가장 강력하고 많이 활용되는 툴 중 하나입니다.
하지만 ArgoCD와 같은 GitOps 기반 배포 방식에서는 컨테이너 이미지의 태그가 변경되면 그 정보를 Git 리포지토리에 수동으로 반영해줘야 하는 번거로움이 있습니다.
이를 해결하기 위해 ArgoCD Image Updater가 등장하게 되었고, 이번 포스팅에서는 ArgoCD Image Updater를 사용하여 컨테이너 레지스트리에 새로운 이미지가 푸시되었는지를 주기적으로 확인하고, 자동으로 Git repo의 매니페스트를 업데이트하거나 ArgoCD에 직접 반영하는 실습까지 진행해 보겠습니다.
ArgoCD ImageUpdater
ArgoCD ImageUpdater란?
Argo CD Image Updater는 Kubernetes에서 Argo CD로 관리되는 워크로드의 컨테이너 이미지를 자동으로 최신 버전으로 업데이트하는 도구입니다. (아직 활발히 개발 중인 도구입니다.)
Argo CD로 배포된 Application 리소스에 ArgoCD Image Updater 관련 주석을 추가하여 업데이트할 이미지와 버전등을 지정하여, Image Updater는 주기적으로 해당 애플리케이션을 확인하고, 새로운 이미지 버전이 발견되면 Argo CD를 통해 애플리케이션을 업데이트합니다.
기존 ArgoCD Architecture

기존에 ArgoCD를 활용한 CI/CD 아키텍처는 위와 같습니다. 개발자가 코드 작업 후 레포지토리에 commit 및 push 하게 되면 webhook과 같은 trigger로 인해 CI가 동작하게 되고, 그 결과를 AWS ECR과 같은 Container Registry에 저장 후 변경된 tag 정보를 Pod의 메니패스트파일이 저장되어 관리되고 있는 Devops Git Repo에 Commit 및 Push 합니다. 최종적으로 ArgoCD를 통해 변경된 내용을 감지하여 Auto Sync, sync 등을 통해 Pod를 배포합니다.
ArgoCd D Image Updater 사용 후 Architecture

ArgoCD Image Updater를 사용하게 되면 앞의 과정은 같지만 CI 통해 변경된 tag를 Devops GIt Repo에 따로 Push 하지 않습니다. 이때, ArgoCD Image Updater가 주기적으로 컨테이너 레지스트리를 확인해 새로운 이미지 태그를 감지하여 ArgoCD Image Updater가 직접 Git Repo에 manifest 파일을 수정해 Commit 및 Push를 합니다.
특징
다양한 업데이트 전략 기능
semver
argocd-image-updater.argoproj.io/image-list: myapp=myregistry/myimage:~1.2
semver은 의미론적 버전(Semantic Versioning) 기준으로 이미지를 업데이트하는 방식입니다.
# X: 메이저 버전 (큰 변화, 호환성 깨질 수 있음)
# Y: 마이너 버전 (기능 추가, 호환성 유지)
# Z: 패치 버전 (버그 수정)
X.Y.Z
# 1.2.x 범위에서 가장 최신
~1.2
# 1로 시작하는 모든 버전 중 최신
1.x
# 1.x랑 같은 의미로 동작함
v1.x
이렇게 하면 주어진 패치 브랜치나 마이너 릴리스 내에서 최신 버전의 이미지로 업데이트하거나 유효한 의미 버전 식별자가 태그 된 최신 버전으로만 업데이트할 수 있습니다.
newest-build
argocd-image-updater.argoproj.io/myapp.update-strategy: newest-build
가장 최근에 생성된 이미지 태그로 업데이트합니다.
alphabetical
argocd-image-updater.argoproj.io/myapp.update-strategy: alphabetical
알파벳 순으로 정렬된 마지막 태그로 업데이트합니다.
만약 alpha, beta, rc1, release의 태그가 존재한다면 실제 배포되는 태그는 releaserk 됩니다.
digest
변경 가능한 태그의 가장 최근 푸시된 버전으로 업데이트
argocd-image-updater.argoproj.io/image-list: myapp=myregistry/myimage:latest
argocd-image-updater.argoproj.io/myapp.update-strategy: digest
제한 사항
애플리케이션은 Argo CD를 사용하여 관리
이미지를 업데이트하려는 애플리케이션은 Argo CD를 사용하여 관리해야 하며, Argo CD를 사용하여 관리되지 않는 워크로드는 지원되지 않습니다.
Kustomize나 Helm을 사용
Kustomize 또는 Helm을 사용하여 구성된 애플리케이션의 컨테이너 이미지만 업데이트할 수 있으며, Helm의 경우 템플릿이 매개변수(즉, image tag)를 사용하여 이미지의 태그나 이름을 지정하는 것을 지원해야 합니다.
동일 cluster에 Image pull secrets 존재
Image pull 관련 secrets은 Argo CD Image Updater가 실행 중이거나 접근 권한이 있는 동일한 Kubernetes 클러스터에 존재해야 합니다.
실습
실습 환경 구축 - CI
AWS ECR 생성
aws ecr create-repository \
--repository-name argo-test \
--region ap-northeast-2
위의 명령어로 container image를 저장할 AWS ECR을 생성합니다.

Github 레포 생성
간단하게 CI/CD 환경을 구축해 보면서 테스트해보기 위해 테스트 앱에 대한 소스코드가 들어갈 argo-image-updater-app 레포와 pod에 대한 명세 파일이 들어갈 argo-image-updater-devops를 생성합니다.
application repo

🔻 코드 보기
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return """
<html>
<head><title>ArgoCD Test App</title></head>
<body style="font-family: sans-serif; text-align: center; margin-top: 100px;">
<h1>✅ Hello from ArgoCD Image Updater test app!</h1>
</body>
</html>
"""
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
# requirements.txt
flask
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]
devops repo

🔻 코드 보기
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: argo-test-app
labels:
app: argo-test
spec:
replicas: 1
selector:
matchLabels:
app: argo-test
template:
metadata:
labels:
app: argo-test
spec:
containers:
- name: app
image: {AWS_COUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/argo-test:latest
ports:
- containerPort: 8080
imagePullSecrets:
- name: ecr-secret
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: argo-test-app
spec:
selector:
app: argo-test
ports:
- port: 80
targetPort: 8080
nodePort: 30001
type: NodePort
github action 설정

test app의 코드가 저장되는 argo-image-updater-app에서 Settings → Secrets and variables → Actions에 위와 같이 secret을 추가합니다.
# .github/workflows/deploy.yaml
name: Build and Push to ECR
on:
push:
branches:
- main # 또는 master
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build and Push Docker image
env:
ECR_REGISTRY: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com
IMAGE_TAG: latest
run: |
IMAGE_URI=$ECR_REGISTRY/${{ secrets.ECR_REPOSITORY }}:$IMAGE_TAG
docker build -t $IMAGE_URI .
docker push $IMAGE_URI
그 후 github action의 workflow 파일을 만들어 위와 같이 파이프라인 코드를 작성합니다.

해당 내용을 commit 후 github actoin 메뉴에서 확인해 보면 위와 같이 정상적으로 CI 파이프라인이 진행된 것을 확인하실 수 있습니다.

CI 파이프라인의 결과로 AWS ECR에 이미지가 정상적으로 업로드된 것을 확인하실 수 있습니다.
실습 환경 구축 - k8s
kind로 local K8s Cluster 구축
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000
- containerPort: 30001
hostPort: 30001
- containerPort: 30002
hostPort: 30002
- containerPort: 30003
hostPort: 30003
- role: worker
- role: worker
위의 설정대로 kind로 k8s cluster를 생성합니다.
...
extraPortMappings:
- containerPort: 30000
hostPort: 30000
- containerPort: 30001 # test app
hostPort: 30001
- containerPort: 30002 # argo cd
hostPort: 30002
- containerPort: 30003 # 임시
hostPort: 30003
...
여기서 중요한 것은 k8s service의 nodePort type으로 웹 UI로 접근해야 할 리소스들이 있어 local port와 매핑시켜 주는 설정입니다.
실습 환경 구축 - ECR 인증 설정
secret 생성
kubectl create secret generic aws-creds -n argocd \
--from-literal=AWS_ACCESS_KEY_ID={AWS_ACCESS_KEY_ID} \
--from-literal=AWS_SECRET_ACCESS_KEY={AWS_SECRET_ACCESS_KEY}
ECR 인증을 진행할 수 있는 aws-creds라는 secret을 생성합니다.
imagePullSecret 생성
kubectl create secret docker-registry ecr-secret \
--docker-server={AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com \
--docker-username=AWS \
--docker-password=$(aws ecr get-login-password --region ap-northeast-2) \
--namespace=default
그리고 생성한 Kubernetes 클러스터 안에서 ECR로 ImagePull 할 수 있게 해주는 Secret을 생성합니다.
deployment.yaml에 secret 참조 추가
...
spec:
containers:
...
ports:
- containerPort: 8080
imagePullSecrets:
- name: ecr-secret
...
test app deployment.yaml에 imagePullSecrets을 추가하여 위에서 생성한 secret을 넣어줍니다.
실습 환경 구축 - CD
ArgoCD 설치
kubectl create ns argocd
먼저 ArgoCD를 배포할 네임스페이스를 생성합니다.
cat <<EOF > argocd-values.yaml
dex:
enabled: false
server:
service:
type: NodePort
nodePortHttps: 30002
extraArgs:
- --insecure # HTTPS 대신 HTTP 사용
EOF
service type을 nodeport로 설정하여 배포할 것이기 때문에 argocd-valuse.yaml을 생성합니다.
helm repo update
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd --version 7.8.13 -f argocd-values.yaml --namespace argocd # 7.7.10
위에서 생성한 argocd-values.yaml 파일을 옵션으로 두고 argocd를 배포합니다.
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
배포 후 웹으로 접근해야 하기 때문에 비밀번호를 알기 위해 위의 명령어로 초기 비밀번호를 조회합니다.
open "http://127.0.0.1:30002"
위의 명령어로 로컬 PC에서 30002 port로 접근해 보겠습니다.


정상적으로 접근한 것을 확인하실 수 있습니다.
github token 설정
argocd에서 github repo와 연결하기 위해 token을 생성하겠습니다.

Developer settings → Personal access tokens → Tokens (classic) -> Generate new token (classic)을 생성하는데 이때 repo (전체), read:package를 선택하여 생성합니다.

그 후 argocd로 돌아와 Setting → Repository에서 Connect 정보를 입력합니다. 이때 repo는 pod 매니페스트 파일이 관리되는 레포(argo-image-updater-devops)를 지정해주셔야 합니다.

new app 버튼을 통해 argo application을 생성합니다.

위와 같이 application이 생성된 것을 확인하실 수 있습니다.

이후 sync를 통해 pod를 정상적으로 배포합니다.
확인

이렇게 배포하고 나서 보면 처음 배포에는 문제가 없습니다. 하지만 code를 수정한다면 어떨까요?
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return """
<html>
<head><title>ArgoCD Test App</title></head>
<body style="font-family: sans-serif; text-align: center; margin-top: 100px;">
<h1> new version Hello from ArgoCD Image Updater test app!</h1>
</body>
</html>
"""
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
위처럼 app.py를 수정해 보도록 하겠습니다.

CI 파이프라인을 진행한 후에 build 결과물인 DockerImage가 ECR에 저장되는데 latest라는 tag로 저장됩니다.

argocd에서도 보면 latest라는 이름은 그대로 이기 때문에 trigger가 변경사항이 없다고 판단하고 아무런 변화가 없는 것을 확인할 수 있습니다.
이때 Argo Image Updater를 통해 해결할 수 있습니다.
실습 환경 구성 - ArgoCD ImageUpdater
ArgoCD Image Updater Vaules 파일 작성
config:
argocd:
grpcWeb: true
serverAddress: "http://argocd-server.argocd"
insecure: true
plaintext: true
logLevel: debug
registries:
- name: ECR
api_url: "https://{AWS_ACCOUNT}.dkr.ecr.ap-northeast-2.amazonaws.com"
prefix: "{AWS_ACCOUNT}.dkr.ecr.ap-northeast-2.amazonaws.com"
ping: true
insecure: false
credentials: "ext:/scripts/auth1.sh"
credsexpire: 10h
authScripts:
enabled: true
scripts:
auth1.sh: |
#!/bin/sh
aws ecr --region ap-northeast-2 get-authorization-token --output text --query 'authorizationData[].authorizationToken' | base64 -d
Image Updater가 prefix에 해당하는 이미지 태그를 확인하고, 인증이 필요하다고 판단되면 aws ecr get-authorization-token 실행 후 토큰을 base64 디코딩하는 스크립트를 실행하는 설정 파일입니다.
ArgoCD ImageUpdater 설치
helm install argocd-image-updater argo/argocd-image-updater \
--namespace argocd \
--values values.yaml
위의 명령어를 통해 argocd-image-updater를 배포합니다.

정상적으로 배포된 것을 확인하실 수 있습니다.
Kustomization
argocd image updater는 helm이나 kustomize로만 사용이 가능하니 해당 구조로 변경하도록 하겠습니다.
# kustomizaion.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
위와 같이 kustomizaion.yaml 파일을 생성하고 다시 push 합니다.
주석 추가
kubectl edit -n argocd applications.argoproj.io test-app
ArgoCD Image Updater는 Argo CD를 사용하여 배포된 애플리케이션에만 적용이 가능하기 때문에 해당 애플리케이션에 아래의 주석을 추가합니다.
# test-app
...
annotations:
argocd-image-updater.argoproj.io/image-list: app={ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/{ECR-REPO}:latest
argocd-image-updater.argoproj.io/app.pull-secret: ext:/scripts/auth1.sh
argocd-image-updater.argoproj.io/app.update-strategy: digest
argocd-image-updater.argoproj.io/app.platforms: linux/arm64,linux/amd64
...
argocd-image-updater.argoproj.io/image-list에는 사용할 ECR 엔드포인트를 적어주시면 됩니다.

로그 확인
kubectl logs -n argocd deploy/argocd-image-updater
2분마다 argocd-image-updater의 trigger가 동작하는데, 해당 pod의 로그를 확인해 보겠습니다.

time="2025-03-28T12:30:24Z" level=debug msg="found 1 from 1 tags eligible for consideration" image="346614024082.dkr.ecr.ap-northeast-2.amazonaws.com/argo-test:latest"
time="2025-03-28T12:30:24Z" level=info msg="Setting new image to 346614024082.dkr.ecr.ap-northeast-2.amazonaws.com/argo-test:latest@sha256:e6987b4a6a997d147345af1a1c660f7d7e0d29755ac35635b55f57a5418b1ac0" alias=app application=test image_name=argo-test image_tag=dummy registry=346614024082.dkr.ecr.ap-northeast-2.amazonaws.com
time="2025-03-28T12:30:24Z" level=info msg="Successfully updated image '346614024082.dkr.ecr.ap-northeast-2.amazonaws.com/argo-test:latest@dummy' to '346614024082.dkr.ecr.ap-northeast-2.amazonaws.com/argo-test:latest@sha256:e6987b4a6a997d147345af1a1c660f7d7e0d29755ac35635b55f57a5418b1ac0', but pending spec update (dry run=false)" alias=app application=test image_name=argo-test image_tag=dummy registry=346614024082.dkr.ecr.ap-northeast-2.amazonaws.com
위의 로그를 통해 AWS ECR에서 새 digest를 가진 최신 latest 이미지가 감지되었고, 해당 digest로 ArgoCD 애플리케이션(test)의 이미지를 성공적으로 업데이트되었다는 것을 알 수 있습니다.
ArgoCD Diff 확인

ArgoCD에 접근해 보면 해당 Argo application이 OutOfSync 상태로 변경된 것을 확인하실 수 있습니다.

그 후 Diff를 통해 변경된 사항을 확인해 보면 위와 같이 digest가 변경된 것을 확인하실 수 있습니다.
ArgoCD Sync
이제 마지막으로 해당 버전으로 sync를 통해 수정을 진행해 보겠습니다.

새롭게 pod가 생성되었고, 다시 웹 접근을 해보겠습니다.

정상적으로 최신 이미지로 pod가 배포된 것을 확인하실 수 있습니다.
참고
https://argocd-image-updater.readthedocs.io/en/stable/
https://github.com/argoproj-labs/argocd-image-updater
GitHub - argoproj-labs/argocd-image-updater: Automatic container image update for Argo CD
Automatic container image update for Argo CD. Contribute to argoproj-labs/argocd-image-updater development by creating an account on GitHub.
github.com
[AWS] ArgoCD Image Updater로 이미지 자동 배포 (with ECR)
ArgoCD Image Updater는 Kubernetes 워크로드와 함께 배포된 컨테이너 이미지의 새 버전을 확인하고, ArgoCD를 사용하여 허용되는 최신 버전으로 자동 업데이트 할 수 있습니다. 오늘은 ECR을 활용하여 ArgoCD
arcozz.tistory.com
https://velog.io/@junsugi/Argo-CD-Image-Updater-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-with.-AWS-EKS
Argo CD Image Updater 사용하기 (with. AWS EKS) (완)
Argo CD에 자동 이미지 태그 플러그인을 추가해서 GitOps를 완성해보자!
velog.io
'스터디 이야기 > 25' AWS EKS' 카테고리의 다른 글
AWS EKS 업그레이드 실습: Control Plane부터 Node Group까지 (0) | 2025.04.02 |
---|---|
AWS EKS의 AutoMode (0) | 2025.03.21 |
EKS에서 ConfigMap 없이 API로 접근 관리하기(Cluster Access Management) (2) | 2025.03.14 |
KWOK를 활용한 Kubernetes AutoScaling 테스트 환경 구축 (1) | 2025.03.08 |