Skip to content
Dokumentatsiya
Sonatype Nexus

Sonatype Nexus Repository Manager

Kirish

Tasavvur qiling: sizning jamoangiz har kuni loyihani build qilganda Maven Central, NuGet Gallery yoki Docker Hubdan yuzlab paketlarni qayta-qayta yuklab oladi. Har bir build internertga so'rov yuboradi, vaqt ketadi, tarmoq yuklanadi. Agar internet sekin bo'lsa yoki tashqi repository vaqtincha ishlamay qolsa — butun CI/CD pipeline to'xtab qoladi.

Aynan shu muammoni hal qilish uchun Sonatype Nexus Repository Manager ishlatiladi.

Nexus — bu markazlashtirilgan artifakt menejeri bo'lib, u quyidagi vazifalarni bajaradi:

  • Tashqi paketlarni keshlash (Proxy) — Maven Central, NuGet, PyPI, Docker Hub kabi tashqi repositorylardan yuklab olingan paketlarni local serverda saqlaydi. Keyingi safar xuddi shu paket kerak bo'lganda, internet o'rniga Nexusdan olinadi.
  • Ichki paketlarni saqlash (Hosted) — kompaniyaning o'ziga xos kutubxonalari va artifaktlarini xavfsiz saqlaydi.
  • Bir nechta repositoryni birlashtirish (Group) — Proxy va Hosted repositorylarni bitta URL ostida birlashtiradi, loyihalaringiz faqat bitta manzilni bilsa kifoya.

Nexus Java (Maven, Gradle), .NET (NuGet), Python (PyPI), Docker, Node.js (NPM), Go, Helm, Cargo va boshqa ko'plab texnologiyalarni qo'llab-quvvatlaydi.

