Profile picture

[Docker] 도커 프라이빗 레지스트리(Docker Private Registry) 서버 구축

JaehyoJJAng2023년 07월 10일

▶︎ Image registry

image
이미지 레지스트리는 이미지를 저장하는 저장소이다.

아마 'Github'를 들어봤을거다.

Github는 코드를 저장하는 저장소인데 개발자는 Github를 사용해서 자신의 소스 코드를 쉽게 보관하고

다른 개발자들과 공유할 수 있다.

Image Registry도 Github와 매우 비슷하다.

가장 많이 사용되는 Public Image Registry는 'Docker Hub'인데

github가 코드를 저장하는 저장소라면 docker hub는 이미지를 저장하는 저장소라고 보면 될 것 같다.

Docker hub에는 소스 코드를 작성해서 만들어진 애플리케이션과 그 애플리케이션을 실행할 수 있는 환경이 모두 포함되어 있는 이미지를 저장하는 곳이다.


image
이미지 레지스트리는 기본적으로 이미지를 다운로드하고 업로드 하는 기능을 제공한다.

그리고 이미지 레지스트리에 있는 이미지들을 검색하고 필요한 이미지를 찾아볼 수 있다.

이미지 레지스트리는 이미지의 버전을 관리하기 때문에 사용자는 이미지를 다운로드할 때 특정 버전의 이미지를 지정해서 다운받을 수도 있다.

또한, 원하는 사용자만 이미지를 다운로드 받도록 인증 처리와 권한 관리 기능도 제공하며

안전한 이미지를 다운로드 받을 수 있도록 업로드된 이미지의 보안을 검증하는 기능 또한 제공한다.

마지막으로 DevOps가 파이프라인 기능과 연계해서 이미지를 업로드 했을 때 자동으로 배포가 이루어질 수 있도록 하는 연계 기능이나 알림 기능도 제공한다.


‣ 이미지 저장 공간

이미지가 저장되는 공간은 크게 세 가지로 분류 해볼 수 있겠다.

먼저 도커가 설치되어 있는 호스트 머신의 로컬 스토리지이다.
image


그리고 온라인 저장소는 크게 두 가지로 종류로 나눌 수 있는데

주로 기업에서 많이 사용하는 프라이빗 레지스트리와 도커 허브 같은 퍼블릭 레지스트리가 그 예시가 되겠다.


image
docker run nginx에서 이미지의 이름을 지정하면 먼저 로컬 스토리지에서 해당하는 이미지가 있는지 검색한다.
(여기서 로컬 스토리지는 도커를 실행하는 호스트 OS의 특정 폴더를 의미함(/var/lib/docker))

그래서 이 로컬 스토리지에 이미지가 있으면 바로 실행이 되고,

스토리지에 이미지가 없으면 호스트 외부의 온라인 레지스트리에서 이미지를 로컬 스토리지로 다운로드 받는다.
image


image
그리고 다운로드 받은 로컬 스토리지의 이미지를 사용해서 컨테이너를 실행하게 되는거다.

그리고 이제 다음부터는 nginx 이미지를 가지고 컨테이너를 생성할 일이 생기면 온라인 레지스트리에서 이미지를 검색하지 않고

로컬 스토리지에서 nginx 이미지를 검색해 바로 컨테이너가 생성되게 된다.


‣ 이미지이름 작명 방법

도커 이미지 네이밍 규칙은 이미지를 만들고 공유하는데에 있어 꼭 필요한 정보이기 때문에 꼼꼼하게 알아보도록 하자.


image
이미지 이름은 크게 레지스트리 주소, 프로젝트 명, 이미지 명, 이미지 태그로 구성된다.

레지스트리 주소는 어떤 레지스트리를 사용할지 지정한다.

위에서 말했듯이 도커 허브 말고도 레지스트리가 여러 개 있을 수도 있기 때문에

이미지를 어떤 레지스트리에서 가져올지 지정해주어야 한다.

이 레지스트리 주소가 비어있는 경우에는 기본 값으로 지정된 레지스트리(docker.io)가 사용된다.
image


만약 내 개인 레지스트리 서버 주소가 wttwiki.com이고 이 레지스트리에서 이미지를 다운받고 싶다면

맨 앞에 wttwiki.com이라는 레지스트리의 주소를 입력해주어야 한다.

아무것도 적지 않으면 도커 허브의 레지스트리 주소인 docker.io가 기본 값으로 사용된다.


프로젝트명은 이미지를 보관하는 폴더 같은 개념이다.

레지스트리마다 이 프로젝트를 정의하는 방식이 저마다 다를 수 있는데

도커 허브의 경우에는 가입한 사용자의 계정명이 프로젝트 명이 된다.

그리고 이미지명은 다운로드 받을 이미지명을 의미하고, 이미지 태그는 이미지가 가지고 있는 버전을 의미한다.


‣ Official image

그런데 nginx 이미지의 경우

레지스트리 / 프로젝트명 / 이미지 태그가 제외된 채 이미지명만 덩그러니 써도 컨테이너가 정상적으로 생성이 되는데 왜 그런걸까?

