
CloudNet@ CICD Study 1기 정리
GitOps의 정의
GitOps는 **Git을 단일한 진실의 원천(Single Source of Truth)**으로 사용하는 인프라 관리 방식입니다.
- 제안자: Weaveworks CEO Alexis Richardson (2017년)
- 등장 배경: 클라우드 네이티브 애플리케이션의 복잡성과 전통적 배포 방식의 한계를 해결하기 위해 등장
- 핵심 개념: 시스템의 원하는 상태(Desired State)를 Git에 선언적(Declarative)으로 정의하여 인프라를 코드로 관리하는 방법론
GitOps의 3대 핵심 원칙
| 1. Git은 단일 소스 | Git이 모든 환경(Dev, Staging, Prod)의 신뢰 가능한 정보 원천으로 작동. 모든 변경은 Git을 통해 수행. |
| 2. 모든 것을 코드로 | 인프라뿐 아니라 애플리케이션 매니페스트, 보안 정책, 모니터링 설정 등 모든 요소를 코드로 선언적 관리. |
| 3. Git 워크플로 기반 운영 | 모든 변경은 **Pull Request(PR)**를 통해 수행되며, 리뷰·버전관리·감사 추적이 가능. |
CNCF OpenGitOps 4대 원칙 (표준 정의)
| 1. 선언적 (Declarative) | 원하는 상태(Desired State)를 코드로 명확히 표현해야 함. |
| 2. 버전 및 불변성 (Versioned & Immutable) | Git 커밋 히스토리로 완전한 변경 이력 유지 및 불변성 보장. |
| 3. 자동 반영 (Pulled Automatically) | GitOps 에이전트(Argo CD, Flux 등)가 Git에서 상태를 자동으로 끌어와 반영. |
| 4. 지속적 조정 (Continuously Reconciled) | 실제 상태를 지속적으로 관찰하고 Git의 원하는 상태와 자동 동기화. |
MacOS에서 Homebrew를 사용하여 필요한 도구들을 설치
brew install kind Kind (Kubernetes IN Docker) 설치
| brew install kubectl | 쿠버네티스 클러스터 관리 도구 설치 | |
| brew install jq tree | JSON 처리 및 디렉토리 구조 확인 도구 설치 | |
| git clone <https://github.com/gitops-cookbook/chapters> | 실습용 소스 코드 저장소 복제 | |
| cd chapters/chapters | 작업 디렉토리 이동 |
필수 준비: Docker Hub 또는 Quay.io에 가입하고, 이미지 푸시를 위해 Access Token을 생성하여 준비.
로컬 쿠버네티스 클러스터 (Kind) 구성
로컬 쿠버네티스 클러스터 (Kind) 구성
Kind를 사용하여 로컬에 쿠버네티스 클러스터를 생성.
단계 명령어 설명
| 1. 클러스터 생성 | 아래 설정을 kind-config.yaml로 저장 후 실행 | Kind 클러스터 (1 Control Plane + 1 Worker) 생성 및 포트 매핑 |
| kind create cluster --name gitops-study --config kind-config.yaml | ||
| 2. 설정 파일 (kind-config.yaml) | yaml<br>kind: Cluster<br>apiVersion: kind.x-k8s.io/v1alpha4<br>nodes:<br>- role: control-plane<br>- role: worker<br> | |
| 3. 상태 확인 | kubectl get nodes -o wide | Kind 클러스터 노드 상태 확인 (Ready 상태여야 함) |
| kubectl cluster-info | 클러스터 정보 확인 |
cat kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
# 호스트 포트 30000, 30001번을 Control Plane 컨테이너에 매핑 (포트 매핑)
extraPortMappings:
- containerPort: 30000
hostPort: 30000
protocol: TCP
- containerPort: 30001
hostPort: 30001
protocol: TCP
- role: worker
apiVersion: Kind 설정 파일의 API 버전을 명시합니다.
- nodes: 클러스터를 구성하는 노드들의 목록을 정의합니다.
◦ role: control-plane: 제어 평면 역할을 하는 노드를 지정합니다.
◦ extraPortMappings: Host OS와 Control Plane 컨테이너 간의 포트 매핑을 정의 (예: NodePort 서비스 접근 시 유용).
◦ role: worker: 작업 부하(Pod)를 실행할 워커 노드를 지정.
클러스터 생성
kind create cluster --name gitops-study --config kind-config.yaml
Kind 클러스터 노드 상태 확인
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
gitops-study-control-plane Ready control-plane 42s v1.34.0 172.18.0.4 <none> Debian GNU/Linux 12 (bookworm) 6.10.14-linuxkit containerd://2.1.3
gitops-study-worker Ready <none> 33s v1.34.0 172.18.0.3 <none> Debian GNU/Linux 12 (bookworm) 6.10.14-linuxkit containerd://2.1.3
클러스터 정보확인
kubectl cluster-info
Kubernetes control plane is running at <https://127.0.0.1:62844>
CoreDNS is running at <https://127.0.0.1:62844/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy>
컨테이너 이미지를 레지스트리에 푸시하려면 인증이 필요