Nexus ikki versiyada mavjud: Nexus OSS (opensource, bepul) va Nexus Pro (pullik, qo'shimcha funksiyalar bilan). Ushbu qo'llanma Nexus OSS bilan ishlashga mo'ljallangan — u ko'pchilik hollarda yetarli.

Qisqacha tarix: Nexus 2007-yilda Sonatype Inc. tomonidan yaratilgan. Dastlab faqat Maven uchun mo'ljallangan bo'lsa, bugungi kunda u deyarli barcha paket menejerlarni qo'llab-quvvatlaydigan universal yechimga aylangan.

Bu qo'llanmada biz Nexusni Docker yordamida o'rnatamiz, domen ulaymiz, repository turlarini tushunib olamiz va oxirida Maven hamda NuGet loyihalarini CI/CD pipeline ichida Nexus bilan integratsiya qilamiz.

Nexus o'rnatish

Nexusni Docker yordamida ishga tushiramiz. O'rnatishning ikkita usulini ko'rib chiqamiz: manual va Ansible orqali avtomatlashtirilgan.

Minimum server talablari

OSRAMCPUXotiraStatic IP
Ubuntu 20.04+ yoki Rocky Linux 8+8GB4 core80GBHa kerak

Nexus juda ko'p metadatalar bilan ishlaydi, shuning uchun RAM va disk hajmi muhim. 4GB RAM bilan ishga tushsa ham, real ishlatishda sekinlashadi.

Docker o'rnatilmagan bo'lsa, avval uni o'rnatib oling — Docker o'rnatish qo'llanmasi (opens in a new tab)

Manual o'rnatish

1-> Nexus o'z ma'lumotlarini (repositorylar, konfiguratsiyalar, keshlangan paketlar) /nexus-data papkasida saqlaydi. Docker container o'chirilsa yoki restart bo'lsa, ichidagi ma'lumotlar yo'qoladi. Shuning uchun biz bu papkani host serverga mount qilamiz:

sudo mkdir -p /mnt/nexus/nexus-data
sudo chown -R 200 /mnt/nexus/nexus-data

Nima uchun chown 200? Nexus container ichida nexus foydalanuvchisi UID 200 bilan ishlaydi. Agar papka egaligi to'g'ri bo'lmasa, Nexus yozish huquqi yo'qligi sababli ishga tushmaydi.

2-> Nexusni Docker bilan ishga tushiramiz:

docker run -d \
  -p 8081:8081 \
  --name nexus \
  --restart=always \
  -v /mnt/nexus/nexus-data:/nexus-data \
  sonatype/nexus3

Bu yerda:

  • -p 8081:8081 — Nexus web interfeysi uchun port
  • --restart=always — server yoki Docker restart bo'lganda Nexus avtomatik qayta ishga tushadi
  • -v /mnt/nexus/nexus-data:/nexus-data — ma'lumotlar host serverda saqlanadi

3-> Nexus birinchi marta ishga tushganda avtomatik admin parol generatsiya qiladi. Uni olish uchun:

docker exec -it nexus cat /nexus-data/admin.password

Bu parol faqat birinchi kirish uchun! Nexus sizdan uni o'zgartirishni talab qiladi. Parolni xavfsiz joyda saqlang.

Birinchi kirish

Nexus o'rnatilgandan so'ng, brauzerda http://server_ip:8081 manzilini oching.

Yuqori o'ng burchakdagi Sign in tugmasini bosing:

admin login va oldingi bosqichda olgan parol bilan kiring:

Nexus sizdan default parolni o'zgartirishni talab qiladi — yangi kuchli parol kiriting:

Keyingi qadamda anonymous access sozlamasini tanlaymiz. Agar faqat autentifikatsiya qilingan foydalanuvchilar kirishi kerak bo'lsa, "Disable anonymous access"ni tanlang:

Tabriklaymiz! Nexus tayyor:

Nexusga domen ulash

Production muhitda Nexusni IP:port orqali emas, balki domen va HTTPS orqali ishlatish kerak. Bu xavfsizlik va qulaylik uchun muhim — ayniqsa CI/CD pipeline'larda credential'lar shifrlanmagan holda yuborilmasligi uchun.

Biz NGINX reverse proxy va Let's Encrypt orqali bepul SSL sertifikat olamiz.

1-> NGINX va Certbot o'rnatamiz:

sudo apt update
sudo apt install nginx certbot python3-certbot-nginx -y

2-> DNS provayderingizda A record yarating — domenni serveringiz IP manziliga yo'naltiring. Masalan, nexus.helm.uz subdomenini serverga ulash:

3-> NGINX konfiguratsiya faylini yaratamiz:

sudo nano /etc/nginx/sites-available/nexus.helm.uz

Quyidagi konfiguratsiyani yozing:

/etc/nginx/sites-available/nexus.helm.uz
server {
    listen 80;
    client_max_body_size 100M;
    server_name nexus.helm.uz;
    location / {
        proxy_pass http://localhost:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

client_max_body_size 100M — bu NGINX orqali yuklanadigan fayllarning maksimal hajmini belgilaydi. Nexusga katta artifaktlar yuklash uchun bu qiymatni oshirish kerak bo'lishi mumkin. Agar 413 Request Entity Too Large xatosi chiqsa, bu qiymatni ko'paytiring.

4-> Konfiguratsiyani faollashtirish uchun sites-enabledga symbolic link yaratamiz:

sudo ln -s /etc/nginx/sites-available/nexus.helm.uz /etc/nginx/sites-enabled/

5-> NGINXni restart qilamiz:

sudo systemctl restart nginx

6-> Let's Encrypt SSL sertifikatini olamiz:

sudo certbot

Certbot sizdan email so'raydi va Terms of Serviceni qabul qilishingizni kutadi — y bosing:

Keyin domenlar ro'yxatidan keraklisini tanlang:

Sertifikat olingandan keyin NGINXni qayta ishga tushiring:

sudo systemctl restart nginx

Endi brauzerda https://nexus.helm.uz (opens in a new tab) ochsangiz, Nexus HTTPS bilan ishlayotganini ko'rasiz:

Nexus bilan tanishuv

Keling, Nexusning asosiy tushunchalari va interfeysini ko'rib chiqamiz.

Qo'llab-quvvatlanadigan texnologiyalar

Nexus deyarli barcha mashhur paket menejerlarni qo'llab-quvvatlaydi:

APT, Cargo, Bower, CocoaPods, Composer, Conan, Conda, Docker, Git LFS, Go, Helm, Hugging Face, Maven, npm, NuGet, p2, PyPI, R, Raw, RubyGems, Yum (RPM)

Sonatype kompaniyasining Nexusdan tashqari Repository Firewall (zararli paketlarni bloklash), Lifecycle (open-source xavfsizlik nazorati) va SBOM (dasturiy ta'minot tarkibini kuzatish) kabi mahsulotlari ham mavjud.

Interfeys bilan tanishish

Nexusga kirganda asosiy sahifa ochiladi:

Server Administration and Configuration — bu yerda Nexusning barcha sozlamalari joylashgan:

Blob Stores — Nexus fayllarni fizik ravishda saqlaydigan joy. Default holatda default nomli bitta blob store mavjud. Katta tashkilotlarda har bir repository turi uchun alohida blob store yaratish tavsiya etiladi:

Repositories — bu yerda barcha repositorylarni ko'rishimiz mumkin. Nexus default holda Maven va NuGet uchun tayyor repositorylar bilan keladi:

Proxy sozlamalari

Agar kompaniyangizda internet proxy orqali chiqilsa, Nexusga ham proxy sozlamalarini kiritish kerak. Settings → System → HTTP bo'limiga o'ting:

HTTP Proxy uchun Enable HTTP Proxyni belgilab, proxy server manzili va portini kiriting:

HTTPS Proxy uchun ham xuddi shunday. Agar proxy autentifikatsiya talab qilsa, Enable HTTPS Proxy Authenticationni belgilab, login va parolni kiriting:

No Proxy Hosts — bu yerda proxy orqali chiqish shart bo'lmagan local manzillarni yozish mumkin (masalan, ichki servislar):

Repositorylar bilan ishlash

Nexusdagi eng muhim tushuncha — repository turlari. Ularni to'g'ri tushunish Nexusdan samarali foydalanish uchun juda muhim.

Proxy Repository — "Aqlli kesh"

Proxy repository tashqi (remote) repositorylarni local serverda keshlaydi.

Hayotiy misol: Tasavvur qiling, siz har kuni do'konga non olishga borasiz. Bir kuni eshik oldiga mini-do'kon ochildi — siz endi uzoqqa bormasdan, o'sha yerdan olasiz. Proxy repository ham xuddi shunday ishlaydi:

  1. Loyihangiz spring-boot-starter paketini so'raydi
  2. Nexus avval o'zining keshida qidiradi
  3. Agar topilmasa — Maven Centraldan yuklab olib, keshda saqlaydi
  4. Keyingi safar xuddi shu paket so'ralganda — internetga chiqmasdan keshdan beradi

Natija: Build tezligi oshadi, internet trafigi kamayadi, tashqi repository ishlamay qolsa ham loyihangiz build bo'laveradi.

Nexusda default maven-central proxy repository mavjud — u https://repo1.maven.org/maven2/ (opens in a new tab) manzilidan paketlarni oladi:

Hosted Repository — "Ichki ombor"

Hosted repository — kompaniyaning o'z paketlarini saqlash uchun. Bu tashqi dunyoga aloqasi yo'q, faqat sizning tashkilotingiz ichida ishlaydi.

Qachon kerak bo'ladi?

  • Kompaniyada umumiy kutubxona (shared library) yozilgan va uni barcha jamoalar ishlatishi kerak
  • Loyihaning SNAPSHOT yoki RELEASE versiyalarini markazlashtirilgan joyda saqlash kerak
  • mvn deploy yoki dotnet nuget push buyruqlari bilan artifaktlarni yuklash uchun

Nexusda default maven-releases va maven-snapshots hosted repositorylar mavjud.

Group Repository — "Yagona kirish nuqtasi"

Group repository — bir nechta repositoryni bitta URL ostida birlashtiradi.

Hayotiy misol: Savdo markazida 50 ta do'kon bor, lekin siz bitta eshikdan kirasiz. Group repository ham shunday — loyihangiz bitta URL biladi, lekin uning orqasida bir nechta repository ishlaydi.

Masalan, maven-public group repository o'z ichiga oladi:

  • maven-central (proxy) — tashqi paketlar
  • maven-releases (hosted) — kompaniyaning release paketlari
  • maven-snapshots (hosted) — kompaniyaning snapshot paketlari

Loyihangiz faqat maven-public URLni ko'rsatadi — qolganini Nexus o'zi hal qiladi.

maven-public ichidagi repositorylar:

Xuddi shunday nuget-group ham nuget-hosted va nuget.org-proxy repositorylarni birlashtiradi:

nuget.org-proxy tashqi https://api.nuget.org/v3/index.json (opens in a new tab) manzilidan NuGet paketlarni keshlaydi:

Xulosa: Nexusda default holda faqat Maven va NuGet uchun repositorylar mavjud. Docker, PyPI, Go, Cargo, Helm va boshqalar uchun repositorylarni o'zingiz yaratishingiz kerak — bu Settings → Repositories → Create Repository orqali amalga oshiriladi.

Nexus Integratsiyasi

Endi eng qiziqarli qismga o'tamiz — Nexusni real loyihalarga va CI/CD pipeline'larga ulash. Biz Java (Maven) va .NET (NuGet) integratsiyalarini ko'rib chiqamiz.

Integratsiya nima beradi?

  • Build tezligi oshadi — paketlar local Nexusdan olinadi, internet kutilmaydi
  • Barqarorlik — tashqi repository ishlamay qolsa ham build ishlaydi
  • Xavfsizlik — barcha paketlar Nexus orqali o'tadi, nazorat qilish oson
  • Trafik tejash — bir xil paket faqat bir marta internetdan yuklanadi

Java Maven

Platformamizda Java Spring Boot Deployment: Gitlab CI va Github Actions (opens in a new tab) amaliyotida biz Spring Boot Maven loyihani CI/CD bilan ishga tushirishni ko'rib chiqgandik. Endi o'sha loyihaga Nexus integratsiyasini qo'shamiz.

1-qadam: pom.xmlga repository qo'shish

Loyihangizning pom.xml fayliga quyidagi konfiguratsiyani qo'shing:

pom.xml
<repositories>
    <repository>
        <id>nexus</id>
        <url>https://nexus.helm.uz/repository/maven-public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>
 
<pluginRepositories>
    <pluginRepository>
        <id>nexus</id>
        <url>https://nexus.helm.uz/repository/maven-public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </pluginRepository>
</pluginRepositories>

Bu yerda ikki bo'lim bor:

  • <repositories> — Mavenga dependencylarni qayerdan yuklab olishni aytadi. maven-public group repository orqali ham tashqi (Maven Central), ham ichki paketlarni olish mumkin.
  • <pluginRepositories> — Maven build jarayonida ishlatiladigan plaginlarni ham Nexus orqali yuklashni ta'minlaydi. Bu muhim, chunki Maven plaginlari (compiler, surefire, jar) ham tashqi repositorydan olinadi.

<id> qiymati (nexus) keyingi bosqichdagi settings.xml dagi server ID bilan bir xil bo'lishi shart — Maven autentifikatsiyani ID orqali moslashtiradi.

2-qadam: settings.xml yaratish

settings.xml — Maven'ning global konfiguratsiya fayli. Bu yerda autentifikatsiya, mirror va profil sozlamalari bo'ladi:

settings.xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
 
    <servers>
        <server>
            <id>nexus</id>
            <username>${env.NEXUS_USER}</username>
            <password>${env.NEXUS_PASSWORD}</password>
        </server>
    </servers>
 
    <mirrors>
        <mirror>
            <id>nexus</id>
            <mirrorOf>*</mirrorOf>
            <url>https://nexus.helm.uz/repository/maven-public/</url>
            <layout>default</layout>
        </mirror>
    </mirrors>
 
    <profiles>
        <profile>
            <id>nexus</id>
            <repositories>
                <repository>
                    <id>nexus</id>
                    <url>https://nexus.helm.uz/repository/maven-public/</url>
                    <releases>
                        <enabled>true</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
            </repositories>
        </profile>
    </profiles>
 
    <activeProfiles>
        <activeProfile>nexus</activeProfile>
    </activeProfiles>
</settings>

Har bir bo'limni tushuntirib o'tamiz:

<servers> — Nexusga kirish uchun login va parol. ${env.NEXUS_USER} va ${env.NEXUS_PASSWORD} environment variable'lardan olinadi — bu CI/CD uchun xavfsiz usul, parollarni kodda saqlash shart emas.

<mirrors><mirrorOf>*</mirrorOf> degani "barcha repositorylar uchun Nexusni mirror sifatida ishlatilsin". Ya'ni Maven Central yoki boshqa tashqi repositoriyaga to'g'ridan-to'g'ri so'rov yuborish o'rniga, hamma narsa Nexus orqali o'tadi.

<profiles> va <activeProfiles>nexus nomli profil yaratiladi va faollashtiriladi. Bu Maven har qanday mvn buyrug'ida Nexus repositorydan foydalanishini ta'minlaydi.

3-qadam: CI/CD environment variable'larni sozlash

NEXUS_USER va NEXUS_PASSWORD ni CI/CD platformangizga qo'shing:

GitlabSettings → CI/CD → Variables:

NEXUS_USER — Nexus foydalanuvchi nomi:

NEXUS_PASSWORD — Nexus paroli:

GithubSettings → Secrets → New repository secret:

NEXUS_USER:

NEXUS_PASSWORD:

Xavfsizlik masalasi: Nexus uchun alohida "read-only" foydalanuvchi yaratish tavsiya etiladi. admin parolni CI/CD'da ishlatmang — agar credential sizib chiqsa, buzg'unchi butun Nexusni boshqarishi mumkin.

4-qadam: Dockerfile'ni yangilash

settings.xmlni Docker build jarayonida Maven'ga tanishtrish uchun Dockerfile'ga quyidagi qatorni qo'shamiz:

COPY settings.xml /root/.m2/settings.xml

To'liq Dockerfile:

Dockerfile
FROM maven:3.9.5-eclipse-temurin-17-alpine AS builder
WORKDIR /app
COPY settings.xml /root/.m2/settings.xml
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests -B
 
FROM eclipse-temurin:17-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
RUN chown -R appuser:appgroup /app
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD wget --spider --quiet http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-jar", "app.jar"]

mvn dependency:go-offline -B — bu buyruq barcha dependencylarni oldindan yuklab oladi. Docker layer caching tufayli, agar pom.xml o'zgarmasa, keyingi buildlarda bu qadam skiplab o'tiladi va build ancha tezlashadi.

5-qadam: CI/CD pipeline'ni yangilash

CI/CD pipeline'da settings.xml ichidagi placeholder'larni haqiqiy qiymatlar bilan almashtirishimiz kerak. Buning uchun sed buyrug'idan foydalanamiz.

Gitlab CIbefore_script bo'limiga qo'shing:

.gitlab-ci.yml
  before_script:
  - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
  - sed -i "s|\${env.NEXUS_USER}|${NEXUS_USER}|g" settings.xml
  - sed -i "s|\${env.NEXUS_PASSWORD}|${NEXUS_PASSWORD}|g" settings.xml

To'liq .gitlab-ci.yml:

.gitlab-ci.yml
stages:
  - build_and_push
  - deploy
 
variables:
  IMAGE_NAME: waifulist
  CONTAINER_NAME: waifulist
  PORT: "8080:8080"
  REPO_NAME: $CI_PROJECT_PATH
  REGISTRY: "registry.gitlab.com"
  SSH_HOST: $SERVER_IP
  SSH_USER: $SERVER_USERNAME
  SSH_KEY: $SSH_PRIVATE_KEY
  SPRING_PROFILES_ACTIVE: dev
  DEV_DATABASE_URL: $DEV_DATABASE_URL
  DEV_DATABASE_USERNAME: $DEV_DATABASE_USERNAME
  DEV_DATABASE_PASSWORD: $DEV_DATABASE_PASSWORD
 
build_and_push:
  stage: build_and_push
  image: docker:stable
 
  services:
    - docker:dind
 
  before_script:
  - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
  - sed -i "s|\${env.NEXUS_USER}|${NEXUS_USER}|g" settings.xml
  - sed -i "s|\${env.NEXUS_PASSWORD}|${NEXUS_PASSWORD}|g" settings.xml
 
  script:
    - docker build -t "$REGISTRY/$REPO_NAME/$IMAGE_NAME:$CI_COMMIT_SHA" .
    - docker push "$REGISTRY/$REPO_NAME/$IMAGE_NAME:$CI_COMMIT_SHA"
 
deploy:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --update --no-cache openssh-client
 
  script:
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "echo "$CI_JOB_TOKEN" | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker pull $REGISTRY/$REPO_NAME/$IMAGE_NAME:$CI_COMMIT_SHA"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker stop $CONTAINER_NAME || true"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker rm $CONTAINER_NAME || true"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no "$SSH_USER@$SSH_HOST" "docker run -d --name $CONTAINER_NAME --restart=always -p $PORT -e SPRING_PROFILES_ACTIVE=$SPRING_PROFILES_ACTIVE -e DEV_DATABASE_URL=$DEV_DATABASE_URL -e DEV_DATABASE_USERNAME=$DEV_DATABASE_USERNAME -e DEV_DATABASE_PASSWORD=$DEV_DATABASE_PASSWORD $REGISTRY/$REPO_NAME/$IMAGE_NAME:$CI_COMMIT_SHA"

Github Actions — yangi step qo'shing:

.github/workflows/main.yml
- name: Replace Nexus Credentials in settings.xml
  run: |
    sed -i "s|\${env.NEXUS_USER}|${{ secrets.NEXUS_USER }}|g" settings.xml
    sed -i "s|\${env.NEXUS_PASSWORD}|${{ secrets.NEXUS_PASSWORD }}|g" settings.xml

To'liq .github/workflows/main.yml:

.github/workflows/main.yml
name: Github Actions CI/CD
 
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
 
env:
  REPO_NAME: ${{ github.repository }}
  CONTAINER_NAME: waifulist
  REGISTRY: ghcr.io
  SSH_HOST: ${{ secrets.SERVER_IP }}
  SSH_USER: ${{ secrets.SERVER_USERNAME }}
  SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
  PORT: 8080:8080
  SPRING_PROFILES_ACTIVE: dev
 
jobs:
  build_and_push:
    runs-on: ubuntu-latest
    permissions:
        contents: read
        packages: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
 
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
 
      - name: Replace Nexus Credentials in settings.xml
        run: |
          sed -i "s|\${env.NEXUS_USER}|${{ secrets.NEXUS_USER }}|g" settings.xml
          sed -i "s|\${env.NEXUS_PASSWORD}|${{ secrets.NEXUS_PASSWORD }}|g" settings.xml
 
      - name: Log in to the Container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
 
      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: "${{ env.REGISTRY }}/${{ env.REPO_NAME }}:${{ github.sha }}"
          cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPO_NAME }}:buildcache
          cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPO_NAME }}:buildcache,mode=max
 
  deploy:
    needs: build_and_push
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Executing remote SSH commands to deploy
        uses: appleboy/ssh-action@master
        with:
          host: "${{ env.SSH_HOST }}"
          username: "${{ env.SSH_USER }}"
          key: "${{ env.SSH_KEY }}"
          script: |
            echo ${{ secrets.GITHUB_TOKEN }} | docker login -u ${{ github.actor }} --password-stdin ${{ env.REGISTRY }}
            docker pull "${{ env.REGISTRY }}/${{ env.REPO_NAME }}:${{ github.sha }}"
            docker stop "${{ env.CONTAINER_NAME }}" || true
            docker rm "${{ env.CONTAINER_NAME }}" || true
            docker run -d --name ${{ env.CONTAINER_NAME }} --restart=always -p ${{ env.PORT }} \
            -e SPRING_PROFILES_ACTIVE=${{ env.SPRING_PROFILES_ACTIVE }} \
            -e DEV_DATABASE_URL=${{ secrets.DEV_DATABASE_URL }} \
            -e DEV_DATABASE_USERNAME=${{ secrets.DEV_DATABASE_USERNAME }} \
            -e DEV_DATABASE_PASSWORD=${{ secrets.DEV_DATABASE_PASSWORD }} \
            ${{ env.REGISTRY }}/${{ env.REPO_NAME }}:${{ github.sha }}

