Openshift 4.12.0 내부 이미지 레지스트리 (Private Image Registry) 구성

리눅스/OpenShift|2023. 2. 16. 13:43
반응형

본 문서는 공식 Documents 를 참고하여 작성하였습니다.

https://docs.openshift.com/container-platform/4.12/registry/index.html

 

Registry 를 구축, 운영하는 이유는 OCP 서버 내부 용량이 적어서 docker 이미지를 저장할 공간이 부족할때 사용하거나

보통은 어디에서든 접근이 가능하도록 Docker hub 처럼 서비스 하려는 목적이 있습니다.

아래는 Docker 이미지를 OpenShift 내부 Docker 레지스트리에 업로드 하는 방법 입니다.

 

[요구사항]
- 클러스터 관리자 권한 필요
- 100G 이상의 용량이 필요

 

 

1. Registry 구성하기

 

1) registry Pod 확인

현재 사용자를 확인합니다.

# export KUBECONFIG=/root/installation_directory/auth/kubeconfig

# oc whoami

system:admin

 

registry Pod 가 있는지 확인합니다.

있을 경우에 구성을 할 필요가 없기 때문입니다.

# oc get pod -n openshift-image-registry -l docker-registry=default
No resources found in openshift-image-registry namespace.

 

2) 이미지 레지스트리 상태 변경

베어메탈과 같은 플랫폼에 클러스터를 구성하면 OpenShift Image Registry Operator 는 자체적으로 Removed 되어 구성됩니다.

그렇기 때문에 Image Registry 사용을 위해서는 클러스터 구성 후 managementState 를 Removed 에서 Managed 로 전환하도록 Image Registry Operator 구성을 편집해야 합니다.

 

configs.imageregistry.operator.openshift.io 구성을 바로 패치 (수정) 합니다.

# oc patch configs.imageregistry.operator.openshift.io cluster --type merge --patch '{"spec": {"managementState":"Managed"}}'

config.imageregistry.operator.openshift.io/cluster patched

 

변경된 레지스트리 구성을 확인합니다.

# oc get configs.imageregistry.operator.openshift.io/cluster -o yaml |grep managementState

    managementState: Managed

 

3) 디렉토리 설정

원래 이미지를 안전하게 저장하기 위해서는 Persistent Volume (별도 스토리지) 을 사용해야 하지만, 여기에서는 동작 여부만 확인하는 것이 목적이므로 이미지 레지스트리 스토리지를 빈 디렉터리로 설정하겠습니다.

레지스트리를 재기동 하면 모든 이미지가 없어지기 때문에 이 방법은 반드시 테스트 환경에서만 사용하여야 합니다.

아래와 같이 config파일에 emptyDir를 추가해주면 됩니다.

# oc patch configs.imageregistry.operator.openshift.io cluster --type merge --patch '{"spec":{"storage":{"emptyDir":{}}}}'

config.imageregistry.operator.openshift.io/cluster patched

 

* 참고

Image Registry Operator가 구성 요소를 초기화하기 전에 이 명령을 실행하면 명령이 실패하며 다음 오류가 발생합니다.
Error from server (NotFound): configs.imageregistry.operator.openshift.io "cluster" not found
몇 분 후에 명령을 다시 실행해 보세요.

 

4) 스토리지 클래스 및 PVC (PersistentVolumeClaim) 구성

사용할 스토리지 클래스 및 가용성 영역을 지정하는 yaml 파일을 생성합니다.

# vi storage_class.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: custom-csi-storageclass
provisioner: cinder.csi.openstack.org
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
  availability: az1

 

metadata: name: 스토리지 클래스를 구분짓는 이름

parameters: availability: 클러스터 구성시 사용한 클러스터 이름

 

구성을 적용합니다.

# oc apply -f storage_class.yaml 
storageclass.storage.k8s.io/custom-csi-storageclass created

 

스토리지 클래스 및 openshift-image-registry 네임스페이스를 사용하는 PVC (영구 볼륨 클레임) 를 지정하는 yaml 파일을 생성합니다. 

# vi pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: csi-pvc-imageregistry
  namespace: openshift-image-registry
  annotations:
    imageregistry.openshift.io: "true"
spec:
  accessModes:
  - ReadWriteMany
  volumeMode: Filesystem
  resources:
    requests:
      storage: 100Gi
  storageClassName: custom-csi-storageclass

