Docker Registry 는 Docker 이미지를 업로드 하거나, 다운로드하여 컨테이너를 생성하는 등 이미지 저장소의 역할을 담당합니다. Docker Hub 와 같이 알려진 공개 Docker Registry 말고, 개인적으로 사용 가능한 Docker Registry 를 직접 만들어 보겠습니다.
보통은 Private Registry 라고 하며 Kubernetes 내에서 생성하고 사설 네트워크로 연결하도록 구성하지만, 여기에서는 별도의 단독 서버 1대 (공인IP) 로만 구성할 예정입니다. Registry 서버가 Kubernetes Cluster 와 동일한 스위치 내에 위치한다면 방화벽을 설치함으로써 Private Registry 과 같은 형태로 만들 수 있습니다. 이런 형태로 서비스에 적용할 예정이라면 스토리지 여러대로 GlusterFS 나 Ceph 를 구성하고 별도로 마운트하고 도커 서비스를 구동할 서버 1대로 구성하면 됩니다.
다시 말씀 드리면, 두가지 방식중 아래 방식으로 진행합니다.
- Kubernetes 설치, 스토리지 준비, PV 및 PVC 생성, Registry Pod 생성
- Docker 설치, Registry Container 생성
[환경 및 사전준비]
OS : Ubuntu 22.04
/data 디렉토리 생성 (로컬 호스트의 이미지 저장소)
1. SSL 인증서 생성
Registry 를 사용할때 파일을 업로드 하거나 다운로드 하게되는데, 이때 암호화 전송이 필요합니다.
(암호화 전송 없이 http 프로토콜을 사용하는 옵션도 있긴 합니다)
인증서가 없을 경우, Let's encrypt SSL 에서 무료 인증서를 발급받을 수 있습니다.
운영체제에 따라 인증서 발급 명령이 다르므로 아래 포스팅을 확인하여 자신의 운영체제에 맞는 명령을 참고하시기 바랍니다.
https://sysdocu.tistory.com/search/let's%20encrypt
발급 방법은 위 포스팅에 있으므로 여기에서는 생략하고 넘어가겠습니다.
이제 도메인 인증서를 생성하였고, 인증서를 master 서버의 /root/certs 디렉토리에 복사해 두었습니다.
- 도메인 : registry.az1.sysdocu.kr
- 인증서 파일 위치 : /opt/registry/certs/
2. Docker 설치
Registry 서비스는 Docker Registry 컨테이너를 이용할 것이기 때문에 Docker 패키지를 설치해야 합니다.
패키지 목록을 최신화하고 업그레이드 합니다.
# apt -y update
# apt -y upgrade
# apt -y install apt-transport-https ca-certificates curl gnupg lsb-release
Docker 공식 GPG 를 설치합니다.
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg |gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Docker 공식 저장소를 추가합니다.
# echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" |tee /etc/apt/sources.list.d/docker.list > /dev/null
Docker 를 설치하고 확인합니다.
# apt -y update
# apt -y install docker-ce docker-ce-cli containerd.io
# docker --version
Docker version 24.0.6, build ed223bc
3. Registry 설치 및 가동
Docker Hub 에서 Docker Registry 최신버전 이미지를 다운로드 합니다.
# docker pull registry:latest
latest: Pulling from library/registry
7264a8db6415: Pull complete
c4d48a809fc2: Pull complete
88b450dec42e: Pull complete
121f958bea53: Pull complete
7417fa3c6d92: Pull complete
Digest: sha256:d5f2fb0940fe9371b6b026b9b66ad08d8ab7b0d56b6ee8d5c71cb9b45a374307
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
다운로드 된 이미지를 확인합니다.
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry latest 0030ba3d620c 3 weeks ago 24.1MB
Registry 에 접근할 사용자를 생성합니다.
사용자 생성 방식은 htpasswd 를 이용하였습니다.
# apt -y install apache2-utils
# mkdir -p /opt/registry/auth
# htpasswd -c -b -B /opt/registry/auth/htpasswd sysdocu 12345678
Adding password for user sysdocu
이제 Registry Docker 이미지, SSL 인증서, 사용자 계정이 준비되었습니다.
컨테이너를 다음과 같은 명령으로 가동합니다.
# docker run --name MyRegistry --restart=always -p 5000:5000 \
-v /opt/registry/auth:/auth \
-v /opt/registry/certs:/certs \
-v /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 registry
* 참고
-v: command not found, -e: command not found 등의 에러 출력시 행 사이에 줄이 떨어져 있는 것이므로 메모장에 기입해 빈 행을 없애거나 역슬래시를 제거하여 한줄 명령으로 사용하면 됩니다.
* 설명
--name MyRegistry : 실행되는 컨테이너의 이름을 MyRegistry 로 설정합니다.
--restart=always : 컨테이너가 종료되거나 실패할 경우 자동으로 다시 시작하도록 설정합니다.
-p 5000:5000 : 호스트의 포트 5000 과 컨테이너의 포트 5000 을 연결하여 Registry 에 엑세스할 수 있게 합니다.
-v /opt/registry/auth:/auth : 호스트의 /opt/registry/auth 디렉토리와 컨테이너 내의 /auth 디렉토리를 볼륨 마운트합니다. 이 디렉토리는 사용자 인증 정보를 저장하기 위한 것으로, htpasswd 형식의 사용자 인증 파일이 여기에 저장됩니다.
-v /opt/registry/certs:/certs : 호스트의 /opt/registry/certs 디렉토리와 컨테이너 내의 /certs 디렉토리를 볼륨 마운트합니다. 이 디렉토리에는 TLS (SSL) 인증서 및 키 파일이 저장됩니다.
-v /data:/var/lib/registry : 호스트의 /data 디렉토리와 컨테이너 내의 /var/lib/registry 디렉토리를 볼륨 마운트합니다. 여기에는 레지스트리의 이미지 데이터가 저장됩니다.
-e "REGISTRY_AUTH=htpasswd" : 환경 변수를 설정하여 레지스트리가 htpasswd 형식의 사용자 인증을 사용하도록 합니다.
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" : htpasswd 형식의 사용자 인증을 위한 Realm 을 설정합니다.
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd : 사용자 인증 정보를 저장하는 htpasswd 파일의 경로를 지정합니다.
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain1.pem : TLS (SSL) 인증서 파일의 경로를 설정합니다.
-e REGISTRY_HTTP_TLS_KEY=/certs/privkey1.pem : TLS (SSL) 인증서의 개인 키 파일의 경로를 설정합니다.
-e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true : Docker Registry v2의 호환성을 유지하고 Docker v1/v1 API를 사용할 수 있도록 활성화합니다.
-d registry : 컨테이너를 백그라운드에서 실행하도록 설정하고, 다운로드 받아놓은 registry 라는 Docker Image 를 사용하여 컨테이너를 시작합니다.
구동된 컨테이너를 확인합니다.
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f246853edd47 registry "/entrypoint.sh /etc…" 6 seconds ago Up 5 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp MyRegistry
포트도 5000 번으로 정상적으로 열린것이 확인되었습니다.
# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 23260/systemd-resol
tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN 54372/docker-proxy
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 18912/sshd: /usr/sb
tcp6 0 0 :::5000 :::* LISTEN 54379/docker-proxy
tcp6 0 0 :::22 :::* LISTEN 18912/sshd: /usr/sb
만들어진 Registry 컨테이너로 로그인을 해봅니다.
계정은 위에서 htpasswd 로 생성했던 계정입니다.
# docker login -u sysdocu -p 12345678 https://registry.az1.sysdocu.kr:5000
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
로그인 성공하여 접근 허용이 되었으면, Registry 이미지 리스트를 확인합니다.
업로드한 이미지가 없기때문에 아직은 아무것도 출력되지 않습니다.
# curl -u sysdocu:12345678 https://registry.az1.sysdocu.kr:5000/v2/_catalog
{"repositories":[]}
여기까지 Registry 구축이 완료되었습니다.
아래는 다른 서버에서 Registry 를 사용하는 방법입니다.
4. 이미지 업로드 및 컨테이너 생성
두가지 방법이 있는데, 여기에서는 기본 컨테이너에서 내용을 변경해보는 아래 방식으로 진행합니다.
- Docker Hub 이미지 그대로 Registry 에 업로드
- Docker Hub 이미지를 받아서 수정하고 Registry 에 업로드
진행할 예제는 php:7.4-apache 기준으로 작성하였습니다.
우선 php:7.4-apache 이미지를 다운로드 합니다.
# docker pull docker.io/php:7.4-apache
테스트용으로 PHP 소스 파일을 만듭니다.
# mkdir ./source
# vi ./source/index.php
Dockerfile 을 아래 내용으로 작성합니다.
# vi Dockerfile
FROM docker.io/php:7.4-apache COPY ./source/ /var/www/html/ RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf CMD ["apache2-foreground"] |
* 설명
FROM docker.io/php:7.4-apache : 기본 이미지를 지정하는 부분입니다. php2.4 와 apache 웹서버가 설치된 이미지 입니다.
COPY ./source/ /var/www/html/ : 호스트 시스템의 ./source/ 디렉토리의 내용을 컨테이너 내부의 /var/www/html/ 디렉토리로 복사하는 명령입니다.
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf : Apache 웹서버에 ServerName 옵션을 추가합니다.
CMD ["apache2-foreground"] : 컨테이너가 시작될 때 실행될 명령입니다. 여기에서는 Apache 웹 서버를 시작합니다.
만들어진 Dockerfile 을 사용하여 Docker 이미지를 새로 만듭니다.
형식) docker build --tag <새 이미지 이름> <Dockerfile 위치>
# docker build --tag php7.4-apache-update .
만들어진 새 이미지가 확인 되었습니다.
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
php7.4-apache-update latest b36ddfe193e1 28 seconds ago 453MB
registry latest 0030ba3d620c 3 weeks ago 24.1MB
이번에는 로컬에 만들어져 있는 php7.4-apache-update 이미지를 Registry 에 올려 보겠습니다.
업로드 권한이 필요하므로 생성했던 htpasswd 계정을 이용해 Registry 에 로그인을 합니다.
(아까 위에서 로그인 했을 경우 생략 가능)
# docker login -u sysdocu -p 12345678 https://registry.az1.sysdocu.kr:5000
태그 설정을 하고 업로드 합니다.
태그 이름은 로컬에 만들어놓은 이름 (php7.4-apache-update) 과 동일하게 하겠습니다.
그리고 sysdocu 라는 디렉토리로 이미지 용도를 구분 짓도록 하겠습니다.
# docker tag php7.4-apache-update registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update
# docker push registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update
Using default tag: latest
The push refers to repository [registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update]
61323a0752b4: Pushed
3d4722dde23c: Pushed
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:2a03e9c0ac98d726ec0f6707d4bd6265aec6de5b0aa3b982315b9eaae0b61123 size: 3449
Registry 컨테이너 가동시 지정했던 로컬 호스트 디렉토리 /data 에서 컨테이너에 올려진 데이터가 확인됩니다.
# ll /data/docker/registry/v2/repositories/sysdocu/php7.4-apache-update/
total 20
drwxr-xr-x 5 root root 4096 Sep 6 02:26 ./
drwxr-xr-x 3 root root 4096 Sep 6 02:26 ../
drwxr-xr-x 3 root root 4096 Sep 6 02:26 _layers/
drwxr-xr-x 4 root root 4096 Sep 6 02:26 _manifests/
drwxr-xr-x 2 root root 4096 Sep 6 02:26 _uploads/
이렇게도 확인이 됩니다.
아까는 빈 내용이였던 Registry 에 업로드한 이미지가 확인됩니다.
# curl -u sysdocu:12345678 https://registry.az1.sysdocu.kr:5000/v2/_catalog
{"repositories":["sysdocu/php7.4-apache-update"]}
이제 업로드 된 이미지를 활용하여 애플리케이션을 구동할 수 있습니다.
방법은 두가지 형식이 있으며 여기에서는 간단히 Docker 컨테이너로 생성해 보겠습니다.
- Kubernetes (Openshift, K-PaaS 등) 에서 Pod 생성, Service 생성
- Docker 에서 컨테이너 생성
# docker run -d -p 80:80 registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update
* 설명
-d : 컨테이너를 백그라운드에서 실행합니다.
-p 80:80 : 호스트의 포트 80 을 컨테이너의 포트 80 으로 매핑합니다. 즉, 웹 서버가 동작하는 포트에 접근할 수 있게 됩니다.
registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update : 실행할 Docker 이미지를 지정합니다.
컨테이너가 실행되면 웹 서버가 시작되어 호스트의 IP 또는 도메인과 80 번 포트로 웹서버에 접속할 수 있게 됩니다.
# curl http://registry.az1.sysdocu.kr
Good job