6-qadam: Natijani tekshirish

CI/CD pipeline ishga tushgandan keyin loglardan barcha paketlarning nexus.helm.uz orqali yuklanayotganini ko'rishingiz mumkin:

Gitlab CI natijasi:

Github Actions natijasi:

Nexus web interfeysida ham keshlangan paketlarni ko'rish mumkin:

maven-central repository'da saqlangan local paketlar:

Diqqat: Birinchi build odatdagidan sekinroq bo'lishi mumkin — chunki Nexus barcha paketlarni birinchi marta internetdan yuklab oladi va keshga saqlaydi. Keyingi buildlar esa ancha tez bo'ladi, chunki hamma narsa local keshdan olinadi.

.NET NuGet

.NET loyihalarida NuGet paket menejeri ishlatiladi. Nexus bilan integratsiya mantiqan Maven bilan bir xil — farqi faqat konfiguratsiya fayllarida.

Ushbu bo'limda Github Actions CI/CD (opens in a new tab) amaliyotida ishlatilgan .NET Core applicationni olamiz va unga Nexus integratsiyasini qo'shamiz.

1-qadam: NuGet.Config yaratish

Loyiha root papkasida NuGet.Config faylini yaratamiz:

NuGet.Config
<configuration>
  <packageSources>
    <clear />
    <add key="Nexus" value="https://nexus.helm.uz/repository/nuget-group/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <Nexus>
      <add key="Username" value="__NEXUS_USER__" />
      <add key="ClearTextPassword" value="__NEXUS_PASSWORD__" />
    </Nexus>
  </packageSourceCredentials>