metadata: name: PVC 를 구분짓는 이름

metadata: namespace: PVC 를 생성할 프로젝트 위치

spec: accessModes: 영구 볼륨 클레임의 액세스 모드

* 참고 : accessMode 옵션 설명

- ReadWriteOnce : 하나의 노드에서만 읽고 쓸 수 있습니다. 즉, PVC를 마운트한 노드만 해당 볼륨에 읽고 쓸 수 있습니다.
- ReadWriteMany : 여러 노드에서 동시에 읽고 쓸 수 있습니다. 즉, 볼륨이 여러 노드에 마운트되어 있어도 모든 노드에서 동시에 읽고 쓸 수 있습니다.

두 개 이상의 노드로 고 가용성을 지원하는 이미지 레지스트리를 배포하려면 ReadWriteMany 액세스가 필요합니다.

 

spec: resources: requests: storage: 사용할 볼륨 크기

spec: resources: storageClassName: 위에서 생성한 스토리지 클래스 이름

 

구성을 적용합니다.

# oc apply -f pvc.yaml

persistentvolumeclaim/csi-pvc-imageregistry created

 

외부에서 사용이 가능하도록 route 노출 시킵니다.

# oc patch configs.imageregistry.operator.openshift.io/cluster --type=merge --patch '{"spec":{"defaultRoute":true}}' -n openshift-image-registry

config.imageregistry.operator.openshift.io/cluster patched

 

5) 상태 확인

Cluster Operator 상태를 확인합니다.

# oc get co image-registry

NAME             VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE   MESSAGE
image-registry   4.12.0    False       False         True       4h34m   Available: Error: storage backend not configured...

 

또는 이렇게 출력될 수 있습니다.

# oc get co image-registry
NAME             VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE   MESSAGE
image-registry   4.12.0    False       True          False      49s     Available: The deployment does not have available replicas...

 

하지만 시간이 지나면 정상적인 상태로 돌아옵니다.

# oc get co image-registry
NAME             VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE   MESSAGE
image-registry   4.12.0    True        False         False      4h51m   

 

레지스트리 Pod 가 확인됩니다.

# oc get pod -n openshift-image-registry -l docker-registry=default
NAME                                              READY   STATUS      RESTARTS   AGE
image-registry-7d646777fb-s6bwk                   1/1     Running     0          2d18h

 

6) Certificate 생성

Image registry 에 접근하기 위해서 연결하려는 도메인에 인증서가 설치 되어 있어야 합니다.

무료 사용을 원하시면 Let's encrypt SSL 또는 StartSSL 을 추천합니다.

https://sysdocu.tistory.com/1781

 

본 매뉴얼에서는 Let's encrypt 로 SSL 인증서를 발급받았으며, 필요한 파일 두개를 아래 디렉토리로 옮겨놓았습니다.

 

# mkdir -p /opt/registry/certs

(발급 인증서 복사 부분 생략)

# ll /opt/registry/certs
합계 12
-rw-r--r--. 1 root root 5701  2월 20 16:15 fullchain1.pem
-rw-------. 1 root root 1704  2월 20 16:15 privkey1.pem

 

참고로 위 파일에서 fullchain1.pem 은 cert1.pem 파일과 chain1.pem 파일의 내용을 모두 포함한 파일입니다.

즉, 공개 SSL 인증서와 인증서 체인이 모두 포함되었습니다.

 

용도 별 디렉토리를 추가로 생성하고 필요한 파일을 복사합니다.

# cd /opt/registry

# mkdir auth data

* 참고

/opt/registry/auth : 계정정보 파일 위치

/opt/registry/certs : 도메인 인증서 위치

/opt/registry/data : 이미지 저장 위치

 

이미지 레지스트리 사용자 계정을 생성을 위해 패키지 설치 및 명령을 수행합니다.

# cd auth

# yum -y install httpd-tools

# htpasswd -c -b -B htpasswd sysdocu 12345678

Adding password for user sysdocu

# cd

 

7) image-registry 컨테이너 생성

docker 를 이용해 image-registry 컨테이너를 가동합니다.

