플랫폼 개발을 진행하며 docker image, package, helm 등의 자료를 공개적인 저장소가 아닌 사내에서 팀원들이 공유할 수 있는 Private Repository가 필요하게 되었습니다. 또한 실제로 사내 보안 때문에 Docker hub로의 접근이 불가능 해 Private Repository에 대부분의 이미지를 저장한 후 다운로드하여 사용하는 구조입니다. 이를 위해 Nexus Repository를 설치하고 테스트하는 과정을 기록합니다.
Repository Manager를 사용하는 이유
- 적은 용량
- 저장소는 라이브러리를 보관하므로 프로젝트마다 필요한 라이브러리를 버전 관리에 추가할 필요가 없고 라이브러리에 대한 메타데이터만 설정하면 빌드할때 내려받으므로 적은 용량을 차지합니다.
- 빠른 프로젝트 체크아웃과 빌드
- 버전 관리 툴을 이용해 프로젝트를 체크아웃할 경우 용량이 적으므로 빨리 체크아웃할 수 있으며 빌드 속도도 빨라집니다.
- 라이브러리 버전 관리 용이
- 메타데이터를 기반으로 라이브러리의 정보와 버전을 관리하므로 라이브러리 자체의 버전을 관리하기가 쉽습니다.
- 공유 및 협업 강화
- 저장소를 통해 컴포넌트를 공유할 수 있으므로 개발자들끼리 손쉽게 산출물을 공유하고 협업할 수 있습니다.
Nexus?
Nexsus는 현재 가장 인기 있는 오픈 소스 Repository Manager로, Docker, Helm,Pypi,Maven 등 다양한 Format을 지원합니다. 다음은 또 다른 Repository Manager인 Artifactory와 비교한 지원하는 Format의 종류입니다. 현재 프로젝트에서 docker, npm, PyPi, Yum, Apt, Helm을 필수로 사용해야 하고 Community 버전(무료)으로 지원하기 때문에 Nexus를 선택했습니다. 아래의 그림에서 X는 commercial support C는 community support를 나타냅니다.
설치 환경
현재 테스트 하기 위해 구성된 환경은 다음과 같습니다. 3개의 서버가 쿠버네티스 클러스터로 구성되어 있습니다. 173 서버에 도커를 통해 Nexus를 설치 후 각 서버에서 접근이 가능하도록 합니다. Nexus는 쿠버네티스 외부에서 설치하여 클러스터의 관리에서 벗어나도록 설치했습니다.
- 106.246.237.171 - Ubuntu 18.04
- 106.246.237.173 - Ubuntu 18.04
- 106,246.237.174 - Ubuntu 18.05
Docker Repositry 생성
1. Nexus Docker 실행
mkdir /nexus-data
docker run --name nexus -d -p 5000:5000 -p 8081:8081 -v /nexus-data:/nexus-data -u root sonatype/nexus3
다음 명령어를 통해 Nexus 도커를 실행합니다. 5000 포트는 Docker 리포지토리를 접근하기 위해 필요한 포트, 8081은 웹 UI를 통해 접근하기 위한 포트입니다. nexus-data에 데이터가 저장돼서 이는 볼륨으로 관리를 하기 위해 설정하였습니다.
2. 웹으로 접속 후 Blob Store 생성
106.246.237.173:8081로 접속 후 초기 ID,PW를 설정합니다. 초기 아이디는 admin PW는 admin123으로 설정되어 있습니다(또는 컨테이너 내부에 저장되어 있는 PW 확인). 이후 Blob Stores에서 docker-hosted, docker-hub를 생성합니다. Blob store는 Proxy repository 나 hosted repository를 통해 배포된 바이너리를 저장하는 저장소로 이해할 수 있습니다.
3) docker hosted
docker hosted는 개인이 만든 이미지를 저장하는데 사용합니다. repository를 생성하는데 아래와 같은 설정이 필요합니다. 5000번 포트를 통해 통신하고 client는 docker registry API를 통해 interact 합니다(V2로 대체 예정)
- HTTP 영역 5000 설정
- Enable Docker V1 API check
- Blob store docker-hosted 선택
4) docker(proxy) repository 생성
docker hosted에서 이미지를 업로드, 다운 받을 수 있고 존재하지 않을 경우 docker(proxy)에서 도커 허브를 통해 이미지를 받을 수 있습니다.
- Name: docker-hub
- Enable Docker v1 API check
- Remote storage : https://registry-1.docker.io 입력(docker-hub)
- Use Docker hub check
5. Realms 설정
docker repository에 접근할 수 있는 인증을 추가합니다. 이는 Docker Authentication에서 제공하는 기본적인 인증 권한을 사용해 익명으로 docker pull을 허용합니다.
- docker bearer Token Realm 추가
6. Docker Image Pull & Push
- docker insecure registry 추가
모든 워커노드에서 Nexus repository에 접근을 허용하기 위한 설정을 진행합니다. 공인 TLS 인증이 되지 않은 Private repository에 HTTP접근을 허용하기 위한 설정이다. 도커를 설치한 후 생성되는 /etc/. docker/damon.json에 다음과 같은 코드를 추가합니다(docker desktop에서는 dashboard를 통해 설정할 수 있습니다).insecure-registries" : ["myregistrydomain.com:5000"]
- docker login 명령어를 통해 Nexus로 로그인 합니다.
- docker image tag 추가
기존에 존재하는 busybox이미지를 활용해 Nexus에 올리기 위해 새로운 태그를 생성합니다.
[Nexus 주소/repo명:version] 형태로 작성합니다.docker tag dc3bacd8b5ea 106.246.237.173:5000/busybox:v20201203
- Nexus image push
생성된 이미지를 push 명령어를 통해 Nexus repository로 올린다. 성공적으로 Push가 이루어졌다면 웹을 통해 확인할 수 있습니다.docker push 106.246.237.173:5000/busybox:v20201203
- Nexsus에서 image 가져오기
반대로 Pull을 통해 image를 로컬로 다운로드할 수 있습니다.docker pull 106.246.237.173:5000/tensorflow
7. Kubernets 파드 배포를 위해 Nexus에서 docker 이미지 받아오기
- K8S private repository를 사용하기 위해서는 Secret을 생성해 Nexsus 환경 변수를 설정해야 합니다. docker login을 통해 저장된 정보로 시크릿을 생성하거나 다음과 같이 CLI을 통해 시크릿을 생성합니다.
kubectl create secret docker-registry regcred\
-- docker-server=Nexus 주소 \
-- docker-username=admin \
-- docker-password=PW \
-- docker-email =seokbin@email.com
- Pod 생성.
파드 생성을 위해 아래와 같은 매니페스트를 작성합니다. private repository에 존재하는 이미지를 시크릿을 설정하면 Nexus를 통해 이미지를 다운로드하여 파드를 생성하게 됩니다.apiVersion: v1 kind: Pod metatdata: name:private-tensorflow spec: container: - name: private-tensorflow-container image: 106.246.237.173:5000/tensorflow:latest imagePullSecrets: - name : regcred
Pypi Repositry 생성
Pypi Repository 또한 docker와 마찬가지로 hosted, proxy를 설정합니다. 각 각 Blob stroage, repository를 생성합니다.
pypi-hosted와 pypi-proxy를 생성한 후 Group을 통해 묶어서 관리할 수 있습니다. Group 또한 Blob storage, repository를 생성한 후 이전에 생성한 hosted와 proxy를 추가해서 생성합니다.
개발이 완료된 패키지를 hosted repository로 업로드할 때는 twine을 사용해 업로드합니다.. pypirc을 작성해 repository 주소와 계정 정보를 입력합니다.
#.pypirc
[distutils]
index-servers = pypi
[pypi]
repository: http://127.0.0.1:8081/repository/pypi-hosted/
username: admin
password: megazone00!
twine upload -r pypi [filename]
명령어를 통해 패키지 업로드(-r 옵션을 통해 repository 지정) 아래와 같이 패키지가 정상적으로 업로드됩니다.
pip download의 경우 pip.conf
파일을 수정해 repository와 연결할 수 있습니다. url은 위에서 생성한 group으로 연결했습니다. pip.conf 파일의 위치는 다음과 같습니다.
UNIX : $HOME/. config/pip/pip.conf
MAC : $HOME/Library/Application Support/pip.pip.conf
Window: % APPDATA%\pip\pip.ini
#pip.conf
[global]
index = http://localhost:8081/repository/pypi-repos/pypi
index-url = http://localhost:8081/repository/pypi-repos/simple
NPM Repositry 구성
NPM repository는 Pypi와 마찬가지로 host, proxy, group을 순서대로 생성합니다.
구성 후 테스트를 위해 패키지를 생성합니다. npm init
을 통해 패키지를 만들고. npmrc를 생성해 패키지에 대한 repository를 설정을 변경합니다. registry 주소와 인증을 위한 아이디 패스워드를 값을 넣어줍니다.
#.npmrc
registry=http://localhost:8081/repository/npm-repos/
#echo -n 'admin:admin123' | openssl base64
_auth=YWRtaW46bWVnYXpvbmUwMCE=
이후 package install시 정상적으로 설치되고 Proxy repository에 해당 패키지가 설치되는 것을 확인할 수 있습니다.
패키지 upload의 경우 package.json
파일에 다음과 같이 registry 주소를 입력합니다. 이후 npm publish [package name]
명령어를 통해 배포할 수 있습니다.
"publishConfig":{
"registry":"http://127.0.0.1:8081/repository/npm-repos/"
}