Canvas 1 Layer 1

도커 레지스트리: 프라이빗 도커 이미지 저장소
설치부터 S3 연동까지

들어가며

도커docker의 장점 중 하나는 빌드한 이미지를 쉽게 공유할 수 있다는 점입니다. 도커에서는 이러한 장점을 살리기 위해 이미지를 공유할 수 있는 공식 저장소를 제공하고 있습니다. 공식 저장소에는 프론트엔드 애플리케이션, 데이터베이스, 백엔드 서버 애플리케이션 등 이미 많은 도커 이미지들이 공유되고 있습니다.

도커 저장소에 공개된 이미지를 활용해보신 분들이라면 자신만의 이미지를 저장하는 서버를 가지고 싶어질 것입니다. 이 글에서는 프라이빗하게 이미지를 공유할 수 있는 위한 도커 레지스트리Docker Registry 서버에 대해서 소개하고자 합니다.

도커 레지스트리 설치

도커 레지스트리는 도커 이미지를 공유하기 위한 서버 애플리케이션입니다. 흥미롭게도 도커 레지스트리 역시 도커 이미지 빌드를 위한 Dockerfile을 깃허브GitHub 저장소에서 제공하고 있습니다. 그리고 이 Dockerfile로 빌드된 이미지를 도커 공식 저장소에서 제공하고 있습니다. 여기서는 공식 저장소에서 제공하는 이미지를 통해서 도커 레지스트리를 실행해보겠습니다.

도커 설치

여기서는 도커가 이미 설치되어있다고 가정하겠습니다. 설치되어있지 않다면 도커를 설치해주세요. 우분투Ubuntu 14.04 LTS에서는 다음 명령어로 도커를 설치할 수 있습니다.

도커 레지스트리 설치

먼저 docker pull 명령어로 공식 저장소에서 도커 레지스트리 이미지의 최신 버전을 받아옵니다.

이미지를 받아왔으면 images 명령어로 이미지가 정상적으로 저장되었는지 확인합니다.

도커 레지스트리 실행

이미지가 정상적으로 받아졌으면 실행은 간단합니다. 여기서 --name은 이름을 지정하는 플래그이며, -d는 백그라운드에서 실행, -p {host_port}:{container_port}는 포트 노출을 위한 맵핑을 의미합니다. 마지막 registry는 실행하고자하는 이미지의 이름입니다.

registry 이미지로 도커를 실행하면 8fa28fa로 시작하는 컨테이너 아이디를 볼 수 있습니다. 컨테이너 아이디는 그 때 그 때 다릅니다. 컨테이너가 정상적으로 실행됐는 지 확인하기 위해 ps -l 명령어를 실행합니다. -l 플래그는 가장 최근에 실행한 컨테이너를 보여줍니다.

정상적으로 실행되었다면 컨텐이너 목록에서 레지스트리 서버를 확인할 수 있습니다.

도커 레지스트리는 도커 명령어를 통해서 사용하는 게 기본입니다만, 5000번 포트를 통해 HTTP로 기본적인 API를 제공하고 있습니다. 이를 통해서 서버가 정상적으로 실행되었는지 확인해보겠습니다.

도커 레지스트리의 실행환경과 버전을 확인할 수 있습니다. 이걸로 도커 레지스트리 서버가 정상적으로 작동중인 것을 확인할 수 있습니다.

도커 레지스트리 사용하기

아무것도 설정하지 않았다면 도커 레지스트리는 기본적으로 로컬 디스크에 데이터를 저장합니다. config_sample.yml을 참조해주세요.

사용자 도커 이미지 만들기

기본적으로 프라이빗 레지스트리는 자신이 직접 빌드한 이미지를 저장하기 위해서 사용합니다. 이미 가지고 있는 이미지를 사용해도 무방합니다만 여기서는 간단한 샘플 이미지를 하나 생성해보겠습니다. 임의의 디렉토리에 아래 내용을 복사해 Dockerfile을 만듭니다.

FROM ubuntu:12.04
MAINTAINER Daekwon Kim <propellerheaven@gmail.com>
CMD echo 'Hello, Docker!'

Dockerfile을 만들었으면 이 파일을 빌드해서 새로운 이미지를 생성하겠습니다. 아래 내용을 참고해서 빌드합니다. 여기서 -t 플래그를 통해서 이미지의 이름을 지정할 수 있습니다.

이미지가 정상적으로 빌드되었는지 images 명령어로 확인해봅니다.

이미지가 정상적으로 빌드되었으니 실행해보겠습니다. 간단히 run에 이미지 이름을 넘겨줍니다.