# docker run --name image-registry --restart=always -p 5000:5000 \
    -v /opt/registry/auth:/auth \
    -v /opt/registry/certs:/certs \
    -v /opt/registry/data:/var/lib/registry \
    -e "REGISTRY_AUTH=htpasswd" \
    -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
    -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
    -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain1.pem \
    -e REGISTRY_HTTP_TLS_KEY=/certs/privkey1.pem \
    -e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true \
    -d docker.io/library/registry:2

17e3d6b238fcebc19ffd87d39634234e4cf4708b4470f1e5c9f1e5ebaeee5264

 

route 정보에서 이미지 레지스트리 URL 을 확인 할 수 있습니다.

# oc get route -n openshift-image-registry
NAME            HOST/PORT                                                     PATH   SERVICES         PORT    TERMINATION   WILDCARD
default-route   default-route-openshift-image-registry.apps.az1.sysdocu.kr           image-registry   <all>   reencrypt     None

 

htpasswd 명령으로 생성했던 계정으로 로그인해서 아래와 같은 결과가 나오면 성공입니다.

# curl -u sysdocu:12345678 https://default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/v2/_catalog
{"repositories":[]}

 

출력이 안될경우 인증서 문제인데, -k 옵션을 사용하여 인증서를 무시하고 결과를 확인 할 수 있으나

이경우는 추천하지 않으므로 올바른 도메인으로 SSL 인증서를 다시 발급받거나

위의 컨테이너 생성 단계에서 인증서 파일에 인증서 및 체인키가 함께 들어 있는지 확인합니다.

 

* 에러 발생

여기에서 인증서 관련 에러 출력 : curl: (60) Peer's Certificate issuer is not recognized.

시스템에서 신뢰하지 않는 SSL 인증서를 사용하는 원격 서버에 접속하려고 할 때 발생합니다.

즉, 인증서 발급자가 시스템에서 인식되지 않을 때 발생하는 오류입니다.

이를 무시하는 방법은 curl -k 옵션을 추가하면 쉽게 해결이 되지만 설정한 인증서에 인증서 Chain 이 빠졌는지 확인해보면 좋습니다.

 

* 에러 발생

여기에서 인증서 관련 에러 출력 : x509: certificate signed by unknown authority

참고 (계정 정책 허용) : https://docs.openshift.com/container-platform/4.12/registry/accessing-the-registry.html

이미지에 직접 로그인 할 수도 있습니다.

# docker login -u sysdocu -p 12345678 default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000
Login Succeeded!

 

* 에러 발생

여기에서 연결 실패 에러 출력 : curl: (7) Failed connect to default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000; 연결이 거부됨

컨테이너 생성이 되지 않아 포트가 열리지 않은 경우가 가장 큰데, docker ps -a 명령으로 registry ID 값을 확인하여 logs 를 살펴보면 단서를 찾을 수 있습니다.

# docker ps -a

# docker logs <컨테이너 생성시 출력된 ID 값>

컨테이너를 삭제하고 재생성이 필요한 경우는 아래와 같이 진행합니다.

# docker stop <컨테이너 ID>

# docker rm <컨테이너 ID>

 

* 에러 발생

여기에서 연결 실패 에러 출력 : curl: (51) Unable to communicate securely with peer: requested domain name does not match the server's certificate.

이 오류는 아래와 같은 경우에 발생합니다.

- 요청한 도메인 이름과 인증서의 CN (Common Name) 이 일치하지 않는 경우 (인증서가 *.sysdocu.kr 인지, 서브도메인까지 일치하는지 확인 필요)

- 인증서의 subjectAltName 에서 요청한 도메인 이름이 발견되지 않는 경우

인증서를 재발급 받거나 인증서에 subjectAltName을 추가하여 요청한 도메인 이름이 인증서에 포함되도록 합니다.

 

 

2. 실습하기 (이미지 업로드)

 

원격으로 apache 가 포함된 php 이미지를 받아 내부 image-registry 에 올려 보도록 하겠습니다.

먼저 도커 사이트에서 이미지를 다운로드 받습니다.

