이미지를 만드는 것(app, Dockerfile)과 어디에 어떻게 띄울지 정하는 것(Helm 차트, 매니페스트)은 바뀌는 주기와 손대는 사람이 다르다. 같은 디렉터리에 두면 애플리케이션 변경과 배포 설정 변경이 한 커밋에 섞여 되돌리기 어려워진다.
git_project/
├── app/ # 애플리케이션 코드
│ ├── src/
│ └── requirements.txt # 또는 pom.xml · package.json
│
├── Dockerfile # 빌드 컨텍스트는 저장소 루트
├── .dockerignore
│
├── deploy/
│ ├── helm/
│ │ └── myapp/
│ │ ├── Chart.yaml
│ │ ├── values.yaml
│ │ └── templates/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── ingress.yaml
│ └── k8s/ # Helm 없이 직접 적용할 때만
│
├── Jenkinsfile
└── README.md
서비스가 여럿이면 services/<이름>/ 아래로 내리고 deploy/helm/<이름>/ 을 짝지운다.
app/helm/ 처럼 애플리케이션 안에 배포 정의를 넣으면 코드와 인프라가 엉킨다. 배포 담당이 분리된 조직에서 같은 디렉터리를 두고 충돌하고, ArgoCD 같은 도구로 배포 정의만 따로 가리키기도 어려워진다.
Dockerfile 을 app/ 안에 두는 것은 가능하지만, 빌드 컨텍스트가 app/ 으로 좁아져 루트의 공통 파일을 참조할 수 없다. 저장소 루트에 두고 COPY app/ /app 형태로 쓰는 편이 유연하다.
빌드 컨텍스트가 루트이면 .git 과 배포 디렉터리까지 데몬으로 전송된다. 빌드가 느려지고 이미지에 불필요한 것이 들어간다.
.git
.gitignore
deploy/
docs/
**/__pycache__/
**/*.pyc
.venv/
node_modules/
target/
*.log
.env
.env 와 자격증명 파일은 반드시 제외한다. COPY . /app 한 줄로 이미지 레이어에 들어가면 나중에 지워도 레이어에는 남는다.
pipeline {
agent any
environment {
IMAGE = "registry.example.com/myapp"
TAG = "${env.GIT_COMMIT.take(8)}"
}
stages {
stage('Checkout') {
steps { checkout scm }
}
stage('Build') {
steps { sh 'cd app && make build' }
}
stage('Image') {
steps {
sh 'docker build -t ${IMAGE}:${TAG} -f Dockerfile .'
}
}
stage('Push') {
steps {
withCredentials([usernamePassword(credentialsId: 'registry',
usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) {
sh 'echo "$REG_PASS" | docker login registry.example.com -u "$REG_USER" --password-stdin'
sh 'docker push ${IMAGE}:${TAG}'
}
}
}
stage('Deploy') {
steps {
sh 'helm upgrade --install myapp deploy/helm/myapp --set image.tag=${TAG} --wait'
}
}
}
}
이미지 태그에 BUILD_NUMBER 만 쓰지 않는다. Jenkins 작업을 새로 만들거나 번호를 초기화하면 같은 태그가 다른 내용을 가리킨다. 커밋 해시를 쓰면 이미지와 소스가 일대일로 대응한다. 릴리스에는 의미 있는 버전 태그를 함께 붙인다.
latest 로만 배포하지 않는다. 롤백할 대상이 없어진다.
자격증명은 withCredentials 로 감싸고 --password-stdin 으로 넘긴다. 명령줄에 쓰면 프로세스 목록과 빌드 로그에 남는다.
Helm 배포를 Jenkins 가 직접 실행하는 대신, 이미지 태그만 배포 저장소에 커밋하고 ArgoCD 가 반영하게 하는 방식이 있다. 이렇게 하면 Jenkins 가 클러스터 자격증명을 들고 있을 필요가 없다.
이 전환을 염두에 둔다면 처음부터 deploy/ 를 분리해 두는 것이 이득이다. 그대로 별도 저장소로 떼어 낼 수 있다.