
Jenkins 및 Gogs 컨테이너 구성 (Docker Compose): Jenkins (CI 서버)와 Gogs (Git 서버)를 Docker 컨테이너로 실행합니다.
Jenkins와 Gogs 컨테이너 서비스를 정의하는 docker-compose.yaml 파일을 작성합니다.
cat << 'EOT' > docker-compose.yaml
services:
jenkins:
container_name: jenkins
image: jenkins/jenkins
restart: unless-stopped
networks:
- cicd-network
ports:
- "8080:8080" # Jenkins 웹 UI (Host:8080 -> Container:8080)
- "50000:50000" # Jenkins Agent 통신 포트
volumes:
- /var/run/docker.sock:/var/run/docker.sock # DooD 설정 (필수)
- jenkins_home:/var/jenkins_home # Jenkins 데이터 영구 저장
gogs:
container_name: gogs
image: gogs/gogs
restart: unless-stopped
networks:
- cicd-network
ports:
- "10022:22" # Gogs SSH 포트
- "3000:3000" # Gogs 웹 UI (Host:3000 -> Container:3000)
volumes:
- gogs-data:/data # Gogs 데이터 영구 저장
volumes:
jenkins_home:
gogs-data:
networks:
cicd-network:
driver: bridge
EOT
참고: volumes: - /var/run/docker.sock:/var/run/docker.sock 설정은 Jenkins 컨테이너 내부에서 호스트의 Docker 데몬을 사용하여 이미지 빌드(DooD)를 가능하게 합니다.
Gogs 서비스 및 볼륨 설정
- image: gogs/gogs: Gogs(셀프 호스팅 Git 서비스) 공식 이미지를 사용합니다.
- ports: - "3000:3000": Gogs의 웹 UI 접근 포트입니다.
- volumes: jenkins_home: 및 gogs-data:: 이들은 Docker 볼륨으로, 컨테이너가 삭제되거나 재시작되어도 Jenkins 설정 및 Gogs 저장소 데이터가 유지되도록 보장합니다.
docker compose logs jenkins -f
jenkins | Running from: /usr/share/jenkins/jenkins.war
jenkins | webroot: /var/jenkins_home/war
jenkins | 2025-11-01 15:06:47.388+0000 [id=1] INFO winstone.Logger#logInternal: Beginning extraction from war file
jenkins | 2025-11-01 15:06:47.791+0000 [id=1] WARNING o.e.j.ee9.nested.ContextHandler#setContextPath: Empty contextPath
jenkins | 2025-11-01 15:06:47.810+0000 [id=1] INFO org.eclipse.jetty.server.Server#doStart: jetty-12.1.3; built: 2025-10-16T14:10:03.576Z; git: f8d520dade4123ea8ce53fb1b9ac3a7a936a9d0f; jvm 21.0.8+9-LTS
Gogs 초기 설정 및 토큰 발급:
◦ Gogs 웹 접속: http://127.0.0.1:3000/install (또는 자신의 PC/WSL IP).
◦ 초기 설정: 데이터베이스 유형을 SQLite3로 설정하고, 관리자 계정 (예: devops/password)을 생성합니다.
◦ 토큰 발급: 로그인 후 Your Settings → Applications에서 새 토큰 (예: devops 이름)을 생성하고 토큰 값을 복사 및 저장합니다.
◦ Private 저장소 생성: 개발팀용 dev-app과 데브옵스팀용 ops-deploy 두 개의 Private Repository를 생성합니다.

◦ 토큰 발급: 로그인 후 Your Settings → Applications에서 새 토큰 (예:
이름)을 생성하고 토큰 값을 복사 및 저장합니다.