# docker pull docker.io/php:7.4-apache
Trying to pull repository docker.io/library/php ... 
7.4-apache: Pulling from docker.io/library/php
a603fa5e3b41: Pull complete 
c428f1a49423: Pull complete 
156740b07ef8: Pull complete 
fb5a4c8af82f: Pull complete 
25f85b498fd5: Pull complete 
9b233e420ac7: Pull complete 
fe42347c4ecf: Pull complete 
d14eb2ed1e17: Pull complete 
66d98f73acb6: Pull complete 
d2c43c5efbc8: Pull complete 
ab590b48ea47: Pull complete 
80692ae2d067: Pull complete 
05e465aaa99a: Pull complete 
Digest: sha256:c9d7e608f73832673479770d66aacc8100011ec751d1905ff63fae3fe2e0ca6d
Status: Downloaded newer image for docker.io/php:7.4-apache

 

내부 이미지 레지스트리에 사용할 주소를 만들기위해 project 를 확인합니다.

각 사용자마다 프로젝트가 다를 수 있으므로 구분하기 위해 프로젝트명을 활용하지만 공용으로 사용하는 명칭도 괜찮습니다.

# oc project
Using project "project412" on server "https://api.az1.sysdocu.kr:6443".

 

Registry 에 로그인을 하지 않았다면 업로드 권한이 없으므로 위에서 생성했던 secret 계정을 이용해 Registry 에 로그인을 합니다.

# docker login -u sysdocu -p 12345678 default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000
Login Succeeded

 

태그 설정을 합니다.

예) docker tag <docker images 명령으로 출력된 이미지명> <내부 리포지토리 주소/프로젝트명/이미지명:버전>

# docker tag docker.io/php:7.4-apache default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/php

 

내부 이미지 레지스트리로 업로드 합니다.

예) docker push <내부 리포지토리 주소/프로젝트명/이미지명:버전>

# docker push default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/php
The push refers to a repository [default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/php]
3d33242bf117: Pushed 
529016396883: Pushed 
5464bcc3f1c2: Pushed 
28192e867e79: Pushed 
d173e78df32e: Pushed 
0be1ec4fbfdc: Pushed 
30fa0c430434: Pushed 
a538c5a6e4e0: Pushed 
e5d40f64dcb4: Pushed 
44148371c697: Pushed 
797a7c0590e0: Pushed 
f60117696410: Pushed 
ec4a38999118: Pushed 
latest: digest: sha256:18b3497ee7f2099a90b66c23a0bc3d5261b12bab367263e1b40e9b004c39e882 size: 3035

 

* 이 부분에서 업로드 되지 않는 경우 체크 사항

- 마지막 행에 'no basic auth credentials' 에러 출력시 Registry 에 로그인을 했는지 확인

- docker ps -a 명령으로 Registry 컨테이너가 정상 가동 되고 있는지 확인

 

명령이 잘 실행 되었다면 이미지 리스트를 다시 확인합니다.

# curl -u sysdocu:12345678 https://default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/v2/_catalog

{"repositories":["project412/php"]}

 

이제 다음과 같은 형태로 어느 호스트에서든 Registry 에 올려진 Docker Image 를 사용할 수 있습니다. (포트 확인)

# docker pull default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/php

 

 

3. Pod 생성하기

 

내부 레지스트리에 올려진 php 이미지로 컨테이너 생성이 가능하지만 접근권한이 없어서 다운로드 (pull) 가 되지 않을것입니다.

secret 을 생성하여 Pod 생성시 내부 레지스트리에 접근 권한을 획득하면 됩니다.

secret 은 현재 위치인 접근자 프로젝트 (예제에서는 project412) 에서 생성하면 됩니다.

# oc create secret docker-registry sysdocu \
  --docker-username=sysdocu \
  --docker-password=12345678 \
  --docker-email=admin@sysdocu.kr \
  --docker-server=default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000

 

Dockerfile 을 이용하여 php:7.4-apache 이미지에 설정을 변경하고 개발 소스를 추가하는 방법으로 진행해 보겠습니다.

테스트용으로 PHP 소스 파일을 만듭니다.

# mkdir ./source

# vi ./source/index.php

<?php
echo "Good job";
?>

 

Dockerfile 을 아래 내용으로 만듭니다.

80 포트를 이미 사용중일때는 바인딩이 되지 않습니다.

그래서 컨테이너는 8080 포트로 열고 외부접근은 80 번으로 접근하도록 합니다.

# vi Dockerfile

FROM default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/php
COPY ./source/ /var/www/html/
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf
RUN sed -i 's/Listen 80/Listen 8080/' /etc/apache2/ports.conf
EXPOSE 8080
CMD ["apache2ctl", "-D", "FOREGROUND"]

 

