티스토리 뷰

IT/Devops

[cicd] 6주차 - Argo CD

Hayley Shim 2025. 11. 22. 23:24

안녕하세요, CICD 학습을 위해 CloudNetaStudy 스터디 모임을 통해 진행한 내용을 정리하였습니다.

 

[Argo CD] 6~8장(263p) - Argo CD 배포 파이프라인, 문제 해결에 대해 중점적으로 학습합니다. 

 

Argo CD 배포 방식에 대한 팀 의견:

현업에서는 App of Apps 패턴 선호도가 높음, 하지만 확장성과 동적 생성은 ApplicationSet이 더 유리함.

 

 

Argo CD 배포 방식 요약

● 유형 1. CLI / API 직접 배포

  • CI/CD 파이프라인에서 kubectl, argocd CLI 직접 호출
  • GitOps 아님 (변경 주도권이 CI/CD 파이프라인에 있음)

● 유형 2. App of Apps 패턴

  • “Root Application”이 여러 App을 생성·관리
  • Git 구조 기반으로 논리적 그룹을 구성
  • 단점:
    • 동적 스케일 불가 (정적 Application 목록 필요)
    • Git 폴더 구조와 강하게 결합
    • 멀티클러스터/테넌트 자동화 어려움

● 유형 3. ApplicationSet

  • 여러 클러스터/폴더/PR 기반으로 “Application 자동 생성”
  • Generator 기반(Dynamic)
  • GitOps + 멀티클러스터 운영에 최적화

 

Cluster Management

mgmt 클러스터 + Ingress + Argo CD 설치

 

  • sed 기반 SSL passthrough 자동 적용
  • 초기 admin PW 자동 변수화
  • UI 자동 오픈

 

#!/usr/bin/env bash
set -e

###############################################
# 1) kind mgmt 클러스터 배포
###############################################
kind create cluster --name mgmt --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  labels:
    ingress-ready: true
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    protocol: TCP
  - containerPort: 443
    hostPort: 443
    protocol: TCP
  - containerPort: 30000
    hostPort: 30000
    protocol: TCP
EOF

###############################################
# 2) ingress-nginx 배포 (kind 전용)
###############################################
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

# SSL Passthrough 옵션 추가
kubectl get deployment ingress-nginx-controller -n ingress-nginx -o yaml \
| sed '/- --publish-status-address=localhost/a\
        - --enable-ssl-passthrough' | kubectl apply -f -

###############################################
# 3) Argo CD HTTPS용 TLS 인증서 생성
###############################################
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout argocd.example.com.key \
  -out argocd.example.com.crt \
  -subj "/CN=argocd.example.com/O=argocd"

kubectl create ns argocd

kubectl -n argocd create secret tls argocd-server-tls \
  --cert=argocd.example.com.crt \
  --key=argocd.example.com.key

###############################################
# 4) Argo CD Helm values 작성
###############################################
cat <<EOF > argocd-values.yaml
global:
  domain: argocd.example.com

server:
  ingress:
    enabled: true
    ingressClassName: nginx
    annotations:
      nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    tls: true
EOF

###############################################
# 5) Argo CD 설치
###############################################
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd --version 9.0.5 \
  -f argocd-values.yaml --namespace argocd

###############################################
# 6) /etc/hosts 등록 (macOS)
###############################################
echo "127.0.0.1 argocd.example.com" | sudo tee -a /etc/hosts

###############################################
# 7) HTTPS 접속 테스트
###############################################
curl -vk https://argocd.example.com/

###############################################
# 8) 초기 admin 비밀번호 확인
###############################################
echo "[INIT PW]"
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d ; echo

###############################################
# 9) CLI 로그인
###############################################
ARGOPW=$(kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d)

argocd login argocd.example.com --insecure \
  --username admin --password "$ARGOPW"

###############################################
# 10) 기본 정보 확인
###############################################
argocd cluster list
argocd proj list
argocd account list

###############################################
# 11) admin 비밀번호 변경
###############################################
argocd account update-password \
  --current-password "$ARGOPW" \
  --new-password qwe12345

