Skip to content
Dokumentatsiya
Sonatype Nexus

Sonatype Nexus Repository Manager

Kirish

Bugungi software development jarayonlarida CI/CD (Continuous Integration/Continuous Deployment) jarayonlarini samarali yuritish muhim ahamiyat kasb etadi. Bunday jarayonlarda paketlar va artifaktlarni boshqarish uchun maxsus repository managerlar kerak bo'ladi. Sonatype Nexus Repository Manager - eng ommabop va ishonchli artifakt menejerlardan biri bo'lib, Java (Maven, Gradle), .NET (NuGet), Python (PyPi), Docker va boshqa paketlarni saqlash va boshqarish uchun eng mashhur va ishonchli yechimlardan biridir.

Nexus opensource (Nexus OSS) va pullik (Nexus Pro) versiyalarda mavjud bo'lib, ushbu qo'llanma asosan Nexus OSS bilan ishlashga yo'naltirilgan.

Sonatype Nexus Repository Manager dasturi dastlab 2007-yilda Sonatype Inc. tomonidan ishlab chiqilgan. U dasturiy ta'minot artifaktlarini saqlash, boshqarish va tarqatish uchun mo'ljallangan markazlashtirilgan repository menejeri sifatida ishlab chiqilgan.

Nexus Repository Manager dasturiy ta'minot ishlab chiqishda artifaktlar va paketlarni saqlash, boshqarish hamda ularga kirishni ta'minlash uchun ishlatiladi. Java (Maven, Gradle), .NET (NuGet), Node.js (NPM), Docker, Python (PyPi) kabi texnologiyalar uchun artifaktlarni markazlashtirilgan holda saqlaydi va boshqaradi.Tashqi repository'lardan yuklash jarayonlarini tezlashtirish va tarmoq yuklamasini kamaytirish imkonini beradi va Korxona ichki(local) repositoriyasini yaratishi, Kompaniyaning o'ziga xos kutubxonalarini(library) boshqarish, xavfsizlikni ta'minlash va dasturiy ta'minot jarayonlarini optimallashtirish uchun ishlatiladi.

Bu amaliyotda biz Sonatype Nexus Repository Managerni docker yordamida o'rnatish va sozlashni va loyihalarimizga va CI/CD ga integratsiya qilishni ko'rib chiqamiz.

Nexus o'rnatish

Bu amaliyotda biz Nexusni docker yordamida ishga tushiramiz va o'rnatishning manual va ansible yordamida qilishni ko'rib chiqamiz.

Minimum Server talabi

OSRAMCPUXotiraStatic IP
Ubuntu 20.04 yoki Rocky Linux 88GB480GBHa kerak

Quyidagi qo'llanmadan foydalanib Docker o'rnatib olishingiz mumkin - Docker o'rnatish (opens in a new tab)

Manual o'rnatish

1-> Nexusni docker orqali o'rnatayotganimiz sababli nexus malumotlarini docker volume yoki hostpath qilib saqlashimiz kerak bo'ladi aks holda nexus container restart bo'lganda malumotlar o'chib ketadi shuning uchun nexusga data papka ochib olamiz.

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

2-> Nexusni docker yordamida ishga tushiramiz va nexus-datani serverimizdagi /mnt/nexus/nexus-dataga ulab qo'yamiz va --restart=always flagi orqali tasodifan server yoki docker restart bo'lganda avtomatik ishga tushirilishini belgilaymiz.

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

3-> Nexusni ishga tushirganimizdan keyin u default admin user va parol bilan birga keladi, admin parolni olish uchun quyidagicha amalni bajaramiz.

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

Nexusni o'rnatib bo'lganimizdan keyin brauzerda server_ip:8081 manzilini ochganimizda Nexus ochilishi kerak. Nexus default porti 8081 bo'ladi.

Bu qismda ->Sign in bosib Nexusning login sahifasiga o'tamiz. Default admin user va generatsiya qilingan default parol bilan kiramiz. Bu qismda esa default parol o'rniga o'zimiz yangi parol qo'yishni talab qiladi yangi parolni yozib kiritamiz. Bu qismda o'zimizga kerak tanlovni tanlaymiz. Sizda admin user bilan kirganingizdan keyin sizda quyidagicha dastlabki sahifa ochiladi.

Nexusga domen ulash

Bu bo'limda biz Nexusni domen orqali ulashni va Letsencrypt sertifikat orqali SSL olishni ko'rib chiqamiz.

1-> Nginx va certbotni o'rnatamiz.

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

