kubectl get applications -n argocd guestbook
NAME        SYNC STATUS   HEALTH STATUS
guestbook   Synced        Progressing

howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get applications -n argocd guestbook -o yaml | kubectl neat | yq
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  destination:
    namespace: guestbook
    server: https://kubernetes.default.svc
  project: default
  source:
    helm:
      valueFiles:
        - values.yaml
    path: helm-guestbook
    repoURL: https://github.com/argoproj/argocd-example-apps
    targetRevision: HEAD
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get pod,svc,ep -n guestbook
NAME                                            READY   STATUS    RESTARTS   AGE
pod/guestbook-helm-guestbook-6585c766d6-k6kqg   1/1     Running   0          68s

NAME                               TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/guestbook-helm-guestbook   ClusterIP   10.96.61.64   <none>        80/TCP    68s

NAME                                 ENDPOINTS        AGE
endpoints/guestbook-helm-guestbook   10.244.0.14:80   68s

실습 환경 배포

## 각 구성 요소 확인
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get-all -n argocd
NAME                                                                    NAMESPACE  AGE
configmap/argocd-cm                                                     argocd     17h  
configmap/argocd-cmd-params-cm                                          argocd     17h  
configmap/argocd-gpg-keys-cm                                            argocd     17h  
configmap/argocd-notifications-cm                                       argocd     17h  
configmap/argocd-rbac-cm                  확인                            argocd     17h 확인configmap/argocd-redis-health-configmap    확인                           argocd     17h  
configmap/argocd-ssh-known-hosts-cm                                     argocd     17h  
configmap/argocd-tls-certs-cm                                           argocd     17h  
configmap/kube-root-ca.crt                                              argocd     17h 
																	 .
																	 .
																	 .

 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get pod,ingress,svc,ep,secret,cm -n argocd
NAME                                                   READY   STATUS    RESTARTS      AGE
pod/argocd-application-controller-0                    1/1     Running   1 (65m ago)   17h
pod/argocd-applicationset-controller-bbff79c6f-62gvg   1/1     Running   1 (65m ago)   17h
pod/argocd-dex-server-6877ddf4f8-vtq5p                 1/1     Running   1 (65m ago)   17h
pod/argocd-notifications-controller-7b5658fc47-v6c2f   1/1     Running   1 (65m ago)   17h
pod/argocd-redis-7d948674-rzs9v                        1/1     Running   1 (65m ago)   17h
pod/argocd-repo-server-7679dc55f5-qzcvl                1/1     Running   1 (65m ago)   17h
pod/argocd-server-7d769b6f48-dfgxn                     1/1     Running   1 (65m ago)   17h

NAME                                      CLASS   HOSTS                ADDRESS     PORTS     AGE
ingress.networking.k8s.io/argocd-server   nginx   argocd.example.com   localhost   80, 443   17h

NAME                                       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
service/argocd-applicationset-controller   ClusterIP   10.96.245.178   <none>        7000/TCP            17h
service/argocd-dex-server                  ClusterIP   10.96.23.36     <none>        5556/TCP,5557/TCP   17h
service/argocd-redis                       ClusterIP   10.96.51.255    <none>        6379/TCP            17h
service/argocd-repo-server                 ClusterIP   10.96.98.210    <none>        8081/TCP            17h
service/argocd-server                      ClusterIP   10.96.133.230   <none>        80/TCP,443/TCP      17h

NAME                                         ENDPOINTS                           AGE
endpoints/argocd-applicationset-controller   10.244.0.11:7000                    17h
endpoints/argocd-dex-server                  10.244.0.12:5557,10.244.0.12:5556   17h
endpoints/argocd-redis                       10.244.0.5:6379                     17h
endpoints/argocd-repo-server                 10.244.0.13:8081                    17h
endpoints/argocd-server                      10.244.0.9:8080,10.244.0.9:8080     17h

NAME                                  TYPE                 DATA   AGE
secret/argocd-initial-admin-secret    Opaque               1      17h
secret/argocd-notifications-secret    Opaque               0      17h
secret/argocd-redis                   Opaque               1      17h
secret/argocd-secret                  Opaque               3      17h
secret/argocd-server-tls              kubernetes.io/tls    2      17h
secret/sh.helm.release.v1.argocd.v1   helm.sh/release.v1   1      17h

NAME                                      DATA   AGE
configmap/argocd-cm                       18     17h
configmap/argocd-cmd-params-cm            20     17h
configmap/argocd-gpg-keys-cm              0      17h
configmap/argocd-notifications-cm         1      17h
configmap/argocd-rbac-cm                  4      17h
configmap/argocd-redis-health-configmap   2      17h
configmap/argocd-ssh-known-hosts-cm       1      17h
configmap/argocd-tls-certs-cm             0      17h
configmap/kube-root-ca.crt                1      17h


howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get ingress -n argocd argocd-server
NAME            CLASS   HOSTS                ADDRESS     PORTS     AGE
argocd-server   nginx   argocd.example.com   localhost   80, 443   17h

 

1. 브라우저 인증서 확인 ( argocd.example.com )

 

2. Argocd server cli 로그인

howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd login argocd.example.com --insecure
Username: admin
Password: 
'admin:login' logged in successfully
Context 'argocd.example.com' updated
 
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd account list
NAME   ENABLED  CAPABILITIES
admin  true     login
 
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd proj list
NAME     DESCRIPTION  DESTINATIONS  SOURCES  CLUSTER-RESOURCE-WHITELIST  NAMESPACE-RESOURCE-BLACKLIST  SIGNATURE-KEYS  ORPHANED-RESOURCES  DESTINATION-SERVICE-ACCOUNTS
default               *,*           *        */*                         <none>                        <none>          disabled            <none>
 
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd repo list
TYPE  NAME  REPO  INSECURE  OCI  LFS  CREDS  STATUS  MESSAGE  PROJECT
 
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd cluster list
SERVER                          NAME        VERSION  STATUS   MESSAGE                                                  PROJECT
https://kubernetes.default.svc  in-cluster           Unknown  Cluster has no applications and is not being monitored.  
 
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd app list
NAME  CLUSTER  NAMESPACE  PROJECT  STATUS  HEALTH  SYNCPOLICY  CONDITIONS  REPO  PATH  TARGET

 

접근 제어

1. “admin” password 변경

## argocd "admin" password 변경
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd account update-password
*** Enter password of currently logged in user (admin): 
*** Enter new password for user admin: 
*** Confirm new password for user admin: 
Password updated
Context 'argocd.example.com' updated

 

2. argocd-cm configmap 구성

## configMap에 아래의 내용 추가
 data:
  # add an additional local user with apiKey and login capabilities
  #   apiKey - allows generating API keys
  #   login - allows to login using UI
  accounts.alice: apiKey, login
  # disables user. User is enabled by default
  # accounts.alice.enabled: "false"
  
  howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl apply -f argocd-cm_new.yaml -n argocd
Warning: resource configmaps/argocd-cm is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
configmap/argocd-cm configured

# 사용자 확인
argocd account list
NAME   ENABLED  CAPABILITIES
admin  true     login
alice  true     apiKey, login

# password 변경
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd account update-password \
> --account alice \
> --current-password qwe12345 \
> --new-password alice12345
Password updated

# 변경된 내용 확인
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get secret -n argocd argocd-secret -o jsonpath='{.data}' | jq
{
  "accounts.alice.password": "JDJhJDEwJFE2OTIwMjJFTDJDSG1oMWhKSU96T2U4R3ROWEVGOXQzNGV5dWZPZm1DQlZTODNtUVByTXEu",
  "accounts.alice.passwordMtime": "MjAyNS0xMS0xMVQwMTo1NDowMFo=",
  "accounts.alice.tokens": "bnVsbA==",
  "admin.password": "JDJhJDEwJFRkcEdERkhTWlp0SVZCMVZFejZ1Y2VSdTBOWjk2Q2ZXWHZFOXVTMmxzZjJuRFlpUzhwRVQu",
  "admin.passwordMtime": "MjAyNS0xMS0xMVQwMToyMzo1OFo=",
  "server.secretkey": "ckJsZ25OZnFCUzlKYWxJYkRjZDMzMWQ1TC9pRWFNRHlaNVg3YjNsLzVKOD0="
}

 

3. Sample application 배포

kubectl get applications -n argocd guestbook
NAME        SYNC STATUS   HEALTH STATUS
guestbook   Synced        Progressing

howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get applications -n argocd guestbook -o yaml | kubectl neat | yq
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  destination:
    namespace: guestbook
    server: https://kubernetes.default.svc
  project: default
  source:
    helm:
      valueFiles:
        - values.yaml
    path: helm-guestbook
    repoURL: https://github.com/argoproj/argocd-example-apps
    targetRevision: HEAD
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get pod,svc,ep -n guestbook
NAME                                            READY   STATUS    RESTARTS   AGE
pod/guestbook-helm-guestbook-6585c766d6-k6kqg   1/1     Running   0          68s

NAME                               TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/guestbook-helm-guestbook   ClusterIP   10.96.61.64   <none>        80/TCP    68s

NAME                                 ENDPOINTS        AGE
endpoints/guestbook-helm-guestbook   10.244.0.14:80   68s

 

4. Argo UI alice 로그인 후 확인 : 권한 없음 ( application , Cluster 정보 안보임 )

 

 

5. 권한 부여 RBAC

# argocd-rbac-cm 권한 수정 후 확인

howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get -n argocd cm argocd-rbac-cm -o yaml > argocd-rbac-cm.yaml


howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice kubectl apply -f argocd-rbac-cm.yaml -n argocd
Warning: resource configmaps/argocd-rbac-cm is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
configmap/argocd-rbac-cm configured

 

 

## CLI 확인

 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd login argocd.example.com --insecure --username alice
Password: 
'alice:login' logged in successfully
Context 'argocd.example.com' updated

 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd cluster list
SERVER                          NAME        VERSION  STATUS      MESSAGE  PROJECT
https://kubernetes.default.svc  in-cluster  1.32     Successful           

 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd app list
NAME              CLUSTER                         NAMESPACE  PROJECT  STATUS  HEALTH   SYNCPOLICY  CONDITIONS  REPO                                             PATH            TARGET
argocd/guestbook  https://kubernetes.default.svc  guestbook  default  Synced  Healthy  Auto-Prune  <none>      https://github.com/argoproj/argocd-example-apps  helm-guestbook  HEAD

## admin 계정 비활성화
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get -n argocd cm argocd-cm -o yaml > argocd-cm.yaml


 ✘ howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl apply -f argocd-cm.yaml -n argocd
configmap/argocd-cm configured

Run 'argocd --help' for usage.
 ✘ howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd account list
NAME   ENABLED  CAPABILITIES
admin  false    login
alice  true     apiKey, login

 

Service Account

1. 서비스어카운트란 : CI/CD 파이프라인과 같은 자동화를 시스템에 인증하는데 사용하는 계정

2. ArgoCD에서 서비스 어카운트를 생성하는 방법은 크게 두가지

  1. login 기능을 제거하고 API 키만을 사용하는 로컬 사용자
  2. 프로젝트 역할을 사용하고 그 역할에 토큰을 할당

3. [ 2-a ] 로컬 서비스 어카운트 RBAC

## apikey만 활성화된 별도의 로컬 계정 생성
kubectl apply -f argocd-cm-account.yaml -n argocd
configmap/argocd-cm configured
 
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd account list
NAME       ENABLED  CAPABILITIES
admin      false    login
alice      true     apiKey, login
gitops-ci  true     apiKey
 
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd account generate-token -a gitops-ci   
{"level":"fatal","msg":"rpc error: code = PermissionDenied desc = permission denied: accounts, update, gitops-ci, sub: alice, iat: 2025-11-11T02:22:33Z","time":"2025-11-11T12:17:22+09:00"}

 

alice 사용자에게 계정 업데이트 권한을 할당 : user-update 새 역할을 생성하고 사용자에게 이 역할을 할당

# argocd-rbac-cm , configmap 수정
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl apply -f argocd-rbac-cm-role.yaml -n argocd
configmap/argocd-rbac-cm configured

# token 발생
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd account generate-token -a gitops-ci 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmdvY2QiLCJzdWIiOiJnaXRvcHMtY2k6YXBpS2V5IiwibmJmIjoxNzYyODMxNDEzLCJpYXQiOjE3NjI4MzE0MTMsImp0aSI6IjkyMWY4Nzk4LTAzZmEtNGI1YS04MWFhLWUyMDMyYTIyMjdkOSJ9.fO-3dFBt_DNQ63hs_zg8p2fc3eOcYmD1CcuHcHKn5K8

# token 작동 확인
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd account  get-user-info --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmdvY2QiLCJzdWIiOiJnaXRvcHMtY2k6YXBpS2V5IiwibmJmIjoxNzYyODMxNDEzLCJpYXQiOjE3NjI4MzE0MTMsImp0aSI6IjkyMWY4Nzk4LTAzZmEtNGI1YS04MWFhLWUyMDMyYTIyMjdkOSJ9.fO-3dFBt_DNQ63hs_zg8p2fc3eOcYmD1CcuHcHKn5K8
Logged In: true
Username: gitops-ci
Issuer: argocd
Groups:

# 포인트는 로컬 계정을 RBAC 그룹에 포함시킬 수 없고 Role을 로컬 사용자에게 할당할 수만 있다

 

4. [ 2-b ] 프로젝트 역할과 토큰

  1. Application 프로젝트는 역할을 통해 application 정의에 일부 제약 조건을 적용하는 방식
  2. 예를 들어 상태를 가져오는 리포지터리, 대상 클러스터 배포할 수 있는 네임스페이스를 지정할 수 있고 설치 할 수 있는 리소스 유형을 피터링 할 수 있다
  3. 위와 같은 이유로 실무에서는 이 방식을 훨씬 많이 쓸것같다
  4. ArgoCD가 설치되면 default라는 기본 프로젝트가 제공되는데 이 기본 프로젝트는 Application에 대한 제한 사항이 설정 돼 있지 않다
## 모든것에 대한 허용 확인
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get appprojects.argoproj.io -n argocd default -o yaml | k neat | yq
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: default
  namespace: argocd
spec:
  clusterResourceWhitelist:
    - group: '*'
      kind: '*'
  destinations:
    - namespace: '*'
      server: '*'
  sourceRepos:
    - '*'

5. AppProject 신규 생성

cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: sample-apps
  namespace: argocd
spec:
  roles:
    - name: read-sync
      description: read and sync privileges
      policies:
        - p, proj:sample-apps:read-sync, applications, get, sample-apps/*, allow
        - p, proj:sample-apps:read-sync, applications, sync, sample-apps/*, allow
  clusterResourceWhitelist:
    - group: '*'
      kind: '*'
  description: Project to configure argocd self-manage application
  destinations:
    - namespace: test
      server: https://kubernetes.default.svc
  sourceRepos:
    - https://github.com/argoproj/argocd-example-apps.git
EOF

## 생성 확인
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get appproject -n argocd
NAME          AGE
default       21h
sample-apps   19s

 

6. 대상 네임스페이스와 클러스터를 제한하고 정해진 리포지터리로부터 상태 파일을 가져옴

 

7. Read and sync라는 역할을 생성하고 AppProject 내의 모든 application에 대한 가져오기, 동기화 작업만 허용

 

8. 해당 프로젝트에 app 배포

howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: pre-post-sync
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: sample-apps
  source:
    path: pre-post-sync
    repoURL: https://github.com/argoproj/argocd-example-apps
    targetRevision: master
  destination:
    namespace: test
    server: https://kubernetes.default.svc
  syncPolicy:
    automated:
      enabled: false
    syncOptions:
    - CreateNamespace=true
EOF

# 동기화 실행시 실패 !
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd app sync argocd/pre-post-sync
{"level":"fatal","msg":"rpc error: code = PermissionDenied desc = permission denied: applications, sync, sample-apps/pre-post-sync, sub: alice, iat: 2025-11-12T12:30:21Z","time":"2025-11-12T21:31:11+09:00"}

 

9. 읽기 및 동기화 역할에 대한 토큰을 통해 수행

# RBAC 수정 , 필요한 권한 추가
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get -n argocd cm argocd-rbac-cm -o yaml > argocd-rbac-cm-token.ya
ml
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  vim argocd-rbac-cm-token.yaml 
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl apply -f argocd-rbac-cm-token.yaml 
configmap/argocd-rbac-cm configured

# 역할에 대한 토큰 생성
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd proj role create-token sample-apps read-sync
Create token succeeded for proj:sample-apps:read-sync.
  ID: 4787a5b9-e809-4428-bf85-ff11e3ee65d8
  Issued At: 2025-11-12T21:37:18+09:00
  Expires At: Never
  Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmdvY2QiLCJzdWIiOiJwcm9qOnNhbXBsZS1hcHBzOnJlYWQtc3luYyIsIm5iZiI6MTc2Mjk1MTAzOCwiaWF0IjoxNzYyOTUxMDM4LCJqdGkiOiI0Nzg3YTViOS1lODA5LTQ0MjgtYmY4NS1mZjExZTNlZTY1ZDgifQ.uXnO30u-n_NKwMm4V7ozSbo4Ryy0vw60wYRvcZkitog

# 위의 토큰으로 application을 수동으로 동기화할 수 있다
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd app sync argocd/pre-post-sync --auth-token $TOKEN
TIMESTAMP                  GROUP        KIND   NAMESPACE                  NAME                    STATUS    HEALTH        HOOK  MESSAGE
2025-11-12T21:38:21+09:00            Service        test  pre-post-sync-kustomize-guestbook-ui  OutOfSync  Missing              
2025-11-12T21:38:21+09:00   apps  Deployment        test  pre-post-sync-kustomize-guestbook-ui  OutOfSync  Missing              
2025-11-12T21:38:21+09:00          Namespace                              test   Running   Synced              namespace/test created
2025-11-12T21:38:21+09:00  batch         Job        test  pre-post-sync-before            Progressing              
2025-11-12T21:38:23+09:00  batch         Job        test  pre-post-sync-before   Running   Synced     PreSync  job.batch/pre-post-sync-before created
2025-11-12T21:38:47+09:00   apps  Deployment        test  pre-post-sync-kustomize-guestbook-ui    Synced  Progressing              
2025-11-12T21:38:47+09:00            Service        test  pre-post-sync-kustomize-guestbook-ui    Synced  Healthy                  
2025-11-12T21:38:48+09:00   apps  Deployment        test  pre-post-sync-kustomize-guestbook-ui    Synced  Healthy              
2025-11-12T21:38:49+09:00  batch         Job        test  pre-post-sync-before                  Succeeded   Synced     PreSync  Reached expected number of succeeded pods
2025-11-12T21:38:49+09:00            Service        test  pre-post-sync-kustomize-guestbook-ui    Synced   Healthy              service/pre-post-sync-kustomize-guestbook-ui created
2025-11-12T21:38:49+09:00   apps  Deployment        test  pre-post-sync-kustomize-guestbook-ui    Synced   Healthy              deployment.apps/pre-post-sync-kustomize-guestbook-ui created
2025-11-12T21:38:49+09:00  batch         Job        test   pre-post-sync-after   Running   Synced    PostSync  job.batch/pre-post-sync-after created
2025-11-12T21:39:05+09:00  batch         Job        test   pre-post-sync-after  Succeeded   Synced    PostSync  Reached expected number of succeeded pods

Name:               argocd/pre-post-sync
Project:            sample-apps
Server:             https://kubernetes.default.svc
Namespace:          test
URL:                https://argocd.example.com/applications/argocd/pre-post-sync
Source:
- Repo:             https://github.com/argoproj/argocd-example-apps
  Target:           master
  Path:             pre-post-sync
SyncWindow:         Sync Allowed
Sync Policy:        Manual
Sync Status:        Synced to master (0d521c6)
Health Status:      Healthy

Operation:          Sync
Sync Revision:      0d521c6e049889134f3122eb32d7ed342f43ca0d
Phase:              Succeeded
Start:              2025-11-12 21:38:21 +0900 KST
Finished:           2025-11-12 21:39:05 +0900 KST
Duration:           44s
Message:            successfully synced (no more tasks)

GROUP  KIND        NAMESPACE  NAME                                  STATUS     HEALTH   HOOK      MESSAGE
       Namespace              test                                  Running    Synced             namespace/test created
batch  Job         test       pre-post-sync-before                  Succeeded           PreSync   Reached expected number of succeeded pods
       Service     test       pre-post-sync-kustomize-guestbook-ui  Synced     Healthy            service/pre-post-sync-kustomize-guestbook-ui created
apps   Deployment  test       pre-post-sync-kustomize-guestbook-ui  Synced     Healthy            deployment.apps/pre-post-sync-kustomize-guestbook-ui created
batch  Job         test       pre-post-sync-after                   Succeeded           PostSync  Reached expected number of succeeded pods

 

 

SSO

  • ArgoCD는 UI 및 CLI에서 SSO 로그인을 제공
  • ArgoCD는 두가지 방법으로 SSO 기능을 제공
    • 설치되는 Dex OIDC 공급자를 사용하
    • dex 설치 없이 다른 OIDC 공급자를 통해 Argo CD를 직접 사용]

1. Admin 계정 다시 활성화

howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get -n argocd cm argocd-cm -o yaml > argocd-cm-admin.yaml
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  vim argocd-cm-admin.yaml  
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl apply -f argocd-cm-admin.yaml
configmap/argocd-cm configured

howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd login argocd.example.com --username admin --password qwe12345 --insecure
'admin:login' logged in successfully
Context 'argocd.example.com' updated
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  argocd app list
NAME                  CLUSTER                         NAMESPACE  PROJECT      STATUS  HEALTH   SYNCPOLICY  CONDITIONS  REPO                                             PATH            TARGET
argocd/guestbook      https://kubernetes.default.svc  guestbook  default      Synced  Healthy  Auto-Prune  <none>      https://github.com/argoproj/argocd-example-apps  helm-guestbook  HEAD
argocd/pre-post-sync  https://kubernetes.default.svc  test       sample-apps  Synced  Healthy  Manual      <none>      https://github.com/argoproj/argocd-example-apps  pre-post-sync   master

 

2. Keycloak 소개 : 애플리케이션에 초점을 맞춘 오픈소스 ID 및 접근 관리 도구

- keycloak은 강력한 인증을 포함해 완전히 사용자의 입맛에 맞게 설정할 수 있는 로그인 페이지를 제공하며 암호 복구, 주기적인 암호 업데이트 설정, 이용 약관 동의 등과 같은 다양한 기능을 제공

- Keycloak은 SSO 기능을 제공

- Keycloak은 OAuth2.0, OIDC, SAML2.0을 지원하는 업계 표준 프로토콜을 기반으로 한다

- 클러스터링 기능을 통해 고가용성을 제공

 

3. keycloak 배포 및 기본 설정

# keycloak docker 실행
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  docker run -d -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin --net host --name dev-keycloak quay.io/keycloak/keycloak:22.0.0 start-dev
Unable to find image 'quay.io/keycloak/keycloak:22.0.0' locally
22.0.0: Pulling from keycloak/keycloak
d1da3ca59af4: Pull complete 
96e5bd002817: Pull complete 
e465405d73d9: Pull complete 
9ff76128529c: Pull complete 
Digest: sha256:1882e5b5b881ec9370a5b2048b4c9e8b877d98eabad5d7a82af12efc697c59da
Status: Downloaded newer image for quay.io/keycloak/keycloak:22.0.0
e8a3caa02ccfb1c834e19b7442c6cd37e85bfd99850e75266ba0830de823df38

# 실행 확인
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  docker ps
CONTAINER ID   IMAGE                              COMMAND                  CREATED         STATUS         PORTS                                                                                                       NAMES
e8a3caa02ccf   quay.io/keycloak/keycloak:22.0.0   "/opt/keycloak/bin/k…"   3 minutes ago   Up 3 minutes                                                                                                               dev-keycloak
7427143efa38   kindest/node:v1.32.8               "/usr/local/bin/entr…"   2 days ago      Up 7 minutes   0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:30000-30003->30000-30003/tcp, 127.0.0.1:52632->6443/tcp   myk8s-control-plane

docker exec -it dev-keycloak java --version
openjdk 17.0.8 2023-07-18 LTS
OpenJDK Runtime Environment (Red_Hat-17.0.8.0.7-1) (build 17.0.8+7-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-17.0.8.0.7-1) (build 17.0.8+7-LTS, mixed mode)


howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  docker images
REPOSITORY                              TAG       IMAGE ID       CREATED        SIZE
jenkins/jenkins                         latest    03113ccbc877   2 weeks ago    518MB
gogs/gogs                               latest    df3dc5f1f1b6   5 weeks ago    131MB
quay.io/argoprojlabs/argocd-autopilot   latest    9bbd32c76e1e   2 months ago   364MB
kindest/node                            <none>    b1b6ffc307b4   2 months ago   1.02GB
kindest/node                            v1.32.8   10dcd90e1d59   2 months ago   1.06GB
quay.io/keycloak/keycloak               22.0.0    456b66461f4b   2 years ago    457MB

# keycloak web 접속
howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  open http://localhost:8080/admin

 

 

4. keycloak에 argoCD를 위한 client 생성

 

5. configuring ArgoCD OIDC

 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl -n argocd patch secret argocd-secret --patch='{"stringData": { "oidc.keycloak.clientSecret": "9vsqPxcl0szshqy30jrKGgqQi69FGpKc" }}'
secret/argocd-secret patched
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl get secret -n argocd argocd-secret -o jsonpath='{.data}' | jq
{
  "accounts.alice.password": "JDJhJDEwJDBFN0EycWJKRXVIdFo1aHRFUEk3SC5wU0NGU0x1c1J3UHY0S0lzcWpuVkpxT3F1SU1NdDYy",
  "accounts.alice.passwordMtime": "MjAyNS0xMS0xMVQwMjoxNzo0OVo=",
  "accounts.alice.tokens": "W3siaWQiOiI2MGExOTYxYi1kOWQzLTQ4NWEtYWIzZi01NTZhZTcxZjRkMDUiLCJpYXQiOjE3NjI4MzA3NjF9XQ==",
  "accounts.gitops-ci.tokens": "W3siaWQiOiI5MjFmODc5OC0wM2ZhLTRiNWEtODFhYS1lMjAzMmEyMjI3ZDkiLCJpYXQiOjE3NjI4MzE0MTN9LHsiaWQiOiI0OWNlODE5MC0yNjUwLTQwNWUtYjhhMS05Mjk0NTI1ZTE3NjQiLCJpYXQiOjE3NjI5NTA2MzZ9XQ==",
  "admin.password": "JDJhJDEwJFRkcEdERkhTWlp0SVZCMVZFejZ1Y2VSdTBOWjk2Q2ZXWHZFOXVTMmxzZjJuRFlpUzhwRVQu",
  "admin.passwordMtime": "MjAyNS0xMS0xMVQwMToyMzo1OFo=",
  "oidc.keycloak.clientSecret": "OXZzcVB4Y2wwc3pzaHF5MzBqcktHZ3FRaTY5RkdwS2M=",
  "server.secretkey": "ckJsZ25OZnFCUzlKYWxJYkRjZDMzMWQ1TC9pRWFNRHlaNVg3YjNsLzVKOD0="
}

# argocd-cm 수정
kubectl apply -f argocd-cm-20251114.yaml 
configmap/argocd-cm configured
 howoo@ttokkang-ui-MacBookAir  ~/Desktop/work/Gasida_series/practice  kubectl rollout restart deploy argocd-server -n argocd
deployment.apps/argocd-server restarted

 

6. Keycloak 인증을 통한 로그인

 

 

 

 

1장. 깃옵스와 쿠버네티스

Gitops 4대원칙

  • Declarative (선언적 구성)
    • “무엇을 원하는지”만 정의, 실행 방법은 명시하지 않음.
    • 예: “컨테이너 3개 사용”을 선언하면, 시스템이 자동으로 상태를 맞춤.
  • Versioned & Immutable (버전 관리 및 불변성)
    • Git과 같은 버전 제어 시스템을 단일 진실 원천(single source of truth)으로 사용.
    • 모든 변경 이력은 추적 가능하고 불변함.
  • Pulled Automatically (자동화된 반영)
    • Git 저장소의 변경 사항이 자동으로 시스템에 반영되어야 함.
    • 수동 배포 작업이 없어야 함.
  • Continuously Reconciled (지속적인 일치 및 조정)
    • 현재 상태와 선언된 상태를 지속적으로 비교하여 자동으로 일치시킴.
    • 이를 폐쇄 루프(closed loop) 제어라 함.

 

kind k8s배포

#기존배포한 k8s를 통해 진행
(⎈|kind-myk8s:default) zosys@4:~$ helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
"geek-cookbook" has been added to your repositories
(⎈|kind-myk8s:default) zosys@4:~$ helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30001 --set env.TZ="Asia/Seoul" --namespace kube-system
NAME: kube-ops-view
LAST DEPLOYED: Mon Nov  3 15:21:48 2025
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

 

 

명령형API 선언형 API

*명령형 방식

(⎈|kind-myk8s:default) zosys@4:~$ k create namespace test-ns
namespace/test-ns created

#test-namespace.yml
(⎈|kind-myk8s:default) zosys@4:~$ k create namespace test-ns --dry-run=client -o yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns

(⎈|kind-myk8s:default) zosys@4:~$ k create -f test-ns.yaml
namespace/test-ns created

절차적 방식으로 진행되어 일련의 명령어를 순서대로 적용 직접명령 또는 구성파일(yaml)사용

 

*선언형 방식

파일을 사용하여 생성하고, 파일 수정 후 업데이트/동기화 명령을 실행한다. 신규/수정 파일 모두 kubectl apply 명령 사용.

(⎈|kind-myk8s:default) zosys@4:~$ cat test-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns
  labels:
    namespace: test-ns

(⎈|kind-myk8s:default) zosys@4:~$ k apply -f test-ns.yaml

 

깃옵스 오퍼레이터 구축 실습

#리포지터리 복제
(⎈|kind-myk8s:default) zosys@4:~/gitops$ git clone https://github.com/PacktPublishing/ArgoCD-in-Practice.git
Cloning into 'ArgoCD-in-Practice'...
remote: Enumerating objects: 1261, done.
remote: Counting objects: 100% (125/125), done.
remote: Compressing objects: 100% (32/32), done.
remote: Total 1261 (delta 99), reused 97 (delta 93), pack-reused 1136 (from 1)
Receiving objects: 100% (1261/1261), 22.43 MiB | 11.46 MiB/s, done.


#go 설치 
(⎈|kind-myk8s:default) zosys@4:~$ sudo apt install golang-go -y
[sudo] password for zosys:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  golang-1.22-go golang-1.22-src golang-src libpkgconf3 pkg-config pkgconf pkgconf-bin
Suggested packages:
  bzr | brz mercurial subversion
The following NEW packages will be installed:
  golang-1.22-go golang-1.22-src golang-go golang-src libpkgconf3 pkg-config pkgconf pkgconf-bin
0 upgraded, 8 newly installed, 0 to remove and 33 not upgraded.
Need to get 45.8 MB of archives.
After this operation, 228 MB of additional disk space will be used.
-----------------------------중략--------------------------------

(⎈|kind-myk8s:default) zosys@4:~/gitops/ArgoCD-in-Practice/ch01$ tree basic-gitops-operator
basic-gitops-operator
├── go.mod
├── go.sum
└── main.go

1 directory, 3 files
(⎈|kind-myk8s:default) zosys@4:~/gitops/ArgoCD-in-Practice/ch01$ tree basic-gitops-operator-config/
basic-gitops-operator-config/
├── deployment.yaml
└── namespace.yaml

#실행
(⎈|kind-myk8s:default) zosys@4:~/gitops/ArgoCD-in-Practice/ch01/basic-gitops-operator$ go run main.go
go: downloading github.com/go-git/go-git/v5 v5.4.2
go: downloading github.com/go-git/go-billy/v5 v5.3.1
go: downloading github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7
go: downloading github.com/sergi/go-diff v1.1.0
go: downloading github.com/imdario/mergo v0.3.12
go: downloading github.com/mitchellh/go-homedir v1.1.0
go: downloading github.com/emirpasic/gods v1.12.0
go: downloading github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
go: downloading github.com/go-git/gcfg v1.5.0
go: downloading golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
go: downloading github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351
go: downloading github.com/xanzy/ssh-agent v0.3.0
go: downloading golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
go: downloading golang.org/x/net v0.0.0-20210520170846-37e1c6afe023
go: downloading gopkg.in/warnings.v0 v0.1.2
------------중략--------------

#생성확인
(⎈|kind-myk8s:default) zosys@4:~$ k get deploy,pod -n nginx
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           43s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-5869d7778c-rqcxl   1/1     Running   0          43s

#강제로 deploy 삭제

(⎈|kind-myk8s:default) zosys@4:~$ k delete deploy -n nginx nginx
deployment.apps "nginx" deleted from nginx namespace

#자동재생성
start repo sync
start manifests apply
deployment.apps/nginx created
namespace/nginx unchanged

#확인
(⎈|kind-myk8s:default) zosys@4:~$ k get deploy,pod -n nginx
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           16s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-5869d7778c-548j8   1/1     Running   0          16s

 

2장. ArgoCD 시작하기

ArgoCD란?

Argo CD는 선언적인 쿠버네티스의 깃옵스 CD Continuous Delivery 도구

 

핵심 개념 및 용어 정리

  • Argo CD는 깃 리포지터리에 선언된 의도한 상태(Helm 차트 등) 를 쿠버네티스 클러스터의
  • 현재 상태와 비교·동기화하는 조정(Reconciling) 루프를 수행한다.이 과정에서 helm install 대신 kubectl apply 를 사용해, 깃옵스의 선언적 배포 원칙을 유지한다.

용어정리.

  • 애플리케이션 application
    • 쿠버네티스 리소스 그룹은 매니페스트에 의해 규정된다. Argo CD에서는 CRD 에서 규정한다.
  • 애플리케이션 소스 타입 application source type
    • 헬름, Kustomize, jsonnet 과 같이 애플리케이션을 구축하는 데 사용하는 도구다.
  • 타깃 상태 target state
    • 애플리케이션의 의도한 상태를 이야기하며 원천 소스인 깃 리포지터리를 의미한다.
  • 현재 상태 live state
    • 애플리케이션의 현재 상태로 쿠버네티스 클러스터에 배포된 상태를 의미한다.
  • 동기화 상태
    • 현재 상태와 타킷 상태가 일치하는지 확인한다.
    • 즉, 쿠버네티스에 배포된 애플리케이션이 깃 리포지터리에서 설명된 의도한 상태와 일치하는지 여부를 확인한다.
  • 동기화 sync
    • 쿠버네티스 클러스터에 변화를 적용해 애플리케이션을 타깃 상태로 변경한다.
  • 동기화 동작 상태 sync operation status
    • 동기화 단계에서 작업이 실패인지 성공인지 여부를 보여준다.
  • 새로고침 refresh
    • 깃 리포지터리의 최신 코드와 현재 상태의 차이점을 비교한다.
  • 서비스 상태 health status
    • 애플리케이션이 요청을 받을 수 있고 운영 중인 상태인지를 말해준다.

 

ArgoCD설치 by Helm

(⎈|kind-myk8s:default) zosys@4:~/ArgoCD/ArgoCD-in-Practice$ k create ns argocd
namespace/argocd created
(⎈|kind-myk8s:default) zosys@4:~/ArgoCD/ArgoCD-in-Practice$ cat <<EOF > argocd-values.yaml
server:
  service:
    type: NodePort
    nodePortHttps: 30002
  extraArgs:
    - --insecure  # HTTPS 대신 HTTP 사용
EOF

(⎈|kind-myk8s:default) zosys@4:~/ArgoCD/ArgoCD-in-Practice$ helm repo add argo https://argoproj.github.io/argo-helm
"argo" has been added to your repositories
(⎈|kind-myk8s:default) zosys@4:~/ArgoCD/ArgoCD-in-Practice$ helm install argocd argo/argo-cd --version 9.0.5 -f argocd-values.yaml --namespace argocd

#구성요소 확인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl get all -n argocd
NAME                                                   READY   STATUS      RESTARTS   AGE
pod/argocd-application-controller-0                    1/1     Running     0          43s
pod/argocd-applicationset-controller-bbff79c6f-2v5vb   1/1     Running     0          43s
pod/argocd-dex-server-6877ddf4f8-rmkwk                 1/1     Running     0          43s
pod/argocd-notifications-controller-7b5658fc47-2hbpf   1/1     Running     0          43s
-----------------중략-------------------------------------

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl get pod,svc,ep,secret,cm -n argocd
NAME                                                   READY   STATUS      RESTARTS   AGE
pod/argocd-application-controller-0                    1/1     Running     0          50s
pod/argocd-applicationset-controller-bbff79c6f-2v5vb   1/1     Running     0          50s
pod/argocd-dex-server-6877ddf4f8-rmkwk                 1/1     Running     0          50s
pod/argocd-notifications-controller-7b5658fc47-2hbpf   1/1     Running     0          50s
pod/argocd-redis-7d948674-jrvxz                        1/1     Running     0          50s
pod/argocd-redis-secret-init-9k4cd                     0/1     Completed   0          81s
pod/argocd-repo-server-7679dc55f5-gq6k7                1/1     Running     0          50s
pod/argocd-server-787fb5f956-xvcvr                     1/1     Running     0          50s

#crd확인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ k get crd | grep argo
applications.argoproj.io      2025-11-03T11:44:33Z
applicationsets.argoproj.io   2025-11-03T11:44:33Z
appprojects.argoproj.io       2025-11-03T11:44:33Z
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl get appproject -n argocd -o yaml
apiVersion: v1
items:
- apiVersion: argoproj.io/v1alpha1
  kind: AppProject
  metadata:
    creationTimestamp: "2025-11-03T11:44:35Z"
    generation: 1
    name: default
    namespace: argocd
    resourceVersion: "846"
    uid: d3b6435f-f139-476d-a25c-911852de4db8


#sa확인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ k get sa -n argocd
NAME                               SECRETS   AGE
argocd-application-controller      0         4m8s
argocd-applicationset-controller   0         4m8s
argocd-dex-server                  0         4m8s
argocd-notifications-controller    0         4m8s
argocd-redis-secret-init           0         4m39s
argocd-repo-server                 0         4m8s
argocd-server                      0         4m8s
default                            0         5m2s

#rolesum확인 ( rolesum은 krew를 이용하여 설치하면된다.)
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ k rolesum -n argocd argocd-server
ServiceAccount: argocd/argocd-server
Secrets:

Policies:
• [RB] argocd/argocd-server ⟶  [R] argocd/argocd-server
  Resource                     Name  Exclude  Verbs  G L W C U P D DC
  applications.argoproj.io     [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖
  applicationsets.argoproj.io  [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖
  appprojects.argoproj.io      [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖
  configmaps                   [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖
  events                       [*]     [-]     [-]   ✖ ✔ ✖ ✔ ✖ ✖ ✖ ✖
  secrets                      [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✖


• [CRB] */argocd-server ⟶  [CR] */argocd-server
  Resource                     Name  Exclude  Verbs  G L W C U P D DC
  *.*                          [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✖ ✔ ✔ ✖
  applications.argoproj.io     [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✔ ✖ ✖ ✖
  applicationsets.argoproj.io  [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✔ ✖ ✖ ✖
  events                       [*]     [-]     [-]   ✖ ✔ ✖ ✔ ✖ ✖ ✖ ✖
  jobs.batch                   [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖
  pods                         [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✖ ✖ ✖ ✖
  pods/log                     [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✖ ✖ ✖ ✖
  workflows.argoproj.io        [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖

#최초 패스워드 확인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
9-R6i9SHluIOfzEz

 

어플리케이션 실행하기

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    helm:
      valueFiles:
      - values.yaml
    path: helm-guestbook
    repoURL: https://github.com/argoproj/argocd-example-apps
    targetRevision: HEAD
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
EOF server: https://kubernetes.default.svc
Warning: metadata.finalizers: "resources-finalizer.argocd.argoproj.io": prefer a domain-qualified finalizer name including a path (/) to avoid accidental conflicts with other finalizer writers
application.argoproj.io/guestbook created


(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl get pod,svc,ep -n guestbook
NAME                                            READY   STATUS    RESTARTS   AGE
pod/guestbook-helm-guestbook-6585c766d6-cd6zl   1/1     Running   0          47s

NAME                               TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/guestbook-helm-guestbook   ClusterIP   10.96.17.19   <none>        80/TCP    47s

NAME                                 ENDPOINTS        AGE
endpoints/guestbook-helm-guestbook   10.244.0.14:80   47s

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl patch svc -n guestbook guestbook-helm-guestbook -p '{"spec":{"type":"NodePort","ports":[{"port":80,"targetPort":80,"nodePort":30003}]}}'
service/guestbook-helm-guestbook patched
^[[A(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl get svc -n guestbook
NAME                       TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
guestbook-helm-guestbook   NodePort   10.96.17.19   <none>        80:30003/TCP   3m20s

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl get svc -n guestbook
NAME                       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
guestbook-helm-guestbook   ClusterIP   10.96.17.19   <none>        80/TCP    3m31s

#확인 후 삭제진행
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl delete applications -n argocd guestbook
application.argoproj.io "guestbook" deleted from argocd namespace

 

 

Argo CLI 설치

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ VERSION=$(curl -L -s https://raw.githubusercontent.com/argoproj/argo-cd/stable/VERSION)
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/download/v$VERSION/argocd-linux-amd64
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ rm argocd-linux-amd64

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd version --client
argocd: v3.1.9+8665140
  BuildDate: 2025-10-17T22:07:41Z
  GitCommit: 8665140f96f6b238a20e578dba7f9aef91ddac51
  GitTreeState: clean
  GoVersion: go1.24.6
  Compiler: gc
  Platform: linux/amd64

 

Argocd CLI로 정보확인하기

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd login 127.0.0.1:30002 --plaintext
Username: admin
Password:
\'admin:login' logged in successfully
Context '127.0.0.1:30002' updated

#로그인후 정보확인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd account list
NAME   ENABLED  CAPABILITIES
admin  true     login
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd proj list
NAME     DESCRIPTION  DESTINATIONS  SOURCES  CLUSTER-RESOURCE-WHITELIST  NAMESPACE-RESOURCE-BLACKLIST  SIGNATURE-KEYS  ORPHANED-RESOURCES  DESTINATION-SERVICE-ACCOUNTS
default               *,*           *        */*                         <none>                        <none>          disabled            <none>
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd repo list
TYPE  NAME  REPO  INSECURE  OCI  LFS  CREDS  STATUS  MESSAGE  PROJECT

 

Argo CLI 로 애플리케이션 배포하기

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path helm-guestbook \
  --dest-server https://kubernetes.default.svc --dest-namespace guestbook --values values.yaml
application 'guestbook' created

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd app list
NAME              CLUSTER                         NAMESPACE  PROJECT  STATUS     HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                 PATH            TARGET
argocd/guestbook  https://kubernetes.default.svc  guestbook  default  OutOfSync  Missing  Manual      <none>      https://github.com/argoproj/argocd-example-apps.git  helm-guestbook
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd app get argocd/guestbook
Name:               argocd/guestbook
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          guestbook
URL:                https://argocd.example.com/applications/guestbook
Source:
- Repo:             https://github.com/argoproj/argocd-example-apps.git
  Target:
  Path:             helm-guestbook
  Helm Values:      values.yaml
SyncWindow:         Sync Allowed
Sync Policy:        Manual
Sync Status:        OutOfSync from  (0d521c6)
Health Status:      Missing

GROUP  KIND        NAMESPACE  NAME                      STATUS     HEALTH   HOOK  MESSAGE
       Service     guestbook  guestbook-helm-guestbook  OutOfSync  Missing
apps   Deployment  guestbook  guestbook-helm-guestbook  OutOfSync  Missing

#직접 Sync진행하기.
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd app sync argocd/guestbook
TIMESTAMP                  GROUP        KIND   NAMESPACE                  NAME        STATUS    HEALTH        HOOK  MESSAGE
2025-11-03T21:09:56+09:00            Service   guestbook  guestbook-helm-guestbook  OutOfSync  Missing
2025-11-03T21:09:56+09:00   apps  Deployment   guestbook  guestbook-helm-guestbook  OutOfSync  Missing
2025-11-03T21:09:56+09:00   apps  Deployment   guestbook  guestbook-helm-guestbook  OutOfSync  Missing              deployment.apps/guestbook-helm-guestbook created
2025-11-03T21:09:56+09:00            Service   guestbook  guestbook-helm-guestbook  OutOfSync  Missing              service/guestbook-helm-guestbook created
2025-11-03T21:09:56+09:00            Service   guestbook  guestbook-helm-guestbook    Synced  Healthy                  service/guestbook-helm-guestbook created
2025-11-03T21:09:56+09:00   apps  Deployment   guestbook  guestbook-helm-guestbook    Synced  Progressing              deployment.apps/guestbook-helm-guestbook created
------------------------중략-----------------------

#삭제 진행
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd app delete argocd/guestbook
Are you sure you want to delete 'argocd/guestbook' and all its resources? [y/n] y
application 'argocd/guestbook' deleted

 

 

 

Argocd-autopilot cli 설치

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ VERSION=$(curl --silent "https://api.github.com/repos/argoproj-labs/argocd-autopilot/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ curl -L --output - https://github.com/argoproj-labs/argocd-autopilot/releases/download/"$VERSION"/argocd-autopilot-linux-amd64.tar.gz | tar zx
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 71.5M  100 71.5M    0     0  7140k      0  0:00:10  0:00:10 --:--:-- 8974k

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ sudo mv ./argocd-autopilot-* /usr/local/bin/argocd-autopilot
[sudo] password for zosys:
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd-autopilot version
v0.4.20

 

Getting Started : Bootstrap Argo-CD

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ export GIT_TOKEN=ghp_.....
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ export GIT_REPO=https://github.com/zeroone5727/autopilot.git

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd-autopilot repo bootstrap
INFO cloning repo: https://github.com/zeroone5727/autopilot.git
INFO empty repository, initializing a new one with specified remote
WARNING --provider not specified, assuming provider from url: github
WARNING --provider not specified, assuming provider from url: github
INFO using revision: "", installation path: ""
INFO using context: "kind-myk8s", namespace: "argocd"
INFO applying bootstrap manifests to cluster...
namespace/argocd created
Warning: resource customresourcedefinitions/applications.argoproj.io is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by apply apply. apply apply should only be used on resources created declaratively by either apply create --save-config or apply apply. The missing annotation will be patched automatically.
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io configured
Warning: resource customresourcedefinitions/applicationsets.argoproj.io is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by apply apply. apply apply should only be used on resources created declaratively by either apply create --save-config or apply apply. The missing annotation will be patched automatically.
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io configured
Warning: resource customresourcedefinitions/appprojects.argoproj.io is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by apply apply. apply apply should only be used on resources created declaratively by either apply create --save-config or apply apply. The missing annotation will be patched automatically.
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io configured
serviceaccount/argocd-application-controller created
serviceaccount/argocd-applicationset-controller created
------------------중략---------------------

#레포가 자신의 깃주소로 되어있음.
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl get applications.argoproj.io -n argocd autopilot-bootstrap -o yaml | grep repoURL
      {"apiVersion":"argoproj.io/v1alpha1","kind":"Application","metadata":{"annotations":{},"creationTimestamp":null,"finalizers":["resources-finalizer.argocd.argoproj.io"],"labels":{"app.kubernetes.io/managed-by":"argocd-autopilot","app.kubernetes.io/name":"autopilot-bootstrap"},"name":"autopilot-bootstrap","namespace":"argocd"},"spec":{"destination":{"namespace":"argocd","server":"https://kubernetes.default.svc"},"ignoreDifferences":[{"group":"argoproj.io","jsonPointers":["/status"],"kind":"Application"}],"project":"default","source":{"path":"bootstrap","repoURL":"https://github.com/zeroone5727/autopilot.git"},"syncPolicy":{"automated":{"allowEmpty":true,"prune":true,"selfHeal":true},"syncOptions":["allowEmpty=true"]}},"status":{"health":{},"sourceHydrator":{},"summary":{},"sync":{"comparedTo":{"destination":{},"source":{"repoURL":""}},"status":""}}}
    repoURL: https://github.com/zeroone5727/autopilot.git
      repoURL: https://github.com/zeroone5727/autopilot.git
        repoURL: https://github.com/zeroone5727/autopilot.git
        repoURL: https://github.com/zeroone5727/autopilot.git
        
#포트포워딩 설정 후 아래와 같이 argocd 접속
(⎈|kind-myk8s:N/A) zosys@4:~$ kubectl port-forward -n argocd svc/argocd-server 8080:80

 

 

Project생성 Application 추가

Project생성

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd-autopilot project create dev
INFO cloning git repository: https://github.com/zeroone5727/autopilot.git
Enumerating objects: 17, done.
Counting objects: 100% (17/17), done.
Compressing objects: 100% (13/13), done.
Total 17 (delta 1), reused 17 (delta 1), pack-reused 0 (from 0)
WARNING --provider not specified, assuming provider from url: github
INFO using revision: "", installation path: "/"
INFO pushing new project manifest to repo
WARNING --provider not specified, assuming provider from url: github
INFO project created: 'dev'

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd-autopilot project create prd
INFO cloning git repository: https://github.com/zeroone5727/autopilot.git
Enumerating objects: 18, done.
Counting objects: 100% (18/18), done.
Compressing objects: 100% (15/15), done.
Total 18 (delta 2), reused 17 (delta 1), pack-reused 0 (from 0)
WARNING --provider not specified, assuming provider from url: github
INFO using revision: "", installation path: "/"
INFO pushing new project manifest to repo
WARNING --provider not specified, assuming provider from url: github
INFO project created: 'prd'

 

Appliaction 추가

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$  argocd-autopilot app create hello-world1 --app github.com/argoproj-labs/argocd-autopilot/examples/demo-app/ -p dev --type kustomize
INFO cloning git repository: https://github.com/zeroone5727/autopilot.git
Enumerating objects: 19, done.
Counting objects: 100% (19/19), done.
Compressing objects: 100% (16/16), done.
Total 19 (delta 3), reused 17 (delta 1), pack-reused 0 (from 0)
WARNING --provider not specified, assuming provider from url: github
INFO using revision: "", installation path: "/"
INFO committing changes to gitops repo...
WARNING --provider not specified, assuming provider from url: github
INFO installed application: hello-world1

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ argocd-autopilot app create hello-world2 --app github.com/argoproj-labs/argocd-autopilot/examples/demo-app/ -p prd --type kustomize
INFO cloning git repository: https://github.com/zeroone5727/autopilot.git
Enumerating objects: 26, done.
Counting objects: 100% (26/26), done.
Compressing objects: 100% (22/22), done.
Total 26 (delta 4), reused 23 (delta 1), pack-reused 0 (from 0)
WARNING --provider not specified, assuming provider from url: github
INFO using revision: "", installation path: "/"
INFO committing changes to gitops repo...
WARNING --provider not specified, assuming provider from url: github
INFO installed application: hello-world2

 

ArgoCD 동기화

  • 동기화(Sync) 는 Kubernetes 클러스터에 변경사항을 적용해 애플리케이션을 원하는 상태(Target State) 로 만드는 과정이다.
  • 이 과정은 여러 단계별 Hook(리소스 훅) 으로 나뉘며, 특정 시점에 원하는 작업을 실행할 수 있다.

 

동기화 윈도우 확인

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl apply -f app-project.yaml -n argocd
Warning: resource appprojects/default is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
appproject.argoproj.io/default configured

 

UI상에서 확인

 

 

3장 ArgoCD 운영

kind k8s 배포 ( 고가용성 구성을 위한 worker node 3EA)

(⎈|N/A:N/A) zosys@4:~/ArgoCD$ kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF
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
- role: worker
EOF
Creating cluster "myk8s" ...


(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
"geek-cookbook" already exists with the same configuration, skipping
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30001 --set env.TZ="Asia/Seoul" --namespace kube-system
NAME: kube-ops-view
LAST DEPLOYED: Mon Nov  3 22:10:40 2025
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

 

HA모드 설치

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ mkdir -p resources
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ cat << EOF > resources/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: argocd
EOF
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl apply -f resources/namespace.yaml
namespace/argocd created
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ wget https://raw.githubusercontent.com/argoproj/argo-cd/refs/heads/master/manifests/ha/install.yaml
--2025-11-03 22:11:32--  https://raw.githubusercontent.com/argoproj/argo-cd/refs/heads/master/manifests/ha/install.yaml
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1516613 (1.4M) [text/plain]
Saving to: ‘install.yaml’

install.yaml                  100%[=================================================>]   1.45M  7.34MB/s    in 0.2s

2025-11-03 22:11:32 (7.34 MB/s) - ‘install.yaml’ saved [1516613/1516613]

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ mv install.yaml resources/
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ kubectl apply -f resources/install.yaml -n argocd
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD$ k get pod -n argocd
NAME                                                READY   STATUS     RESTARTS   AGE
argocd-application-controller-0                     1/1     Running    0          93s
argocd-applicationset-controller-694b4774cd-2tdnx   1/1     Running    0          93s
argocd-dex-server-66585dc685-vd28n                  1/1     Running    0          93s
argocd-notifications-controller-7c584f65cc-pfpj6    1/1     Running    0          93s
argocd-redis-ha-haproxy-7487b954d9-85v7m            1/1     Running    0          93s
argocd-redis-ha-haproxy-7487b954d9-f46m5            1/1     Running    0          93s
argocd-redis-ha-haproxy-7487b954d9-m9qpn            1/1     Running    0          93s
argocd-redis-ha-server-0                            0/3     Init:0/1   0          93s
argocd-repo-server-74b54f7cb-mnqmf                  1/1     Running    0          93s
argocd-repo-server-74b54f7cb-mtnqf                  1/1     Running    0          93s
argocd-server-8b767f58c-jjskk                       0/1     Running    0          93s
argocd-server-8b767f58c-n48bb                       1/1     Running    0          93s

 

ArgoCD 자체 관리

cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argocd
  namespace: argocd
spec:
  project: default
  source:
    path: resources
    repoURL: https://github.com/zeroone5727/my-sample-app
    targetRevision: main
  syncPolicy:
    automated: {}
  destination:
    namespace: argocd
    server: https://kubernetes.default.svc
EOF

 

ArgoCD 설정변경

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources$ kubectl get networkpolicies.networking.k8s.io -n argocd
NAME                                              POD-SELECTOR                                              AGE
argocd-application-controller-network-policy      app.kubernetes.io/name=argocd-application-controller      38m
argocd-applicationset-controller-network-policy   app.kubernetes.io/name=argocd-applicationset-controller   38m
argocd-dex-server-network-policy                  app.kubernetes.io/name=argocd-dex-server                  38m
argocd-notifications-controller-network-policy    app.kubernetes.io/name=argocd-notifications-controller    38m
argocd-redis-ha-proxy-network-policy              app.kubernetes.io/name=argocd-redis-ha-haproxy            38m
argocd-redis-ha-server-network-policy             app.kubernetes.io/name=argocd-redis-ha                    38m
argocd-repo-server-network-policy                 app.kubernetes.io/name=argocd-repo-server                 38m
argocd-server-network-policy                      app.kubernetes.io/name=argocd-server                      38m

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ vi install.yaml

#네트워크 폴리시 삭제후 원격저장소 푸시
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ git add . && git commit -m "Delete Network Policy Resource" && git push -u origin main
[main e877c84] Delete Network Policy Resource
 1 file changed, 227 deletions(-)
Username for 'https://github.com': zeroone5727
Password for 'https://zeroone5727@github.com':
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 412 bytes | 412.00 KiB/s, done.
Total 4 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/zeroone5727/my-sample-app.git
   a061807..e877c84  main -> main
branch 'main' set up to track 'origin/main'.

#삭제되는것을 확인할수있다.
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ watch -d kubectl get networkpolicies.networking.k8s.io -n argocd
Every 2.0s: kubectl get networkpolicies.networking.k8s.io -n argocd                          4: Mon Nov  3 22:53:55 2025

No resources found in argocd namespace.

 

 

관찰가능성 실습

kube-prometheus-stack 설치

#REPO추가 
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
"prometheus-community" has been added to your repositories

#파라미터 파일 생성
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ cat <<EOT > monitor-values.yaml
prometheus:
  prometheusSpec:
    scrapeInterval: "15s"
    evaluationInterval: "15s"
  service:
    type: NodePort
    nodePort: 30002

grafana:
  defaultDashboardsTimezone: Asia/Seoul
  adminPassword: prom-operator
  service:
    type: NodePort
    nodePort: 30003

alertmanager:
  enabled: false
defaultRules:
  create: false
prometheus-windows-exporter:
  prometheus:
    monitor:
      enabled: false
EOT

#배포
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 75.15.1 \
-f monitor-values.yaml --create-namespace --namespace monitoring
NAME: kube-prometheus-stack
LAST DEPLOYED: Mon Nov  3 23:00:04 2025
NAMESPACE: monitoring
STATUS: deployed
REVISION: 1
NOTES:

접속 확인

 

#설치 확인 및 각종 정보 확인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ helm list -n monitoring
NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                           APP VERSION
kube-prometheus-stack   monitoring      1               2025-11-03 23:00:04.046910353 +0900 KST deployed        kube-prometheus-stack-75.15.1   v0.83.0


(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl get prometheus,servicemonitors -n monitoring
NAME                                                                VERSION   DESIRED   READY   RECONCILED   AVAILABLE   AGE
prometheus.monitoring.coreos.com/kube-prometheus-stack-prometheus   v3.5.0    1         1       True         True        2m31s

NAME                                                                                  AGE
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-apiserver                  2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-coredns                    2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-grafana                    2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-controller-manager    2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-etcd                  2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-proxy                 2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-scheduler             2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kube-state-metrics         2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-kubelet                    2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-operator                   2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-prometheus                 2m31s
servicemonitor.monitoring.coreos.com/kube-prometheus-stack-prometheus-node-exporter   2m31s

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl exec -it sts/prometheus-kube-prometheus-stack-prometheus -n monitoring -c prometheus -- prometheus --version
prometheus, version 3.5.0 (branch: HEAD, revision: 8be3a9560fbdd18a94dedec4b747c35178177202)
  build user:       root@4451b64cb451
  build date:       20250714-16:15:23
  go version:       go1.24.5
  platform:         linux/amd64
  tags:             netgo,builtinassets

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl get servicemonitors.monitoring.coreos.com -n monitoring kube-prometheus-stack-apiserver -o yaml | grep labels: -A10
  labels:
    app: kube-prometheus-stack-apiserver
    app.kubernetes.io/instance: kube-prometheus-stack
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/part-of: kube-prometheus-stack
    app.kubernetes.io/version: 75.15.1
    chart: kube-prometheus-stack-75.15.1
    heritage: Helm
    release: kube-prometheus-stack
  name: kube-prometheus-stack-apiserver
  namespace: monitoring

 

ArgoCD구성요소에 대한 ServiceMonitor생성하기

#테스트파드구성
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80
EOF
pod/nginx created

#메트릭 호출
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl exec -it -n default nginx -- curl argocd-metrics.argocd.svc:8082/metrics
# HELP argocd_app_info Information about application.
# TYPE argocd_app_info gauge
argocd_app_info{autosync_enabled="true",dest_namespace="argocd",dest_server="https://kubernetes.default.svc",health_status="Healthy",name="argocd",namespace="argocd",operation="",project="default",repo="https://github.com/zeroone5727/my-sample-app",sync_status="Synced"} 1
# HELP argocd_app_k8s_request_total Number of kubernetes requests executed during application reconciliation.
# TYPE argocd_app_k8s_request_total counter
argocd_app_k8s_request_total{dry_run="false",name="argocd",namespace="argocd",project="default",resource_kind="api",resource_namespace="",response_code="200",server="https://10.96.0.1:443",verb="Get"} 10
----------------------중략-------------------------


(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl get svc,ep -n argocd -l app.kubernetes.io/name=argocd-metrics
NAME                     TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
service/argocd-metrics   ClusterIP   10.96.212.0   <none>        8082/TCP   64m

NAME                       ENDPOINTS         AGE
endpoints/argocd-metrics   10.244.2.5:8082   64m

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl get pod -n argocd -l app.kubernetes.io/name=argocd-application-controller
NAME                              READY   STATUS    RESTARTS   AGE
argocd-application-controller-0   1/1     Running   0          65m

#Service Monitor 생성
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: argocd-metrics
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-metrics
  endpoints:
    - port: metrics
  namespaceSelector:
    matchNames:
      - argocd
EOF
servicemonitor.monitoring.coreos.com/argocd-metrics created

#argocd-server 메트릭호출
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl exec -it -n default nginx -- curl argocd-server-metrics.argocd.svc:8083/metrics | more
# HELP argocd_info ArgoCD version information
# TYPE argocd_info gauge
argocd_info{version="v3.3.0+4ea2768"} 1                                                                                                         # HELP argocd_kubectl_rate_limiter_duration_seconds Kubectl rate limiter latency
# TYPE argocd_kubectl_rate_limiter_duration_seconds histogram
argocd_kubectl_rate_limiter_duration_seconds_bucket{host="10.96.0.1:443",verb="Get",le="0.005"} 4
-------------------------------------중략--------------------------------

#전체 서비스모니터 생성완료
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl get servicemonitors -n monitoring | grep argocd
argocd-applicationset-controller-metrics         5s
argocd-dex-server                                5s
argocd-metrics                                   4m11s
argocd-notifications-controller                  5s
argocd-redis-haproxy-metrics                     5s
argocd-repo-server-metrics                       14s
argocd-server-metrics                            21s

 

 

그라파나 대시보드 추가 및 확인

cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    helm:
      valueFiles:
      - values.yaml
    path: helm-guestbook
    repoURL: https://github.com/argoproj/argocd-example-apps
    targetRevision: HEAD
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
  destination:
    namespace: guestbook
    server: https://kubernetes.default.svc
EOF

 

 

백업 및 복원

백업(argocd cli활용)

#패스워드 확인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
#패스워드설정
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ ARGOPW=""

#CLI로그인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ argocd login localhost:8080  --username admin --password $ARGOPW --insecure
'admin:login' logged in successfully
Context 'localhost:8080' updated

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ argocd cluster list
SERVER                          NAME        VERSION  STATUS      MESSAGE  PROJECT
https://kubernetes.default.svc  in-cluster  1.32     Successful
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ argocd app list
NAME              CLUSTER                         NAMESPACE  PROJECT  STATUS  HEALTH   SYNCPOLICY  CONDITIONS  REPO                                             PATH            TARGET
argocd/argocd     https://kubernetes.default.svc  argocd     default  Synced  Healthy  Auto-Prune  <none>      https://github.com/zeroone5727/my-sample-app     resources       main
argocd/guestbook  https://kubernetes.default.svc  guestbook  default  Synced  Healthy  Auto-Prune  <none>      https://github.com/argoproj/argocd-example-apps  helm-guestbook  HEAD

#백업생성 및 파일확인
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ argocd admin export -n argocd > backup.yaml
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ cat backup.yaml | more
apiVersion: v1
data:
  resource.customizations.ignoreResourceUpdates.ConfigMap: |
    jqPathExpressions:
      # Ignore the cluster-autoscaler status
      - '.metadata.annotations."cluster-autoscaler.kubernetes.io/last-updated"'
      # Ignore the annotation of the legacy Leases election
      - '.metadata.annotations."control-plane.alpha.kubernetes.io/leader"'
  resource.customizations.ignoreResourceUpdates.Endpoints: |
    jsonPointers:
      - /metadata
      - /subsets

 

 

추가 클러스터 생성 및 복원 작업

(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kubectl config get-contexts
CURRENT   NAME         CLUSTER      AUTHINFO     NAMESPACE
*         kind-myk8s   kind-myk8s   kind-myk8s
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kind create cluster --name myk8s2 --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 31000
    hostPort: 31000
  - containerPort: 31001
    hostPort: 31001
  - containerPort: 31002
    hostPort: 31002
  - containerPort: 31003
    hostPort: 31003
- role: worker
- role: worker
- role: worker
EOF
Creating cluster "myk8s2" ...

#wsl2환경에서 myk8s2생성시 문제가 되어 docker-desktop으로 클러스터 구현
Creating cluster "myk8s2" ...
 ✓ Ensuring node image (kindest/node:v1.32.8) 🖼
 ✗ Preparing nodes 📦 📦 📦 📦
Deleted nodes: ["myk8s2-worker3" "myk8s2-worker" "myk8s2-control-plane" "myk8s2-worker2"]
ERROR: failed to create cluster: could not find a log line that matches "Reached target .*Multi-User System.*|detected cgroup v1"
PS C:\Users\zosys> kubectl apply -f resources/namespace.yaml
namespace/argocd created
PS C:\Users\zosys> kubectl apply -f resources/install.yaml -n argocd
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/applicationsets.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io created
serviceaccount/argocd-application-controller created
serviceaccount/argocd-applicationset-controller created
--------------------------중략------------------------------

 

 

#파워쉘내에 argocd 설치 진행 
PS C:\Users\zosys> $url = "https://github.com/argoproj/argo-cd/releases/download/" + $version + "/argocd-windows-amd64.exe"
PS C:\Users\zosys> $output = "argocd.exe"
PS C:\Users\zosys> Invoke-WebRequest -Uri $url -OutFile $output

PS C:\Users\zosys> .\argocd.exe login localhost:8081  --username admin --password "" --insecure        
'admin:login' logged in successfully
Context 'localhost:8081' updated

#현황보기
PS C:\Users\zosys> .\argocd.exe app list                                                                   
NAME  CLUSTER  NAMESPACE  PROJECT  STATUS  HEALTH  SYNCPOLICY  CONDITIONS  REPO  PATH  TARGET
PS C:\Users\zosys> .\argocd.exe cluster list                                                               
SERVER                          NAME        VERSION  STATUS   MESSAGE                                      
            PROJECT
https://kubernetes.default.svc  in-cluster           Unknown  Cluster has no applications and is not being monitored.

#백업파일로 복원 진행
PS C:\Users\zosys\resources> Get-Content -Raw .\backup.yaml | ..\argocd.exe admin import -n argocd -
import process started argocd
/ConfigMap argocd-cm in namespace argocd updated
/ConfigMap argocd-rbac-cm in namespace argocd updated
/ConfigMap argocd-ssh-known-hosts-cm in namespace argocd updated
/ConfigMap argocd-tls-certs-cm in namespace argocd updated
/Secret argocd-secret in namespace argocd updated
argoproj.io/Application argocd in namespace argocd created
{"level":"info","msg":"Warning: metadata.finalizers: \"resources-finalizer.argocd.argoproj.io\": prefer a domain-qualified finalizer name to avoid accidental conflicts with other finalizer writers","time":"2025-11-04T00:10:51+09:00"}
argoproj.io/Application guestbook in namespace argocd created
Import process comple

#복원 확인
PS C:\Users\zosys> .\argocd.exe app list                                                                   
NAME              CLUSTER                         NAMESPACE  PROJECT  STATUS     HEALTH       SYNCPOLICY  CONDITIONS  REPO                                             PATH            TARGET
argocd/argocd     https://kubernetes.default.svc  argocd     default  OutOfSync  Degraded     Auto-Prune  <none>      https://github.com/zeroone5727/my-sample-app     resources       main
argocd/guestbook  https://kubernetes.default.svc  guestbook  default  Synced     Progressing  Auto-Prune  <none>      https://github.com/argoproj/argocd-example-apps  helm-guestbook  HEAD
PS C:\Users\zosys> .\argocd.exe cluster list                                                               
SERVER                          NAME        VERSION  STATUS      MESSAGE  PROJECT
https://kubernetes.default.svc  in-cluster  1.31     Successful
#리소스 삭제 
(⎈|kind-myk8s:N/A) zosys@4:~/ArgoCD/resources/resources$ kind delete cluster --name myk8s
Deleting cluster "myk8s" ...

가시다님 및 운영진분들께서 운영하시는 클라우드닷넷의 이번주차 스터디는 Jenkins + ArgoCD로 스터디에서는 다음 구성으로 스터디를 진행하였다.

 

5년전쯤 CI도구로 Jenkins를 사용했었는데 플러그인 관리에 상당히 애를 먹었던 기억이 있다. 그 이후로 GitLab CI를 주로 사용하고 있다. 따라서 이번 실습에서 나는 현재 사용중인 GitLab CI를 활용해서 실무 환경을 소개하며 스터디를 진행했고, 구성도는 다음과 같다.

 

 

 

GitLab 파이프라인의 핵심 구성 요소

Pipeline (파이프라인)

  • 전체 CI/CD 프로세스를 의미
  • 여러 개의 Stage로 구성

Stage (스테이지)

  • 파이프라인의 논리적 단계
  • 순차적으로 실행됨
  • 예: build → test → deploy

Job (잡)

  • 실제로 실행되는 작업 단위
  • 각 Job은 특정 Stage에 속함
  • 같은 Stage의 Job들은 병렬로 실행

Runner (러너)

  • Job을 실행하는 에이전트
  • Shared Runner 또는 Specific Runner 사용 가능
  • Docker, Shell, Kubernetes 등 다양한 Executor 지원
 

gitlab-ci.yml 파일 구조

프로젝트 루트에 .gitlab-ci.yml 파일을 생성하면 자동으로 CI/CD가 활성화된다.

기본 구조

# Stage 정의
stages:
  - build
  - test
  - deploy

# Job 정의
job_name:
  stage: stage_name
  script:
    - command1
    - command2

최소 구성 예제

stages:
  - build

build-job:
  stage: build
  script:
    - echo "Hello, GitLab CI!"

핵심 문법 요소

Stages (스테이지)

파이프라인의 실행 순서를 정의한다.

stages:
  - build
  - test
  - deploy
  • 정의한 순서대로 순차 실행
  • 한 Stage의 모든 Job이 성공해야 다음 Stage로 진행
  • 정의하지 않으면 기본값: build, test, deploy

Jobs (잡)

 
job_name:
  stage: test
  script:
    - npm install
    - npm test


Job 이름 규칙

  • 영문자, 숫자, 하이픈(-), 언더스코어(_) 사용 가능
  • .으로 시작하면 숨겨진 Job (템플릿용)

Script (스크립트)

실행할 명령어를 정의한다.

 
job_name:
  script:
    - echo "Starting build"
    - docker build -t myapp .
    - docker push myapp:latest


멀티라인 스크립트

job_name:
  script:
    - |
      if [ "$CI_COMMIT_BRANCH" == "main" ]; then
        echo "Deploying to production"
      else
        echo "Deploying to staging"
      fi

Image (이미지)

Docker 이미지를 지정한다.

# 전역 이미지
image: node:18

# Job별 이미지
build-job:
  image: node:18
  script:
    - npm install

test-job:
  image: python:3.9
  script:
    - pytest

Before Script / After Script

# 모든 Job 전후에 실행
before_script:
  - echo "Setting up environment"

after_script:
  - echo "Cleaning up"

# Job별 설정
test-job:
  before_script:
    - npm install
  script:
    - npm test
  after_script:
    - rm -rf node_modules

Variables (변수)

# 전역 변수
variables:
  DATABASE_URL: "postgres://localhost/db"
  DEPLOY_ENV: "staging"

# Job별 변수
deploy-job:
  variables:
    DEPLOY_ENV: "production"
  script:
    - echo "Deploying to $DEPLOY_ENV"

GitLab 제공 기본 변수

script:
  - echo "Branch: $CI_COMMIT_BRANCH"
  - echo "Commit SHA: $CI_COMMIT_SHA"
  - echo "Project Name: $CI_PROJECT_NAME"
  - echo "Pipeline ID: $CI_PIPELINE_ID"

Only / Except (실행 조건)

# 특정 브랜치에서만 실행
deploy-production:
  stage: deploy
  script:
    - ./deploy.sh
  only:
    - main

# 특정 브랜치 제외
test-job:
  stage: test
  script:
    - npm test
  except:
    - main

Rules (고급 조건)

only/except보다 강력한 조건 설정이다.

deploy-job:
  stage: deploy
  script:
    - ./deploy.sh
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: always
    - if: '$CI_COMMIT_BRANCH == "develop"'
      when: manual
    - when: never

Artifacts (아티팩트)

Job 간 파일을 공유하거나 다운로드 가능하게 한다.

build-job:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week

deploy-job:
  stage: deploy
  script:
    - ls dist/  # build-job의 artifacts 사용 가능

Artifacts 옵션

artifacts:
  paths:
    - build/
    - dist/
  exclude:
    - "*.log"
  expire_in: 30 days
  when: on_success  # on_success, on_failure, always

Cache (캐시)

의존성 등을 캐싱하여 빌드 속도를 개선한다.

# 전역 캐시
cache:
  paths:
    - node_modules/
  key: $CI_COMMIT_REF_SLUG

# Job별 캐시
test-job:
  cache:
    key: npm-cache
    paths:
      - node_modules/
  script:
    - npm install
    - npm test

Cache vs Artifacts

  • Cache: 빌드 속도 향상 목적, Job 간 공유 불보장
  • Artifacts: Job 간 파일 전달, 다운로드 가능

Dependencies (의존성)

특정 Job의 artifacts만 사용한다.

build-app:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/

build-docs:
  stage: build
  script:
    - npm run docs
  artifacts:
    paths:
      - docs/

deploy:
  stage: deploy
  dependencies:
    - build-app  # build-app의 artifacts만 다운로드
  script:
    - deploy dist/

Services (서비스)

데이터베이스 등의 보조 컨테이너를 실행한다.

test-job:
  image: node:18
  services:
    - postgres:14
    - redis:latest
  variables:
    POSTGRES_DB: test_db
    POSTGRES_USER: user
    POSTGRES_PASSWORD: password
  script:
    - npm test

When (실행 시점)

deploy-manual:
  stage: deploy
  script:
    - ./deploy.sh
  when: manual  # 수동 실행

cleanup-on-failure:
  stage: cleanup
  script:
    - ./cleanup.sh
  when: on_failure  # 실패 시에만 실행

when 옵션

  • on_success: 이전 Stage 성공 시 (기본값)
  • on_failure: 이전 Stage 실패 시
  • always: 항상 실행
  • manual: 수동 트리거
  • delayed: 지연 실행

 

stage, job을 활용한 기본 스크립트는 다음과 같다.

stages:
  - prepare
  - build
  - test
  - deploy

# ==================== PREPARE STAGE ====================
setup-environment:              # Job 이름: setup-environment
  stage: prepare                # 이 Job은 prepare Stage에 속함
  script:
    - echo "환경 설정 중..."

# ==================== BUILD STAGE ====================
build-frontend:                 # Job 이름: build-frontend
  stage: build                  # 이 Job은 build Stage에 속함
  script:
    - echo "프론트엔드 빌드 중..."

build-backend:                  # Job 이름: build-backend
  stage: build                  # 이 Job은 build Stage에 속함
  script:
    - echo "백엔드 빌드 중..."

build-docker-image:             # Job 이름: build-docker-image
  stage: build                  # 이 Job은 build Stage에 속함
  script:
    - echo "Docker 이미지 빌드 중..."

# ==================== TEST STAGE ====================
unit-test:                      # Job 이름: unit-test
  stage: test                   # 이 Job은 test Stage에 속함
  script:
    - echo "단위 테스트 실행 중..."

integration-test:               # Job 이름: integration-test
  stage: test                   # 이 Job은 test Stage에 속함
  script:
    - echo "통합 테스트 실행 중..."

security-scan:                  # Job 이름: security-scan
  stage: test                   # 이 Job은 test Stage에 속함
  script:
    - echo "보안 스캔 중..."

# ==================== DEPLOY STAGE ====================
deploy-staging:                 # Job 이름: deploy-staging
  stage: deploy                 # 이 Job은 deploy Stage에 속함
  script:
    - echo "스테이징 배포 중..."
  only:
    - develop

deploy-production:              # Job 이름: deploy-production
  stage: deploy                 # 이 Job은 deploy Stage에 속함
  script:
    - echo "프로덕션 배포 중..."
  when: manual
  only:
    - main
태그를 안넣어서 stuck 상태

 

 

GitLab Runner 파드외에 추가로 파이프라인용 파드가 실행되는것을 볼 수 있다.

 

파이프라인의 해당 스테이지별로 파드가 실행됨

 

그렇다면 컨테이너 이미지 저장소 및 Manifest는 어떻게 지정할까 ?

 

위와 같이 파이프라인 스크립트 내에 변수로 지정할 수 있다. 다만 이렇게 설정할 경우 변수가 유출 될 수 있다. 특히 프라이빗 컨테이너 저장소 자격증명 토큰은 절대 파이프라인에 직접 저장하면 안된다.

이때는 GitLab의 그룹 변수, 또는 프로젝트 변수를 활용할 수 있다.

 

 

자, 파이프라인을 활용하여 빌드를 진행해보자.

include:
  - project: 'devops/gitlab-ci-template'
    ref: main
    file:
      - 'ecr-build.yml'
      - 'manifest-update.yml'
      - 'slack-notification.yml'

stages:
  - build
  - update-manifest

variables:
  # ECR 레지스트리 URL
  DEV_ECR_REGISTRY_URL: "178522123123.dkr.ecr.ap-northeast-2.amazonaws.com/test-sabo"
  PROD_ECR_REGISTRY_URL: "178522123123.dkr.ecr.ap-northeast-2.amazonaws.com/live-test-sabo"
  
  # 매니페스트 리포지토리 & 파일 경로
  MANIFEST_REPO_URL: "https://gitlab.santander.co.kr/devops/k8s-manifest.git"
  DEV_MANIFEST_FILE_PATH: "dev/test-sabo/2-ro-test-sabo.yaml"
  PROD_MANIFEST_FILE_PATH: "live/test-sabo/2-ro-test-sabo.yaml"
  
  # Slack Webhook URL
  SLACK_WEBHOOK_URL: "https://hooks.slack.com/services/T0C0TQGTE/123DBQND2EM/123h84123jyW123123AJXN0Me"

# ----------------------------------------------------------
# Build: dev → DEV_ECR_REGISTRY_URL / main → PROD_ECR_REGISTRY_URL
# + Build 실패 시 Slack 알림
# ----------------------------------------------------------
build-image:
  extends: .ecr_build_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'
      variables:
        ECR_REGISTRY_URL: $DEV_ECR_REGISTRY_URL
        ENVIRONMENT: "dev"
    - if: '$CI_COMMIT_BRANCH == "main"'
      variables:
        ECR_REGISTRY_URL: $PROD_ECR_REGISTRY_URL
        ENVIRONMENT: "prod"
  after_script:
    - !reference [.slack_notification_build_failed, after_script]

# ----------------------------------------------------------
# Manifest: dev → DEV_MANIFEST_FILE_PATH / main → PROD_MANIFEST_FILE_PATH
# + 성공/실패 Slack 알림
# ----------------------------------------------------------
update-manifest-image:
  extends: .manifest_update_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'
      variables:
        ENV_NAME: "dev"
        TARGET_MANIFEST_FILE: "$DEV_MANIFEST_FILE_PATH"
    - if: '$CI_COMMIT_BRANCH == "main"'
      variables:
        ENV_NAME: "prod"
        TARGET_MANIFEST_FILE: "$PROD_MANIFEST_FILE_PATH"
  after_script:
    - !reference [.slack_notification_deploy_success, after_script]
    - !reference [.slack_notification_manifest_failed, after_script]

 

빌드 구간 스크립트는 위와 같다. 근데 실제 빌드 명령어는 어디에도 없다.

이는 include로 다른 파이프라인을 참조시키고, 이를 extends와 refrence 기능으로 연결해줬기 때문이다. 중복적으로 사용되는 스크립트를 각각의 레포지토리마다 적어줄 필요 없이 이와같이 사용하면 좋다. 

extend: 해당 스크립트 통으로 사용시

reference: 해당 스크립트 내 일부 스테이지 사용시

 

자 그럼 실제 파이프라인의 빌드(include중 ecr-build) 구간을 살펴보자.

# ECR Docker 빌드 템플릿
# 사용법: .gitlab-ci.yml에서 include하여 사용

.ecr_build_template:
  stage: build
  image: moby/buildkit:master
  tags: [devops]
  variables:
    DOCKER_HOST: ""
    AWS_DEFAULT_REGION: "ap-northeast-2"
  before_script:
    - apk add --no-cache aws-cli docker-cli tzdata curl jq git
    - |
      set -e
      : "${ECR_REGISTRY_URL:?ECR_REGISTRY_URL not set}"
      : "${ENVIRONMENT:?ENVIRONMENT not set}"
      ECR_REGISTRY_HOST="$(echo "$ECR_REGISTRY_URL" | cut -d/ -f1)"
      aws ecr get-login-password --region "$AWS_DEFAULT_REGION" \
        | docker login --username AWS --password-stdin "$ECR_REGISTRY_HOST"
  script:
    - |
      set -e
      IMAGE_TAG="${ENVIRONMENT}-$(TZ="Asia/Seoul" date +'%Y%m%d-%H%M%S')"
      FULL_IMAGE_NAME="${ECR_REGISTRY_URL}:${IMAGE_TAG}"

      buildctl-daemonless.sh build \
        --frontend dockerfile.v0 \
        --local context=. \
        --local dockerfile=. \
        --opt build-arg:SYSTEM=aws \
        --opt build-arg:ENVIRONMENT=${ENVIRONMENT} \
        --output type=image,name=${FULL_IMAGE_NAME},push=true

      echo "FULL_IMAGE_NAME=${FULL_IMAGE_NAME}" > build.env
      echo "ENVIRONMENT=${ENVIRONMENT}" >> build.env
  artifacts:
    reports:
      dotenv: build.env

# dev 브랜치용 빌드
.ecr_build_dev:
  extends: .ecr_build_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'
      variables:
        ECR_REGISTRY_URL: $DEV_ECR_REGISTRY_URL
        ENVIRONMENT: "dev"

# main/prod 브랜치용 빌드
.ecr_build_prod:
  extends: .ecr_build_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      variables:
        ECR_REGISTRY_URL: $PROD_ECR_REGISTRY_URL
        ENVIRONMENT: "prod"

 

주요 동작:

  1. 베이스 템플릿 (.ecr_build_template): BuildKit을 사용해 Docker 이미지를 빌드하고 ECR에 푸시
  2. 환경 설정: AWS CLI로 ECR 로그인 후, 환경별(dev/prod) 이미지 태그 자동 생성 (예: dev-20241031-143022)
  3. 브랜치별 분기: dev 브랜치는 개발 ECR로, main 브랜치는 프로덕션 ECR로 자동 배포
  4. 아티팩트 전달: 빌드된 이미지 정보를 build.env 파일로 저장해 다음 Job에서 사용 가능

 여기서 이미지 태그는 시간으로만 지정 돼 있는 상태인데, 깃랩(GitLab) 파이프라인에서 기본 제공되는 커밋 SHA 변수는 도커 이미지 태그로 가장 널리 사용되는값으로 대표적으로 사용되는 변수는 다음과 같다.

- CI_COMMIT_SHA : 현재 파이프라인을 실행한 전체 커밋 SHA(길이 40)
- CI_COMMIT_SHORT_SHA : 전체 SHA의 앞 8자리 등, 짧은 형태

이 변수들은 도커 이미지의 태그로 바로 사용할 수 있어, 소스와 이미지의 트레이싱 및 일관성 관리에 적합하다.

 

예시

variables:
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t my-app:${IMAGE_TAG} .
    - docker push my-app:${IMAGE_TAG}

 

여튼, 이런 방식으로 이미지를 빌드하고, 컨테이너 레지스트리로 이미지를 푸시한다. 

위 플로우에서 2, 3번 단계가 진행됐다고 보면 된다.

자, 이제 빌드가 끝났으니 다음으로 쿠버네티스에 적용될 manifest 업데이트 구간(플로우의 4번)을 살펴보자

 

테스트 레포지토리의 내용은 앞서 build 구간처럼 include, extends를 사용하여 별다른 내용이 없다.

실제 manifest-update 스크립트의 내용은 다음과 같다.

 

# Manifest 업데이트 템플릿
# 사용법: .gitlab-ci.yml에서 include하여 사용

.manifest_update_template:
  stage: update-manifest
  image: alpine:3.18
  tags: [devops]
  before_script:
    - apk add --no-cache git curl jq
    - git config --global user.email "gitlab-ci@test-sabo.co.kr"
    - git config --global user.name "GitLab CI/CD"
  script:
    - |
      set -e
      : "${FULL_IMAGE_NAME:?FULL_IMAGE_NAME not provided from build step}"
      : "${TARGET_MANIFEST_FILE:?TARGET_MANIFEST_FILE not set}"
      : "${MANIFEST_REPO_URL:?MANIFEST_REPO_URL not set}"

      git clone "https://oauth2:${GIT_ACCESS_TOKEN}@${MANIFEST_REPO_URL#https://}"
      MANIFEST_DIR="$(basename "${MANIFEST_REPO_URL}" .git)"
      cd "${MANIFEST_DIR}"

      # Busybox sed 호환: 첫 번째 image: 라인만 교체(들여쓰기 보존)
      sed -i -e "1,/^[[:space:]]*image:[[:space:]]*/s#^\([[:space:]]*image:[[:space:]]*\).*#\1${FULL_IMAGE_NAME}#" "$TARGET_MANIFEST_FILE"

      git add "$TARGET_MANIFEST_FILE"
      git commit -m "Deploy: Update image to ${FULL_IMAGE_NAME} for ${CI_PROJECT_PATH}" || echo "No changes to commit, skipping push."
      git push origin main

      echo "Manifest update successful. ArgoCD will now sync the changes..."

# dev 브랜치용 Manifest 업데이트
.manifest_update_dev:
  extends: .manifest_update_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'
      variables:
        ENV_NAME: "dev"
        TARGET_MANIFEST_FILE: "$DEV_MANIFEST_FILE_PATH"

# main/prod 브랜치용 Manifest 업데이트
.manifest_update_prod:
  extends: .manifest_update_template
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      variables:
        ENV_NAME: "prod"
        TARGET_MANIFEST_FILE: "$PROD_MANIFEST_FILE_PATH"

 

주요 동작:
1. 이전 Job 연계: 빌드 단계에서 생성된 FULL_IMAGE_NAME (이미지 정보)을 받아서 사용
2. Manifest 저장소 클론: 별도의 Git 저장소에서 Kubernetes 배포 매니페스트를 가져옴
3. 이미지 태그 교체: sed 명령어로 YAML 파일 내 image: 필드를 새 이미지로 자동 변경
4. 변경사항 커밋 & 푸시: 업데이트된 매니페스트를 Git 저장소에 자동 커밋
5. ArgoCD 연동: Manifest가 업데이트되면 ArgoCD가 자동으로 감지해 Kubernetes 클러스터에 배포
ps. 브랜치별 동작: dev 브랜치는 개발 매니페스트, main 브랜치는 프로덕션 매니페스트 업데이트

 

보는것처럼 Manifest 모음 레포지토리가 있고, 이를 파이프라인을 실행하기 위해 생성된 파드에 git clone 후 해당 이미지 태그 부분만 sed로 교체하고 git push 하는 방식이다.

 

실제 수정되는 rollout manifest는 다음과 같다.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: test-sabo
  namespace: test-sabo
  labels:
    app: test-sabo
    version: v1
spec:
  replicas: 1
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: test-sabo
  template:
    metadata:
      labels:
        app: test-sabo
        version: v1
    spec:
      containers:
      - name: test-sabo
        image: 178512310749.dkr.ecr.ap-northeast-2.amazonaws.com/dev-test-sabo:dev-20251028-180217
        imagePullPolicy: Always
        ports:
        - containerPort: 9080

        env:
        - name: TZ
          value: Asia/Seoul
        - name: DB_TYPE
          value: "mysql"
        - name: MYSQL_DB_HOST
          valueFrom:
            secretKeyRef:
              name: mysql-auth
              key: MYSQL_DB_HOST
        - name: MYSQL_DB_PORT
          valueFrom:
            secretKeyRef:
              name: mysql-auth
              key: MYSQL_DB_PORT
        - name: MYSQL_DB_USER
          valueFrom:
            secretKeyRef:
              name: mysql-auth
              key: MYSQL_DB_USER
        - name: MYSQL_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-auth
              key: MYSQL_DB_PASSWORD
        - name: MYSQL_DB_NAME
          valueFrom:
            secretKeyRef:
              name: mysql-auth
              key: MYSQL_DB_NAME

        resources:
          limits:
            memory: 2048Mi
            #cpu: 500m
          requests:
            cpu: 300m
            memory: 1024Mi
      restartPolicy: Always
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: role
                    operator: In
                    values:
                      - service
      tolerations:
        - key: "role"
          operator: "Equal"
          value: "service"
          effect: "NoSchedule"
  strategy:
    blueGreen:
      activeService: test-sabo-svc
      previewService: test-sabo-preview-svc
      autoPromotionEnabled: true

 

manifest 업데이트 스테이지가 실행되면(아래 플로우의 4번)

manifest가 업데이트 되고, 설치돼있던 argocd에서 manifest git 저장소가 변경될 때 sync되어 신규 서비스가 배포되는 방식(현재 구성에서는 블루/그린 배포)이다.

 

자 그럼 이제 argocd가 manifest를 sync하여 실제 쿠버네티스에 배포 될 수 있도록 아르고시디에서 프로젝트, 애플리케이션을 등록해보자.

 

레포지토리 등록

 

 

argocd를 통해 배포된 리소스들을 확인할 수 있다.

쿠버네티스에서 확인된 실제 배포 상태.

 

 

자, 이제 그러면 처음부터 끝까지, 즉 코드 푸시부터 배포까지 진행해보자. 이번에 진행할때는 앞서 구축한 파이프라인 외에 이미지 태그를 디비로 관리하는것까지 추가로 설명한다.

 

1. 코드 푸시

 

 

2. 파이프라인 실행

 

2-1) 파이프라인 실행 상세 내용

a) 보는것처럼 .pre 스테이지에서 사전 검증을 진행하고 build / deploy를 진행한다. build/deploy 방식은 앞서 설명한것과 동일하다.

b)아르고시디의 실제 배포된 화면이다.

배포전 이미지 태그이다.

 

 

파이프라인이 실행되면서 신규 파드가 배포되는 상태이다.

 

파드가 정상적으로 종료되고 신규 파드만 남은 상태이다.

변경된 이미지 태그

 

자 그럼 이미지 태그 관리는 어떻게 할까 ?

현재 시스템에서는 go로 짜여진 파이프라인용 허브 서비스가 있고 파이프라인 트리거를 파이프라인 허브 서비스를 통해 진행되고 있다.

 

플로우

 

 

services/common/version_controller.go - 버전 컨트롤 로직
ControlUpdateVersion() 함수로 major.minor.feature 형식의 시맨틱 버저닝 관리
업데이트 타입에 따라 버전 자동 증가

 

routes/interact.go - 버전 생성 및 적용
Build: ControlUpdateVersion()으로 버전 증가
Rebuild: 기존 버전에 -rebuild-YYMMDD-HHMM 형식 추가

services/query/write_build_info.go - 버전 정보 DB 저장
WriteBuildUpdateHistory(): 일반 빌드 버전 저장
WriteRebuildUpdateHistory(): 리빌드 버전 저장

 

실제 저장되는 태그 디비는 다음과 같다.

 

 

 

 

+ Recent posts