###############################################
# 12) 웹 브라우저 열기
###############################################
open "https://argocd.example.com"

 

kind dev/prd k8s 배포 & k8s 자격증명 수정

 

  • dev/prd kind 클러스터 자동 생성
  • Docker 네트워크에서 IP 자동 확인
  • IP 기반 API 서버 통신 검증
  • kubeconfig 자동 백업 + 자동 패치
  • dev/prd 정상 접근 여부 테스트

 

#!/usr/bin/env bash
set -e

###############################################
# 0) 설치 전 kubeconfig context 확인
###############################################
kubectl config get-contexts

###############################################
# 1) Docker 네트워크(kind) 확인
###############################################
docker network ls
docker network inspect kind | jq || true

###############################################
# 2) kind dev / prd 클러스터 생성
###############################################
kind create cluster --name dev --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
EOF

kind create cluster --name prd --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 32000
    hostPort: 32000
EOF

###############################################
# 3) kubeconfig context 확인
###############################################
kubectl config get-contexts

###############################################
# 4) mgmt context로 변경
###############################################
kubectl config use-context kind-mgmt
kubectl config get-contexts

###############################################
# 5) 클러스터 노드/파드 상태 확인
###############################################
kubectl get node -v=6 --context kind-mgmt
kubectl get node -v=6 --context kind-dev
kubectl get node -v=6 --context kind-prd

kubectl get pod -A --context kind-mgmt
kubectl get pod -A --context kind-dev
kubectl get pod -A --context kind-prd

###############################################
# 6) alias 설정 (선택)
###############################################
alias k8s1='kubectl --context kind-mgmt'
alias k8s2='kubectl --context kind-dev'
alias k8s3='kubectl --context kind-prd'

k8s1 get node -owide
k8s2 get node -owide
k8s3 get node -owide

###############################################
# 7) Docker 네트워크에서 IP 확인
###############################################
docker network inspect kind | grep -E 'Name|IPv4Address'

# 예)
# mgmt-control-plane → 192.168.97.2
# dev-control-plane  → 192.168.97.3
# prd-control-plane  → 192.168.97.4

###############################################
# 8) 클러스터 간 API Server 통신 확인
###############################################
docker ps

docker exec -it mgmt-control-plane curl -sk https://dev-control-plane:6443/version
docker exec -it mgmt-control-plane curl -sk https://prd-control-plane:6443/version
docker exec -it dev-control-plane  curl -sk https://prd-control-plane:6443/version

###############################################
# 9) 로컬 PC에서 ping 확인
###############################################
ping -c 1 192.168.97.2 || true
ping -c 1 192.168.97.3 || true
ping -c 1 192.168.97.4 || true

###############################################
# 10) kubeconfig 백업 및 API server 주소 변경
###############################################
cp ~/.kube/config ./kube-config.bak

# 자동 패치 (localhost → docker IP)
sed -i.bak 's/https:\/\/127.0.0.1:[0-9]*/https:\/\/192.168.97.3:6443/' ~/.kube/config
sed -i.bak 's/https:\/\/127.0.0.1:[0-9]*/https:\/\/192.168.97.4:6443/' ~/.kube/config

echo "[수정한 kubeconfig 확인]"
cat ~/.kube/config

###############################################
# 11) dev/prd 접근 확인
###############################################
kubectl get node -v=6 --context kind-dev
kubectl get node -v=6 --context kind-prd

 

Argo CD에 다른 K8S Cluster 등록 - Docs , Cluster* , CMD , KrBlog

 

  • Argo CD가 가진 cluster 목록 확인
  • dev/prd 클러스터(ServiceAccount·RoleBinding 포함) 등록
  • 등록된 클러스터의 Secret(credential) 자동 확인
  • Argo CD가 관리 가능한 cluster 목록을 최종 출력

 

#!/usr/bin/env bash
set -e

###############################################
# 1) 기본 Cluster 상태 확인
###############################################
argocd cluster list
argocd cluster list -o json | jq

kubectl get secret -n argocd
kubectl get secret -n argocd argocd-secret -o jsonpath='{.data}' | jq