</configuration>

Bu yerda nima bo'lyapti:

  • <clear /> — NuGet'ning default manbalarini (nuget.org) o'chiradi. Endi faqat Nexus orqali paketlar olinadi.
  • nuget-group — Maven'dagi maven-public kabi, bu ham group repository bo'lib, o'z ichiga nuget-hosted va nuget.org-proxy repositorylarni oladi.
  • __NEXUS_USER__ va __NEXUS_PASSWORD__ — bu placeholder'lar. CI/CD pipeline'da ular haqiqiy qiymatlar bilan almashtiriladi.

2-qadam: CI/CD environment variable'larni sozlash

Maven bo'limidagi 3-qadam bilan bir xil — NEXUS_USER va NEXUS_PASSWORDni CI/CD platformangizga qo'shing:

GitlabSettings → CI/CD → Variables:

NEXUS_USER:

NEXUS_PASSWORD:

GithubSettings → Secrets → New repository secret:

NEXUS_USER:

NEXUS_PASSWORD:

3-qadam: Dockerfile'ni yangilash

NuGet.Config faylini Docker build jarayonida .NET SDK'ga tanishtiramiz:

COPY NuGet.Config /root/.nuget/NuGet/NuGet.Config

To'liq Dockerfile:

Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
WORKDIR /app
 
