Try   HackMD

Nuxt3 Deployment

Here is a memo for deployment. It skips lots of detail and only focus on nuxt3 project setup.

I. Web App Project Settings

First, get started with web project settings to understand how to start a server in dockerfile.

Package.json

There are there scripts required in deployment.

  • build: Build nitro server in production. If there is variable that is not runtime env, pass it as env arg.
  • start: Start nitro server in production. If there is variable that is runtime env, pass it as env arg.
  • coverage: Run overall vitest to get coverage report. It's useful to prepare report for sonarqube.
{
  "scripts": {
    "build": "nuxt build",
    "start": "node .output/server/index.mjs",
    "coverage": "vitest run --coverage"
  }
}

Dotenv File

Create a dotenv file for production env.
(Please be careful NOT to expose private variables in commit. If you need to pass private variables, put them through env while launching docker image.)

NUXT_PUBLIC_PHASE=production
NUXT_PUBLIC_WEB_API_URL=https://xxx.com

Dockerfile

Although it's not recommended by nuxt official. You can use hecky way to export dotenv file variables and then start the nitro server if your team relies on it to manage different environment variables. Let me show you how to do it.

Handle launching server command in dockerfile. Using a bash script to start server at entrypoint.

# ./web-app.dockerfile

FROM node:18.19.1

# Pnpm Setup
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable

WORKDIR /app

ENTRYPOINT ["bash", "./entrypoint.sh"]

Bash Script

Then, export env varirables by phase as NODE_ENV variables and start nitro server.

# ./entrypoint.sh

export $(cat .env.${PHASE})

pnpm start

II. Github Action

Then, go further more to create a github action workflow to build web application and build docker image based on previous section.

Workflow

The main concept is:

  • Web application will be built every time.
  • Docker image will be built and published if and only tags and push trunk branch triggering.
  • Docker image is tagged with github sha.
  • Web server is starting in web-app.dockerfile.
# .github/workflows/pipeline.yaml

name: 🚦 Deployment

on:
  push:
    branches:
        - 'trunk'
  tags:
    - 'beta'
    - 'staging'
    - '*.*.*'
  pull_request:

jobs:        
  build-web-app:
    shell: bash
    name: build-web-app
    runs-on: [ self-hosted, Linux ]
    container: node:18.19.1

    steps:
      - name: Clone
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 9

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18.19.1
          cache: 'pnpm'
          cache-dependency-path: pnpm-lock.yaml

      - name: Install dependencies
        run: pnpm install
        
      - name: Coverage web app
        run: pnpm coverage

      - name: Build web app
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
        run: pnpm build

      - if: ${{ github.event_name != 'pull_request' }}
        name: Setup Docker
        run: |
          apt-get update && apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
          curl -fsSL https://get.docker.com | sh

      - if: ${{ github.event_name != 'pull_request' }}
        name: Setup Docker Meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.IMAGE_BASE }}

      - if: ${{ github.event_name != 'pull_request' }}
        name: Setup QEMU
        uses: docker/setup-qemu-action@v3

      - if: ${{ github.event_name != 'pull_request' }}
        name: Setup Docker Buildx
        uses: docker/setup-buildx-action@v3
        with:
          version: latest
          buildkitd-flags: --debug
          buildkitd-config-inline: |
            [registry."docker.io"]
              mirrors = ["${{ vars.DOCKER_HUB_MIRROR }}"]

      - if: ${{ github.event_name != 'pull_request' }}
        name: Login to Image Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ vars.DOCKER_REGISTRY }}
          username: ${{ secrets.HARBOR_USERNAME }}
          password: ${{ secrets.HARBOR_PASSWORD }}

      - if: ${{ github.event_name != 'pull_request' }}
        name: Docker Build and Push to Registry
        uses: docker/build-push-action@v5
        with:
          platforms: linux/amd64,linux/arm64
          labels: ${{ steps.meta.outputs.labels }}
          push: true
          provenance: false
          tags: ${{ vars.DOCKER_REGISTRY }}/${{ env.HARBOR_PROJECT_NAME }}/web-app:${GITHUB_SHA:0:7}
          file: web-app.dockerfile
          context: .

III. K8S Manifest

Finally, pass PHASE while initializing a docker container so it can run the server with env variables.

Here is the ingress config in another k8s manifest repo.

# overlays/production/apps/patches
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  template:
    spec:
      containers:
        - name: web-app
          image: harbor.xxx.com/web-app
          env:
            - name: PHASE
              value: "production"

That's all! Feel free to copy the template and modify it as you wish.

tags: Work Nuxt3 Github Workflow Docker