###############################################
# 2) kind-dev, kind-prd의 kube-system SA 확인
###############################################
kubectl --context kind-dev get sa -n kube-system
kubectl --context kind-prd get sa -n kube-system

###############################################
# 3) dev 클러스터 Argo CD에 등록
###############################################
argocd cluster add kind-dev --name dev-k8s --yes

kubectl --context kind-dev get sa -n kube-system argocd-manager
kubectl rolesum -n kube-system argocd-manager --context kind-dev || true

###############################################
# 4) Argo CD cluster secret 확인
###############################################
kubectl get secret -n argocd -l argocd.argoproj.io/secret-type=cluster

###############################################
# 5) Argo CD cluster 정보 출력
###############################################
argocd cluster list -o json | jq
argocd cluster list

###############################################
# 6) prd 클러스터 Argo CD에 등록
###############################################
argocd cluster add kind-prd --name prd-k8s --yes

kubectl --context kind-prd get sa -n kube-system argocd-manager

kubectl get secret -n argocd -l argocd.argoproj.io/secret-type=cluster

###############################################
# 7) 최종 클러스터 등록 상태 확인
###############################################
argocd cluster list

 

Argo CD로 3개의 K8S Cluster 에 각각 Nginx 배포

#!/usr/bin/env bash
set -e

###############################################
# 1) kind 네트워크에서 클러스터 IP 확인
###############################################
docker network inspect kind | grep -E 'Name|IPv4Address'

# 수동 변수 설정 (필요 시 docker inspect 결과 기반 자동 파싱 가능)
DEVK8SIP=192.168.97.3
PRDK8SIP=192.168.97.4
echo "[DEV IP:$DEVK8SIP] [PRD IP:$PRDK8SIP]"

###############################################
# 2) Argo CD Application - mgmt 환경 배포
###############################################
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: mgmt-nginx
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    helm:
      valueFiles:
      - values.yaml
    path: nginx-chart
    repoURL: https://github.com/gasida/cicd-study
    targetRevision: HEAD
  syncPolicy:
    automated:
      prune: true
    syncOptions:
    - CreateNamespace=true
  destination:
    namespace: mgmt-nginx
    server: https://kubernetes.default.svc
EOF

###############################################
# 3) Argo CD Application - dev 환경 배포
###############################################
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: dev-nginx
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    helm:
      valueFiles:
      - values-dev.yaml
    path: nginx-chart
    repoURL: https://github.com/gasida/cicd-study
    targetRevision: HEAD
  syncPolicy:
    automated:
      prune: true
    syncOptions:
    - CreateNamespace=true
  destination:
    namespace: dev-nginx
    server: https://$DEVK8SIP:6443
EOF

############################################

 

 

App of Apps 패턴 개요

Argo CD에서 부모 Application( root app ) 하나가 여러 자식 Application을 선언적으로 생성·관리하는 패턴.

장점

  • 여러 Application을 하나의 그룹처럼 묶어 관리
  • 부모 Application 한 번으로 모든 자식 Application 배포 가능
  • 그룹 전체 Sync/Health 확인 가능

사용 예시

Helm 템플릿으로 Applications YAML을 반복 생성:

{{- range .Values.applications }}
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: example.{{ .name }}
  namespace: argocd
spec:
  destination:
    namespace: {{ .namespace }}
    server: {{ $.Values.config.spec.destination.server }}
  source:
    repoURL: {{ $.Values.config.spec.source.repoURL }}
    targetRevision: {{ $.Values.config.spec.source.targetRevision }}
    path: {{ .path }}
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
---
{{- end }}

 

App of Apps 패턴의 한계

App of Apps는 정적(Static) 구조라서 확장이 어려움.

 

주요 단점

  1. 동적 확장 불가
    • 애플리케이션 수가 늘면 YAML에 수동 추가해야 함
    • 고객 100명 = Application 100개 직접 추가
  2. Git 폴더 구조에 종속
    • Git 디렉토리 변경 시 Root App 수정 필요
  3. 다중 클러스터 확장 어려움
    • 클러스터 5개 → Application 5개 수동 생성
  4. 대규모 멀티 테넌트에서 비효율적
    • Root App YAML이 거대해짐
    • Conflict 빈번
  5. 동적 자동 생성 미지원
    • label 기반 자동 배포 불가
    • region/tenant 구조 자동화 불가