Dockerfile을 유심히 보셨다면 눈치채셨겠지만, Hello, Docker!를 출력하는 단순한 이미지입니다. 중요한 점은 echo 명령어는 실행하자마자 종료되는 프로세스이기 때문에 docker ps에서 이 컨테이너를 확인할 수 없다는 점입니다. 컨테이너에서는 자신에게 주어진 주 프로세스가 종료되면 컨테이너도 따라 종료됩니다. 이를 확인하기 위해서 -a 플래그를 사용합니다.

도커 레지스트리에 푸시(Push)하기

이미지가 정상적으로 작동하는 것을 확인했으니 이제 이미지를 도커 레지스트리에 집어넣어보겠습니다. 먼저 이미지를 도커 레지스트리에 넣기 위해서 이미지에 적당한 이름을 붙여줍니다. docker tag 명령어로 이미지에 새로운 이름을 붙여보겠습니다.

tag 명령어를 실행하면 같은 이미지에 새로운 이름이 부여됩니다. images 명령어로 확인해봅니다.

IMAGE ID에서 확인할 수 있듯이 열거된 두 이미지는 이름만 다른 같은 이미지입니다. 이렇게 / 앞에 도커 레지스트리의 주소를 지정해 이름을 부여하고 push하면 해당하는 도커 레지스토리에 이미지가 업로드됩니다.

출력된 마지막의 주소를 통해서 실제 도커 레지스트리 서버에 이미지가 정상적으로 올라갔는지 확인해봅니다.

이미지 ID에서 확인할 수 있듯이 로컬의 0.0.0.0:5000/hello_docker:latest와 도커 레지스트리에 올린 hello_docker:latest는 같은 이미지입니다.

도커 레지스트리에서 풀(Pull) 받아 실행하기

이제 가장 중요한 부분입니다. 도커 레지스트리에 이미지를 업로드했으니 거꾸로 이 도커 레지스트르에서 이미지를 pull 받아 실행해보도록 하겠습니다. 로컬 도커 서버에 같은 이미지가 있으면 정확한 확인이 안 되니, 로컬에서 실행했던 컨테이너와 이미지를 삭제하겠습니다.

먼저 앞서 실행한 종료 상태에 있는 컨테이너를 삭제해야합니다. 컨테이너가 종료되었더라도 삭제되지 않은 상태로 있으면 컨테이너의 부모 이미지는 삭제할 수 없습니다. 앞서 ps -a 명령어를 참조해 컨테이너를 삭제합니다.

rm 명령어에 컨테이너 이름이나 아이디를 지정해 컨테이너를 삭제합니다. 다음으로 이미지를 삭제합니다.

docker images를 실행해 삭제되었는지 확인해봅니다.

이 상태에서 삭제된 이미지를 사용하면 당연히 실행되지 않겠죠? 하지만 앞서서 도커 레지스트리의 주소를 지정한 이름을 사용하면 도커는 해당하는 주소에 도커 이미지가 있는지 먼저 검색합니다. 공유된 도커 이미지의 실행은 먼저 풀(Pull)을 받고 실행하는 단계를 거칩니다만, 바로 실행(run) 명령어를 사용하면 도커는 자동적으로 해당하는 주소의 이미지를 풀 받고 실행합니다. 여기서는 바로 앞서 푸시한 도커 이미지를 실행하겠습니다.

명령어는 위에서 로컬에 있던 이미지를 실행하는 것과 같습니다. 하지만 실행 과정의 출력을 보면 알 수 있듯이 로컬에 이미지가 없으니 0.0.0.0:5000의 도커 레지스트리에서 이미지를 다운 받는 것을 확인할 수 있습니다. 그리고 마지막에는 정상적으로 이미지가 실행되어 Hello, Docker!가 출력되었습니다!

원격에서 도커 레지스트리 사용하기

이 예제에서는 로컬에서 도커 레지스트리와 도커 실행 서버를 둘 다 운영하고 있어서 실제로 제대로 작동하는 건지 확인하기가 어렵습니다. 가능하다면 자신의 로컬 머신을 외부에 노출시켜서 다른 도커 서버에서 실행해봅니다.

도커 레지스트리 서버에 접속 가능한 도커 서버에서도 로컬에서와 같은 결과를 볼 수 있습니다. *

* 17.231.14.21:5000는 예제로 사용한 주소로 실제로는 동작하지 않습니다. 직접 실행한 도커 레지스트리 서버의 외부 IP로 치환해야합니다.

AWS S3에 도커 이미지 저장하기

이미지를 로컬에 저장하는 것은 여러모로 불편한 일입니다. 도커를 사용해 도커 레지스트리를 실행하는 경우 기본적으로 컨테이너 레이어에 이미지가 저장됩니다. 컨테이너가 종료되면 이미지가 사라질 뿐만 아니라 확장성도 매우 떨어집니다. AWS S3와 같은 외부 저장소를 사용할 수 있다면, 편리할 뿐만 아니라 확작성 면에서도 유리합니다.

