TheKoguryo's 기술 블로그

 Version 2024.04.01

1.4.2 Image Registry로 Nexus Repository 사용하기

컴퓨트 인스턴스에 Nexus 설치

Step 1 - 컴퓨트 인스턴스 생성

  1. 시스템 요구사항에 맞춰 컴퓨트 인스턴스를 생성합니다. 여기서는 최소사항에 맞춰 설치하겠습니다.

Step 2 – JDK 설치

참조 문서 - https://blogs.oracle.com/developers/post/how-to-install-oracle-java-in-oracle-cloud-infrastructure

  1. Nexus Repository Manager의 설치 요구사항에 맞춰 Java 1.8 버전을 설치합니다.

  2. Oracle Linux 8 인스턴스상의 Repository에서 설치 가능한 JDK 버전을 확인합니다.

    $ yum list jdk*
    Available Packages
    jdk-11.x86_64                                                              2000:11.0.17-ga                                                         ol8_oci_included
    ...
    jdk-17.x86_64                                                              2000:17.0.5-ga                                                          ol8_oci_included
    ...
    jdk1.8.x86_64                                                              2000:1.8.0_361-fcs                                                      ol8_oci_included
    
  3. JDK 1.8을 설치합니다.

    sudo yum install -y jdk1.8
    
  4. 설치 버전 확인

    $ java -version
    java version "1.8.0_361"
    Java(TM) SE Runtime Environment (build 1.8.0_361-b09)
    Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)
    

Step 3 – Oracle Linux 8에 Sonatype Nexus Repository 설치하기

https://www.atlantic.net/dedicated-server-hosting/how-to-install-sonatype-nexus-repository-manager-on-oracle-linux-8/

  1. Nexus를 실행할 유저를 생성합니다.

    sudo adduser nexus
    
  2. 최신 버전을 다운로드 받습니다. SELinux로 인한 실행시 오류를 막기 위해 /opt 위치에 설치합니다.

    cd /opt
    sudo wget -O nexus.tar.gz https://download.sonatype.com/nexus/3/latest-unix.tar.gz
    
  3. 다운로드 받은 파일을 압축해제합니다.

    sudo tar -xvf nexus.tar.gz
    
  4. 폴더명을 변경합니다.

    sudo mv nexus-3* nexus3
    
  5. 압축 해제된 Nexus 폴더의 소유자와 권한을 변경합니다.

    sudo chown -R nexus:nexus /opt/nexus3
    sudo chown -R nexus:nexus /opt/sonatype-work
    
  6. 설정파일에서 실행 유저를 변경합니다.

    sudo vi /opt/nexus3/bin/nexus.rc
    
    • 다음 내용 변경

      run_as_user="nexus"
      

Step 4 – Systemd Service File 생성