현재 디렉토리에 있는 Dockerfile 을 사용하여 Docker 이미지를 새로 만듭니다.

형식) docker build --tag <새 이미지 이름> <Dockerfile 위치>

# docker build --tag my-app5 .

 

새로운 이미지가 확인 되었습니다.

# docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
my-app5                              latest              b0aeb2e3c8af        42 seconds ago      453 MB

docker.io/php                        7.4-apache          20a3732f422b        4 months ago        453 MB

default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/php   latest        20a3732f422b     4 months ago     453 MB

 

이번에는 로컬에 만들어져 있는 my-app5 이미지를 내부 레지스트리에 올려놓고 그것을 이용해 Pod 를 생성해보겠습니다.

업로드 권한이 필요하므로 생성했던 secret 계정을 이용해 Registry 에 로그인을 합니다.

# docker login -u sysdocu -p 12345678 default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000
Login Succeeded

 

태그 설정을 하고 업로드 합니다.

# docker tag my-app5 default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/custom-php

# docker push default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/custom-php

 

Pod 생성을 위해 deployment yaml 파일을 만듭니다.

Deployment 는 Pod 를 생성, 업데이트, 롤백 및 모니터링하는데 사용되는 추상화 계층입니다.

Deployment 는 Pod 의 명세를 정의하며, 해당 명세를 기반으로 하나 이상의 파드를 자동으로 생성합니다.

아래 deployment 생성 후 Pod 를 삭제하면 다시 생성되는 것을 볼 수 있습니다. Pod 유지 개수는 replicas 값에 따라 결정 됩니다.

내부 레지스트리에 올려진 이미지 주소와 하단부에 imagePullSecret (위에서 만든 secret 이름) 을 잘 지정하여 작성합니다.

# vi deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app5  // Deployment 이름. Pod 이름도 같은 이름으로 생성되지만 뒤에 랜덤 문자가 붙음
spec:
  replicas: 1
  selector:
    matchLabels:
      app: l-app5  // 아래랑 같아야 함
  template:
    metadata:
      labels:
        app: l-app5  // 위랑 같아야 함
    spec:
      containers:
      - name: c-app5
        image: default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/custom-php
        ports:
        - containerPort: 8080
      imagePullSecrets:
      - name: sysdocu

 

Deployment 를 생성합니다.

# oc apply -f deployment.yaml

 

----- Deployment 생성시 Pod 가 함께 생성되었기 때문에 이 부분은 건너 뜁니다 -----

참고로 Deployment 없이 Pod 만 생성하는 방법입니다.

# vi pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: app5
spec:
  label:
    app: l-app5
  securityContext:
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: c-app5
    image: default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/custom-php
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
      runAsNonRoot: true
  imagePullSecrets:
  - name: sysdocu

 

Pod 를 생성합니다.

# oc apply -f pod.yaml

-----------------------------------------------------------------------------------------------------------

 

Pod 가 생성된 것이 확인되었습니다.

# oc get pod
NAME   READY   STATUS    RESTARTS   AGE
app5   1/1     Running   0          3s

 

외부에서 접근하려면 service 와 endpoint, route 까지 생성해야 합니다.

명령 한줄로 service 와 endpoint 가 같이 생성됩니다.

형식) oc expose deployment <Deployment 이름> --type=LoadBalancer --name=<생성할 Service 이름>

# oc expose deployment app5 --type=LoadBalancer --name=s-app5

 

----- Service 생성시 이 부분은 건너 뜁니다 -----

# vi service.yaml

apiVersion: v1
kind: Service
metadata:
  name: s-app5
spec:
  type: LoadBalancer
  selector:
    app: l-app5
  ports:
    - name: p-app5
      protocol: TCP
      port: 80
      targetPort: 8080

 

* 설명

- type : 옵션이 없으면 클러스터 내부에서만 접속 가능한 Cluster-IP 가 부여되는데

            외부에서 접속 가능하게 하려면 NodePort 또는 LoadBalancer 로 설정 해야 합니다.

            ㄴ NodePort : 단일 사용자 및 단일 Pod 연결의 경우 NodePort 가 적절하며 개발 및 테스트 용도로 사용합니다.

                                   노드의 IP 와 포트로 직접 접근할 수 있으므로 보안이 취약합니다.

            ㄴ LoadBalancer : 다수의 Pod 제공이 가능하며 주로 프로덕션 환경에서 사용됩니다. 또한 안전하고 성능이 우수합니다.