2-> Nexusga bo'glamoqchi bo'lgan domenimiz DNS serveridan A record ochib serverimiz IP manzilini qo'shib qo'yamiz. Rasmda ahost misolida helm.uz domeniga nexus subdomen qo'shib ko'rsatilgan. 3-> Bog'lamoqchi bo'lgan domenimiz nomi bilan nginx konfiguratsiyasini yaratamiz.

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

Quyidagicha konfiguratsiyani yozamiz.

/etc/nginx/sites-available/nexus.helm.uz
server {
    listen 80;
    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;
    }
}

4-> Konfiguratsiyani sites-enabled papkasiga joylaymiz.

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

5-> Nginxga restart beramiz.

sudo systemctl restart nginx

6-> certbot orqali Letsencrypt sertifikatni olish uchun quyidagi buyruqni yozamiz.

sudo certbot

Bunda siz certbot uchun email yozasiz va Terms of Service ni qabul qilishingiz kerak bo'ladi y bosib o'tib ketasiz. Bu qismda sizning domenlaringizni ko'rsatadi siz kerakli domenlarni tanlab Enter bosib o'tib ketasiz, bizning holatda 1. Sertifikat muvaffaqiyatli olinganidan keyin nginxni restart qilamiz.

sudo systemctl restart nginx

Tekshirib ko'rish uchun brauzerda https://nexus.helm.uz (opens in a new tab) manzilini ochganimizda Nexus https bilan ochilishi kerak.

Nexus bilan tanishuv

Nexus Repository Manager APT, Cargo, Bower CocoaPods, Composer, Conan, Conda, Docker, Git LFS, Go, Helm, Hugging Face, Maven, npm, NuGet, p2, PyPI, R, Raw, RubyGems, Yum(RPM) kabi texnologiyalar uchun repositorylar yaratish va boshqarishni qo'llab-quvvatlaydi.

Sonatype Incning Sonatype Nexus Repositorydan tashqari Sonatype Repository Firewall, Sonatype Lifecycle va Sonatype SBOM kabi service'lari ham mavjud.

Nexusga kirganimizda asosiy sahifa ochiladi. -> Server Administration and Configuration bo'limida server va konfiguratsiyalarini o'zgartirish imkoniyati mavjud. -> Blob Stores bo'limida Nexusning fayllarni saqlash uchun ishlatiladigan papkalarni ko'rishimiz mumkin, bizning holda default papkasi(blobstore) mavjud. -> Repository bo'limida repositorylarimizni ko'rishimiz mumkin, nexusda default maven-public, maven-central, maven-releases, maven-snapshots, nuget-group, nuget-hosted, nuget.org-proxy repositorylar mavjud.

Agar siz kompaniyangizda Proxy bilan internetga chiqish talab qilinsa -> Settings -> System -> HTTP bo'limiga o'tib proxy sozlashimiz mumkin. HTTP Proxy uchun Enable HTTP Proxyni belgilaymiz va HTTP Proxy Host ga proxy serverimiz addresi va HTTP Proxy Port ga portni kiritamiz. HTTPS Proxy uchun Enable HTTPS Proxyni belgilaymiz va HTTPS Proxy Hostga proxy serverimiz addresi va HTTPS Proxy Port ga portni kiritamiz. Agar sizning proxyyingiz HTTPS Authenticationni talab qilinsa Enable HTTPS Proxy Authenticationni belgilaymiz va HTTPS Proxy Username va HTTPS Proxy Passwordni kiritib ishlatishimiz mumkin. Nexus servergfa proxy sozlamalarini sozlagandan keyin proxysiz ulanadigan local sercvicelarimizga NO Proxy Hosts qismida yozishimiz mumkin.

Repositorylar bilan ishlash

Sonatype Nexus Repository Manager repositoriyalarni tashkil qilish va boshqarish uchun turli xil turlarni(repo type) qo'llab-quvvatlaydi, ulardan eng asosiylari Proxy, Hosted va Group repositoriyalaridir.

Proxy typedagi repositoriya - tashqi (remote) repositoriyalarni mahalliy (local) server orqali kechlashtirish (cache) va ulardan foydalanishni optimallashtirish uchun ishlatiladi. U Maven Central, NuGet Gallery, Docker Hub, NPM Registry, PyPi va boshqa repositoriyalardan paketlarni olish uchun qo'llaniladi. Bu turdagi repositoriyaning asosiy maqsadi internetga chiqishni kamaytirish va local serverda paketlarni saqlashdir, loyihamiz nexusga ulanganidan keyin u paketlarni yuklab olish uchun birinchi bo'lib nexusga so'rov yuboradi agar loyiha so'ragan package nexus local repositoriyada bo'lmasa Proxy typedagi repositoriya berilgan remote repositorydan oladi va nexus local repositoriyada cache qilib saqlaydi.

