Docker registry
컨테이너를 이용하여 어플리케이션의 실행환경을 가상화하기 위해서 도커 이미지가 필요한 만큼 이미지의 관리 또한 중요하다. 특히 개발/운영 환경에서 CI/CD 를 적용하여 이미지를 배포 하는 경우에는 이미지를 로컬 환경에 보관하는 것보다 저장가능한 다른 저장소에 보관하는 것이 좋다. 도커 측은 사용자가 컨테이너 생성을 위한 이미지를 저장하고 다른 사용자들과 공유할 수 있도록 컨테이너 이미지에 대한 저장소(이하 registry) 서비스를 제공하고 있다. 이를 통하여 사용자는 쉽게 이미지를 registry에 저장(push)하고 필요한 이미지를 받아올(pull) 수 있다.
이러한 registry 서비스는 공개유형에 따라 public, private 으로 구분 가능하다. public registry의 경우 모든 사람들이 자유롭게 이용할 수 있도록 이미지가 공개되어 있으며, 사용자들은 필요에 따라 자신이 원하는 이미지를 검색하고 해당 이미지를 사용할 수 있다. private registry는 사용자가 자신만의 별도의 registry를 따로 생성하여 custom image들을 보관할 수 있도록 해준다. 여기서는 public/private registry에 대하여 조금 더 다뤄본다.
Docker public registry
도커 측은 docker hub(https://hub.docker.com/) 라는 public registry를 제공한다. 물론 docker hub 의 경우 회원가입/로그인 후에 private한 용도로도 사용할 수 있으나 docker hub 자체는 public registry로서의 성격이 더 크고, 후술할 docker registry 가 private registry 로서의 기능을 제공하고 있으므로 여기서는 public registry 로서의 docker hub 만을 알아보기로 한다.
docker hub를 통하여 사용자는 이미지를 조회/검색할 수 있으며, 특정 이미지에 대한 description을 확인할 수 있다. 또한 CLI 환경에서도 docker search 명령어를 이용할 경우 docker hub에서 사용되는 이미지를 조회할 수 있다. 아래 화면은 각각 docker hub와 docker client를 이용하여 nginx 이미지를 조회한 예이다.
[그림1 : docker hub / docker search 등을이용하여 nginx 이미지를 조회한 예]
이렇게 조회한 이미지의 경우 CLI 환경에서 docker pull 명령어로 누구나 해당 이미지를 조회할 수 있다.
Docker private registry
위와 같이 public registry 인 docker hub를 이용하여 자주 사용되는 이미지들을 쉽게 받아서 실행 시킬 수 있지만, 컨테이너를 이용하여 이미지를 받고 또 받은 이미지를 이용하여 새로운 이미지를 생성하다보면 타인에게 공개되지 않고 자신만이 사용할 수 있는 이미지들도 존재하게 된다. 이러한 이미지는 public registry에 올리기 어려운데 이럴 때 사용자가 자신의 이미지를 저장하고 특정 개인/집단에게만 공유할 수 있도록 해주는 private registry를 사용할 수 있다.
private registry는 host PC에 background daemon으로 구동되는 것이 아니라, host PC에 docker 플랫폼 위에 도커 컨테이너로서 구동된다. 즉, 컨테이너 이미지를 저장하는 저장소 또한 컨테이너로 구동되어지는 방식이다. 당연히 host PC에는 Docker 가 필수적으로 설치되어 있어야 하며, registry 컨테이너를 구동하기 위한 docker image가 필요하다. 해당 이미지는 docker hub에서 쉽게 조회해서 받아올 수 있다.
아래와 같은 명령어를 사용하여 registry 이미지를 조회하고 docker hub를 통해서 내려받자.
1 | $ docker search registry |
받아온 이미지로 docker registry container를 구동하기 전에 알아둬야 할 사항들이 있다. 먼저 registry는 내부적으로 5000번 포트를 사용한다. 컨테이너로 registry 를 구동한 후에 외부에서 해당 컨테이너에 접속하기 위해서 5000번 포트를 노출시켜줄 필요가 있다.
또한 저장소 성격을 가진 컨테이너이므로 해당 컨테이너가 삭제 될 경우 저장되어 있는 내용(여기서는 도커 이미지)이 모두 지워지는 것을 방지하기 위하여 미리 컨테이너 내부의 실제 저장 파일 위치를 docker volume 으로 연결해줘야 한다.
1 | $ docker run -d --name=private_registry -p 5000:5000 -v /test/registry_data:/var/lib/registry registry:latest |
이제 컨테이너로 private registry를 구동하였다. 이 registry는 로컬 port 5000번으로 노출되어 있어, 해당 포트를 통해 registry pull/push를 사용할 수 있다. 먼저 호스트에 있는 debian 이미지를 로컬 url 로 태그를 변경한 후에 다시 push 보면 아래와 같이 registry 에 이미지를 저장할 수 있다.
1 | $ docker tag debian:latest localhost:5000/debian:latest |
이제 호스트에 debian 이미지가 삭제되어도, 컨테이너 저장소 안에 해당 이미지가 존재하므로, docker pull 명령어를 이용하여 해당 이미지를 언제든지 불러올 수 있다. 위와 같은 방식을 이용하여 private registry를 docker container의 형태로 구동하고, custom 이미지를 자유롭게 저장하고 불러올 수 있다.
Docker registry config
docker registry를 사용하면, private 한 환경에서 image registry를 구축할 수 있다. 이번에는 단순하게 registry를 사용하는 것 뿐만 아니라 registry 를 배포하고 설정을 변경하여 실제 개발/운영 환경에서 사용하기 위한 추가사항에 대하여 다루어본다.
1. Registry 를 항상 재시작 하도록 설정
Docker registry 컨테이너가 구동되는 호스트가 재부팅 되거나, 호스트 내에서 docker process 가 재시작 될 경우 자동으로 registry 컨테이너가 구동되도록 할 경우, container 구동(run)시에 ‘–restart=always’ 옵션을 추가할 수 있다. public registry를 사용하지 않고, 로컬 환경이나 private 환경에서 고정적으로 registry를 사용하는 경우 이 옵션을 부여하여, 호스트의 docker 환경이 재부팅 되더라도 항상 registry가 구동되어 있도록 설정해주자. (사용 예는 아래 3번 예제와 함께 표시한다.)
2. Registry 의 포트를 지정하여 구동
registry는 기본적으로 5000번 포트를 사용하여 서비스를 노출한다. 따라서 registry를 사용하기 위해서는 구동시에 port 옵션으로 5000번 포트를 그대로 노출하여 사용하는 것이 일반적이다. 하지만 특별한 경우에 따라서 로컬 환경에서 이미 5000번 포트를 사용하는 경우, container내부의 5000번 포트와 로컬환경의 다른 포트를 연결해줘야 한다. 물론 이렇게 다른 포트를 지정할 수도 있지만, 직관성을 위하여 컨테이너와 호스트에서 동일한 포트를 사용하고자 할 경우 컨테이너 내부의 환경변수로 REGISTRY_HTTP_ADDR 을 지정하여 내부의 registry 포트를 변경하고 동일한 포트로 호스트 포트를 바인딩 할 수도 있다. 아래 3번 예제를 참고하자.
3. Volume directory를 지정
registry 는 기본적으로 저장소 역할을 하기 때문에 컨테이너 내부에 계속 해서 데이터(이 경우는 docker image)가 적재 되는 구조이다. 기본적으로 컨테이너 내부의 /var/lib/registry 에 적재되는 데이터는 컨테이너가 삭제될 경우 컨테이너와 함께 삭제되어 유지되지 않는다. 따라서 registry 의 적재되는 데이터는 docker volume 명령어를 이용하여 호스트 환경에 영구적으로(persistent) 유지해 주는 것이 좋다. restart 옵션과 함께 사용할 경우, 호스트 docker 서비스가 중지 되는 경우에도 재기동 후에 registry 안의 데이터를 유지할 수 있다. 컨테이너 내부에 적재되는 데이터는 휘발성이므로, 비단 registry 이미지가 아니더라도, 데이터 성격의 컨테이너의 경우 항상 volume 옵션을 사용해주자. (적재되는 경로는 config 파일에 지정하여 변경 가능하다)
1 | $ docker run -d --name=registry --restart=always -e REGISTRY_HTTP_ADDR=0.0.0.0:5007 -p 5007:5007 -v |
4. 외부에서 registry 에 접근가능하도록 설정
앞에서의 방법을 이용하여 registry를 구동하는 경우 기본적으로 localhost 로만 접근이 가능하다. 즉, 모든 이미지가 local에 있으며 이미지의 full name은 localhost:5000/image:tag 등으로 사용된다. 하지만 아무리 private한 환경에서 사용하기 위한 registry라고 해도 이렇게 로컬 호스트에서만 접근이 가능할 경우 활용성이 매우 떨어진다. 이번에는 private 네트워크 내부의, registry가 떠있는 host로 접근이 가능한, 다른 서버에서 registry를 이용하여 이미지를 저장하고 받아올 수 있도록 registry를 외부로 노출해보자. 먼저 registry가 구동되어 있는 host에 대한 crt 파일과 key 파일을 준비한다. (해당 파일을 생성하는 과정에 대해서는 여기서 다루지 않으니 다른 관련 자료를 참조하자.) 2개의 인증서 파일이 /certs 경로에 있다고 가정할 경우 아래와 같은 구동 명령어를 사용하여 registryf를 구동한다.
1 | docker run -d \ |
위와 같이 구동할 경우 registry 호스트에 접근가능한 다른 네트워크에서 인증서에 등록된 도메인으로 docker pull/push 등이 가능하다.
5. registry 접근제어
안전성이 보증되는 네트워크에서 구동되는 경우가 아니라면 registry 에 대한 접근제어 또한 필요하다. docker registry는 기본적인 패스워드 기반의 인증을 제공하고 있다. 이번에는 registry 내부에서 이미 설치되어 있는 htpasswd 유틸리티를 이용하여 registry 접근 제어를 구현해보자. 먼저 registry 내부의 htpasswd 명령어를 사용하기 위해 아래의 명령을 실행한다. 해당 명령은 아이디와 패스워드를 각각 ‘admin’, ‘password’로 지정하여 특정 위치에 해당 계정 정보와 관련된 파일을 생성해준다.
1 | $ mkdir $PWD/auth |
이제 생성된 파일을 이용하여 registry를 구동한다.
1 | $ docker run -d --name registry \ |
위와 같이 구동할 경우, 지정한 아이디와 패스워드를 이용하여 아래와 같이 로그인이 가능하다.
1 | $ docker login localhost:5000 |