- Added MLFilter class to load and evaluate LightGBM model for trading signals. - Introduced retraining mechanism to update the model daily based on new data. - Created feature engineering and label building utilities for model training. - Updated bot logic to incorporate ML filter for signal validation. - Added scripts for data fetching and model training. Made-with: Cursor
12 KiB
Jenkins + Gitea 이미지 레지스트리 CI/CD 구현 계획
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Jenkins가 Gitea(10.1.10.28:3000)의 코드 변경을 감지하면 Docker 이미지를 빌드하여 Gitea Container Registry(10.1.10.28:5000 또는 Gitea 내장 패키지 레지스트리)에 push하고, docker-compose.yml이 해당 이미지를 pull해서 실행하도록 전체 CI/CD 파이프라인을 구성한다.
Architecture:
- Jenkins는 Gitea webhook을 통해 main 브랜치 push 이벤트를 수신한다.
- Jenkinsfile(파이프라인 스크립트)이 프로젝트 루트에 위치하며,
docker build → docker push → (선택) 원격 배포단계를 수행한다. - Gitea의 내장 Container Registry(Packages)를 이미지 저장소로 사용한다. 이미지 이름 형식:
10.1.10.28:3000/gihyeon/cointrader:<tag> - docker-compose.yml은
build: .대신 레지스트리 이미지를 직접 참조하도록 수정한다.
Tech Stack: Jenkins, Gitea Container Registry, Docker, docker-compose v2, Jenkinsfile(Declarative Pipeline)
사전 확인 사항
- Gitea 서버:
http://10.1.10.28:3000 - Gitea 저장소:
http://10.1.10.28:3000/gihyeon/cointrader.git - Gitea Container Registry 주소:
10.1.10.28:3000(HTTP 사용 시 Docker insecure-registries 설정 필요) - Jenkins 서버 주소: 별도 확인 필요 (아래 Task 1에서 확인)
- 현재 Dockerfile:
FROM python:3.12-slim기반,/app에서python main.py실행
Task 1: 환경 사전 점검
Files:
- 확인:
Dockerfile - 확인:
docker-compose.yml
Step 1: Gitea Container Registry(Packages) 활성화 확인
브라우저에서 http://10.1.10.28:3000/gihyeon/cointrader/packages 접속.
- 패키지 탭이 보이면 활성화된 것.
- 안 보이면 Gitea 관리자 패널 →
Site Administration→Configuration→Enable Packages체크 필요.
Step 2: Gitea Access Token 생성 (Jenkins용)
http://10.1.10.28:3000/user/settings/applications 접속:
- Token Name:
jenkins-cointrader - 권한:
read:packages,write:packages(또는 전체 권한) Generate Token클릭 후 토큰 값을 반드시 복사 (다시 볼 수 없음)
Step 3: Docker insecure-registries 설정 (HTTP 레지스트리 사용 시)
Jenkins가 실행되는 서버(또는 로컬 Mac)에서:
# /etc/docker/daemon.json 또는 Docker Desktop의 경우 Settings > Docker Engine
cat /etc/docker/daemon.json
아래 내용이 없으면 추가:
{
"insecure-registries": ["10.1.10.28:3000"]
}
Docker Desktop 사용 시: Settings → Docker Engine → JSON에 위 내용 병합 → Apply & Restart
Step 4: Docker login 테스트
docker login 10.1.10.28:3000 -u gihyeon -p <위에서_생성한_토큰>
Expected:
Login Succeeded
Task 2: Jenkinsfile 작성
Files:
- Create:
Jenkinsfile
Step 1: Jenkinsfile 생성
/Users/gihyeon/github/cointrader/Jenkinsfile 파일을 아래 내용으로 생성:
pipeline {
agent any
environment {
REGISTRY = '10.1.10.28:3000'
IMAGE_NAME = 'gihyeon/cointrader'
IMAGE_TAG = "${env.BUILD_NUMBER}"
FULL_IMAGE = "${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
LATEST_IMAGE = "${REGISTRY}/${IMAGE_NAME}:latest"
GITEA_CREDS = credentials('gitea-registry-credentials')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build Image') {
steps {
sh "docker build -t ${FULL_IMAGE} -t ${LATEST_IMAGE} ."
}
}
stage('Push to Gitea Registry') {
steps {
sh """
echo ${GITEA_CREDS_PSW} | docker login ${REGISTRY} -u ${GITEA_CREDS_USR} --password-stdin
docker push ${FULL_IMAGE}
docker push ${LATEST_IMAGE}
"""
}
}
stage('Cleanup') {
steps {
sh """
docker rmi ${FULL_IMAGE} || true
docker rmi ${LATEST_IMAGE} || true
"""
}
}
}
post {
success {
echo "Build #${env.BUILD_NUMBER} pushed: ${FULL_IMAGE}"
}
failure {
echo "Build #${env.BUILD_NUMBER} FAILED"
}
}
}
참고:
GITEA_CREDS는 Jenkins Credentials에 등록할 Username+Password 자격증명 ID다 (Task 3에서 등록).IMAGE_TAG는 Jenkins 빌드 번호를 사용한다. 태그 전략을 git 커밋 해시로 바꾸려면"${env.GIT_COMMIT[0..7]}"사용.Cleanup스테이지는 Jenkins 서버 디스크 절약을 위해 빌드 후 로컬 이미지를 삭제한다.
Step 2: Jenkinsfile 내용 확인
cat /Users/gihyeon/github/cointrader/Jenkinsfile
Expected: 위 내용이 출력됨
Task 3: Jenkins에 Gitea Credentials 등록
Step 1: Jenkins 웹 UI 접속
http://<jenkins-서버-주소>:8080 접속 (Jenkins 서버 주소 확인 필요)
Step 2: Credentials 등록
Jenkins → Manage Jenkins → Credentials → System → Global credentials → Add Credentials:
| 항목 | 값 |
|---|---|
| Kind | Username with password |
| Scope | Global |
| Username | gihyeon |
| Password | Task 1 Step 2에서 생성한 Gitea Access Token |
| ID | gitea-registry-credentials |
| Description | Gitea Container Registry for cointrader |
Create 클릭
Step 3: 등록 확인
Credentials 목록에 gitea-registry-credentials가 표시되는지 확인
Task 4: Jenkins Pipeline Job 생성
Step 1: 새 Pipeline Job 생성
Jenkins → New Item:
- Item name:
cointrader - Type:
Pipeline OK클릭
Step 2: Pipeline 설정
Pipeline 섹션에서:
- Definition:
Pipeline script from SCM - SCM:
Git - Repository URL:
http://10.1.10.28:3000/gihyeon/cointrader.git - Credentials: (Gitea 저장소 접근용 credentials 추가, 없으면 Task 3과 동일하게 추가)
- Branch Specifier:
*/main - Script Path:
Jenkinsfile
Save 클릭
Step 3: 수동 빌드 테스트
Build Now 클릭 → Console Output 확인
Expected:
[Pipeline] stage: Build Image
Successfully built ...
[Pipeline] stage: Push to Gitea Registry
Login Succeeded
The push refers to repository [10.1.10.28:3000/gihyeon/cointrader]
...
latest: digest: sha256:... size: ...
[Pipeline] stage: Cleanup
Finished: SUCCESS
Task 5: Gitea Webhook 설정 (자동 트리거)
Step 1: Gitea 저장소 Webhook 추가
http://10.1.10.28:3000/gihyeon/cointrader/settings/hooks 접속:
Add Webhook→Gitea- Target URL:
http://<jenkins-서버-주소>:8080/gitea-webhook/post- Jenkins Gitea Plugin 사용 시 위 URL 형식
- 일반 Generic Webhook 사용 시:
http://<jenkins-서버-주소>:8080/job/cointrader/build?token=<토큰>
- Trigger:
Push Events - Branch filter:
main Add Webhook클릭
Step 2: Jenkins에 Gitea Plugin 설치 (미설치 시)
Manage Jenkins → Plugins → Available plugins → Gitea 검색 → 설치 후 재시작
Step 3: Webhook 테스트
Gitea Webhook 설정 페이지에서 Test Delivery 클릭
Expected: Jenkins에서 새 빌드가 자동으로 시작됨
Task 6: docker-compose.yml 수정
Files:
- Modify:
docker-compose.yml
현재 docker-compose.yml은 build: .으로 로컬 빌드를 사용한다. 이를 레지스트리 이미지를 pull해서 실행하도록 변경한다.
Step 1: docker-compose.yml 수정
/Users/gihyeon/github/cointrader/docker-compose.yml을 아래 내용으로 교체:
services:
cointrader:
image: 10.1.10.28:3000/gihyeon/cointrader:latest
container_name: cointrader
restart: unless-stopped
env_file:
- .env
volumes:
- ./logs:/app/logs
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
변경 사항:
build: .→image: 10.1.10.28:3000/gihyeon/cointrader:latest- 이제
docker compose up -d를 실행하면 로컬 빌드 없이 레지스트리에서 이미지를 pull한다.- 배포 서버에서 최신 이미지로 업데이트하려면:
docker compose pull && docker compose up -d
Step 2: 변경 내용 확인
cat /Users/gihyeon/github/cointrader/docker-compose.yml
Expected: image: 필드가 레지스트리 주소를 가리킴
Step 3: (선택) 로컬 개발용 docker-compose.override.yml 생성
로컬에서 소스 코드를 직접 빌드해서 테스트하고 싶을 때를 위한 override 파일:
# docker-compose.override.yml (로컬 개발 전용, git에 포함하지 않아도 됨)
services:
cointrader:
build: .
image: cointrader:local
이 파일이 있으면 docker compose up -d가 자동으로 build: .을 사용한다. 프로덕션 서버에는 이 파일을 두지 않는다.
Task 7: 변경사항 커밋 및 Push
Step 1: 변경 파일 확인
cd /Users/gihyeon/github/cointrader
git status
Expected: Jenkinsfile(new), docker-compose.yml(modified)이 표시됨
Step 2: 스테이징
git add Jenkinsfile docker-compose.yml
Step 3: .env 미포함 확인
git diff --cached --name-only
Expected: Jenkinsfile, docker-compose.yml 두 파일만 표시됨
Step 4: 커밋
git commit -m "ci: Jenkins pipeline + Gitea registry CI/CD 설정"
Expected: main 브랜치에 새 커밋 생성
Step 5: Gitea에 Push
git push origin main
Expected: Push 성공 + (Webhook 설정 완료 시) Jenkins 빌드 자동 시작
Task 8: 엔드-투-엔드 검증
Step 1: 코드 변경 후 push 테스트
cd /Users/gihyeon/github/cointrader
# 아무 파일이나 사소하게 변경 (예: README 한 줄 추가)
echo "# CI/CD test" >> README.md
git add README.md
git commit -m "test: CI/CD 파이프라인 검증용 더미 커밋"
git push origin main
Step 2: Jenkins 빌드 자동 시작 확인
Jenkins UI에서 cointrader 잡의 빌드가 자동으로 시작되는지 확인 (30초 이내)
Step 3: Gitea 레지스트리에 이미지 push 확인
http://10.1.10.28:3000/gihyeon/cointrader/packages 접속 → cointrader 컨테이너 패키지에 새 태그가 생성되었는지 확인
Step 4: 이미지 pull 테스트
docker pull 10.1.10.28:3000/gihyeon/cointrader:latest
Expected:
latest: Pulling from gihyeon/cointrader
...
Status: Downloaded newer image for 10.1.10.28:3000/gihyeon/cointrader:latest
Step 5: docker compose로 실행 테스트
cd /Users/gihyeon/github/cointrader
docker compose up -d
docker compose logs -f --tail=20
Expected: 컨테이너가 정상 시작되고 로그가 출력됨
트러블슈팅
| 문제 | 원인 | 해결 |
|---|---|---|
http: server gave HTTP response to HTTPS client |
Docker가 HTTPS로 레지스트리 접근 시도 | daemon.json에 insecure-registries 추가 후 Docker 재시작 |
unauthorized: authentication required |
Credentials 미등록 또는 토큰 만료 | Task 1 Step 2에서 새 토큰 발급 후 Jenkins Credentials 업데이트 |
connection refused to Jenkins |
Jenkins URL 오타 또는 방화벽 | Jenkins 서버 주소 재확인 |
| Webhook이 Jenkins를 트리거하지 않음 | Jenkins URL이 Gitea 서버에서 접근 불가 | Jenkins가 Gitea 서버와 같은 네트워크에 있는지 확인, 방화벽 8080 포트 오픈 |
image not found on docker compose pull |
이미지가 아직 push되지 않음 | Jenkins 빌드 완료 후 재시도 |
Jenkins에서 docker: command not found |
Jenkins 에이전트에 Docker 미설치 | Jenkins 서버에 Docker 설치 또는 Docker-in-Docker 설정 |