image
도커는 도커사가 직접 검증한 이미지는 오피셜 이미지로 제공하고 있는데

이 오피셜 이미지는 라이브러리라는 프로젝트에서 관리하고 있다. 그래서 별도로 계정명을 지정하지 않으면 라이브러리가 기본 값으로 적용된다.

즉, 공식 nginx 이미지는 아래와 같은 축약된 이미지명이 된다는 뜻이다.

docker.io/library/nginx:latest

▶︎ 레지스트리 구축

  • 개인용, 테스트용으로 제일 많이 사용되는 Private Registry인 docker.io/registry를 구축해보자.

‣ 서버 스펙

  • Ubuntu 18.04
  • Docker 18.09
  • Docker-Compose v2.15.1

‣ Registry 구축

1. docker-compose.yaml 파일을 작성할 디렉토리 생성

$ mkdir -p /docker/docker-registry
$ cd /docker/docker-registry
$ vim docker-compose.yaml

2. docker-compose.yaml 작성

version: "3"

services:
  docker-registry:
    image: registry:latest
    restart: always
    ports:
      - "5001:5000"
    volumes:
      - "regi-data:/var/lib/registry/docker/registry/v2"
    container_name: registry

volumes:  
  regi-data: {}

registry 컨테이너가 종료되면 컨테이너 내부의 이미지 레지스트리들이 전부 날라가기 때문에 이미지 레지스트리 저장 경로인 /var/lib/registry/docker/registry/v2를 도커 볼륨에 맵핑해주었다.


3. docker-compose 실행

$ docker-compose up -d --build

4. Listen Port 확인

$ netstat -anp | grep '5001'
tcp6       0      0 :::5001                 :::*                    LISTEN      9389/docker-proxy

‣ insecure-registries

  • Pull (다운로드) 하려는 서버에 설정함

/etc/docker/daemon.json 파일을 열어 아래 insecure-registries 부분을 추가한다.
registry 실행 시 포워딩된 Port가 5001번이기 때문에 5001번 포트를 입력하면 된다.

{
  # ...
  "insecure-registries" : [
      "localhost:5001"
  ],
}

‣ Push / Pull 테스트

Registry 서버 구축이 완료되었으니 간단한 Dockerfile을 생성하여 Push / Pull 테스트를 진행해보자.


‣ Push 테스트

1. Dockerfile 작성

FROM alpine:latest
CMD ["echo", "Hello World"]

2. 이미지 빌드

$ docker build --tag yshrim12/helloworld .

3. Image 태그 생성

$ docker tag yshrim12/helloworld localhost:5001/helloworld:0.1

4. 생성된 태그 확인

$ docker images localhost:5001/helloworld:0.1
REPOSITORY                  TAG       IMAGE ID       CREATED       SIZE
localhost:5001/helloworld   0.1       370770081562   6 weeks ago   7.66MB

5. Registry에 Push로 이미지 업로드

$ docker push localhost:5001/helloworld:0.1
The push refers to repository [localhost:5001/helloworld]
b2191e2be29d: Pushed
0.1: digest: sha256:b0b7cb83d326af085d96165b4a3defc585c16ad07bbd55ca520cf87bef07ac3a size: 527

‣ Pull 테스트

  • 위에서 업로드된 localhost:5001/helloworld:0.1 이미지를 Pull로 받아와보자.

1. 그 전에 태그로 생성된 localhost:5001/helloworld:0.1 이미지를 삭제하자

$ docker rmi localhost:5001/helloworld:0.1
Untagged: localhost:5001/helloworld:0.1
Untagged: localhost:5001/helloworld@sha256:b0b7cb83d326af085d96165b4a3defc585c16ad07bbd55ca520cf87bef07ac3a

2. Pull로 다운로드 받아보자

$ docker pull localhost:5001/hellworld:0.1
0.1: Pulling from helloworld
Digest: sha256:b0b7cb83d326af085d96165b4a3defc585c16ad07bbd55ca520cf87bef07ac3a
Status: Downloaded newer image for localhost:5001/helloworld:0.1
localhost:5001/helloworld:0.1

3. 마지막으로 받아온 이미지를 컨테이너로 실행해 테스트해보자

$ docker run localhost:5001/helloworld:0.1
Hello World

정상적으로 작동한다.


‣ 배포된 이미지는 어디로?

docker push를 사용하여 로컬 Registry 서버에 이미지를 업로드했을 때 업로드된 이미지들은 어디서 확인이 가능한걸까?
registry-구축하기 여기서 작성했던 docker-compose.yaml의 volumes 항목을 보도록 하자.

    volumes:
      - "regi-data:/var/lib/registry/docker/registry/v2"

Push된 이미지들은 도커 볼륨에 매핑되어 컨테이너가 다운되더라도 레지스트리들이 보존된다. 어떤 이미지들이 업로드 되었는지 궁금하다면 컨테이너의 맵핑된 볼륨을 찾아보면 될 것이다.

$ docker exec registry ls -lh /var/lib/registry/docker/registry/v2/repositories
drwxr-xr-x    5 root     root        4.0K Sep 21 08:20 helloworld

Loading script...