예제 이미지 빌드
docker build -f Dockerfile -t $MYREGISTRY/$MYUSER/pythonapp:latest .
빌드된 이미지 확인
docker images | grep pythonapp
wish2rich/pythonapp latest cc8839a919d7 2 minutes ago 892MB
이미지 푸쉬
docker push $MYREGISTRY/$MYUSER/pythonapp:latest
The push refers to repository [docker.io/wish2rich/pythonapp]
832ff574d03b: Pushed
951f234ec339: Pushed
93df63592272: Pushed
60f598c3b559: Pushed
c389346289d1: Pushed
7f0ee204bbc3: Pushed
426b5cb0a28c: Pushed
607b1f009670: Pushed
latest: digest: sha256:3bc7831a01170be6cd02d2b2cc1161c27ffad070dfce7bc5d5015a2485b678ad size: 1999
로컬테스트
docker run -d --name myweb -p 8080:8080 $MYREGISTRY/$MYUSER/pythonapp:latest
curl <http://localhost:8080>
Hello, World!
컨테이너 정리
docker rm -f myweb
Dockerless 빌드 - Jib 사용 (Java 애플리케이션)
Jib은 Docker 데몬이나 Dockerfile 없이 Maven/Gradle 플러그인을 통해 JVM 기반 언어 이미지를 빌드하고 레지스트리에 푸시
Worker 노드 접속
docker exec -it gitops-study-worker bash
root@gitops-study-worker:/#
Maven/Java 설치
명령어 설명 출처
| apt update | 패키지 리스트를 최신 정보로 업데이트 | |
| mkdir -p /usr/share/man/man1 | 일부 리눅스 환경에서 설치 시 발생하는 오류 방지를 위해 디렉토리를 생성 | |
| apt install openjdk-17-jdk -y | OpenJDK 17 JDK를 설치. | |
| apt install maven -y | Maven 빌드 도구를 설치. | |
| apt install git tree wget curl jq -y | 실습에 필요한 추가적인 툴(Git, Tree, Wget, Curl, jq 등)을 설치. | |
| java -version | 설치된 Java 버전을 확인 (17 버전이 나와야 함). | |
| mvn -version | 설치된 Maven 버전을 확인. |
springboot-app 이동
mvn compile com.google.cloud.tools:jib-maven-plugin:3.4.6:build \\
-Dimage=docker.io/<자신의-ID>/jib-example:latest \\ # <-- 1번
-Djib.to.auth.username=<자신의-ID> \\ # <-- 2번
-Djib.to.auth.password=<자신의-Access-Token> \\ # <-- 3번
-Djib.from.platforms=linux/arm64
푸쉬된 docker 이미지 실행
docker run -d --name myweb2 -p 8080:8080 docker.io/$MYUSER/jib-example
curl -s 127.0.0.1:8080/hello
{"id":1,"content":"Hello, World!"}%
Kustomize 실습 (Base와 Overlay 패턴)
Kustomize는 YAML 템플릿 없이 Base와 Overlay 구조를 통해 환경별 설정을 관리
mkdir -p kustomize-test/{base,dev,prod}
depployment.yaml 생성
cat << EOF > base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2 # 기본 복제본 수
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx:alpine
ports:
- containerPort: 80
EOF
base/service.yaml 생성
cat << EOF > base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
Base Kustomization YAML 생성
cat << EOF > base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
EOF
tree base
base
├── deployment.yaml
├── kustomization.yaml
└── service.yaml
Dev Overlay 파일 작성 (dev/kustomization.yaml)
cat << EOF > dev/kustomization.yaml
resources:
- ../base # Base 디렉토리에 정의된 Deployment, Service 등을 참조
namePrefix: dev- # Base의 리소스 이름 앞에 'dev-' 접두사 추가
EOF
Prod Overlay 파일 작성 (prod/kustomization.yaml)
cat << EOF > prod/kustomization.yaml
resources:
- ../base # Base 디렉토리를 참조
namePrefix: prod- # Base의 리소스 이름 앞에 'prod-' 접두사 추가
EOF
Dev 환경 배포 확인
kubectl kustomize dev
apiVersion: v1
kind: Service
metadata:
labels:
run: my-nginx
name: dev-my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dev-my-nginx
spec:
replicas: 2
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: nginx:alpine
name: my-nginx
ports:
- containerPort: 80
적용
kubectl apply -k dev/
Prod 환경 배포 확인
kubectl kustomize prod/
kubectl kustomize prod/
apiVersion: v1
kind: Service
metadata:
labels:
run: my-nginx
name: prod-my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: prod-my-nginx
spec:
replicas: 2
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: nginx:alpine
name: my-nginx
ports:
- containerPort: 80
kubectl apply -k prod/
배포된 리소스 확인
kubectl get all
NAME READY STATUS RESTARTS AGE
pod/dev-my-nginx-945b795f8-848hj 1/1 Running 0 2m14s
pod/dev-my-nginx-945b795f8-pz25v 1/1 Running 0 2m14s
pod/prod-my-nginx-945b795f8-4jzl5 1/1 Running 0 48s
pod/prod-my-nginx-945b795f8-f7g22 1/1 Running 0 48s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/dev-my-nginx ClusterIP 10.96.228.23 <none> 80/TCP 2m14s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 60m
service/prod-my-nginx ClusterIP 10.96.68.81 <none> 80/TCP 48s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/dev-my-nginx 2/2 2 2 2m14s
deployment.apps/prod-my-nginx 2/2 2 2 48s
NAME DESIRED CURRENT READY AGE
replicaset.apps/dev-my-nginx-945b795f8 2 2 2 2m14s
replicaset.apps/prod-my-nginx-945b795f8 2 2 2 48s
정리
kubectl delete -k dev
kubectl delete -k prod
Buildpacks를 사용한 Dockerless 빌드
Buildpacks는 Dockerfile 없이 소스 코드를 자동으로 감지하여 이미지를 빌드.
Pack CLI 설치
brew install buildpacks/tap/pack
빌드
pack build nodejs-app --platform linux/arm64 --builder heroku/builder:24
실행확인
docker images | grep nodejs-app
nodejs-app latest 7989ff2a6843 45 years ago 706MB
docker run -d --name myapp --rm -p 3000:3000 nodejs-app
6f3feca8eef92390a1446a70d93925b59638c61ef5158f91bec31944dad4c565
curl -s 127.0.0.1:3000
Hello Buildpacks!
클러스터 삭제
kind delete cluster --name gitops-study
'CI&CD' 카테고리의 다른 글
| CI/CD Study [3주차] (0) | 2025.11.02 |
|---|---|
| ECR에 스프링부트 이미지 올리기(github action) (0) | 2023.05.07 |
| Github actions를 이용한 CICD - 2 (7) | 2021.08.10 |
| Github actions를 이용한 CICD - 1 (1) | 2021.08.10 |
| Docker 컨테이너 만들어보기 (0) | 2020.11.24 |