Hosted typedagi repository - lokal serverda paketlarni saqlash uchun ishlatiladi. U Maven, NuGet, Docker, PyPi va boshqa paketlarni saqlash uchun ishlatiladi. Bu turdagi repositorylar loyihalarga xizmat qilish uchun ishlatiladi, loyiha paketlarini yuklash uchun ishlatiladi. Bu turdagi repositoriyaning asosiy maqsadi Kompaniya uchun maxsus yozilgan packagelar uchun local repository bo'lib xizmat qiladi.

Group repository - bu bir nechta repositoriyalarni bitta umumiy repositoriya sifatida boshqarish imkonini beruvchi repository turi. Group repository bir vaqtning o'zida Proxy, Hosted va boshqa repositoriyalarni bitta URL orqali boshqarishga yordam beradi. Bu turdagi repositoriya ishlatishga bitta misol: maslan sizda maven-central, maven-releases, maven-snapshots repositorylar mavjud bo'lsa siz ularni bitta maven-public repositoryda birlashtirib qo'yishingiz mumkin va loyihalarga bitta URL orqali boshqarish imkonini beradi, yani siz loyihangizni Nexusga ulaganingizda bitta maven-public repositoriyani belgilab ishlatishingiz mumkin uching ichida esa maven-central, maven-releases, maven-snapshots repositorylar mavjud bo'ladi.

Nexusda default holda Maven va Nuget uchun Proxy, Hosted va Group repositorylar mavjud bo'ladi, Python, Go, Docker, Cargo va boshqalar uchun o'zingiz repositoriyalar yaratishingiz kerak bo'ladi.

-> Server Administration and Configuration bo'limidan -> Repositories bo'limiga o'tib repositoriyalarni ko'rishimiz mumkin. Nexus default repositoriyalar. Keling masalan maven-central repositoryni ko'rib chiqamiz. Bu repositoriya turi Proxy bo'lib internetdan https://repo1.maven.org/maven2/ (opens in a new tab) manzilidan ma'lumotlarni olish uchun ishlatiladi. Quyidagi rasmda maven packagelarni qaysi global repositoriyadan olishini ko'rishimiz mumkin https://repo1.maven.org/maven2/ (opens in a new tab).

maven-public repositoriya group repositoriya bo'lib maven-central, maven-releases, maven-snapshots repositoriyalarini birlashtirgan repositoriya bo'lib, bu repositoriyadan maven packagelarni olishimiz mumkin. Bu rasmda maven-public repositoriyamiz o'z ichiga olgan maven-central, maven-releases, maven-snapshots repositoriyalarini ko'rishimiz mumkin. nuget-group repository ham group repository bo'lib nuget-hosted, nuget.org-proxy repositorylarini birlashtirgan repositoriya bo'lib, bu repositoriyadan nuget packagelarni yani .NET packagelarni olishimiz mumkin. nuget.org-proxy repositoriya proxy repositoriya bo'lib https://api.nuget.org/v3/index.json (opens in a new tab) addresidan nuget packagelarni olish uchun ishlatiladi.

Nexus Integratsiyasi

Bu bosqichda Maven va NuGet loyihalarini Sonatype Nexus Repository Manager bilan integratsiya qilish va shuningdek, CI/CDga qo'shishni ko'rib chiqamiz. Bu bilan biz Nexus'ni ishlatish orqali build vaqtlarini qisqartirish, paketlarni local boshqarish va xavfsizlikni oshirish imkoniyatiga ega bo'lamiz.

Java Maven

Platformamizda Java Spring Boot Deployment: Gitlab CI va Github Actions (opens in a new tab) amaliyotida biz Spring Boot Maven projectni GItlab CI va Github Actyions bilan CI/CD yozib ishga tushirishni ko'rib chiqgandik endi bu bosqichda unga nexus inetgratsiyani ko'rib chiqamiz.

1-> Loyihangizda pom.xml faylga quyidagicha dependencyni qo'shib qo'yamiz.

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>

<repositories> bo'limi Mavenga Nexusdagi dependencylarni yuklab olish uchun qayerga murojaat qilish kerakligini bildiradi. <id> - Repositoriyani identifikatsiya qilish uchun unikal nom (nexus deb belgilangan) <url> - Nexus repositoriyaning manzili (https://nexus.helm.uz/repository/maven-public/ (opens in a new tab)). <releases> - Release versiyalarning yuklab olinishi yoqilgan (true). <snapshots> - Snapshot versiyalar ham qollab-quvvatlanishi yoqilgan (true).