GitOps CI/CD 파이프라인의 핵심은 개발팀과 데브옵스팀의 책임을 분리.
이를 위해 두 개의 독립된 Private Repository가 필요합니다.
저장소 이름 역할 (팀) 저장되는 내용 (SSOT) 파이프라인에서의 역할
| dev-app | 개발팀 (CI의 Source) | 애플리케이션 소스 코드, Dockerfile, VERSION 파일, Jenkinsfile | CI(Continuous Integration)의 시작점. 코드가 푸시되면 Jenkins가 이미지를 빌드하고 태그를 지정하여 Docker Hub에 푸시합니다. |
| ops-deploy | 데브옵스팀/운영팀 (CD의 Source of Truth) | 쿠버네티스 배포 매니페스트 (Deployment.yaml, Service.yaml), Helm Chart 또는 Kustomize 파일 | GitOps CD(Continuous Delivery)의 단일 진실 공급원(SSOT). Jenkins가 빌드 후 이 저장소의 이미지 버전을 업데이트하면, ArgoCD가 이를 감지하여 배포합니다. |
저장소를 분리하는 이유
저장소 분리는 책임 분리와 보안 측면에서 이점.
- 책임 분리: 개발팀은 dev-app (코드)에만 집중하고, 데브옵스팀은 ops-deploy (인프라 설정)에만 집중할 수 있습니다.
- 보안: 개발팀이 직접 운영 클러스터에 접근할 필요가 없어 클러스터 접근 권한을 최소화할 수 있습니다.
2. Jenkins 초기 설정
◦ 초기 암호 확인: docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword.
Jenkins 웹 접속: http://127.0.0.1:8080에 접속하여 초기 암호를 입력하고 "Install suggested plugins"를 선택합니다.