COPY NuGet.Config /root/.nuget/NuGet/NuGet.Config
COPY . .
WORKDIR "/app/GitHub.Actions.API"
RUN dotnet publish "GitHub.Actions.API.csproj" -o /app/build -c Release
 
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
ENV ASPNETCORE_ENVIRONMENT=Development
ENV TZ="Asia/Tashkent"
COPY --from=build-env /app/build .
ENTRYPOINT ["dotnet", "GitHub.Actions.API.dll", "--urls=http://0.0.0.0:4001"]

4-qadam: CI/CD pipeline'ni yangilash

Gitlab CIbefore_script bo'limiga placeholder almashtirishni qo'shamiz:

.gitlab-ci.yml
before_script:
  - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  - sed -i 's|__NEXUS_USER__|'"$NEXUS_USER"'|g' NuGet.Config
  - sed -i 's|__NEXUS_PASSWORD__|'"$NEXUS_PASSWORD"'|g' NuGet.Config

To'liq .gitlab-ci.yml:

.gitlab-ci.yml
stages:
  - build_and_push
  - deploy
 
variables:
  API_IMAGE_NAME: github-api
  API_CONTAINER_NAME: github-api
  UI_IMAGE_NAME: github-ui
  UI_CONTAINER_NAME: github-ui
  UI_PORT: "4000:4000"
  API_PORT: "4001:4001"
  REPO_NAME: $CI_PROJECT_PATH
  REGISTRY: "registry.gitlab.com"
  SSH_HOST: $SERVER_IP
  SSH_USER: $SERVER_USERNAME
  SSH_KEY: $SSH_PRIVATE_KEY
 