<pluginRepositories> Maven pluginlarini Nexus repositoriyadan yuklash uchun ishlatiladi. Bu Maven build va test jarayonlari uchun zarur bo'lgan plaginlarni Nexus orqali yuklashni taminlaydi. Agar loyiha Maven pluginlari uchun Nexusdan foydalanmoqchi bo'lsa, ushbu bo'lim kiritilishi shart.

2-> Loyihangizda settings.xml faylga quyidagicha sozlamalarni qo'shib qo'yamiz.

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>

<servers> bo'limi Autentifikatsiya konfiglarini o'z ichiga oladi. <id> - pom.xmldagi repository ID bilan bir xil bo'lishi kerak (nexus). <username> va <password> - Nexusga kirish uchun foydalanuvchi nomi va parol. Nexusga kirish uchun login va parol environment variable sifatida yozilgan ${env.NEXUS_USER} va ${env.NEXUS_PASSWORD}. Bu konfiguratsiya Nexusga artifaktlarni yuklash (mvn deploy) yoki yuklab olish (mvn install) uchun autentifikatsiyani ta'minlaydi.

<mirrorOf>*</mirrorOf> - Barcha (*) repositoriyalar uchun Nexusni o'zgartirilgan mirror sifatida ishlatishni bildiradi. <url> - Nexus'ning maven-public repositoriyasi orqali barcha dependencylarni yuklash bildiradi. <layout> esa default Maven repository arxitekturasi ishlatiladi. Bu bo'lim Maven Central yoki boshqa tashqi repositoriyalarni bevosita ishlatish o'rniga, ularni Nexus orqali yuklab olishni ta'minlaydi.

<profiles> bo'limi turli xil konfiguratsiyalarni yaratish va ishlatish imkonini beradi, bunda biz <id> nexus nomli profil yaratib olamiz va <repositories> bu Maven repositoriyalarini yaratish uchun ishlatiladi, unga biz Nexus repositoriya urlni qo'shib qo'yamiz va <activeProfiles> bo'limida nexusni profilni faollashtiramiz, shunda mvn buyruqlari bajarilganda, Maven ushbu profilni ishlatadi, nexus profili faollashtirilganda, Maven dependencylarni https://nexus.helm.uz/repository/maven-public/ (opens in a new tab) orqali yuklaydi.

3-> ${env.NEXUS_USER} va ${env.NEXUS_PASSWORD} environment variablelarni agar sizda Gitlab bo'lsa Gitlab CI/CD variablesga yoki Githubda bo'lsa Github Secretsga qo'shib qo'yishimiz kerak bo'ladi.

Gitlabda Settings -> CI/CD -> Variables bo'limiga o'tib quyidagicha variablelarni qo'shib qo'yamiz.

NEXUS_USER - Nexusga kirish uchun foydalanuvchi nomi. NEXUS_PASSWORD - Nexusga kirish uchun foydalanuvchi paroli.

Githubda esa Settings -> Secrets -> New repository secret bo'limiga o'tib quyidagicha secretlarni qo'shib qo'yamiz.

NEXUS_USER - Nexusga kirish uchun foydalanuvchi nomi. NEXUS_PASSWORD - Nexusga kirish uchun foydalanuvchi paroli.

4-> Maven loyihani settings.xml bilan ishga tushirish uchun Dockerfileni ham yangilashimiz kerak bo'ladi.

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

qatorini Dockerfilega qo'shib qo'yamiz.

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"]

5-> Loyihamiz CI/CD'sida ham o'zgarishlar kiritishimiz kerak bo'ladi.

Gitlab CI uchun before_script bo'limiga quyidagicha yangilamymiz bu qatorlar sed yordamida settings.xml faylga NEXUS_USER va NEXUS_PASSWORD environment variablelarni yozadi.

.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 .gitlab-ci.yml fayli quyidagicha ko'rinishda bo'ladi.

.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 uchun.

.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 Actions .github/workflows/main.yml fayli quyidagicha ko'rinishda bo'ladi.

.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-> Keling endi loyiha CI/CD orqali ishga tushirib uni tekshirib ko'ramiz, loyihamiz barcha package va dependencylarni Nexus orqali yuklab olishi kerak.

Gitlab CI'da ko'rib turganinigizdek barcha package va dependencylarni nexus.helm.uz/repository/maven-public/ manzili orqali yuklab olyapti. Github Actionsda

Nexusga brazuerdan kirib ko'rganimizda ham o'zgarishlarni sezishimiz mumkin.

Nexusdan maven-central repositoryni ko'rib chiqadigan bo'lsak nexus o'zida saqlayotgan local package va dependencylarni ko'rishimiz mumkin.

