Docker Hub์ Free ํ๋์์๋ Private Repository๋ฅผ 1๊ฐ๋ง ์์ฑํ ์ ์๋ค. ์๋น์ค๊ฐ ํ๋์ผ ๋๋ ๋ฌธ์ ๊ฐ ์์ง๋ง, backend์ frontend์ฒ๋ผ ์ด๋ฏธ์ง๊ฐ 2๊ฐ ์ด์ ํ์ํด์ง๋ฉด ์ ๋ฃ ํ๋์ ๊ณ ๋ คํ๊ฑฐ๋, ์์ฒด Registry๋ฅผ ์ด์ํด์ผ ํ๋ค.
์ด ๊ธ์์๋ ์จํ๋ ๋ฏธ์ค Kubernetes ํด๋ฌ์คํฐ์ Nexus Repository Manager๋ฅผ ๋ฐฐํฌํ๊ณ , ๊ธฐ์กด Docker Hub ๊ธฐ๋ฐ CI/CD ํ์ดํ๋ผ์ธ์ Nexus๋ก ์ ํํ ๊ณผ์ ์ ์ ๋ฆฌํ๋ค.
๊ธฐ์กด์๋ Jenkins(Kaniko)๊ฐ Docker Hub์ ์ด๋ฏธ์ง๋ฅผ pushํ๊ณ , ํด๋ฌ์คํฐ๊ฐ Docker Hub์์ pullํ๋ ๊ตฌ์กฐ์๋ค.
์ด ๊ตฌ์กฐ์ ๋ฌธ์ :
์์ฒด Docker Registry๋ฅผ ์ด์ํ๋ ์ ํ์ง๋ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์๋ค.
| ์๋ฃจ์ | ์ฅ์ | ๋จ์ |
|---|---|---|
| Docker Registry (OSS) | ๊ฐ๋ณ๊ณ ๋จ์ | UI ์์, ๊ธฐ๋ฅ ์ต์ |
| Harbor | ๋ณด์ ์ค์บ๋, RBAC | ๋ฆฌ์์ค ๋ฌด๊ฑฐ์, PostgreSQL/Redis ํ์ |
| Nexus | Docker ์ธ Maven/npm ๋ฑ ๋ค๋ชฉ์ , ๊ฐ๋ฒผ์ด ๋จ์ผ ์ธ์คํด์ค | ์ผ๋ถ ๊ธฐ๋ฅ Pro ํ์ |
๊ฐ์ธ ์ธํ๋ผ ๊ท๋ชจ์์๋ ๋จ์ผ ์ธ์คํด์ค๋ก ์ด์ ๊ฐ๋ฅํ๊ณ , Docker ์ธ ๋ค๋ฅธ ํจํค์ง ์ ์ฅ์๋ ๊ฒธํ ์ ์๋ Nexus๊ฐ ์ ํฉํ๋ค๊ณ ํ๋จํ๋ค.
๊ธฐ์กด ์ธํ๋ผ๊ฐ ArgoCD์ App of Apps ํจํด์ผ๋ก ๊ด๋ฆฌ๋๊ณ ์์ผ๋ฏ๋ก, Nexus๋ ๋์ผํ๊ฒ ๊ตฌ์ฑํ๋ค.
๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ:
argocd-cluster/
โโโ nexus/
โ โโโ values.yaml # Helm values
โ โโโ manifests/
โ โโโ pvc.yaml # PVC (๋ณ๋ ๊ด๋ฆฌ)
โโโ argocd/addons/apps/
โ โโโ nexus.yaml # ArgoCD Application
โโโ routes/nexus/
โโโ httproute-nexus.yaml # nexus.minseoky.me (Web UI)
โโโ httproute-registry.yaml # registry.minseoky.me (Docker API)
โโโ ...
Jenkins์ ๋์ผํ multi-source ํจํด์ ์ฌ์ฉํ๋ค. Helm chart + values.yaml ์ฐธ์กฐ + ์ถ๊ฐ ๋งค๋ํ์คํธ(PVC)๋ฅผ 3๊ฐ์ source๋ก ๊ตฌ์ฑํ๋ค.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nexus
namespace: argocd
spec:
project: default
destination:
server: https://kubernetes.default.svc
namespace: nexus
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
sources:
- repoURL: https://sonatype.github.io/helm3-charts/
chart: nexus-repository-manager
targetRevision: 64.2.0
helm:
releaseName: nexus
valueFiles:
- $values/nexus/values.yaml
- repoURL: https://github.com/minseoky/argocd-cluster.git
targetRevision: prod
ref: values
- repoURL: https://github.com/minseoky/argocd-cluster.git
targetRevision: prod
path: nexus/manifests
image:
repository: sonatype/nexus3
tag: "3.89.1"
nexus:
docker:
enabled: true
registries:
- host: null
port: 5000
env:
- name: INSTALL4J_ADD_VM_PARAMS
value: "-Xms1g -Xmx2g -XX:MaxDirectMemorySize=2g"
resources:
requests:
cpu: "500m"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
persistence:
enabled: true
existingClaim: nexus-data
deploymentStrategy: Recreate
ํต์ฌ ํฌ์ธํธ:
ํด๋ฌ์คํฐ๋ NFS ๋์ ํ๋ก๋น์ ๋(nfs-client StorageClass)์ ์ฌ์ฉํ๋ค. PVC๋ฅผ ๋ณ๋๋ก ์์ฑํ๊ณ existingClaim์ผ๋ก ์ฐธ์กฐํ๋ ์ด์ ๋, Helm ์ฐจํธ๊ฐ PVC์ ์ปค์คํ
annotation์ ๋ฃ๋ ๊ฒ์ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nexus-data
namespace: nexus
annotations:
nfs.io/storage-path: "nexus-data"
spec:
accessModes: [ReadWriteOnce]
storageClassName: nfs-client
resources:
requests:
storage: 50Gi
NFS ํน์ฑ์ PVC์ ์ค์ ํ ์ฉ๋(50Gi)์ ๋ ผ๋ฆฌ์ ์ ์ธ์ผ ๋ฟ, ์ค์ ๋ก๋ NAS ์ ์ฒด ๋ณผ๋ฅจ์ด ๋ง์ดํธ๋๋ค. Nexus UI์์๋ Blob Store ์ฉ๋์ด NAS ์ ์ฒด ์ฉ๋์ผ๋ก ํ์๋๋ค.
๋ฐ์ดํฐ ์์ ์ฑ ์ธก๋ฉด์์๋ StorageClass์ reclaimPolicy: Retain + archiveOnDelete: true ์ค์ ๋๋ถ์, PVC๋ฅผ ์ญ์ ํด๋ NAS ๋๋ ํ ๋ฆฌ๊ฐ archived- ์ ๋์ฌ๋ก ๋ณด์กด๋๋ค.
Nexus์ ๋ชจ๋ ๋ฐ์ดํฐ(์ค์ , ์ฌ์ฉ์, ๋น๋ฐ๋ฒํธ, Blob Store)๋ /nexus-data/ ์ ์ ์ฅ๋๋ฉฐ, ์ด ๊ฒฝ๋ก๊ฐ PVC์ ๋ง์ดํธ๋๋ค.
/nexus-data/admin.password ํ์ผ๋ก ์์ฑ. UI์์ ๋ณ๊ฒฝํ๋ฉด ํ์ผ์ด ์ญ์ ๋๊ณ H2 DB์ ์ ์ฅ๋จ.์ธ๋ถ ์ ๊ทผ์ ์ํด ๋ ๊ฐ์ ์๋ธ๋๋ฉ์ธ์ ๊ตฌ์ฑํ๋ค.
| ์๋ธ๋๋ฉ์ธ | ์ฉ๋ | ๋ฐฑ์๋ Service | ํฌํธ |
|---|---|---|---|
nexus.minseoky.me |
Web UI / REST API | nexus-nexus-repository-manager | 8081 |
registry.minseoky.me |
Docker push/pull | nexus-nexus-repository-manager-docker-5000 | 5000 |
Web UI์ Docker Registry๋ฅผ ๋ถ๋ฆฌํ ์ด์ ๋, Docker ํด๋ผ์ด์ธํธ๊ฐ ์ ์ฉ ํฌํธ(5000)๋ก ํต์ ํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ฐ์ ๋๋ฉ์ธ์ ๋นํ์ค ํฌํธ๋ฅผ ์ฐ๋ ๊ฒ๋ณด๋ค, ๋ณ๋ ์๋ธ๋๋ฉ์ธ์ผ๋ก ๋ถ๋ฆฌํ๋ ๊ฒ์ด ๊ธฐ์กด Gateway ์์ผ๋์นด๋(*.minseoky.me) ๋ฆฌ์ค๋๋ฅผ ๊ทธ๋๋ก ํ์ฉํ ์ ์์ด ๊น๋ํ๋ค.
# Docker Registry์ฉ HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: nexus-registry
namespace: nexus
spec:
parentRefs:
- name: gw-public
namespace: gateway
sectionName: https
hostnames:
- registry.minseoky.me
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: nexus-nexus-repository-manager-docker-5000
port: 5000
๋ณ๊ฒฝ ํฌ์ธํธ๋ Build & Push ๋จ๊ณ์ Deploy ๋จ๊ณ ๋ ๊ณณ์ด๋ค.
Build & Push โ ์ธ์ฆ ๋์๊ณผ destination ๋ณ๊ฒฝ:
// ๋ณ๊ฒฝ ์
withCredentials([usernamePassword(
credentialsId: 'docker-hub-credentials',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASS'
)]) {
sh '''
echo '{"auths":{"https://index.docker.io/v1/":{"username":"..."}}}' \
> /kaniko/.docker/config.json
/kaniko/executor \
--destination=$DOCKER_USER/pullab-backend:$VERSION
'''
}
// ๋ณ๊ฒฝ ํ
withCredentials([usernamePassword(
credentialsId: 'nexus-registry-credentials',
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS'
)]) {
sh '''
echo '{"auths":{"registry.minseoky.me":{"username":"..."}}}' \
> /kaniko/.docker/config.json
/kaniko/executor \
--destination=registry.minseoky.me/pullab-backend:$VERSION
'''
}
Deploy โ sed ํจํด ๋ณ๊ฒฝ:
// ๋ณ๊ฒฝ ์
sed -i 's|image: minseoky/pullab-backend:.*|...|'
// ๋ณ๊ฒฝ ํ
sed -i 's|image: .*pullab-backend:.*|image: registry.minseoky.me/pullab-backend:'"$VERSION"'|'
sed ํจํด์ .*pullab-backend๋ก ๋ณ๊ฒฝํ์ฌ, ์ด์ ๊ฒฝ๋ก(minseoky/)๋ ์ ๊ฒฝ๋ก(registry.minseoky.me/)๋ ๋ชจ๋ ๋งค์นญ๋๋๋ก ํ๋ค.
์ด๋ฏธ์ง ๊ฒฝ๋ก ๋ณ๊ฒฝ๊ณผ ํจ๊ป imagePullSecrets๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค. Nexus๋ ์ธ์ฆ์ด ํ์ํ private registry์ด๊ธฐ ๋๋ฌธ์ด๋ค.
spec:
template:
spec:
imagePullSecrets:
- name: nexus-pull-secret # ๊ฐ ๋ค์์คํ์ด์ค์ ์๋ ์์ฑ
containers:
- image: registry.minseoky.me/pullab-backend:0.1.58
pull secret์ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ๋ ๊ฐ ๋ค์์คํ์ด์ค๋ง๋ค ์์ฑํด์ผ ํ๋ค:
kubectl create secret docker-registry nexus-pull-secret \
-n <namespace> \
--docker-server=registry.minseoky.me \
--docker-username=admin \
--docker-password=<password>
Helm ์ฐจํธ ๊ธฐ๋ณธ ๋ฒ์ (3.64.0)์ผ๋ก ์ต์ด ๊ธฐ๋ํ ํ, ๋ณด์ ์ทจ์ฝ์ ๊ฒฝ๊ณ ๊ฐ ํ์๋์ด 3.89.1๋ก ์ ๊ทธ๋ ์ด๋ํ๋ค. ๊ทธ๋ฐ๋ฐ Pod๊ฐ CrashLoopBackOff์ ๋น ์ก๋ค.
This instance is using a legacy Orient database.
You must migrate to H2 or PostgreSQL before upgrading to this version.
3.64.0์ด OrientDB๋ก ์ด๊ธฐํํ ๋ฐ์ดํฐ๊ฐ PVC์ ๋จ์ ์์๊ณ , 3.89.1์ OrientDB๋ฅผ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ ๊ท ์ค์น์์ผ๋ฏ๋ก PVC ๋ฐ์ดํฐ๋ฅผ ์ ๋ฆฌํ๊ณ ์ฌ์์ํ์ฌ ํด๊ฒฐํ๋ค.
๊ตํ: Nexus ๋ฒ์ ์ ์ฌ๋ฆด ๋๋ DB ๋ง์ด๊ทธ๋ ์ด์ ์๊ตฌ์ฌํญ์ ๋ฐ๋์ ํ์ธํด์ผ ํ๋ค.
PVC ๋ฐ์ดํฐ ์ ๋ฆฌ ์ blobs ๋๋ ํ ๋ฆฌ๊น์ง ์ญ์ ๋์ด, Nexus ๊ธฐ๋ ํ ๊ธฐ๋ณธ Blob Store(default)๊ฐ "not available" ์ํ๊ฐ ๋๋ค. Pod๋ฅผ ์ฌ์์ํ์ฌ ์๋ ๋ณต๊ตฌ๋์๋ค.
| ํญ๋ชฉ | ๋ณ๊ฒฝ ์ | ๋ณ๊ฒฝ ํ |
|---|---|---|
| Registry | Docker Hub | Nexus (์์ฒด ํธ์คํ ) |
| Private Image ์ ํ | 1๊ฐ | ๋ฌด์ ํ |
| Pull Rate Limit | 200/6h | ์์ |
| ์ด๋ฏธ์ง ์ ์ก | ์ธ๋ถ ์ธํฐ๋ท | ๋ด๋ถ ๋คํธ์ํฌ |
| ์ถ๊ฐ ๋น์ฉ | ์ ๋ฃ ํ๋ ํ์ ์ | ์์ (NAS ์คํ ๋ฆฌ์ง ํ์ฉ) |
| ๊ด๋ฆฌ ๋ถ๋ด | ์์ | Nexus ์ด์ ํ์ |
Docker Hub์ ์ ํ์ ํด๊ฒฐํ๋ฉด์, ์ด๋ฏธ์ง๊ฐ ๋ด๋ถ ๋คํธ์ํฌ์์ ์ ์ก๋๋ฏ๋ก pull ์๋๋ ๋นจ๋ผ์ก๋ค. ๊ธฐ์กด ArgoCD + Helm ํจํด์ ๊ทธ๋๋ก ํ์ฉํ์ฌ ์ถ๊ฐ ์ด์ ๋ณต์ก๋๋ ์ต์ํํ ์ ์์๋ค.