◦ 관리자 계정 (예: admin/password)을 생성합니다.
필수 플러그인 설치: Jenkins 관리 → Plugins → Available plugins에서 Pipeline Stage View, Docker Pipeline, Gogs (또는 Generic Webhook) 플러그인을 설치합니다.
Jenkins 자격증명 설정: Jenkins 관리 → Credentials → Global → Add Credentials에서 다음 3가지 자격증명을 설정.
◦ Gogs 저장소 자격증명 (gogs-crd):
▪ Kind: Username with password
▪ Username: devops
▪ Password: <Gogs 토큰> (단계 2.1에서 저장한 토큰).
◦ Docker Hub 자격증명 (dockerhub-crd):
▪ Kind: Username with password
▪ Username: <도커 계정명>
▪ Password: <도커 계정 암호 또는 토큰>.
◦ Kubernetes 자격증명 (k8s-crd):
▪ Kind: Secret file
▪ File: <kubeconfig 파일 업로드> (Kind 클러스터 생성 후 생성된 ~/.kube/config 파일 사용).
CI 환경 구성 및 Docker Hub Secret 설정
- dev-app 저장소 클론 및 초기 파일 추가: 로컬에서 dev-app 저장소를 클론하고 애플리케이션 파일 (server.py, Dockerfile, VERSION)을 추가합니다.
- Kubernetes Docker Hub Secret 생성 (이미지 Pull 권한 부여): Kind 클러스터가 Docker Hub의 Private 이미지에 접근할 수 있도록 Secret을 생성합니다.
환경 변수 설정 (Docker Hub 계정 및 토큰 사용)
export DHUSER=<자신의 도커 허브 계정명> export DHPASS=<자신의 도커 허브 암호 또는 토큰>
kubectl create secret docker-registry dockerhub-secret \\
--docker-server=https://index.docker.io/v1/ \\
--docker-username=$DHUSER \\
--docker-password=$DHPASS
secret/dockerhub-secret created
# Secret 목록 확인
kubectl get secret dockerhub-secret
Gogs에 devops 계정으로 클론 (비밀번호 대신 토큰 사용)
git clone http://devops:$TOKEN@$GOGS_IP:3000/devops/ops-deploy.git cd ops-deploy
Git 환경 설정
git config --local user.name "devops" git config
--local user.email "a@a.com"
dev-app 디렉터리 생성 및 Manifest 파일 추가
mkdir dev-app export VERSION="0.0.1"
VERSION 파일 (Jenkins가 나중에 업데이트할 버전 정보)
cat <<EOF > dev-app/VERSION $VERSION EOF
timeserver Deployment Manifest
cat < dev-app/timeserver.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: timeserver
spec:
replicas: 2
selector:
matchLabels:
pod: timeserver-pod
template:
metadata:
labels:
pod: timeserver-pod
spec:
containers:
- name: timeserver-container
image: [docker.io/$DHUSER/dev-app:$VERSION](<http://docker.io/$DHUSER/dev-app:$VERSION>)
livenessProbe:
initialDelaySeconds: 30
periodSeconds: 30
httpGet:
path: /healthz
port: 80
scheme: HTTP
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
# 이전 단계에서 생성한 Secret을 사용하여 Private 이미지 접근 권한 부여
imagePullSecrets:
- name: dockerhub-secret
EOF
Service Manifest (NodePort로 외부 노출)
cat <<EOF > dev-app/service.yaml
apiVersion: v1
kind: Service
metadata:
name: timeserver
spec:
selector:
pod: timeserver-pod
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 30000 # Kind 클러스터의 30000번 포트로 노출
type: NodePort
EOF
Git에 푸시하여 ArgoCD가 바라볼 상태 정의
git add dev-app/ git commit -m "Add dev-app deployment yaml" git push -u origin main
ArgoCD 네임스페이스 생성
kubectl create ns argocd [12-15]
Helm values 파일 작성 (NodePort 및 HTTP 접속 설정)
cat <<EOF > argocd-values.yaml
dex:
enabled: false # 외부 인증(Dex) 비활성화 [12-15]
server:
service:
type: NodePort
nodePortHttps: 30002 # ArgoCD 웹 UI를 30002번 포트로 노출 [12-15]
extraArgs:
- --insecure # HTTPS 대신 HTTP 접속 허용 (랩 환경 편의) [13-15]
EOF
Helm 저장소 추가 및 ArgoCD 설치
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
ArgoCD 초기 관리자 암호 확인
설치 후 admin 계정의 초기 암호를 Secret에서 추출합니다.
kubectl -n argocd get secret argocd-initial-admin-secret \ -o jsonpath="{.data.password}" | base64 -d ; echo
ArgoCD 웹 접속
브라우저에서 아래 주소로 접속 후, 추출한 초기 암호로 로그인합니다.
http://127.0.0.1:{아르고CD 포트}
ArgoCD 설치 및 접속:
ArgoCD에 Gogs Repo 등록: ArgoCD 웹 UI (Settings → Repositories)에서 Gogs ops-deploy 저장소 URL을 등록.
이때 Gogs devops 계정명과 토큰을 사용합니다.


apiVersion: apps/v1
kind: Deployment
metadata:
name: timeserver
spec:
replicas: 2
selector:
matchLabels:
pod: timeserver-pod
template:
metadata:
labels:
pod: timeserver-pod
spec:
containers:
- name: timeserver-container
image: docker.io/<자신의 도커 허브 계정>/dev-app:0.0.1 # 이미지 태그는 VERSION과 일치해야 함
livenessProbe:
initialDelaySeconds: 30
httpGet:
path: /healthz # 헬스 체크 경로 (소스에 포함됨 [12, 13])
port: 80
imagePullSecrets:
- name: dockerhub-secret # Docker Hub Secret 이름 (사전 생성되어야 함)

ArgoCD Application 생성 (선언적 자동 동기화): ArgoCD 애플리케이션 자체를 YAML로 관리하고 자동 동기화
timeserver 애플리케이션을 생성합니다.
CI/CD 파이프라인 구축 및 테스트
Jenkinsfile 작성 (CI + GitOps Manifest 업데이트): dev-app 저장소의 루트에 다음 Jenkinsfile을 작성하여, 빌드가 완료된 후
자동으로 ops-deploy 저장소의 버전 정보를 업데이트하고 Git Push하도록 합니다.
Jenkins Item 생성 (SCM Pipeline): Jenkins에서 새 Item (예: full-cicd-scm)을 생성하고 Pipeline script from SCM으로 설정한 뒤, dev-app Git 저장소와 Jenkinsfile 경로를 지정합니다.
CI/CD 테스트: 개발팀의 변경을 테스트
◦ dev-app 로컬 디렉토리에서 VERSION 파일을 0.0.4로 업데이트하고, server.py 내부의 버전 정보도 0.0.4로 수정합니다.
◦ 변경된 코드를 Gogs dev-app에 푸시합니다.
◦ 결과 확인:
◦ Jenkins가 자동으로 빌드를 시작합니다.
◦ 빌드 성공 후, ops-deploy 저장소가 자동으로 0.0.4 버전으로 업데이트됩니다.
◦ ArgoCD가 ops-deploy의 변경사항을 감지하고 (자동 동기화 설정 시) 자동으로 쿠버네티스 클러스터에 새 버전 (0.0.4)을 배포합니다.
◦ 배포 확인: curl http://127.0.0.1:30000 (버전 0.0.4가 출력되는지 확인)
'CI&CD' 카테고리의 다른 글
| CI/CD Study [1주차] (0) | 2025.10.18 |
|---|---|
| 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 |