diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index baa8c0c..9aac851 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -1,64 +1,84 @@ -# This worklflow will perform following actions when the code is pushed to the development branch: -# - Build the latest docker image in development which needs test to pass first. -# - Push the docker image to Docker Hub under namespace - nfdi4chem with tag:dev-latest. +# This workflow will perform following actions when code is pushed to the development branch: +# - Run tests and linting checks (can be enabled via needs: test_and_lint) +# - Build and push nmrKit Docker image with layer caching for faster builds +# - Conditionally build nmr-cli image only if files in app/scripts/nmr-cli/ changed +# - Push images to Docker Hub under namespace nfdi4chem with dev-latest tag +# - Prevent redundant builds using concurrency control # # Maintainers: # - name: Nisha Sharma # - email: nisha.sharma@uni-jena.de -name : Dev Build, Test and Publish +name : Prod Build and Publish to Dev on: push: branches: [development] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: - DOCKER_HUB_USERNAME : ${{ secrets.DOCKER_USERNAME }} - DOCKER_HUB_PASSWORD : ${{ secrets.DOCKER_PASSWORD }} NMRKIT_REPOSITORY_NAME: nmrkit NMR_CLI_REPOSITORY_NAME: nmr-cli REPOSITORY_NAMESPACE: nfdi4chem RELEASE_TAG: dev-latest jobs: - test_and_lint: - uses: ./.github/workflows/test.yml - - push_to_registry: + # test_and_lint: + # uses: NFDI4Chem/nmrkit/.github/workflows/test.yml@main + build_and_push_to_registry: name: Push Docker image to Docker Hub runs-on: ubuntu-latest needs: test_and_lint steps: + # Clone repository code to runner - name: Check out the repo uses: actions/checkout@v4 + # Enable advanced Docker build features (required for caching) + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Authenticate with Docker Hub for image push access - name: Log in to Docker Hub - uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + # Detect changes in nmr-cli folder to skip unnecessary builds + - name: Check for file changes + id: changes + uses: dorny/paths-filter@v3 with: - username: ${{ env.DOCKER_HUB_USERNAME }} - password: ${{ env.DOCKER_HUB_PASSWORD }} + filters: | + nmr-cli: + - 'app/scripts/nmr-cli/**' + # Build main nmrKit image with registry caching for faster builds - name: Build and push nmrKit Docker image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile push: true - build-args: | - RELEASE_VERSION=dev-latest + build-args: RELEASE_VERSION=${{ env.RELEASE_TAG }} tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMRKIT_REPOSITORY_NAME }}:${{ env.RELEASE_TAG }} - username: ${{ env.DOCKER_HUB_USERNAME }} - password: ${{ env.DOCKER_HUB_PASSWORD }} + cache-from: type=registry,ref=${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMRKIT_REPOSITORY_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMRKIT_REPOSITORY_NAME }}:buildcache,mode=max + # Build nmr-cli image only if files in app/scripts/nmr-cli/ changed - name: Build and push nmr-cli Docker image - uses: docker/build-push-action@v4 + if: steps.changes.outputs.nmr-cli == 'true' + uses: docker/build-push-action@v6 with: context: ./app/scripts/nmr-cli/ file: ./app/scripts/nmr-cli/Dockerfile push: true - build-args: | - RELEASE_VERSION=dev-latest + build-args: RELEASE_VERSION=${{ env.RELEASE_TAG }} tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMR_CLI_REPOSITORY_NAME }}:${{ env.RELEASE_TAG }} - username: ${{ env.DOCKER_HUB_USERNAME }} - password: ${{ env.DOCKER_HUB_PASSWORD }} \ No newline at end of file + cache-from: type=registry,ref=${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMR_CLI_REPOSITORY_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMR_CLI_REPOSITORY_NAME }}:buildcache,mode=max \ No newline at end of file diff --git a/.github/workflows/prod-build.yml b/.github/workflows/prod-build.yml index b6c4eea..b99f7a4 100644 --- a/.github/workflows/prod-build.yml +++ b/.github/workflows/prod-build.yml @@ -1,60 +1,120 @@ -# This worklflow will perform following actions when the code is pushed to main branch: -# - Build the latest docker image in main which needs test to pass first. -# - Push the docker image to Docker Hub under namespace - nfdi4chem with tag:[release_version]. +# This workflow will perform following actions when code is pushed to the main branch: +# - Run tests and linting checks (can be enabled via needs: test_and_lint) +# - Build and push nmrKit Docker image with layer caching for faster builds +# - Conditionally build nmr-cli image only if files in app/scripts/nmr-cli/ changed +# - Push images to Docker Hub under namespace nfdi4chem with latest tag +# - Prevent redundant builds using concurrency control # # Maintainers: # - name: Nisha Sharma # - email: nisha.sharma@uni-jena.de -name : Prod Build, Test and Publish +name : Prod Build and Publish +# Runs on manual workflow_dispatch with confirmation on: - release: - types: [published] + workflow_dispatch: + inputs: + confirm: + description: "Type 'DEPLOY' to confirm production deployment" + required: true + type: string + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true env: - DOCKER_HUB_USERNAME : ${{ secrets.DOCKER_USERNAME }} - DOCKER_HUB_PASSWORD : ${{ secrets.DOCKER_PASSWORD }} - REPOSITORY_NAME: nmrkit + NMRKIT_REPOSITORY_NAME: nmrkit + NMR_CLI_REPOSITORY_NAME: nmr-cli REPOSITORY_NAMESPACE: nfdi4chem + RELEASE_TAG: latest jobs: - push_to_registry: + # test_and_lint: + # uses: NFDI4Chem/nmrkit/.github/workflows/test.yml@main + + # Guard: confirm input and authorize actor + guard: + name: Access control and confirmation + runs-on: ubuntu-latest + steps: + - name: Validate actor and confirmation + shell: bash + run: | + echo "Actor: ${GITHUB_ACTOR}" + # Confirm input (workflow_dispatch) + if [[ "${{ github.event.inputs.confirm }}" != "DEPLOY" ]]; then + echo "Confirmation token mismatch. Expected 'DEPLOY'." + exit 1 + fi + + # Authorize actor (comma/space separated list in secret) + AUTHORIZED_ACTORS="${{ secrets.PROD_DEPLOY_AUTHORIZED_ACTORS }}" + allowed=0 + for u in ${AUTHORIZED_ACTORS//,/ }; do + if [[ "${u,,}" == "${GITHUB_ACTOR,,}" ]]; then + allowed=1 + break + fi + done + if [[ $allowed -ne 1 ]]; then + echo "User '${GITHUB_ACTOR}' is not authorized to trigger this workflow." + exit 1 + fi + echo "Authorization check passed." + + build_and_push_to_registry: name: Push Docker image to Docker Hub runs-on: ubuntu-latest + needs: guard steps: + # Clone repository code to runner - name: Check out the repo uses: actions/checkout@v4 - - #Fetch Latest release - - name: Fetch latest release - id: fetch-latest-release - uses: InsonusK/get-latest-release@v1.0.1 - with: - myToken: ${{ github.token }} - exclude_types: "draft" - view_top: 10 - - name: "Print release name" - run: | - echo "tag_name: ${{ steps.fetch-latest-release.outputs.tag_name }}" - - #Login to Docker Hub + + # Enable advanced Docker build features (required for caching) + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Authenticate with Docker Hub for image push access - name: Log in to Docker Hub - uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + uses: docker/login-action@v3 with: - username: ${{ env.DOCKER_HUB_USERNAME }} - password: ${{ env.DOCKER_HUB_PASSWORD }} - - #Build and push Docker image - - name: Build and push Docker image - uses: docker/build-push-action@v4 + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + # Detect changes in nmr-cli folder to skip unnecessary builds + - name: Check for file changes + id: changes + uses: dorny/paths-filter@v3 + with: + filters: | + nmr-cli: + - 'app/scripts/nmr-cli/**' + + # Build main nmrKit image with registry caching for faster builds + - name: Build and push nmrKit Docker image + uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile push: true - build-args: | - RELEASE_VERSION=${{ steps.fetch-latest-release.outputs.tag_name }} - tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:${{ steps.fetch-latest-release.outputs.tag_name }} - username: ${{ env.DOCKER_HUB_USERNAME }} - password: ${{ env.DOCKER_HUB_PASSWORD }} \ No newline at end of file + build-args: RELEASE_VERSION=${{ env.RELEASE_TAG }} + tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMRKIT_REPOSITORY_NAME }}:${{ env.RELEASE_TAG }} + cache-from: type=registry,ref=${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMRKIT_REPOSITORY_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMRKIT_REPOSITORY_NAME }}:buildcache,mode=max + + # Build nmr-cli image only if files in app/scripts/nmr-cli/ changed + - name: Build and push nmr-cli Docker image + if: steps.changes.outputs.nmr-cli == 'true' + uses: docker/build-push-action@v6 + with: + context: ./app/scripts/nmr-cli/ + file: ./app/scripts/nmr-cli/Dockerfile + push: true + build-args: RELEASE_VERSION=${{ env.RELEASE_TAG }} + tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMR_CLI_REPOSITORY_NAME }}:${{ env.RELEASE_TAG }} + cache-from: type=registry,ref=${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMR_CLI_REPOSITORY_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REPOSITORY_NAMESPACE }}/${{ env.NMR_CLI_REPOSITORY_NAME }}:buildcache,mode=max \ No newline at end of file diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 1f774ca..9ab91ec 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -1,31 +1,20 @@ - -# This worklflow will perform following actions when the code is pushed to main branch. -# - Test linting with pylint. -# - Test the code with pytest. -# - Trigger release-please action to create release which needs test to pass first. -# -# Maintainers: -# - name: Nisha Sharma -# - email: nisha.sharma@uni-jena.de - -name: release-please-action +name: Release Please on: push: branches: - main + workflow_dispatch: {} jobs: - test_and_lint: - uses: NFDI4Chem/nmrkit/.github/workflows/test.yml@main - release-please: runs-on: ubuntu-latest - needs: test_and_lint + permissions: + contents: write + pull-requests: write steps: - - uses: google-github-actions/release-please-action@v3 + - uses: googleapis/release-please-action@v4.2.0 with: release-type: python - package-name: release-please-action - token: ${{ secrets.PAT }} - prerelease: true \ No newline at end of file + target-branch: main + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/env.template b/env.template index 6a4dca7..548cdb8 100644 --- a/env.template +++ b/env.template @@ -1,4 +1,4 @@ -POSTGRES_USER=sail +POSTGRES_USER=user POSTGRES_PASSWORD=password POSTGRES_SERVER=pgsql POSTGRES_PORT=5432 diff --git a/ops/docker-compose-dev.yml b/ops/docker-compose-dev.yml index 5508f04..e9c3a2b 100644 --- a/ops/docker-compose-dev.yml +++ b/ops/docker-compose-dev.yml @@ -1,5 +1,3 @@ -version: "3.8" - services: traefik: image: traefik:v2.10 @@ -13,9 +11,9 @@ services: - 80:80 # - 8080:8080 # Optional: Expose Traefik dashboard on port 8080 volumes: - - /var/run/docker.sock:/var/run/docker.sock - - web: + - "/var/run/docker.sock:/var/run/docker.sock:ro" + nmrkit-api: + container_name: nmrkit-api image: nfdi4chem/nmrkit:dev-latest pull_policy: always labels: @@ -23,110 +21,42 @@ services: - "traefik.http.routers.web.rule=Host(`dev.nmrkit.nmrxiv.org`)" - "traefik.http.routers.web.entrypoints=web" - "traefik.http.services.web.loadbalancer.server.port=80" + volumes: + - ../app:/code/app + - "/var/run/docker.sock:/var/run/docker.sock" + - shared-data:/shared healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:80/latest/registration/health"] - interval: 1m + test: + [ + "CMD", + "curl", + "-f", + "http://localhost:80/latest/registration/health" + ] + interval: 1m30s timeout: 10s - retries: 10 - start_period: 40s + retries: 20 + start_period: 60s env_file: - - ./.env - - nmr-load-save: + - ../.env + nmr-converter: + #build: ./app/scripts/nmr-cli + container_name: nmr-converter image: nfdi4chem/nmr-cli:dev-latest entrypoint: /bin/sh stdin_open: true tty: true - container_name: nmr-converter nmr-respredict: + #build: ./app/scripts/nmr-respredict + container_name: nmrkit-respredict image: nfdi4chem/nmr-respredict:dev-latest entrypoint: /bin/sh stdin_open: true tty: true - container_name: nmr-respredict volumes: - shared-data:/shared - - prometheus: - image: prom/prometheus - container_name: nmrkit_prometheus - ports: - - 9090:9090 - volumes: - - ./../prometheus_data/prometheus.yml:/etc/prometheus/prometheus.yml - command: - - '--config.file=/etc/prometheus/prometheus.yml' - - grafana: - image: grafana/grafana - container_name: nmrkit_grafana - ports: - - 3000:3000 - volumes: - - /mnt/data/grafana_data:/var/lib/grafana - - redis: - image: "redis:alpine" - ports: - - "${FORWARD_REDIS_PORT:-6379}:6379" - volumes: - - "/mnt/data/redis:/data" - networks: - - default - healthcheck: - test: ["CMD", "redis-cli", "ping"] - retries: 3 - timeout: 5s - - pgsql: - image: "informaticsmatters/rdkit-cartridge-debian" - ports: - - "${FORWARD_DB_PORT:-5432}:5432" - env_file: - - ./.env - volumes: - - "/mnt/data/pgsql:/var/lib/postgresql/data" - networks: - - default - healthcheck: - test: - [ - "CMD", - "pg_isready", - "-q", - "-d", - "${POSTGRES_DB}", - "-U", - "${POSTGRES_USER}", - ] - retries: 3 - timeout: 5s - minio: - image: 'minio/minio:latest' - ports: - - '${FORWARD_MINIO_PORT:-9001}:9001' - - '${FORWARD_MINIO_CONSOLE_PORT:-8900}:8900' - environment: - - ./.env - volumes: - - /mnt/data/minio:/data/minio - networks: - - default - command: minio server /data/minio --console-address ":8900" - volumes: - prometheus_data: - driver: local - driver_opts: - o: bind - type: none - device: /mnt/data/prometheus_data - grafana_data: - driver: local - driver_opts: - o: bind - type: none - device: /mnt/data/grafana_data + shared-data: networks: default: name: nmrkit_vpc diff --git a/ops/docker-compose-prod.yml b/ops/docker-compose-prod.yml index a5c1bd3..a00f396 100644 --- a/ops/docker-compose-prod.yml +++ b/ops/docker-compose-prod.yml @@ -1,5 +1,3 @@ -version: "3.8" - services: traefik: image: traefik:v2.10 @@ -13,105 +11,52 @@ services: - 80:80 # - 8080:8080 # Optional: Expose Traefik dashboard on port 8080 volumes: - - /var/run/docker.sock:/var/run/docker.sock - - web: - image: nfdi4chem/nmrkit:v0.1.0 + - "/var/run/docker.sock:/var/run/docker.sock:ro" + nmrkit-api: + container_name: nmrkit-api + image: nfdi4chem/nmrkit:latest pull_policy: always labels: - "traefik.enable=true" - - "traefik.http.routers.web.rule=Host(`dev.nmrkit.nmrxiv.org`)" + - "traefik.http.routers.web.rule=Host(`nmrkit.nmrxiv.org`)" - "traefik.http.routers.web.entrypoints=web" - "traefik.http.services.web.loadbalancer.server.port=80" - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:80/latest/registration/health"] - interval: 1m - timeout: 10s - retries: 10 - start_period: 40s - env_file: - - ./.env - - prometheus: - image: prom/prometheus - container_name: nmrkit_prometheus - ports: - - 9090:9090 - volumes: - - ./../prometheus_data/prometheus.yml:/etc/prometheus/prometheus.yml - command: - - '--config.file=/etc/prometheus/prometheus.yml' - - grafana: - image: grafana/grafana - container_name: nmrkit_grafana - ports: - - 3000:3000 - volumes: - - /mnt/data/grafana_data:/var/lib/grafana - - redis: - image: "redis:alpine" - ports: - - "${FORWARD_REDIS_PORT:-6379}:6379" - volumes: - - "/mnt/data/redis:/data" - networks: - - default - healthcheck: - test: ["CMD", "redis-cli", "ping"] - retries: 3 - timeout: 5s - - pgsql: - image: "informaticsmatters/rdkit-cartridge-debian" - ports: - - "${FORWARD_DB_PORT:-5432}:5432" - env_file: - - ./.env volumes: - - "/mnt/data/pgsql:/var/lib/postgresql/data" - networks: - - default + - ../app:/code/app + - "/var/run/docker.sock:/var/run/docker.sock" + - shared-data:/shared healthcheck: test: [ - "CMD", - "pg_isready", - "-q", - "-d", - "${POSTGRES_DB}", - "-U", - "${POSTGRES_USER}", + "CMD", + "curl", + "-f", + "http://localhost:80/latest/registration/health" ] - retries: 3 - timeout: 5s - minio: - image: 'minio/minio:latest' - ports: - - '${FORWARD_MINIO_PORT:-9001}:9001' - - '${FORWARD_MINIO_CONSOLE_PORT:-8900}:8900' - environment: - - ./.env + interval: 1m30s + timeout: 10s + retries: 20 + start_period: 60s + env_file: + - ../.env + nmr-converter: + #build: ./app/scripts/nmr-cli + container_name: nmr-converter + image: nfdi4chem/nmr-cli:latest + entrypoint: /bin/sh + stdin_open: true + tty: true + nmr-respredict: + #build: ./app/scripts/nmr-respredict + container_name: nmrkit-respredict + image: nfdi4chem/nmr-respredict:latest + entrypoint: /bin/sh + stdin_open: true + tty: true volumes: - - /mnt/data/minio:/data/minio - networks: - - default - command: minio server /data/minio --console-address ":8900" - + - shared-data:/shared volumes: - prometheus_data: - driver: local - driver_opts: - o: bind - type: none - device: /mnt/data/prometheus_data - grafana_data: - driver: local - driver_opts: - o: bind - type: none - device: /mnt/data/grafana_data + shared-data: networks: default: name: nmrkit_vpc diff --git a/ops/zero-downtime-deployment-script.sh b/ops/zero-downtime-deployment-script.sh index 0f91cb9..754ef83 100644 --- a/ops/zero-downtime-deployment-script.sh +++ b/ops/zero-downtime-deployment-script.sh @@ -1,87 +1,87 @@ -#!/bin/bash - -# Define variables -COMPOSE_FILE="/mnt/data/nmrkit/ops/docker-compose-dev.yml" -DOCKER_REPO_NAME="nfdi4chem/nmrkit:dev-latest" -IMAGE_NAME="nfdi4chem/nmrkit:dev-latest" -NEW_CONTAINER_ID="" -IS_CONTAINER_HEALTHY=1 - -# Function to check the health of the container -check_health() { - - HEALTH=$(docker inspect --format='{{json .State.Health.Status}}' $NEW_CONTAINER_ID) - - if [[ $HEALTH == *"healthy"* ]]; then - echo "Container is healthy." - return 0 - else - echo "Container is unhealthy or still starting" - return 1 + #!/bin/bash + + # Define variables + PROJECT_DIR="/mnt/data/nmrkit" + COMPOSE_FILE="docker-compose-prod.yml" + NMRKIT_IMAGE="nfdi4chem/nmrkit:dev-latest" + NMR_CLI_IMAGE="nfdi4chem/nmr-cli:dev-latest" + LOG_FILE="/var/log/nmrkit-deploy.log" + LOG_OWNER="${SUDO_USER:-$(whoami)}" + + # Create log file if it doesn't exist + if [ ! -f "$LOG_FILE" ]; then + sudo touch "$LOG_FILE" + sudo chmod 644 "$LOG_FILE" + sudo chown "$LOG_OWNER":"$LOG_OWNER" "$LOG_FILE" fi -} - -# Check if there is a new image available in the Docker repository -if [ "$(docker pull $DOCKER_REPO_NAME | grep "Status: Image is up to date" | wc -l)" -eq 0 ]; then - - # Scale up a new container - echo "Scale up new container.." - docker-compose -f $COMPOSE_FILE up -d --scale web=2 --no-recreate - - NEW_CONTAINER_ID=$(docker ps -q -l) - - echo "New Container Id is.." - echo "$NEW_CONTAINER_ID" - - # Wait for new containers to start and health checks to pass - echo "Waiting for the new containers to start and health check to pass retry 5 times.." - n=0; - while [ $n -le 10 ] - do - if ! check_health; then - n=$(( $n + 1 )) - sleep 1m - echo "Container not healthy.. Check again.." - else - IS_CONTAINER_HEALTHY=0 - break - fi - done - - # Remove old containers and images - if [ $IS_CONTAINER_HEALTHY == 0 ] ; then - - # Set the desired container name prefix - CONTAINER_NAME_PREFIX="ops_web" - - # Retrieve the container IDs that match the prefix - container_ids=$(docker ps -a --filter "name=^/${CONTAINER_NAME_PREFIX}" --format "{{.ID}}") - - # Sort the container IDs by creation date in ascending order - sorted_container_ids=$(echo "$container_ids" | xargs docker inspect --format='{{.Created}} {{.ID}}' | sort | awk '{print $2}') - - # Get the oldest container ID - oldest_container_id=$(echo "$sorted_container_ids" | head -n 1) - - # Check if any container IDs were found - if [[ -z "$oldest_container_id" ]]; then - echo "No containers found with the name prefix '${CONTAINER_NAME_PREFIX}'." - exit 1 + # Unified logging function + log_message() { + echo "$1" + echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" + } + + # === Start of script === + log_message "๐Ÿš€ ==========================================" + log_message "๐Ÿš€ Starting NMRKit Deployment Script" + log_message "๐Ÿš€ ==========================================" + + # Change to project directory to ensure paths resolve correctly + cd "$PROJECT_DIR/ops" || { + log_message "โŒ Failed to change to directory $PROJECT_DIR/ops" + exit 1 + } + log_message "๐Ÿ“‚ Working directory: $(pwd)" + + # === Functions === + + # Cleanup function + cleanup() { + log_message "๐Ÿงน Cleaning up dangling images..." + docker image prune -f >/dev/null 2>&1 || true + log_message "โœ… Cleanup completed" + } + + # Deploy a service by pulling latest image and recreating container if updated + deploy_service() { + local service_name=$1 + local image=$2 + + log_message "๐Ÿ“ฆ Starting deployment for service: $service_name" + log_message "๐Ÿ” Checking for new image: $image" + + # Pull the latest image + if [ "$(docker pull "$image" | grep -c "Status: Image is up to date")" -eq 0 ]; then + log_message "โœจ New image detected for $service_name" + log_message "๐Ÿš€ Recreating container with updated image..." + docker compose -f "$COMPOSE_FILE" up -d --force-recreate --no-deps "$service_name" + log_message "โœ… Deployment of $service_name completed successfully" + else + log_message "โœ… Image for $service_name is up to date. Skipping deployment." fi - - # Delete the old container and unused images - docker stop $oldest_container_id - docker rm $oldest_container_id - docker image prune -af - echo "Deleted the oldest container with ID: ${oldest_container_id}" - - else - echo "Couldnot complete the deployment as the container is unhealthy.." - docker stop $NEW_CONTAINER_ID - docker rm $NEW_CONTAINER_ID - fi - -else - echo "Skipping deployment as no new image available.." -fi + } + + # Main deployment process + main() { + log_message "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + log_message "๐Ÿ”„ Deploying NMRKit API Service" + log_message "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + deploy_service "nmrkit-api" "$NMRKIT_IMAGE" + + log_message "" + log_message "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + log_message "๐Ÿ”„ Deploying NMR-Load-Save Service" + log_message "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" + deploy_service "nmr-converter" "$NMR_CLI_IMAGE" + + log_message "" + cleanup + + log_message "" + log_message "๐ŸŽ‰ ==========================================" + log_message "๐ŸŽ‰ All Deployments Completed Successfully!" + log_message "๐ŸŽ‰ ==========================================" + } + + # Execute main deployment + main