서비스로써 인스턴스 재시작시 실행될 수 있도록 관련 파일을 설정합니다.

  1. 다음 파일을 생성합니다.

    sudo vi /etc/systemd/system/nexus.service
    
    • 다음 내용 추가

      [Unit]
      Description=nexus service
      After=network.target
      
      [Service]
      Type=forking
      LimitNOFILE=65536
      ExecStart=/opt/nexus3/bin/nexus start
      ExecStop=/opt/nexus3/bin/nexus stop
      User=nexus
      Restart=on-abort
      TimeoutSec=600
      
      [Install]
      WantedBy=multi-user.target
      
  2. 서비스 활성화

    sudo systemctl daemon-reload
    sudo systemctl enable nexus.service
    sudo systemctl start nexus.service
    
  3. 서비스 상태 확인

    systemctl status nexus
    
    • 정상 시작시 상태 - active (running) 상태

      ● nexus.service - nexus service
         Loaded: loaded (/etc/systemd/system/nexus.service; enabled; vendor preset: disabled)
         Active: active (running) since Mon 2023-03-13 09:30:22 GMT; 5s ago
        Process: 12799 ExecStart=/opt/nexus3/bin/nexus start (code=exited, status=0/SUCCESS)
       Main PID: 13014 (java)
          Tasks: 55 (limit: 48440)
         Memory: 903.3M
         CGroup: /system.slice/nexus.service
                 └─13014 /usr/java/jdk1.8.0_361-amd64/bin/java -server -Dinstall4j.jvmDir=/usr/java/jdk1.8.0_361-amd64 -Dexe4j.moduleName=/opt/nexus3/bin/nexus -XX:+Unl>
      
      Mar 13 09:30:22 nexus systemd[1]: Starting nexus service...
      Mar 13 09:30:22 nexus systemd[1]: Started nexus service.
      
  4. 로그 확인

    tail -f /opt/sonatype-work/nexus3/log/nexus.log
    
    • 정상 기동시 - 8081 포트로 서비스 됩니다.

      tail -f /opt/sonatype-work/nexus3/log/nexus.log
      2023-03-13 09:30:53,941+0000 INFO  [jetty-main-1]  *SYSTEM org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.w.WebAppContext@3e0f2b26{Sonatype Nexus,/,file:///opt/nexus3/public/,AVAILABLE}
      2023-03-13 09:30:53,975+0000 INFO  [jetty-main-1]  *SYSTEM org.eclipse.jetty.server.AbstractConnector - Started ServerConnector@3d2ab5e1{HTTP/1.1, (http/1.1)}{0.0.0.0:8081}
      2023-03-13 09:30:53,975+0000 INFO  [jetty-main-1]  *SYSTEM org.eclipse.jetty.server.Server - Started @31643ms
      2023-03-13 09:30:53,975+0000 INFO  [jetty-main-1]  *SYSTEM org.sonatype.nexus.bootstrap.jetty.JettyServer - 
      -------------------------------------------------
      
      Started Sonatype Nexus OSS 3.49.0-02
      
      -------------------------------------------------
      2023-03-13 09:31:52,105+0000 INFO  [periodic-4-thread-1]  *SYSTEM org.sonatype.nexus.repository.httpclient.internal.HttpClientFacetImpl - Repository status for nuget.org-proxy changed from READY to AVAILABLE - reason n/a for n/a
      

Step 5 - 방화벽에서 서비스 포트 열기

  1. 컴퓨트 인스턴스에서 OS 상의 방화벽에서 대상 포트를 엽니다.

    • Nexus Repository Manager UI: 8081

    • Image Registry 호스트용: 5000

    • Docker Hub 프락시용: 5001

      # OS 방화벽에서 Nexus Repository Manager UI, 8081 포트 개방
      sudo firewall-cmd --permanent --add-port=8081/tcp
      # OS 방화벽에서 호스트용, 프락시용 포트, 5000,5001 포트 개방
      sudo firewall-cmd --permanent --add-port=5000/tcp
      sudo firewall-cmd --permanent --add-port=5001/tcp
      # 방화벽 변경정보 다시 반영
      sudo firewall-cmd --reload
      
  2. 컴퓨트 인스턴스가 속한 Security List에 관련 포트를 Ingress Rule에 추가합니다.

    • 포트는 동일: 8081, 5000, 5001

Step 6 – Nexus Repository Manager 접속 및 Repository 설정

  1. Nexus Repository Manager 접속합니다.

    • 주소: http://<인스턴스 IP>:8081
  2. 컴퓨트 인스턴스에 관리자 패스워드를 확인하여 Sign in 합니다.

    • username: admin

    • 패스워드: 최초 로그인 후 아래 파일은 자동으로 삭제됩니다.

      cat /opt/sonatype-work/nexus3/admin.password
      

    image-20230313220557095

  3. 패스워드를 변경합니다.

    image-20230313220836861

  4. 익명으로 접근에 대한 권한을 설정합니다.

    image-20230313220910754

  5. 설정을 완료합니다.

  6. 이미지가 저장될 Blob Store를 만듭니다.

    image-20230313222209679

    • docker-hosted: File 타입으로 만듭니다.

      image-20230313222630145

    • docker-hub도 같은 방법으로 만듭니다.

      image-20230313222747744

    • 필요에 따라 컴퓨트 인스턴스에 Block Volume을 마운트해서 해당 경로로 지정하는 방법도 있습니다.

  7. docker-hosted Repository를 만듭니다.

    • Repositories > Create Repository 클릭합니다.

    • Recipe에서 docker (hosted)를 선택

    • 아래 정보를 입력하여 생성합니다.

      • Name: docker-hosted
      • HTTP: 포트 5000
      • Allow anonymous docker pull: 체크 - 로그인 없이 docker pull 할 수 있는지, 즉 Public Repository 인지 설정하는 부분
      • Blob store: 앞서 만든 docker-hosted 선택

      image-20230313224413683

  8. docker-hub Repository를 만듭니다.

    • Repositories > Create Repository 클릭합니다.

    • Recipe에서 docker (proxy)를 선택

      • 다른 Registry(예, Docker Hub)의 이미지를 캐쉬로 저장하는 유형입니다.
    • 아래 정보를 입력하여 생성합니다.

      • Name: docker-hub
      • HTTP: 포트 5001
      • Allow anonymous docker pull: 체크 - 로그인 없이 docker pull 할 수 있는지, 즉 Public Repository 인지 설정하는 부분

      image-20230313225304547

      image-20230313225423269

      • Blob store: 앞서 만든 docker-hosted 선택

      image-20230313225557156

      • 나머지는 기본값 사용
  9. Allow anonymous docker pull을 사용하기 위해 Security > Realms에서 Docker Bearer Token Realm을 추가합니다.

    • Docker Bearer Token Realm을 오른쪽 Active 화면으로 이동시킵니다.

    • 적용을 위해 Save합니다.

      image-20230313230250371

  10. Allow anonymous docker pull을 사용하기 위해 Acnonymous Access를 활성화합니다.

    image-20230313233512516

설치구성한 Nexus Repository을 Image Registry로 사용하기 테스트

Docker 클라이언트로 테스트하기

생성한 Repository를 HTTP로만 서비스를 하도록 설정하였기 때문에, Docker 클라이언트에서 insecure-registries 설정을 해야 연결이 가능합니다. 내부 네트워크에서 사용하는 경우, HTTP로만 하는 경우가 있어, 해당 내용을 기준으로 테스트합니다.

HTTPS로 서비스시는 SSL Certificate 발급 및 등록 작업이 필요합니다. 여기서는 편의상 HTTP로만 사용합니다.

  1. Docker 클라이언트를 설치합니다.

  2. /etc/docker/daemon.json 파일이 없는 경우 생성하여 아래 내용을 추가합니다.

    {
            "insecure-registries" : ["10.0.30.250:5000", "10.0.30.250:5001"]
    }
    
  3. 서비스 재시작

    sudo service docker restart
    
  4. docker-hub Repository에서 docker pull 합니다. 현재 docker-hub는 없어도, Docker Hub를 통해 가져오는 것을 볼 수 있습니다.

    $ docker pull 10.0.30.250:5001/busybox:latest
    latest: Pulling from busybox
    1487bff95222: Pull complete 
    Digest: sha256:c118f538365369207c12e5794c3cbfb7b042d950af590ae6c287ede74f29b7d4
    Status: Downloaded newer image for 10.0.30.250:5001/busybox:latest
    10.0.30.250:5001/busybox:latest
    
  5. Nexus Repository Manager 접속하여 Browse에서 docker-hub를 클릭합니다. Docker Hub에서 가져와서 캐쉬된 것을 볼 수 있습니다.

    image-20230313235116341

  6. docker-hosted Repository에 로그인합니다.

    $ docker login 10.0.30.250:5000
    Username: admin
    Password: 
    WARNING! Your password will be stored unencrypted in /home/opc/.docker/config.json.
    Configure a credential helper to remove this warning. See
    https://docs.docker.com/engine/reference/commandline/login/#credentials-store
    
    Login Succeeded
    
  7. docker pull 해서 docker-hosted Repository에 push 하기

    • docker pull

      $ docker pull nginx:latest
      latest: Pulling from library/nginx
      Digest: sha256:aa0afebbb3cfa473099a62c4b32e9b3fb73ed23f2a75a65ce1d4b4f55a5c2ef2
      Status: Downloaded newer image for nginx:latest
      docker.io/library/nginx:latest
      
    • tag 하기

      $ docker tag nginx:latest 10.0.30.250:5000/nginx:latest
      
    • docker-hosted Repository에 push

      $ docker push 10.0.30.250:5000/nginx:latest
      The push refers to repository [10.0.30.250:5000/nginx]
      101af4ba983b: Pushed 
      d8466e142d87: Pushed 
      83ba6d8ffb8c: Pushed 
      e161c82b34d2: Pushed 
      4dc5cd799a08: Pushed 
      650abce4b096: Pushed 
      latest: digest: sha256:942ae2dfd73088b54d7151a3c3fd5af038a51c50029bfcfd21f1e650d9579967 size: 1570
      
  8. Nexus Repository Manager 접속하여 Browse에서 docker-hosted를 클릭합니다. Docker 클라이언트로 push한 이미지가 등록된 것을 확인할 수 있습니다.

    image-20230313235212564

OKE 클러스터에서 Nexus에서 이미지 가져오기

OKE는 쿠버네티스 버전 1.20.8 부터 Docker 대신 CRI-O를 컨테이너 런타임으로 사용하고 있습니다. HTTP로 컨테이너 이미지를 가져오기 위해서는 Docker Client에서 설정한 insecure-registries에 대응되는 추가 설정이 필요합니다.

  1. Worker Node에 SSH로 접속하여 Nexus에서 이미지를 잘 가져오는 지 확인해 봅니다.

    [opc@oke-cdajpvfkfoq-nkm2nn3kbfa-sb34tztom5a-0 ~]$ sudo crictl pull 10.0.30.250:5000/nginx:latest
    E0314 02:07:35.127303   35031 remote_image.go:238] "PullImage from image service failed" err="rpc error: code = Unknown desc = pinging container registry 10.0.30.250:5000: Get \"https://10.0.30.250:5000/v2/\": http: server gave HTTP response to HTTPS client" image="10.0.30.250:5000/nginx:latest"
    FATA[0000] pulling image: rpc error: code = Unknown desc = pinging container registry 10.0.30.250:5000: Get "https://10.0.30.250:5000/v2/": http: server gave HTTP response to HTTPS client
    
    • HTTP를 사용하는 경우 오류가 발생합니다.
  2. /etc/containers/registries.conf.d 폴더 하위에 레지스트리관련 추가 파일을 생성합니다.

    • 예, /etc/containers/registries.conf.d/my-private-registry.conf
    • Nexus 컴퓨트 인스턴스의 Private IP을 사용한 예시입니다. insecure = true로 설정합니다.
    • Nexus 컴퓨트 인스턴스가 OKE 클러스터와 같은 VCN인 경우 인스턴스의 Internal FQDN(예, nexus.oketoolssubnet.okecluster1.oraclevcn.com)를 Private IP 대신 사용할 수 있습니다.
    [[registry]]
    location = "10.0.30.250:5000"
    insecure = true
    
    [[registry]]
    location = "nexus.oketoolssubnet.okecluster1.oraclevcn.com:5000"
    insecure = true
    
    [[registry]]
    prefix = "docker.io"
    insecure = false
    blocked = false
    location = "docker.io"
    [[registry.mirror]]
    location = "nexus.oketoolssubnet.okecluster1.oraclevcn.com:5001"
    insecure = true
    
  3. 설정을 반영합니다.

    sudo systemctl daemon-reload
    sudo systemctl restart crio
    
  4. Nexus에서 이미지를 잘 가져오는 지 다시 확인해 봅니다.

    [opc@oke-cdajpvfkfoq-nkm2nn3kbfa-sb34tztom5a-0 ~]$ sudo crictl pull 10.0.30.250:5000/nginx:latest
    Image is up to date for 10.0.30.250:5000/nginx@sha256:942ae2dfd73088b54d7151a3c3fd5af038a51c50029bfcfd21f1e650d9579967
    [opc@oke-cdajpvfkfoq-nkm2nn3kbfa-sb34tztom5a-0 ~]$ sudo crictl images
    IMAGE                                                                                  TAG                 IMAGE ID            SIZE
    10.0.30.250:5000/nginx                                                                 latest              904b8cb13b932       146MB
    ...
    
  5. OKE 클러스터에서 실행하면, 위에서 설정한 Worker Node에 Pod가 배포되는 경우 이미지를 가져와 Running 상태가 됩니다.

    • 작업한 oke-cdajpvfkfoq-nkm2nn3kbfa-sb34tztom5a-0(10.0.10.38) Worker Node에서 Running 상태이며 나머지 노드에 배포된 Pod는 ErrImagePull 에러가 발생하였습니다.
    $ kubectl get nodes -o wide -L hostname
    NAME         STATUS   ROLES   AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                  KERNEL-VERSION                      CONTAINER-RUNTIME       HOSTNAME
    10.0.10.16   Ready    node    5m5s    v1.24.1   10.0.10.16    <none>        Oracle Linux Server 8.6   5.4.17-2136.314.6.2.el8uek.x86_64   cri-o://1.24.1-76.el8   oke-cdajpvfkfoq-nkm2nn3kbfa-sb34tztom5a-2
    10.0.10.38   Ready    node    60m     v1.24.1   10.0.10.38    <none>        Oracle Linux Server 8.6   5.4.17-2136.314.6.2.el8uek.x86_64   cri-o://1.24.1-76.el8   oke-cdajpvfkfoq-nkm2nn3kbfa-sb34tztom5a-0
    10.0.10.93   Ready    node    5m33s   v1.24.1   10.0.10.93    <none>        Oracle Linux Server 8.6   5.4.17-2136.314.6.2.el8uek.x86_64   cri-o://1.24.1-76.el8   oke-cdajpvfkfoq-nkm2nn3kbfa-sb34tztom5a-1
    $ kubectl create deploy nginx --image=10.0.30.250:5000/nginx:latest --replicas=6
    deployment.apps/nginx created
    $ kubectl get pod -o wide
    NAME                                        READY   STATUS         RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
    nginx-67c575b4fb-8kc6v                      1/1     Running        0          10s   10.244.4.151   10.0.10.38   <none>           <none>
    nginx-67c575b4fb-8rjxx                      0/1     ErrImagePull   0          10s   10.244.5.5     10.0.10.93   <none>           <none>
    nginx-67c575b4fb-g82k4                      0/1     ErrImagePull   0          10s   10.244.5.133   10.0.10.16   <none>           <none>
    nginx-67c575b4fb-q2nr9                      0/1     ErrImagePull   0          10s   10.244.5.134   10.0.10.16   <none>           <none>
    nginx-67c575b4fb-qt5h5                      0/1     ErrImagePull   0          10s   10.244.5.4     10.0.10.93   <none>           <none>
    nginx-67c575b4fb-zm5n6                      0/1     ErrImagePull   0          10s   10.244.5.135   10.0.10.16   <none>           <none>
    
    • 에러 없이 실행하기 위해서는 모든 Worker Node에 동일한 작업이 필요합니다.
  6. 생성되는 Worker Node에 자동으로 적용하기 위해서는 Custom Cloud-init Initialization Script을 활용하여, Worker Node 인스턴스 생성시 관련 스크립트가 자동으로 실행되게 설정하면 됩니다.

    • Node Pool 생성 또는 수정시 고급 옵션에 Initialization script 항목이 있습니다.
    • Custom Cloud Init Script Template을 다운로드 받아 OKE가 실행하는 oke-init.sh 다음에 실행할 커스텀 스크립트를 그림과 같이 추가합니다.
    • 적용후 신규 생성되는 Worker Node에 적용이 되므로 기존 노드가 있는 경우 삭제후 재생성합니다.

    image-20230314114511020



이 글은 개인으로서, 개인의 시간을 할애하여 작성된 글입니다. 글의 내용에 오류가 있을 수 있으며, 글 속의 의견은 개인적인 의견입니다.

Last updated on 14 Mar 2023