→ 그래서 Argo CD 팀이 ApplicationSet 컨트롤러를 개발함

 

ApplicationSet Controller 개요

Argo CD가 사용하는 Application 리소스를 대량·자동 생성/관리하기 위한 전용 컨트롤러.

기능

  • 여러 클러스터에 동시 배포
  • 여러 Git Repo에서 Application 자동 생성
  • Multi-tenant 지원
  • 대규모 배포 자동화
  • 동적 generator 기반 Application 생성

목적

 

ApplicationSet은 정의한 규칙에 따라 Application들을 자동 생성·갱신·삭제하여 상태를 일관되게 유지하는 컨트롤러

 

 

ApplicationSet Generators (핵심)

ApplicationSet은 “제너레이터”가 Application을 자동 생성함.

주요 Generator 종류

List 정해진 요소 목록 기반으로 Application 생성
Cluster Argo CD에 등록된 클러스터 목록 기반 자동 생성
Git Git 디렉토리 구조 기반 App 생성
Matrix 두 개의 generator 조합
Merge generator 병합
SCM Provider GitHub/GitLab repo 자동 검색
Pull Request PR 자동 검색 후 App 생성
Cluster Decision Resource 사용자 정의 CR 기반 클러스터 대상 생성
Plugin 외부 HTTP RPC로 값 생성

 

ApplicationSet 실습

(1) List Generator 실습

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  goTemplate: true
  generators:
  - list:
      elements:
      - cluster: dev-k8s
        url: https://192.168.97.3:6443
      - cluster: prd-k8s
        url: https://192.168.97.4:6443
  template:
    metadata:
      name: '{{.cluster}}-guestbook'
    spec:
      project: default
      source:
        repoURL: https://github.com/gasida/cicd-study.git
        targetRevision: HEAD
        path: appset/list/{{.cluster}}
      destination:
        server: '{{.url}}'
        namespace: guestbook
      syncPolicy:
        syncOptions:
          - CreateNamespace=true

→ 자동으로 아래 Application이 생성됨

  • dev-k8s-guestbook
  • prd-k8s-guestbook

(2) Cluster Generator 실습 (모든 클러스터 자동 대상화)

generators:
- clusters: {}

→ Argo CD에 등록된 모든 클러스터를 자동 대상으로 삼음.

 

(3) Cluster Generator + Label selector (특정 클러스터만)

 
generators:
- clusters:
    selector:
      matchLabels:
        env: "stg"

→ 라벨 붙인 클러스터만 배포됨.

예:

kubectl label secret cluster-192.168.97.3-xxxx -n argocd env=stg
ApplicationSet 주요 명령 요약
 
kubectl get applicationsets -n argocd
argocd appset list
argocd app list -l managed-by=applicationset
kubectl get applications -n argocd --show-labels
argocd app sync -l managed-by=applicationset

 

삭제:

argocd appset delete guestbook --yes
 
 

✔ App of Apps = “정적 구조, 작은 규모에 적합”

✔ ApplicationSet = “동적 생성 + 멀티클러스터 + 멀티테넌트 + 자동화에 특화”

규모가 커지거나 동적 배포가 필요하면 ApplicationSet이 필수

 

 

OpenLDAP + Keycloak + Argo CD + Jenkins 구성

구성 요소역할

 

OpenLDAP 인증 데이터 저장소
Keycloak LDAP 연동 + OIDC Provider (Auth Server)
Argo CD Keycloak OIDC 로그인 사용
Jenkins Keycloak OIDC 로그인 사용
CoreDNS hosts Plugin 내부 도메인 → ClusterIP 매핑

이 구조를 통해:

  • 외부/내부 모두 동일한 도메인으로 Keycloak 접근
  • ArgoCD/Jenkins SSO (OAuth2/OIDC) 연동 가능

 

1. Keycloak 설치 및 기본 설정