하지만 도커 레지스트리는 파이썬Python 플라스크Flask에 기반한 웹 어플리케이션입니다. 따라서 S3에서는 도커 레지스트리를 구동할 수 없습니다. 즉, 도커 레지스트리는 EC2나 로컬 서버를 이용해서 별도로 실행해야합니다. 이 레지스트리 설정에 이미지 저장 공간으로 로컬 드라이브가 아닌 S3 버킷을 지정해두면 해당하는 버킷에 이미지를 저장합니다. 이렇게 설정하면 도커 레지스트리에 이미지를 푸시할 때 도커 레지스트리는 이 이미지를 S3로 복사합니다. S3에 복사되면 아마존은 이 이미지를 안전하게 보관해줍니다.

도커 레지스트리 저장공간으로 S3 설정하기

S3 가입과 버킷 생성법은 별도로 다루지 않습니다. 먼저 s3api 명령어나 aws 웹콘솔에서 S3에 docker-registry라는 새로운 버킷bucket을 만들어줍니다. *

* 아래 이미지에서는 docker-registry라는 이름을 사용하고 있습니다. 하지만 S3의 이름은 모든 사용자에게 공유되기 때문에 적절한 접미사를 붙이는 등 고유한 이름을 붙여주어야합니다.

AWS S3 버핏 생성
AWS S3 버핏 생성

다음으로 아래와 같이 config.yml 파일을 작성합니다. 버핏 이름과 <>로 둘러쌓인 변수들을 자신의 값으로 바꿔줍니다. <SECRET_KEY>에는 임의의 값을 적절히 입력해줍니다. 여기서는 도쿄를 사용하고 있다고 가정하고, s3_region에는 ap-northeast-1을 지정합니다. 이 파일을 적절히 새로운 디렉토리에 저장합니다. 여기서는 /home/nacyot/src/registry-conf/config.yml에 저장한다고 가정합니다.

prod:
    storage: s3
    boto_bucket: docker-registry
    s3_access_key: <S3_ACCESS_KEY>
    s3_secret_key: <S3_SECRET_KEY>
    s3_bucket: docker-registry
    s3_encrypt: true
    s3_secure: true
    s3_region: ap-northeast-1
    secret_key: <SECRET_KEY>
    storage_path: /images

이제 이 설정을 적용해서 도커 레지스트리를 실행할 차례입니다. 이 설정 파일을 컨테이너를 실행해 직접 복사하거나 작성하고 커밋하는 방식으로 설정 파일이 적용된 이미지를 새로 만들 수도 있습니다만, 여기서는 도커 컨테이너에 호스트의 디렉토리를 마운트하는 기능을 사용합니다. -v {HOST_DIR}:{CONTAINER_DIR}과 같이 지정하면 HOST_DIR이 컨테이너 내부의 CONTAINER_DIR에 마운트됩니다. 앞서서 /home/naycot/src/registry-conf에 설정 파일을 넣어뒀으니 컨테이너에서는 /registry-conf 디렉토리를 통해서 config.yml에 접근할 수 있습니다. 다음으로 -e는 컨테이너 내부의 환경 변수를 지정할 수 있습니다. DOCKER_REGISTRY_CONFIG는 설정 파일 위치를 지정하는 환경변수입니다. 다음으로 SETTINGS_FLAVOR는 실행 환경을 선택하는 환경변수입니다. 환경변수들을 아래와 같이 지정하고 컨테이너를 실행합니다.

ps 명령어로 컨테이너가 정상적으로 실행되었는지 확인합니다.

앞서 로컬에서와 마찬가지로 0.0.0.0:5000에 이미지를 푸시해봅니다.

정상적으로 푸시된 것을 확인할 수 있습니다. 이 출력을 봐서는 실제로 이미지가 어디에 저장되었는지 확인하기 어렵습니다. 실제로 s3에 들어가 저장이 되었는지 확인해봅니다.

S3에 도커 이미지를 저장한 결과
S3에 도커 이미지를 저장한 결과

푸시한 이미지들이 S3에 저장되어있는 것을 확인할 수 있습니다. S3 설정을 사용하는 경우 이미지를 어디에 저장하는 지만 차이가 있을 뿐, 풀(Pull)과 실행(Run)은 로컬에서 서버를 실행해서 사용하는 경우와 다르지 않습니다.

마치며

앞서 이야기했듯이 이미지를 쉽게 공유할 수 있다는 건 도커의 큰 장점 중 하나입니다. 공개된 레지스트리 서비스를 사용하는 것도 편리합니다만, 프로덕션 환경에서는 접근이 제한된 레지스트리 서버가 필요합니다. 직접 도커 레지스트리 서버를 운영함으로써 커스텀 이미지를 일괄적으로 관리할 수 있고, 분산된 도커 서버들에서 이를 사용할 수 있습니다.