Skip to content

Latest commit

 

History

History
executable file
·
399 lines (354 loc) · 12.1 KB

README.md

File metadata and controls

executable file
·
399 lines (354 loc) · 12.1 KB

Docker NodeJs (PNPM)

Docker Automated build Docker Pulls

This project docker image utility CICD on GitLab Runner and running NuxtJs V3 application using PNPM

Image OS

  • Alpine Linux (3.19)
  • Debian (11.0 - Bullseye slim)

Additional services

Versioning

Docker Tag Git Release Node Version OS Version Support Functions
18-slim Main Branch 18.19.0 Bookwarm slim library Canvas Nuxt JS Build Process (GitLab CI/CD)
18-nuxt Main Branch 18.19.0 Alpine 3.19 With images Library Nuxt JS Running Production (Docker Compose)
20-slim Main Branch 20.10.0 Bookwarm slim library Canvas Nuxt JS Build Process (GitLab CI/CD)
20-nuxt Main Branch 20.10.0 Alpine 3.19 With images Library Nuxt JS Running Production (Docker Compose)

How To Use

Package NuxtJS (V3) config

{
  "name": "nuxt-app-v1",
  "description": "Nuxtjs v3 application",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare",
    "lint": "eslint --ext \".ts,.js,.vue,.html,.json\" --ignore-path .gitignore .",
    "lint:fix": "eslint --fix --ext \".ts,.js,.vue,.html,.json\" --ignore-path .gitignore .",
    "prepare": "husky install && husky set .husky/pre-commit \"pnpm lint-staged\" && husky set .husky/commit-msg  \"npx --no -- commitlint --edit ${1}\"",
    "build:production": "NODE_OPTIONS=--max_old_space_size=1024 nuxt build",
    "start:production": "pm2-runtime start pm2.json --only nuxt-app-v1",
    "reload:production": "pm2-runtime reload pm2.json --only nuxt-app-v1",
    "stop:production": "pm2-runtime stop pm2.json --only nuxt-app-v1",
    "delete:production": "pnpm stop:production && pm2-runtime delete pm2.json --only nuxt-app-v1"
  },
...
}

Run Docker Compose

---
version: "3.1"

networks:
    proxy:
        external: true

services:
    nuxt-app:
        container_name: nuxt-app
        image: asapdotid/node:18-nuxt
        restart: unless-stopped
        tty: true
        environment:
            - "TZ=Asia/Jakarta"
        networks:
            - proxy
        expose:
            - "3000"
        volumes:
            - ./project-app:/app:rw
            - ./entrypoint.sh:/entrypoint.sh:ro
        command: sh -c "chmod -R 777 /entrypoint.sh && sh /entrypoint.sh"

Sample entrypoint for NuxtJs version 3(can edit with your application setup):

#!/bin/sh

set -o errexit
set -o nounset
set -o pipefail

print_line() {
  echo "-----------------------------------------------------------------------------"
}

setup_applications() {
  echo "Setting up the application"
  if [ -d "./.nuxt" ] && [ -d "./.output" ] && [ -f "./nuxt.config.ts" ] && [ -f "./.env" ] && [ -f "./pm2.json" ]; then
    echo "Project ready for starting, please wait a moment set back and relax!"
    if [ -f "./yarn.lock" ]; then
      /usr/local/bin/yarn start:production
    elif [ -f "./package-lock.json" ]; then
      /usr/local/bin/npm run start:production
    elif [ -f "./pnpm-lock.yaml" ]; then
      /usr/local/bin/pnpm start:production
    fi
  else
    echo "Project ready for starting, please wait a moment to build and start!"
    if [ -f "./yarn.lock" ]; then
      /usr/local/bin/yarn install --frozen-lockfile
      /usr/local/bin/yarn cache clean --force
      /usr/local/bin/yarn build:production
      /usr/local/bin/yarn start:production
    elif [ -f "./package-lock.json" ]; then
      /usr/local/bin/npm ci
      /usr/local/bin/npm cache clean --force
      /usr/local/bin/npm run build:production
      /usr/local/bin/npm run start:production
    elif [ -f "./pnpm-lock.yaml" ]; then
      /usr/local/bin/pnpm install --frozen-lockfile
      /usr/local/bin/pnpm build:production
      /usr/local/bin/pnpm start:production
    fi
  fi
}