build_and_push:
  stage: build_and_push
  image: docker:stable
 
  services:
    - docker:dind
 
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - sed -i 's|__NEXUS_USER__|'"$NEXUS_USER"'|g' NuGet.Config
    - sed -i 's|__NEXUS_PASSWORD__|'"$NEXUS_PASSWORD"'|g' NuGet.Config
 
  script:
    - docker build -t $REGISTRY/$REPO_NAME/$API_IMAGE_NAME:$CI_COMMIT_SHA -f ./API.Dockerfile .
    - docker push $REGISTRY/$REPO_NAME/$API_IMAGE_NAME:$CI_COMMIT_SHA
    - docker build -t $REGISTRY/$REPO_NAME/$UI_IMAGE_NAME:$CI_COMMIT_SHA -f ./UI.Dockerfile .
    - docker push $REGISTRY/$REPO_NAME/$UI_IMAGE_NAME:$CI_COMMIT_SHA
 
deploy:
  stage: deploy
  image: alpine:latest
 
  before_script:
    - apk add --update --no-cache openssh-client
 
  script:
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "echo "$CI_JOB_TOKEN" | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker pull $REGISTRY/$REPO_NAME/$API_IMAGE_NAME:$CI_COMMIT_SHA"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker pull $REGISTRY/$REPO_NAME/$UI_IMAGE_NAME:$CI_COMMIT_SHA"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker stop $UI_CONTAINER_NAME || true"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker stop $API_CONTAINER_NAME || true"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker rm $UI_CONTAINER_NAME || true"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker rm $API_CONTAINER_NAME || true"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker run -d --name $API_CONTAINER_NAME --restart=always -p $API_PORT $REGISTRY/$REPO_NAME/$API_IMAGE_NAME:$CI_COMMIT_SHA"
    - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "docker run -d --name $UI_CONTAINER_NAME --restart=always -p $UI_PORT $REGISTRY/$REPO_NAME/$UI_IMAGE_NAME:$CI_COMMIT_SHA"

