이번 글에서는 Kubernetes 클러스터 내부에 Private Registry를 배포하고, 로컬 Docker 환경과 Kubernetes 노드에서 해당 Registry를 사용할 수 있도록 설정하는 과정을 정리합니다.
구성은 다음과 같습니다.
- Registry 데이터를 저장할 PersistentVolume / PersistentVolumeClaim
- Registry Pod를 실행할 Deployment
- 외부에서 Registry에 접근하기 위한 NodePort Service
- Docker에서 HTTP Registry로 이미지를 push하기 위한 insecure registry 설정
- Kubernetes 노드의 containerd에서 HTTP Registry 이미지를 pull할 수 있도록 하는 설정
이 예제에서는 NFS 볼륨을 Registry 저장소로 사용하고, registry:3 이미지를 이용해 Private Registry를 배포합니다.
Kubernetes Private Registry 배포
1. Registry Namespace 생성
Registry 관련 리소스를 별도 namespace에서 관리하기 위해 registry namespace를 생성합니다.
kubectl create namespace registry
2. PersistentVolume 생성
Registry에 push한 이미지 데이터는 Pod가 재시작되더라도 유지되어야 합니다.
이를 위해 NFS 기반 PersistentVolume을 생성합니다.
apiVersion: v1
kind: PersistentVolume
metadata:
name: registry-pv
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /nfsvolume
server: 172.25.46.10
여기서 중요한 점은 PV가 namespace에 속하지 않는 클러스터 범위 리소스라는 점입니다. 따라서 일반적으로 PersistentVolume에는 namespace를 지정하지 않습니다.
3. PersistentVolumeClaim 생성
이제 Registry Pod에서 사용할 PersistentVolumeClaim을 생성합니다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-pvc
namespace: registry
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
생성 후 PV와 PVC가 정상적으로 바인딩되었는지 확인합니다.
kubectl get pv,pvc -n registry
PVC의 상태가 Bound이면 정상적으로 연결된 것입니다.
4. Registry Deployment 생성
registry:3 이미지를 사용해 Private Registry를 배포합니다.
Registry는 기본적으로 /var/lib/registry 경로에 이미지 데이터를 저장합니다. 따라서 앞에서 만든 PVC를 해당 경로에 마운트합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
namespace: registry
labels:
app: registry
spec:
replicas: 1
selector:
matchLabels:
app: registry
template:
metadata:
labels:
app: registry
spec:
containers:
- name: registry
image: registry:3
ports:
- containerPort: 5000
volumeMounts:
- name: nfs
mountPath: /var/lib/registry
volumes:
- name: nfs
persistentVolumeClaim:
claimName: registry-pvc
배포 후 Pod 상태를 확인합니다.
kubectl get pods -n registry
Pod가 Running 상태가 되면 Registry 컨테이너가 정상적으로 실행된 것입니다.
5. NodePort Service 생성
클러스터 외부에서 Registry에 접근할 수 있도록 NodePort 타입의 Service를 생성합니다.
apiVersion: v1
kind: Service
metadata:
name: registry
namespace: registry
labels:
app: registry
spec:
type: NodePort
selector:
app: registry
ports:
- port: 5000
targetPort: 5000
nodePort: 32000
protocol: TCP
Service 생성 후 상태를 확인합니다.
kubectl get svc -n registry
이제 Registry는 다음 주소로 접근할 수 있습니다.
172.25.46.10:32000
여기서 172.25.46.10은 Registry Service에 접근 가능한 Kubernetes 노드 IP이고, 32000은 Service에 지정한 NodePort입니다.
Docker에서 Private Registry로 이미지 Push하기
현재 구성한 Registry는 HTTPS가 아닌 HTTP로 열려 있습니다.
따라서 Docker에서 이미지를 push하려면 Docker Desktop에 insecure registry 설정을 추가해야 합니다.
운영 환경에서는 HTTP Registry보다 TLS가 적용된 HTTPS Registry 구성을 권장합니다.
여기서는 로컬 또는 내부 테스트 환경을 기준으로 HTTP Registry를 사용합니다.
1. Docker Desktop 설정
Docker Desktop을 사용하는 경우 다음 메뉴로 이동합니다.
Settings → Docker Engine
설정 JSON에 다음 항목을 추가합니다.
"insecure-registries": [
"172.25.46.10:32000"
]
전체 설정 예시는 다음과 같습니다.
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": false,
"insecure-registries": [
"172.25.46.10:32000"
]
}
설정을 저장한 뒤 Docker Desktop을 재시작합니다.
2. 이미지 Push 테스트
예를 들어 nginx 이미지를 Private Registry로 push하려면 다음과 같이 실행합니다.
docker pull nginx
docker tag nginx 172.25.46.10:32000/nginx:latest
docker push 172.25.46.10:32000/nginx:latest
정상적으로 push되면 Registry의 NFS 저장소에 이미지 데이터가 저장됩니다.
Kubernetes 노드에서 Private Registry 이미지 Pull 설정하기
Docker Desktop의 insecure registry 설정은 로컬 Docker CLI에서 이미지를 push하기 위한 설정입니다.
하지만 Kubernetes에서 Pod를 실행할 때 이미지를 pull하는 주체는 Docker Desktop이 아니라 각 Kubernetes 노드의 CRI 런타임입니다. 이 예제에서는 containerd를 사용한다고 가정합니다.
따라서 Kubernetes 노드에서도 HTTP Registry를 사용할 수 있도록 containerd 설정을 추가해야 합니다.
1. containerd registry 설정 경로 지정
각 Kubernetes 노드에서 /etc/containerd/config.toml 파일을 수정합니다.
version = 3
[plugins."io.containerd.cri.v1.images".registry]
config_path = "/etc/containerd/certs.d"
이 설정은 Registry별 설정 파일을 /etc/containerd/certs.d 아래에서 읽도록 지정합니다.
containerd 버전이나 Kubernetes 배포판에 따라 설정 구조가 다를 수 있습니다.
실제 환경의 /etc/containerd/config.toml 구조를 확인한 뒤 적용하는 것이 좋습니다.
2. Registry별 hosts.toml 생성
Registry 주소와 동일한 이름으로 디렉터리를 생성합니다.
sudo mkdir -p /etc/containerd/certs.d/172.25.46.10:32000
이후 hosts.toml 파일을 생성합니다.
sudo vi /etc/containerd/certs.d/172.25.46.10:32000/hosts.toml
다음 내용을 추가합니다.
server = "http://172.25.46.10:32000"
[host."http://172.25.46.10:32000"]
capabilities = ["pull", "resolve", "push"]
skip_verify = true
plain_http = true
이 설정을 통해 containerd가 172.25.46.10:32000 Registry를 HTTP Registry로 인식하고 이미지를 pull할 수 있게 됩니다.
3. containerd 재시작
설정을 적용하기 위해 각 노드에서 containerd를 재시작합니다.
sudo systemctl restart containerd
sudo systemctl status containerd
재시작 후 Kubernetes 노드 상태도 확인합니다.
kubectl get nodes
노드가 Ready 상태이면 정상입니다.
4. Kubernetes에서 이미지 Pull 테스트
Private Registry에 push한 이미지를 사용하는 테스트 Pod를 생성합니다.
apiVersion: v1
kind: Pod
metadata:
name: private-registry-test
spec:
containers:
- name: nginx
image: 172.25.46.10:32000/nginx:latest
restartPolicy: Always
Pod가 정상적으로 실행되는지 확인합니다.
kubectl get pod private-registry-test
kubectl describe pod private-registry-test
ImagePullBackOff 또는 ErrImagePull이 발생하지 않고 Pod가 Running 상태가 되면 설정이 정상적으로 적용된 것입니다.
정리
Kubernetes에 Private Registry를 배포할 때는 단순히 Registry Pod만 실행한다고 끝나지 않습니다.
크게 세 가지 구성이 필요합니다.
1. Registry 저장소 구성
- NFS 기반 PV/PVC 생성
- Registry Deployment에 /var/lib/registry 경로로 PVC 마운트
- Pod가 재시작되어도 이미지 데이터가 유지되도록 구성
2. 외부 접근 구성
- NodePort Service 생성
- 172.25.46.10:32000 형태로 Registry 접근
- Docker CLI에서 해당 주소로 이미지 push
3. HTTP Registry 허용 설정
- Docker Desktop에서는 insecure-registries 설정
- Kubernetes 각 노드에서는 containerd의 certs.d/hosts.toml 설정
이번 설정에서 가장 헷갈리기 쉬운 부분은 push하는 환경과 pull하는 환경이 다르다는 점입니다.
Docker Desktop의 설정은 로컬에서 이미지를 push하기 위한 설정이고, Kubernetes 노드의 containerd 설정은 Pod가 이미지를 pull하기 위한 설정입니다.
따라서 HTTP 기반 Private Registry를 사용할 때는 양쪽 설정을 모두 확인해야 합니다.
Reference
'Devops > Kubernetes' 카테고리의 다른 글
| Helm으로 Argo CD 설치 후 Gateway API와 TLS로 접속 구성하기 (0) | 2026.05.26 |
|---|---|
| Kubernetes kubelet의 컨테이너 로그 로테이션 설정 정리 (0) | 2026.05.25 |
| 로컬 Kubernetes에서 MetalLB로 LoadBalancer IP 할당하기 (0) | 2026.05.20 |
| Gateway API와 Envoy Gateway로 로컬 Kubernetes 서비스 노출하기 (0) | 2026.05.20 |
| Kubernetes에서 NFS 스토리지 구성하기 (0) | 2026.05.20 |