Docker Registry UI 구축 삽질기

SB신범
5분 읽기
조회수 로딩 중...

Docker Registry UI 구축 삽질기

들어가며

개인 프로젝트에서 Docker Registry를 구축하고, 이를 편리하게 관리하기 위해 Registry UI를 연동하는 과정에서 여러 난관에 부딪혔습니다. 이 글에서는 Docker Registry와 Registry UI를 구축하면서 겪은 문제들과 해결 방법을 공유하고자 합니다.

초기 설정

처음에는 간단한 Docker Registry와 Joxit의 Docker Registry UI를 연동하는 기본적인 Docker Compose 파일을 작성했습니다:

yaml
1services: 2 # Docker Registry 3 registry: 4 image: registry:2 5 ports: 6 - "5000:5000" 7 restart: always 8 volumes: 9 - ./registry-data:/var/lib/registry 10 - ./registry-config:/etc/docker/registry 11 environment: 12 REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry 13 14 # Registry UI 15 registry-ui: 16 image: joxit/docker-registry-ui:latest 17 ports: 18 - "8180:80" 19 environment: 20 - REGISTRY_URL=http://registry:5000 21 - REGISTRY_TITLE=My Private Registry 22 - SINGLE_REGISTRY=true 23 depends_on: 24 - registry

개선 사항 적용 시도

기본 설정으로는 Registry UI의 기능이 제한적이었고, 이미지 삭제 기능이나 컨텐츠 다이제스트 표시 등 추가 기능이 필요했습니다. 그래서 다음과 같은 향상된 설정을 적용하고자 했습니다:

yaml
1version: '3.8' 2services: 3 registry-ui: 4 image: joxit/docker-registry-ui:main 5 restart: always 6 ports: 7 - 80:80 8 environment: 9 - SINGLE_REGISTRY=true 10 - REGISTRY_TITLE=Docker Registry UI 11 - DELETE_IMAGES=true 12 - SHOW_CONTENT_DIGEST=true 13 - NGINX_PROXY_PASS_URL=http://registry-server:5000 14 - SHOW_CATALOG_NB_TAGS=true 15 - CATALOG_MIN_BRANCHES=1 16 - CATALOG_MAX_BRANCHES=1 17 - TAGLIST_PAGE_SIZE=100 18 - REGISTRY_SECURED=false 19 - CATALOG_ELEMENTS_LIMIT=1000 20 container_name: registry-ui 21 22 registry-server: 23 image: registry:2.8.2 24 restart: always 25 environment: 26 REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin: '[http://registry.example.com]' 27 REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods: '[HEAD,GET,OPTIONS,DELETE]' 28 REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials: '[true]' 29 REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers: '[Authorization,Accept,Cache-Control]' 30 REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers: '[Docker-Content-Digest]' 31 REGISTRY_STORAGE_DELETE_ENABLED: 'true' 32 volumes: 33 - ./registry/data:/var/lib/registry 34 container_name: registry-server

문제 1: 배열 형태의 환경 변수 설정

첫 번째 문제는 Docker Compose에서 배열 형태의 환경 변수를 설정하는 것이었습니다. 특히 REGISTRY_HTTP_TLS_CLIENTCAS 같은 환경 변수는 배열로 설정해야 했는데, Docker Compose에서는 이를 직접 지원하지 않았습니다.

시도한 방법:

yaml
1environment: 2 REGISTRY_HTTP_TLS_CLIENTCAS: 3 - /certs/ca.crt

오류 메시지:

Service 'registry' configuration key 'environment' 'REGISTRY_HTTP_TLS_CLIENTCAS' contains ['/certs/ca.crt'], which is an invalid type, it should be a string, number, boolean or a null

그래서 문자열로 변경해봤지만:

yaml
1environment: 2 REGISTRY_HTTP_TLS_CLIENTCAS: /certs/ca.crt

또 다른 오류가 발생했습니다:

registry_1 | configuration error: error parsing /etc/docker/registry/config.yml: yaml: unmarshal errors: registry_1 | line 1: cannot unmarshal !!str `/certs/...` into []string

해결책:

GitHub 이슈를 검색한 결과, 다음과 같은 세 가지 해결 방법을 찾았습니다:

  1. 인덱싱된 환경 변수를 사용하는 방법:
yaml
1environment: 2 REGISTRY_HTTP_TLS_CLIENTCAS_0: /certs/ca.crt
  1. YAML 배열 표기법을 사용하는 방법:
yaml
1environment: 2 REGISTRY_HTTP_TLS_CLIENTCAS: ' - /certs/ca.crt'
  1. config.yml 파일을 직접 생성하여 볼륨으로 마운트하는 방법:
yaml
1volumes: 2 - ./registry-config/config.yml:/etc/docker/registry/config.yml

문제 2: CORS 설정

Registry UI가 Registry API에 접근할 때 CORS 오류가 발생했습니다. Registry 서버에서 CORS 허용 설정이 필요했습니다.

원래 설정:

yaml
1REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin: '[http://registry.example.com]'

모든 오리진 허용으로 변경:

yaml
1REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin: '["*"]'

환경변수 설정시에, cors 설정할때에 꼭 더블 쿼테이션 처리 해주어야 합니다. 안그러면 계속 오류나더라구요.

CORS를 모든 오리진에서 허용하려면 대괄호 안에 별표를 넣는 형식을 사용해야 했습니다. 이는 Registry 내부에서 YAML 배열로 파싱되는 방식 때문입니다.

최종 Docker Compose 파일

여러 문제를 해결한 후 최종적으로 완성된 Docker Compose 파일은 다음과 같습니다:

yaml
1version: '3.8' 2services: 3 # Docker Registry 4 registry: 5 image: registry:2.8.2 6 ports: 7 - "5000:5000" 8 restart: always 9 volumes: 10 - ./registry-data:/var/lib/registry 11 - ./registry-config:/etc/docker/registry 12 environment: 13 REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry 14 REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin: '[*]' 15 REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods: '[HEAD,GET,OPTIONS,DELETE]' 16 REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials: '[true]' 17 REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers: '[Authorization,Accept,Cache-Control]' 18 REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers: '[Docker-Content-Digest]' 19 REGISTRY_STORAGE_DELETE_ENABLED: 'true' 20 container_name: registry-server 21 22 # Registry UI 23 registry-ui: 24 image: joxit/docker-registry-ui:main 25 ports: 26 - "8180:80" 27 restart: always 28 environment: 29 - SINGLE_REGISTRY=true 30 - REGISTRY_TITLE=My Private Registry 31 - DELETE_IMAGES=true 32 - SHOW_CONTENT_DIGEST=true 33 - NGINX_PROXY_PASS_URL=http://registry:5000 34 - SHOW_CATALOG_NB_TAGS=true 35 - CATALOG_MIN_BRANCHES=1 36 - CATALOG_MAX_BRANCHES=1 37 - TAGLIST_PAGE_SIZE=100 38 - REGISTRY_SECURED=false 39 - CATALOG_ELEMENTS_LIMIT=1000 40 depends_on: 41 - registry 42 container_name: registry-ui 43 44 # Gitea Runner 45 runner: 46 image: docker.io/gitea/act_runner:nightly 47 network_mode: "host" # 호스트 네트워크 사용 48 environment: 49 CONFIG_FILE: /config.yml 50 GITEA_INSTANCE_URL: "${INSTANCE_URL}" 51 GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}" 52 GITEA_RUNNER_NAME: "${RUNNER_NAME}" 53 GITEA_RUNNER_LABELS: "${RUNNER_LABELS}" 54 volumes: 55 - ./config.yml:/config.yml 56 - ./data:/data 57 - /var/run/docker.sock:/var/run/docker.sock 58 depends_on: 59 - registry

삽질 후기

Docker Registry와 Registry UI를 구축하는 과정은 예상보다 복잡했지만, 결국 모든 문제를 해결하고 원하는 기능이 동작하는 시스템을 구축할 수 있었습니다. 이 글이 비슷한 문제로 고민하는 분들에게 도움이 되었으면 합니다.

Docker 환경 구성, 특히 레지스트리 관련 설정에서는 세부적인 문법과 표현 방식이 중요하며, 때로는 직관적이지 않은 방식으로 문제를 해결해야 할 때도 있다는 것을 배웠습니다.