main() {
  print_line
  setup_applications
}

main "$@"

PM2 Config:

{
    "apps": [
        {
            "name": "nuxt-app-v1",
            "exec_mode": "cluster",
            "instances": "2",
            "script": "./.output/server/index.mjs",
            "watch": true,
            "out_file": "/dev/null",
            "error_file": "/dev/null",
            "env": {
                "HOST": "0.0.0.0",
                "PORT": 3000,
                "NODE_ENV": "production"
            }
        }
    ]
}

GitLab CI (gitlab-ci.yml)

Please see setup & build job stage, how to use the image.

Sample gitlab-ci.yml file for CI/CD NuxtJS App (staging branch):

image: asapdotid/alpine:ssh

stages:
    - init
    - setup
    - build
    - deploy
    - cleaning

variables:
    DOCKER_DRIVER: overlay2
    DEPLOY_SERVER_PATH: "/home/application/nuxt-app-v1"
    DEPLOY_SERVER_ARTIFACTS_PATH: "$DEPLOY_SERVER_PATH/artifacts"
    DEPLOY_SERVER_RELEASES_PATH: "$DEPLOY_SERVER_PATH/releases"
    DEPLOY_SERVER_ACTIVATE_PATH: "$DEPLOY_SERVER_PATH/current"

default:
    before_script:
        - eval $(ssh-agent -s)
        - ssh-add <(echo "${SSH_PRIVATE_KEY}")

# Caches
.node_modules-cache: &node_modules-cache
    key:
        files:
            - pnpm-lock.yaml
    paths:
        - node_modules/
    policy: pull

.pnpm-cache: &pnpm-cache
    key: pnpm-$CI_JOB_IMAGE
    paths:
        - .pnpm-store/
    policy: pull-push

.build-cache: &build-cache
    key: build-$CI_JOB_IMAGE
    paths:
        - .nuxt
        - .output
        - .env
        - public
    policy: pull-push

### INIT STAGING ###
init:staging:
    stage: init
    tags:
        - docker
    rules:
        - if: $CI_COMMIT_BRANCH == "staging"
    script:
        - echo "DEPLOY_USER=root" >> staging.env
        - echo "DEPLOY_SERVER=10.10.0.1" >> staging.env
        - echo "DEPLOY_SERVER_PORT=22" >> staging.env
    artifacts:
        reports:
            dotenv: staging.env

### SETUP STAGING ###
setup:staging:
    stage: setup
    dependencies:
        - init:staging
    rules:
        - if: $CI_COMMIT_BRANCH == "staging"
          # changes:
          #   - "package.json"
          when: always
    tags:
        - docker
    image: asapdotid/node:18-slim
    before_script:
        - pnpm config set store-dir .pnpm-store
    script:
        - pnpm install --frozen-lockfile
    retry:
        max: 2
        when:
            - runner_system_failure
            - stuck_or_timeout_failure
    cache:
        - <<: *node_modules-cache
          policy: pull-push
        - <<: *pnpm-cache
    artifacts:
        expire_in: 1 hour
        paths:
            - node_modules