Keycloak 배포

  • Deployment + Service + Ingress 구성
  • keycloak.example.com 도메인으로 접근
  • /etc/hosts 에 127.0.0.1 매핑
  • admin / admin 로그인 후 realm 생성
#
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
  labels:
    app: keycloak
spec:
  replicas: 1
  selector:
    matchLabels:
      app: keycloak
  template:
    metadata:
      labels:
        app: keycloak
    spec:
      containers:
        - name: keycloak
          image: quay.io/keycloak/keycloak:26.4.0
          args: ["start-dev"]     # dev mode 실행
          env:
            - name: KEYCLOAK_ADMIN
              value: admin
            - name: KEYCLOAK_ADMIN_PASSWORD
              value: admin
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: keycloak
spec:
  selector:
    app: keycloak
  ports:
    - name: http
      port: 80
      targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: keycloak
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  ingressClassName: nginx
  rules:
    - host: keycloak.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: keycloak
                port:
                  number: 8080
EOF

# 확인
kubectl get deploy,svc,ep keycloak
kubectl get ingress keycloak
NAME       CLASS   HOSTS                  ADDRESS     PORTS   AGE
keycloak   nginx   keycloak.example.com   localhost   80      91s

#
curl -s -H "Host: keycloak.example.com" http://127.0.0.1 -I
HTTP/1.1 302 Found
Location: http://keycloak.example.com/admin/

# 도메인 설정
## macOS의 /etc/hosts 파일 수정
echo "127.0.0.1 keycloak.example.com" | sudo tee -a /etc/hosts
cat /etc/hosts

## C:\Windows\System32\drivers\etc\hosts 관리자모드에서 메모장에 내용 추가
127.0.0.1 keycloak.example.com

# keycloak 웹 접속 : admin / admin
curl -s http://keycloak.example.com -I
open "http://keycloak.example.com/admin"

 

2. 클러스터 내부에서 Keycloak·Argo CD·Jenkins 도메인 접근 설정

Pod 내부에서 keycloak.example.com 이 resolve 되지 않아 접근 불가 문제 발생 → CoreDNS hosts 플러그인으로 해결.

# 경량의 curl 테스트용 파드 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: curl
  namespace: default
spec:
  containers:
  - name: curl
    image: curlimages/curl:latest
    command: ["sleep", "infinity"]
EOF

#
kubectl get pod -l app=keycloak -owide
kubectl get pod -l app=keycloak -o jsonpath='{.items[0].status.podIP}'
KEYCLOAKIP=$(kubectl get pod -l app=keycloak -o jsonpath='{.items[0].status.podIP}')
echo $KEYCLOAKIP 

# 기본 통신 및 정보 확인 : ClusterIP 메모!
kubectl get svc keycloak
NAME       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
keycloak   ClusterIP   10.96.58.66   <none>        80/TCP   25m

kubectl get svc -n argocd argocd-server
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
argocd-server   ClusterIP   10.96.156.196   <none>        80/TCP,443/TCP   134m

kubectl exec -it curl -- ping -c 1 $KEYCLOAKIP
kubectl exec -it curl -- curl -s http://keycloak.default.svc.cluster.local/realms/myrealm/.well-known/openid-configuration | jq

# 왜 호출이 되지 않을까?
kubectl exec -it curl -- curl -s http://keycloak.example.com -I
kubectl exec -it curl -- nslookup -debug keycloak.example.com
kubectl exec -it curl -- nslookup keycloak.example.com

# 해결해보자 : coredns 에 hosts 플러그인 활용
KUBE_EDITOR="nano" kubectl edit cm -n kube-system coredns
.:53 {
       ...
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
           ttl 30
        }
        hosts {
           <CLUSTER IP> keycloak.example.com
           <CLUSTER IP> argocd.example.com
           fallthrough
        }
        reload # cm 설정 변경 시 자동으로 reload 적용됨
...

# cm 설정 변경 시 자동으로 reload 적용 로그 확인
kubectl logs -n kube-system -l k8s-app=kube-dns --timestamps