- selector: app : 위에 app.yaml 에서 명시한 label 이름

- port : Service 가 노출하고 있는 포트

- targetPort : Service 가 연결하려는 백엔드 Pod 의 포트

 

위 yaml 파일을 적용합니다.

# oc apply -f service.yaml

------------------------------------------------------------

 

service 생성된것이 확인되었습니다.

# oc get service
NAME     TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)          AGE
s-app5   LoadBalancer   172.30.40.43   115.68.142.106   8080:30343/TCP   26s

 

route 를 생성하여 외부에서 접근 가능하도록 합니다.

형식) oc expose service <service 이름> --name=<생성할 route 이름> --port=<open 할 포트>

# oc expose service s-app5 --name=r-app5 --port=8080
route.route.openshift.io/r-app5 exposed

 

생성된 route 를 확인합니다.

# oc get route
NAME     HOST/PORT                             PATH   SERVICES   PORT   TERMINATION   WILDCARD
r-app5   r-app5-project412.apps.az1.sysdocu.kr          s-app5     8080                 None

 

외부에서 접근 테스트를 합니다.

# curl r-app5-project412.apps.az1.sysdocu.kr

Good job

 

[ oc new-app 명령어 사용하기 ]

위에 Pod, Service, Endpoint, Route 생성을 자동으로 도와주는 oc new-app 명령이 있습니다.

이 방법은 추후에 추가하도록 하겠습니다...

 

 

4. Registry 이미지 삭제하기

 

운영 서버 용량 부족이나 기타 사유로 인해 Registry 의 이미지를 지워야 할때나

같은 이름의 리포지토리가 있으면 push 를 해도 덮어씌우기가 적용되지 않고 그냥 넘어가므로 (pass) 기존 이미지를 지워야 할때가 있습니다.

그럴때 사용하는 명령인데, 올바른지 모르겠지만 아래와 같은 형식으로 명령을 실행했더니 에러가 출력되었습니다.

 

1) Registry 에서 삭제

예시) project412 에 올려놓은 ruby3 이미지 삭제

# oc adm prune images --registry-url=default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/ruby3 --confirm

error: you must use a client config with a token

 

하지만 더 간단한 방법이 있습니다.

위 예제를 따라서 구성하였다면 registry 에 올려진 이미지의 경로는 아래와 같습니다.

/opt/registry/data/docker/registry/v2/repositories/<프로젝트명>

 

registry 에 업로드 된 이미지를 확인해 봅니다.

# curl -u sysdocu:12345678 https://default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/v2/_catalog
{"repositories":["project412/custom-php","project412/custom-php2","project412/ruby","project412/ruby2","project412/ruby3"]}

 

로컬 디스크에 저장된 이미지를 확인합니다.

# ll /opt/registry/data/docker/registry/v2/repositories/project412
합계 0
drwxr-xr-x. 5 root root 55  4월  5 14:28 custom-php
drwxr-xr-x. 5 root root 55  4월 11 10:30 custom-php2
drwxr-xr-x. 5 root root 55  4월 18 09:12 ruby
drwxr-xr-x. 5 root root 55  4월 18 14:33 ruby2
drwxr-xr-x. 5 root root 55  4월 18 15:01 ruby3

 

시스템의 rm 명령을 이용하여 원하는 이미지 디렉토리를 삭제합니다.

# rm -rf /opt/registry/data/docker/registry/v2/repositories/project412/ruby3

 

지워진것이 확인되었습니다.

# curl -u sysdocu:12345678 https://default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/v2/_catalog
{"repositories":["project412/custom-php","project412/custom-php2","project412/ruby","project412/ruby2"]}

 

2) ImageStream 목록에서 삭제

이미지 Registry 를 재설치하거나 Repository 를 한개 삭제 했다 하더라도 이미지 스트림 목록에는 여전히 보입니다.

이미지 스트림은 Openshift 내부에서 관리되며, 클러스터 노드에서 호스팅되는 Docker 레지스트리와는 별개이기 때문입니다.