Github Actions — yangi step qo'shing:

.github/workflows/ci-cd.yml
- name: Replace Nexus Credentials in NuGet.Config
  run: |
    sed -i "s|__NEXUS_USER__|${{ secrets.NEXUS_USER }}|g" NuGet.Config
    sed -i "s|__NEXUS_PASSWORD__|${{ secrets.NEXUS_PASSWORD }}|g" NuGet.Config

To'liq .github/workflows/ci-cd.yml:

.github/workflows/ci-cd.yml
name: Docker CI/CD
 
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
 
env:
  API_IMAGE_NAME: github-api
  API_CONTAINER_NAME: github-api
  UI_IMAGE_NAME: github-ui
  UI_CONTAINER_NAME: github-ui
  UI_PORT: 4000:4000
  API_PORT: 4001:4001
 
  REPO_NAME: ${{ github.repository }}
  REGISTRY: ghcr.io
  SSH_HOST: ${{ secrets.SERVER_IP }}
  SSH_USER: ${{ secrets.SERVER_USERNAME }}
  SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
 
jobs:
  build_and_push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
 
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
 
      - name: Log in to the Container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
 
      - name: Replace Nexus Credentials in NuGet.Config
        run: |
          sed -i "s|__NEXUS_USER__|${{ secrets.NEXUS_USER }}|g" NuGet.Config
          sed -i "s|__NEXUS_PASSWORD__|${{ secrets.NEXUS_PASSWORD }}|g" NuGet.Config
 
      - name: Build and push API Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./API.Dockerfile
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.API_IMAGE_NAME }}:${{ github.sha }}
          cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.API_IMAGE_NAME }}:buildcache
          cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.API_IMAGE_NAME }}:buildcache,mode=max
 
      - name: Build and push UI Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./UI.Dockerfile
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.UI_IMAGE_NAME }}:${{ github.sha }}
          cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.UI_IMAGE_NAME }}:buildcache
          cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.UI_IMAGE_NAME }}:buildcache,mode=max
 
  deploy:
    needs: build_and_push
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Executing remote SSH commands to deploy
        uses: appleboy/ssh-action@master
        with:
          host: "${{ env.SSH_HOST }}"
          username: "${{ env.SSH_USER }}"
          key: "${{ env.SSH_KEY }}"
          script: |
            echo ${{ secrets.GITHUB_TOKEN }} | docker login -u ${{ github.actor }} --password-stdin ${{ env.REGISTRY }}
            docker pull "${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.API_IMAGE_NAME }}:${{ github.sha }}"
            docker pull "${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.UI_IMAGE_NAME }}:${{ github.sha }}"
            docker stop "${{ env.UI_CONTAINER_NAME }}" || true
            docker stop "${{ env.API_CONTAINER_NAME }}" || true
            docker rm "${{ env.UI_CONTAINER_NAME }}" || true
            docker rm "${{ env.API_CONTAINER_NAME }}" || true
            docker run -d --name "${{ env.API_CONTAINER_NAME }}" --restart=always -p "${{ env.API_PORT }}" "${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.API_IMAGE_NAME }}:${{ github.sha }}"
            docker run -d --name "${{ env.UI_CONTAINER_NAME }}" --restart=always -p "${{ env.UI_PORT }}" "${{ env.REGISTRY }}/${{ env.REPO_NAME}}/${{ env.UI_IMAGE_NAME }}:${{ github.sha }}"

5-qadam: Natijani tekshirish

Github Actions muvaffaqiyatli tugagandan keyin:

Nexus interfeysida keshlangan NuGet paketlarni ko'rish mumkin:

nuget-group repository ichidagi paketlar:

Xulosa

Ushbu qo'llanmada biz:

  1. Nexusni Docker yordamida o'rnatdik (manual va Ansible orqali)
  2. Domen va HTTPS uladik (NGINX + Let's Encrypt)
  3. Repository turlarini (Proxy, Hosted, Group) tushunib oldik
  4. Maven va NuGet loyihalarini Nexus bilan integratsiya qildik
  5. Gitlab CI va Github Actions pipeline'larida Nexusdan foydalanishni sozladik

Keyingi qadam sifatida Docker, PyPI, Go, Cargo, Helm va boshqa texnologiyalar uchun ham Nexusda repositorylar yaratib, loyihalaringizni ulashingiz mumkin — mantiq bir xil, farqi faqat konfiguratsiya formatida.

Qo'shimcha