간단하게 인증서 설정없이 Docker Private Registry를 k8s에 설치하는 방법이다. 설치 후 UI 적용할 예정.
1. id, password 생성 (굳이 안 해도 됨)
nerdctl run --entrypoint htpasswd httpd:2 -Bbn testuser testpassword > auth/htpasswd
2. namespace 생성 및 secret 생성
$ kubectl create ns registry
$ kubectl create secret generic registry-auth --from-file=idpass=./htpasswd -n registry
3. pv, pvc, deployment, service 생성
storageclass가 없을 경우 pv를 생성하고 workernode에 registry폴더를 생성한다.(해당 경로는 적절히 수정해서 사용하면 됨)
1번에 id, password 생성 하지 않았으면, deployment 내 registry-auth 부분들 삭제하고 진행
아래 yaml 생성 후 kubectl apply -f registry.yaml -n registry 명령어 실행
$ vi registry.yaml
$ kubectl apply -f registry.yaml -n registry
apiVersion: v1
kind: PersistentVolume
metadata:
name: registry-pv
labels:
reg: registry
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: "/root/registry"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-pvc
labels:
reg: registry
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
selector:
matchLabels:
reg: registry
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
labels:
reg: registry
spec:
replicas: 1
selector:
matchLabels:
reg: registry
template:
metadata:
labels:
reg: registry
spec:
containers:
- name: registry
image: registry:2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
volumeMounts:
- name: registry-auth
mountPath: /auth # 이미지 내 기본 registry auth 경로
- name: registry-data
mountPath: /var/lib/registry
env:
- name: REGISTRY_AUTH_HTPASSWD_PATH # 기본 설정
value: /auth/idpass # secert에 들어가는 파일을 idpass로 생성
- name: REGISTRY_AUTH_HTPASSWD_REALM # 기본 설정
value: "Registry Realm"
- name: REGISTRY_STORAGE_DELETE_ENABLED
value: "true"
volumes:
- name: registry-auth
secret:
secretName: registry-auth
- name: registry-data
persistentVolumeClaim:
claimName: registry-pvc
---
apiVersion: v1
kind: Service
metadata:
name: registry
spec:
type: NodePort
ports:
- port: 5000
targetPort: 5000
nodePort: 30050
protocol: TCP
selector:
reg: registry
4. 테스트
curl localhost:30050/v2/_catalog -u "testuser:testpassword"
5. UI 적용 (UI가 굳이 필요없으면 안 해도 됨)
UI 는 아래 오픈소스를 사용할 예정이다.
https://github.com/Joxit/docker-registry-ui
우선 위에 생성한 registry 에 ingress 를 등록해야한다. (Domain이 일치해야 UI에서 인증을 사용할 수 있음.)
$ vi registry-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: registry
nginx.ingress.kubernetes.io/proxy-body-size: 4096m # 이미지 업로드 용량으로 반드시 설정필요하며 필요에 따라 설정
spec:
ingressClassName: nginx
rules:
- host: registry.wky.kr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: registry
port:
number: 5000
또한, 위에 생성한 Deployment에 환경변수를 추가해야한다.
$ kubectl edit deploy -n registry registry
...
- env:
- name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin # 추가
value: '[http://registry-ui.wky.kr:30080]'
- name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods # 추가
value: '[HEAD,GET,OPTIONS,DELETE]'
- name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials # 추가
value: '[true]'
- name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers # 추가
value: '[Authorization,Accept]'
- name: REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers # 추가
value: '[Docker-Content-Digest]'
- name: REGISTRY_STORAGE_DELETE_ENABLED
value: "true"
- name: REGISTRY_AUTH_HTPASSWD_PATH
value: /auth/idpass
- name: REGISTRY_AUTH_HTPASSWD_REALM
value: Registry Realm
...
UI 설치
특히 아래 yaml의 NGINX_PROXY_PASS_URL은 k8s service domain을 넣거나 nodeport를 넣거나 ingress를 넣어주면된다.
$ vi registry-ui.yaml
$ kubectl apply -f registry-ui -n registry
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry-ui
labels:
reg: registry-ui
spec:
replicas: 1
selector:
matchLabels:
reg: registry-ui
template:
metadata:
labels:
reg: registry-ui
spec:
containers:
- name: registry-ui
image: joxit/docker-registry-ui:main
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
env:
- name: SINGLE_REGISTRY
value: "true"
- name: REGISTRY_TITLE
value: Docker Registry UI
- name: DELETE_IMAGES
value: "true"
- name: SHOW_CONTENT_DIGEST
value: "true"
- name: SHOW_CATALOG_NB_TAGS
value: "true"
- name: CATALOG_MIN_BRANCHES
value: "1"
- name: CATALOG_MAX_BRANCHES
value: "1"
- name: TAGLIST_PAGE_SIZE
value: "100"
- name: REGISTRY_SECURED
value: "true"
- name: CATALOG_ELEMENTS_LIMIT
value: "1000"
- name: NGINX_PROXY_PASS_URL
value: http://registry.registry:5000 # http://registry.wky.kr:30050 또는 http://registry.wky.kr:30080
- name: REGISTRY_SECURED
value: "true"
---
apiVersion: v1
kind: Service
metadata:
name: registry-ui
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30051
protocol: TCP
selector:
reg: registry-ui
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: registry-ui
spec:
ingressClassName: nginx
rules:
- host: registry-ui.wky.kr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: registry-ui
port:
number: 80
결과 확인
기타 : https 로 여는법
사설 인증서를 생성하고, 사설인증서이기 때문에 해당 registry를 실제 사용할 서버를 위해 ca파일도 생성한다.
# 사설 인증서 생성
$ openssl req -newkey rsa:4096 -nodes -sha256 -keyout domain.key -subj "/CN=registry.wky.kr" -addext "subjectAltName=DNS:registry.wky.kr" -x509 -days 365 -out domain.crt
# 이미지 push 또는 pull 위한 ca 파일 생성
$ cat domain.crt domain.key > domain.pem
registry에 마운트할 secret과 ingress에 등록할 secert 2개를 생성한다.
# registry 인증서용
$ kubectl create secret generic https-registry --from-file=domain.crt=./domain.crt --from-file=domain.key=./domain.key -n registry
# registry ingress용
$ kubectl create secret tls tls-registry --key ./domain.key --cert ./domain.crt -n registry
deployment와 service, ingress 수정
# deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
labels:
reg: registry
spec:
replicas: 1
selector:
matchLabels:
reg: registry
template:
metadata:
labels:
reg: registry
spec:
containers:
- name: registry
image: registry:2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 443 # 443으로 수정
volumeMounts:
- name: registry-auth
mountPath: /auth
- name: registry-data
mountPath: /var/lib/registry
- name: https-registry # 인증서파일 마운트
mountPath: /tmp
env:
- name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin
value: '[http://registry-ui.wky.kr:30080]'
- name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods
value: '[HEAD,GET,OPTIONS,DELETE]'
- name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials
value: '[true]'
- name: REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers
value: '[Authorization,Accept]'
- name: REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers
value: '[Docker-Content-Digest]'
- name: REGISTRY_STORAGE_DELETE_ENABLED
value: "true"
- name: REGISTRY_AUTH_HTPASSWD_PATH
value: /auth/idpass
- name: REGISTRY_AUTH_HTPASSWD_REALM
value: Registry Realm
- name: REGISTRY_STORAGE_DELETE_ENABLED
value: "true"
- nmae: REGISTRY_HTTP_TLS_CERTIFICATE # 인증서 설정
value: /tmp/domain.crt
- name: REGISTRY_HTTP_TLS_KEY # 인증서 설정
value: /tmp/domain.key
- name: REGISTRY_HTTP_ADDR # 443으로 포트 열기
value: 0.0.0.0:443
volumes:
- name: registry-auth
secret:
secretName: registry-auth
- name: registry-data
persistentVolumeClaim:
claimName: registry-pvc
- name: https-registry # 인증서 secret 마운트
secret:
secretName: https-registry
# serivce
apiVersion: v1
kind: Service
metadata:
name: registry
spec:
type: ClusterIP # NodePort도 관계없음.
ports:
- port: 443 # 443으로 수정
targetPort: 443 # 443으로 수정
protocol: TCP
selector:
reg: registry
# ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: registry
nginx.ingress.kubernetes.io/backend-protocol: HTTPS # HTTPS 통신
nginx.ingress.kubernetes.io/proxy-body-size: 4096m
spec:
ingressClassName: nginx
rules:
- host: registry.wky.kr
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: registry
port:
number: 443
tls: # tls secret 마운트
- hosts:
- registry.wky.kr
secretName: tls-registry
참고 :
https://distribution.github.io/distribution/
https://github.com/Joxit/docker-registry-ui