# 도메인 질의 시, ClusterIP로 변경 확인 : 파드 내에 dns 쿼리 캐시는 없는 걸까요???
kubectl exec -it curl -- nslookup -debug keycloak.example.com
kubectl exec -it curl -- nslookup keycloak.example.com
 

 

3. Keycloak에 Argo CD OIDC Client 생성

Argo CD용 Keycloak client 설정

Argo CD OIDC 설정(ConfigMap)

#
kubectl -n argocd patch secret argocd-secret --patch='{"stringData": { "oidc.keycloak.clientSecret": "<REPLACE_WITH_CLIENT_SECRET>" }}'
kubectl -n argocd patch secret argocd-secret --patch='{"stringData": { "oidc.keycloak.clientSecret": "mV3IZO3nmHoZr3BBC37UpdrMSMkF9Umt" }}'

# 확인
kubectl get secret -n argocd argocd-secret -o jsonpath='{.data}' | jq
...
  "oidc.keycloak.clientSecret": "bVYzSVpPM25tSG9acjNCQkMzN1VwZHJNU01rRjlVbXQ=",

 

# 설정 추가
kubectl patch cm argocd-cm -n argocd --type merge -p '
data:
  oidc.config: |
    name: Keycloak
    issuer: http://keycloak.example.com/realms/myrealm
    clientID: argocd
    clientSecret: mV3IZO3nmHoZr3BBC37UpdrMSMkF9Umt
    requestedScopes: ["openid", "profile", "email"]
'

# 확인
kubectl get cm -n argocd argocd-cm -o yaml | grep oidc.config: -A5
 
 
4. Keycloak 인증 기반 Argo CD 로그인 확인
  • alice로 로그인 → 정상 인증
  • Keycloak 콘솔에서 해당 세션 조회 가능

 

5. Jenkins 배포 및 OIDC 연동

#
kubectl create ns jenkins
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pvc
  namespace: jenkins
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins
  namespace: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      securityContext:
        fsGroup: 1000
      containers:
        - name: jenkins
          image: jenkins/jenkins:lts
          ports:
            - name: http
              containerPort: 8080
            - name: agent
              containerPort: 50000
          volumeMounts:
            - name: jenkins-home
              mountPath: /var/jenkins_home
      volumes:
        - name: jenkins-home
          persistentVolumeClaim:
            claimName: jenkins-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: jenkins-svc
  namespace: jenkins
spec:
  type: ClusterIP
  selector:
    app: jenkins
  ports:
    - port: 8080
      targetPort: http
      protocol: TCP
      name: http
    - port: 50000
      targetPort: agent
      protocol: TCP
      name: agent
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jenkins-ingress
  namespace: jenkins
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
spec:
  ingressClassName: nginx
  rules:
    - host: jenkins.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: jenkins-svc
                port:
                  number: 8080
EOF

# 확인
kubectl get deploy,svc,ep,pvc -n jenkins
kubectl get ingress -n jenkins jenkins-ingress
NAME              CLASS   HOSTS                 ADDRESS     PORTS   AGE
jenkins-ingress   nginx   jenkins.example.com   localhost   80      60s

# 도메인 설정
## macOS의 /etc/hosts 파일 수정
echo "127.0.0.1 jenkins.example.com" | sudo tee -a /etc/hosts
cat /etc/hosts

## C:\Windows\System32\drivers\etc\hosts 관리자모드에서 메모장에 내용 추가
127.0.0.1 jenkins.example.com


# 초기 암호 확인
kubectl exec -it -n jenkins deploy/jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword
7521bc306a4049a6a0fd75391ae4b235

# 웹 접속 : 기본 설정 진행
curl -s http://jenkins.example.com -I
open "http://jenkins.example.com"

 

Jenkins OIDC 설정

alice/bob으로 Keycloak 인증 로그인 가능.

 

6. OpenLDAP 설치 및 사용자/그룹 생성

OpenLDAP + phpLDAPadmin 분석

  • Base DN: dc=example,dc=org
  • 관리자 DN: cn=admin,dc=example,dc=org

LDAP 엔트리 구성