Openshift 의 Docker 이미지 레지스트리는 기본적으로 Docker V2 이미지 프로토콜을 지원하며, 이 레지스트리에는 이미지 스트림에서 참조하는 Docker 이미지가 저장됩니다.
정리하면, 이미지 스트림은 Openshift 서버 내에서 관리되며, 이미지는 Openshift의 Docker 이미지 레지스트리에 저장됩니다.

그렇기 때문에 Registry 에서도 삭제한 아이템을 ImageStream 에서도 따로 지워줘야 합니다.

 

# oc get is
NAME            IMAGE REPOSITORY                                                                    TAGS                UPDATED
custom-php      default-route-openshift-image-registry.apps.az1.sysdocu.kr/project412/custom-php      latest              8 days ago

custom-php2     default-route-openshift-image-registry.apps.az1.sysdocu.kr/project412/custom-php2     latest              8 days ago
ruby             default-route-openshift-image-registry.apps.az1.sysdocu.kr/project412/ruby            latest              7 days ago
ruby2            default-route-openshift-image-registry.apps.az1.sysdocu.kr/project412/ruby2           latest              8 days ago

ruby3            default-route-openshift-image-registry.apps.az1.sysdocu.kr/project412/ruby3           latest              8 days ago

 

# oc delete is ruby3

imagestream.image.openshift.io "ruby3" deleted

 

 

* 참고 : 외부 이미지를 Registry 로 바로 가져오기

 

외부 Registry 의 이미지를 내부 Registry 로 가져오는 방법 (import-image) 입니다.

import-image 를 이용하여 가져온 이미지는 docker images 로는 이미지가 보이지 않으며 oc get is 명령으로 이미지 확인이 가능합니다.

형식) oc import-image <이미지 스트림 이름> --from=<원본 이미지 경로> --confirm

# oc import-image my-image --from=default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/library/my-app5 --confirm

 

이번엔 Docker Hub 에서 한 가지 더 받아보겠습니다.

# oc import-image test --from=docker.io/nginx --confirm

 

특이사항은 등록 상태를 확인해보면 현재의 project 명 (project412) 과 이미지 스트림 이름으로 서비스 주소가 완성 되어진 것이 보입니다.

그렇기 때문에 이미지 스트림 이름을 명확히 해야 추후 이미지를 이용할때 혼동되지 않습니다.

# oc get is

NAME       IMAGE REPOSITORY                                                                 TAGS     UPDATED
my-image   default-route-openshift-image-registry.apps.az1.sysdocu.kr/project412/my-image   latest   

test             default-route-openshift-image-registry.apps.az1.sysdocu.kr/project412/test             latest

 

 

* 참고 : 내부 이미지 레지스트리 삭제

 

1) PVC 삭제

서비스 중지 또는 재설치 등의 이유로 Registry 를 재설치할 경우 아래와 같은 절차를 따릅니다.

모든 프로젝트에서 PVC 를 확인하면 image registry pvc 가 어느 네임스페이스에 있는지 확인이 됩니다.

# oc get pvc -A
NAMESPACE                  NAME                    STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS              AGE
openshift-image-registry   csi-pvc-imageregistry   Pending                                      custom-csi-storageclass   4d21h

 

이름과 네임스페이스를 이용하여 pvc 정보를 삭제합니다.

# oc delete pvc csi-pvc-imageregistry -n openshift-image-registry
persistentvolumeclaim "csi-pvc-imageregistry" deleted

 

2) Pod 삭제

openshift-image-registry 프로젝트 (네임스페이스) 에서 이미지 레지스트리 Pod 이름을 확인합니다.

# oc get pod -n openshift-image-registry -l docker-registry=default
NAME                              READY   STATUS    RESTARTS   AGE
image-registry-6dfb9c8f99-xbzbd   1/1     Running   0          4d21h

 

프로젝트명을 명시하여 해당 이미지 레지스트리 Pod 를 삭제하면 곧바로 다른 이름으로 되살아납니다.
# oc delete pod image-registry-6dfb9c8f99-xbzbd -n openshift-image-registry
pod "image-registry-6dfb9c8f99-xbzbd" deleted

 

그렇기에 완전히 삭제를 원할 경우 이미지 레지스트리 구성의 상태값에 Removed 로 표기를 해야 합니다.