### BUILD STAGING ###
build:staging:
    stage: build
    dependencies:
        - setup:staging
    rules:
        - if: $CI_COMMIT_BRANCH == "staging"
    tags:
        - docker
    image: asapdotid/node:18-slim
    before_script:
        - pnpm config set store-dir .pnpm-store
        - \cp ./.env.example ./.env
        - PACKAGE_VERSION=$(grep '"version":' ./package.json | cut -d\" -f4);
        - |
            sed -i ./.env \
            -e "s|%%APP_URL%%|$STAGING_APP_URL|g" \
            -e "s|%%API_URL%%|$STAGING_API_URL|g" \
            -e "s|%%GH_PAT%%|$GH_PAT|g" \
            -e "s|%%VERSION%%|$PACKAGE_VERSION-$CI_COMMIT_SHORT_SHA|g";
    script:
        - pnpm build:production
    retry:
        max: 2
        when:
            - runner_system_failure
            - stuck_or_timeout_failure
    artifacts:
        name: "$CI_COMMIT_BRANCH"
        paths:
            - .nuxt
            - .output
            - .env
            - pm2.json
            - nuxt.config.ts
            - package.json
            - pnpm-lock.yaml
            - public
        expire_in: 1 hour
    cache:
        - <<: *node_modules-cache
        - <<: *build-cache

### DEPLOY TO STAGING ###
prepare:release:staging:
    stage: deploy
    needs:
        - job: init:staging
          artifacts: true
        - job: build:staging
          artifacts: true
    rules:
        - if: $CI_COMMIT_BRANCH == "staging"
    tags:
        - docker
    script:
        - |
            tar --exclude='.git' --exclude='.env.example' --exclude='README.md' \
            --exclude='.editorconfig' --exclude='.gitattributes' --exclude='.gitignore' \
            --exclude='.gitlab-ci.yml' --exclude='.gitpod.yml' --exclude='.vscode' --exclude='.husky' --exclude='.pnpm-store' \
            -czf $CI_COMMIT_SHA.tar.gz * .??*
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "mkdir -p $DEPLOY_SERVER_PATH"
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "mkdir -p $DEPLOY_SERVER_ARTIFACTS_PATH"
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "mkdir -p $DEPLOY_SERVER_RELEASES_PATH"
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "chmod -R 755 $DEPLOY_SERVER_PATH"
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "mkdir -p $DEPLOY_SERVER_RELEASES_PATH/$CI_COMMIT_SHA"
        - scp -P $DEPLOY_SERVER_PORT $CI_COMMIT_SHA.tar.gz $DEPLOY_USER@$DEPLOY_SERVER:$DEPLOY_SERVER_ARTIFACTS_PATH
        - |
            ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER \
            "tar -xzf $DEPLOY_SERVER_ARTIFACTS_PATH/$CI_COMMIT_SHA.tar.gz -C $DEPLOY_SERVER_RELEASES_PATH/$CI_COMMIT_SHA"
        - |
            ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER \
            "find $DEPLOY_SERVER_RELEASES_PATH/$CI_COMMIT_SHA -type d -exec chmod 0755 {} \;"
        - |
            ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER \
            "find $DEPLOY_SERVER_RELEASES_PATH/$CI_COMMIT_SHA -type f -exec chmod 0644 {} \;"
    retry:
        max: 2
        when:
            - runner_system_failure
            - stuck_or_timeout_failure
    cache:
        - <<: *node_modules-cache
        - <<: *build-cache

activate:release:staging:
    stage: deploy
    needs:
        - job: init:staging
          artifacts: true
        - job: prepare:release:staging
    rules:
        - if: $CI_COMMIT_BRANCH == "staging"
    tags:
        - docker
    script:
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "mkdir -p $DEPLOY_SERVER_ACTIVATE_PATH"
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "rsync -azrh --delete $DEPLOY_SERVER_RELEASES_PATH/$CI_COMMIT_SHA/ $DEPLOY_SERVER_ACTIVATE_PATH/"
    retry:
        max: 2
        when:
            - runner_system_failure
            - stuck_or_timeout_failure

### CLEANING ARTIFACT & RELEASE STAGING ###
clean:release:staging:
    stage: cleaning
    needs:
        - job: init:staging
          artifacts: true
        - job: activate:release:staging
    rules:
        - if: $CI_COMMIT_BRANCH == "staging"
    tags:
        - docker
    script:
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_SERVER_ARTIFACTS_PATH && ls -t -1 | tail -n +5 | xargs rm -rf"
        - ssh -p $DEPLOY_SERVER_PORT $DEPLOY_USER@$DEPLOY_SERVER "cd $DEPLOY_SERVER_RELEASES_PATH && ls -t -1 | tail -n +5 | xargs rm -rf"
    retry:
        max: 2
        when:
            - runner_system_failure
            - stuck_or_timeout_failure

License

GNU distributed

Author Information

JogjaScript

This project was created in 2023 by Asapdotid. 🚀