dc=example,dc=org     # Base DN(Root DN)
 ├── ou=people
 │    ├── uid=alice
 │    └── uid=bob
 └── ou=groups
      ├── cn=devs
      └── cn=admins

 

User/Group 생성 및 검색

  • ldapadd로 people, groups, users(bob/alice), group entries 생성
  • ldapsearch, ldapwhoami로 검증

 

7. Keycloak ↔ LDAP 연동

Keycloak User Federation(LDAP) 설정

  • LDAP URL: ldap://openldap.openldap.svc:389
  • Bind DN: cn=admin,dc=example,dc=org
  • Users DN: ou=people,dc=example,dc=org
  • Edit Mode: WRITABLE
  • Search scope: Subtree

User Sync

  • Keycloak → "Sync all users"
    → LDAP의 alice, bob이 Keycloak user로 등록됨

 

8. LDAP Group → Keycloak Group 동기화

Keycloak Mapper 생성:

  • Mapper type: group-ldap-mapper
  • LDAP Groups DN: ou=groups,dc=example,dc=org
  • LDAP attribute:
    • name: cn
    • member attribute: member
  • Mode: READ_ONLY

→ Keycloak Groups에 admins, devs 자동 생성
→ 각 그룹에 alice/bob 자동 연결됨

 

9. Group 정보를 Token으로 전달 (ArgoCD/Jenkins RBAC)

Keycloak Client Scope 생성

  • Scope name: groups
  • Mapper: Group Membership
  • Token Claim Name: groups

Keycloak → argocd, jenkins Client에 scope 추가(Default)

Argo CD requestedScopes에 groups 추가

 
requestedScopes: ["openid","profile","email","groups"]

Jenkins에도 groups scope 추가

→ bob 로그인 시 devs 그룹 씌워진 것 확인

 

10. Argo CD RBAC 설정

devs 그룹에 ArgoCD admin 권한 부여

argocd-rbac-cm 설정:

 
policy.csv: | g, devs, role:admin

→ bob(devs 그룹) 로그인 시 ArgoCD 관리자 권한 획득

 

11. Applicationset 배포 테스트

  • Argo CD ApplicationSet 샘플 guestbook 배포
  • bob 로그인 시 RBAC에 따라 접근 권한이 달라짐
#
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - clusters: {}
  template:
    metadata:
      name: '{{.name}}-guestbook'
      labels:
        managed-by: applicationset
    spec:
      project: "default"
      source:
        repoURL: https://github.com/gasida/cicd-study
        targetRevision: HEAD
        path: guestbook
      destination:
        server: '{{.server}}'
        namespace: guestbook
      syncPolicy:
        syncOptions:
          - CreateNamespace=true
EOF

# sync
argocd app sync -l managed-by=applicationset

# 생성된 application yaml 확인
kubectl get applications -n argocd in-cluster-guestbook -o yaml | k neat | yq
kubectl get applications -n argocd dev-k8s-guestbook -o yaml | k neat | yq
kubectl get applications -n argocd prd-k8s-guestbook -o yaml | k neat | yq

# 각 k8s 에 배포된 파드 정보 확인
k8s1 get pod -n guestbook
k8s2 get pod -n guestbook
k8s3 get pod -n guestbook

 

12. 최종 결과

OpenLDAP 사용자/그룹 → Keycloak 자동 동기화
Keycloak → Argo CD · Jenkins OIDC SSO

CoreDNS로 Kubernetes 내부에서도 동일 도메인 접근 가능
RBAC을 그룹 기반으로 통합 관리
bob(devs) / alice(admins) 의 권한이 ArgoCD/Jenkins 모두에 일관 적용

 

'IT > Devops' 카테고리의 다른 글

[cicd] 5주차 - Argo CD  (0) 2025.11.16
[cicd] 4주차 - Argo CD  (0) 2025.11.09
[cicd] 3주차 - Jenkins + ArgoCD  (0) 2025.11.02
[cicd] 2주차 - Helm, Tekton  (0) 2025.10.25
[cicd] 1주차 - Image Build  (0) 2025.10.19
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2025/11   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
글 보관함