.NET NuGet

.NET Core loyihalarida Sonatype Nexus Repository Manager bilan integratsiya qilish uchun quyidagicha bosqichlarni bajaramiz. NuGet - bu .NET loyihalari uchun paket menejeri bo'lib, u turli librarylar va tollarni boshqarish uchun ishlatiladi. NuGet.Config fayli NuGet paketlarini Nexus'ga yo'naltirish, hamda autentifikatsiya ma'lumotlarini kiritish uchun ishlatiladi.

Ushbu bo'limda Github Actions CI/CD (opens in a new tab) amaliyotida ishlatilgan https://github.com/devops-journey-uz/devops-journey-github-actions (opens in a new tab) .NET Core applicationini ishlatamiz, bunga oldin biz Github Actions bilan CI/CD yozib ishga tushirishni ko'rib chiqgandik endi bu bosqichda unga nexus inetgratsiyani ko'rib chiqamiz.

1-> Loyihamizda NuGet.Config faylini yaratamiz va quyidagicha configuratsiya qilamiz.

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>

Konfiguratsiyada packageSources - NuGet paket manbalarini aniqlash uchun ishlatiladi. <clear /> avvalgi NuGet manbalarini tozalaydi va faqat biz bergan nexus manbadan foydalanadi. <add key="Nexus" value="https://nexus.helm.uz/repository/nuget-group/index.json" /> Nexus nomli yangi NuGet repositoriya qo'shiladi url esa nuget packagelarni yuklab olish uchun berilgan nexus repositoriya manzili. packageSourceCredentials Autentifikatsiya ma'lumotlarini o'z ichiga oladi. Bu yerdagi __NEXUS_USER__ va __NEXUS_PASSWORD__ o'zgaruvchilar Gitlab CI variable yoki Github Secretsga qo'shib ishlatiladi.

2-> __NEXUS_USER__ va __NEXUS_PASSWORD__ environment variablelarni agar sizda Gitlab bo'lsa Gitlab CI/CD variablesga yoki Githubda bo'lsa Github Secretsga qo'shib qo'yishimiz kerak bo'ladi.

Gitlabda Settings -> CI/CD -> Variables bo'limiga o'tib quyidagicha variablelarni qo'shib qo'yamiz.

NEXUS_USER - Nexusga kirish uchun foydalanuvchi nomi. NEXUS_PASSWORD - Nexusga kirish uchun foydalanuvchi paroli.

Githubda esa Settings -> Secrets -> New repository secret bo'limiga o'tib quyidagicha secretlarni qo'shib qo'yamiz.

NEXUS_USER - Nexusga kirish uchun foydalanuvchi nomi. NEXUS_PASSWORD - Nexusga kirish uchun foydalanuvchi paroli.

3-> Dockerfile faylini quyidagicha yangilaymiz.

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

qatorini Dockerfilega qo'shib qo'yamiz.

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-> Loyihamiz CI/CD'sida ham o'zgarishlar kiritishimiz kerak bo'ladi.

Gitlab CI uchun before_script bo'limiga quyidagicha yangilamymiz bu qatorlar sed yordamida NuGet.Config faylga NEXUS_USER va NEXUS_PASSWORD environment variablelarni yozadi.

.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 .gitlab-ci.yml fayli quyidagicha ko'rinishda bo'ladi.

.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 .github/workflows/ci-cd.yml faylini quyidagicha yangilaymiz.

.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 Actions .github/workflows/ci-cd.yml fayli quyidagicha ko'rinishda bo'ladi.

.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-> Keling endi loyihani CI/CD orqali ishga tushirib uni tekshirib ko'ramiz, loyihamiz barcha package va dependencylarni Nexus orqali yuklab olishi kerak.

Ko'rib turganingizdek Github Actions CI/CD muvaffaqiyatli yakunlangan.

Nexusga brazuerdan kirib ko'rganimizda ham o'zgarishlarni sezishimiz mumkin.

Nexusdan nuget-group repositoriyani ko'rib chiqadigan bo'lsak nexus o'zida saqlayotgan local package va dependencylarni ko'rishimiz mumkin.

Nihoyat biz bugungi Sonatype Nexus Repository Manager bilan bo'lgan amaliyotimizni shu yerda yakunlaymiz, o'ylaymanku bu sizga foydali bo'ldi. Agar sizda savollar yoki takliflar bo'lsa, ularni shu post izohlariga yozishingiz mumkin. Qolgan PyPI, Docker, Go, Cargo va boshqa package repositoriyalarni sozlashni o'zingiz davom ettirasiz ))

Qo'shimcha