# oc patch configs.imageregistry.operator.openshift.io cluster -p '{"spec":{"managementState":"Removed"}}' --type='merge'
config.imageregistry.operator.openshift.io/cluster patched

 

Terminating 상태이므로 시간이 지나 삭제 됩니다.

# oc get pod -n openshift-image-registry -l docker-registry=default
NAME                                              READY   STATUS        RESTARTS        AGE
image-registry-6dfb9c8f99-r89vg                   1/1     Terminating   0               10m

 

삭제 되었습니다.

# oc get pod -n openshift-image-registry -l docker-registry=default
No resources found in openshift-image-registry namespace.

 

3) Docker 컨테이너 및 이미지 삭제

컨테이너 ID 를 확인하고 중지, 삭제합니다.

# docker ps
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                    NAMES
46d0300f61f6        docker.io/library/registry:2   "/entrypoint.sh /e..."   37 minutes ago      Up 37 minutes       0.0.0.0:5000->5000/tcp   image-registry

 

# docker stop 46d0300f61f6
46d0300f61f6

 

# docker rm 46d0300f61f6
46d0300f61f6

 

끝으로 Docker 이미지를 저장하였던 폴더를 비워줍니다.

# rm -rf /opt/registry/data/*

 

 

* 참고 : SSL 인증서 업데이트

 

SSL 인증서 사용기간이 정해져있어 만료일이 도래하기 전에 인증서 업데이트를 해주어야 정상적인 서비스가 가능하며, 인증서를 교체하지 않고 기간이 만료된 경우 Pod 생성 에러 'Failed to pull image' 가 발생됩니다.

 

Registry 인증서가 있는 디렉토리로 이동합니다.

# cd /opt/registry/certs
# ll
합계 20
-rw-r--r-- 1 root root 1960  3월 20 10:55 cert1.pem
-rw-r--r-- 1 root root 3749  3월 20 10:55 chain1.pem
-rw-r--r-- 1 root root 5709  3월 20 10:55 fullchain1.pem
-rw------- 1 root root 1704  3월 20 10:55 privkey1.pem

 

갱신한 SSL 인증서를 아래와 같이 덮어씌워 교체 하였습니다. (교체 방법 생략)

참조 : https://sysdocu.tistory.com/1546

# ll
합계 40
-rw-r--r-- 1 root root 2232  6월 23 08:48 cert1.pem
-rw-r--r-- 1 root root 3749  6월 23 08:48 chain1.pem
-rw-r--r-- 1 root root 5981  6월 23 08:48 fullchain1.pem
-rw------- 1 root root 3272  6월 23 08:48 privkey1.pem

 

Let's encrypt 로 생성했다면 필요한 파일은 fullchain1.pem 과 privkey1.pem 두개 입니다.

docker 를 이용해 image-registry 컨테이너를 재가동합니다. 재가동 방식은 기존 image-registry 컨테이너를 삭제하고 재생성 하는 방법입니다.

# docker ps
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                    NAMES
d1fba07b40ef        docker.io/library/registry:2   "/entrypoint.sh /e..."   6 weeks ago         Up 6 weeks          0.0.0.0:5000->5000/tcp   image-registry

 

출력된 CONTAINER ID 를 이용하여 image-registry 컨테이너를 중지하고 삭제합니다.

# docker stop d1fba07b40ef
d1fba07b40ef

# docker rm d1fba07b40ef
d1fba07b40ef

 

다시 생성합니다.

# docker run --name image-registry --restart=always -p 5000:5000 \
    -v /opt/registry/auth:/auth \
    -v /opt/registry/certs:/certs \
    -v /opt/registry/data:/var/lib/registry \
    -e "REGISTRY_AUTH=htpasswd" \
    -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
    -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
    -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain1.pem \
    -e REGISTRY_HTTP_TLS_KEY=/certs/privkey1.pem \
    -e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true \
    -d docker.io/library/registry:2

1c3e5d916cf9665658e9828db7ca973062dc4fa4bdc8fb2a0d5b9fe110883045

 

이제 Registry 이미지가 잘 다운로드 되는지 테스트 하는 방법은 Pod 를 직접 생성해본다거나, 다음과 같이 docker images 로 출력되는 REPOSITORY 중에 하나를 받아보는 것입니다.

# docker pull default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/python

 

반응형

댓글()