diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..c253228ca5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +node_modules +dist +.git +.github +infrastructure +*.log +.env +.env.* +test +coverage +README.md diff --git a/.github/workflows/api-dev.yaml b/.github/workflows/api-dev.yaml index ceba1a5c3a..57b52ad49a 100644 --- a/.github/workflows/api-dev.yaml +++ b/.github/workflows/api-dev.yaml @@ -1,3 +1,5 @@ +# Legacy Azure deploy — will be removed after DFX server migration cutover. +# New deploy pipeline: dfx-api-dev.yaml (Docker + SSH to dfxdev). name: API DEV CI/CD on: diff --git a/.github/workflows/api-prd.yaml b/.github/workflows/api-prd.yaml index ae2f1e2c9a..3b151ee017 100644 --- a/.github/workflows/api-prd.yaml +++ b/.github/workflows/api-prd.yaml @@ -1,3 +1,5 @@ +# Legacy Azure deploy — will be removed after DFX server migration cutover. +# New deploy pipeline: dfx-api-prd.yaml (Docker + SSH to dfxprd). name: API PRD CI/CD on: diff --git a/.github/workflows/dfx-api-dev.yaml b/.github/workflows/dfx-api-dev.yaml new file mode 100644 index 0000000000..dfa16be97b --- /dev/null +++ b/.github/workflows/dfx-api-dev.yaml @@ -0,0 +1,57 @@ +name: DFX API DEV CI/CD + +on: + push: + branches: [develop] + paths-ignore: + - '**.md' + - 'infrastructure/**' + workflow_dispatch: + +env: + DOCKER_TAGS: dfxswiss/dfx-api:beta + +permissions: + contents: read + +jobs: + build-and-deploy: + name: Build and deploy to DEV + runs-on: ubuntu-24.04-arm + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ env.DOCKER_TAGS }} + platforms: linux/arm64 + + - name: Install cloudflared + run: | + curl -fsSL https://github.com/cloudflare/cloudflared/releases/download/2025.4.0/cloudflared-linux-arm64 -o /usr/local/bin/cloudflared + chmod +x /usr/local/bin/cloudflared + + - name: Deploy + run: | + mkdir -p ~/.ssh + echo "${{ secrets.DEPLOY_DEV_SSH_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + echo "${{ secrets.DEPLOY_DEV_SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts + ssh -i ~/.ssh/deploy_key \ + -o ProxyCommand="cloudflared access ssh --hostname ${{ secrets.DEPLOY_DEV_HOST }}" \ + ${{ secrets.DEPLOY_DEV_USER }}@${{ secrets.DEPLOY_DEV_HOST }} \ + "dfx-api" diff --git a/.github/workflows/dfx-api-prd.yaml b/.github/workflows/dfx-api-prd.yaml new file mode 100644 index 0000000000..3a091d9714 --- /dev/null +++ b/.github/workflows/dfx-api-prd.yaml @@ -0,0 +1,54 @@ +name: DFX API PRD CI/CD + +on: + push: + branches: [main] + workflow_dispatch: + +env: + DOCKER_TAGS: dfxswiss/dfx-api:latest + +permissions: + contents: read + +jobs: + build-and-deploy: + name: Build and deploy to PRD + runs-on: ubuntu-24.04-arm + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ env.DOCKER_TAGS }} + platforms: linux/arm64 + + - name: Install cloudflared + run: | + curl -fsSL https://github.com/cloudflare/cloudflared/releases/download/2025.4.0/cloudflared-linux-arm64 -o /usr/local/bin/cloudflared + chmod +x /usr/local/bin/cloudflared + + - name: Deploy + run: | + mkdir -p ~/.ssh + echo "${{ secrets.DEPLOY_PRD_SSH_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + echo "${{ secrets.DEPLOY_PRD_SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts + ssh -i ~/.ssh/deploy_key \ + -o ProxyCommand="cloudflared access ssh --hostname ${{ secrets.DEPLOY_PRD_HOST }}" \ + ${{ secrets.DEPLOY_PRD_USER }}@${{ secrets.DEPLOY_PRD_HOST }} \ + "dfx-api" diff --git a/Dockerfile b/Dockerfile index 264af30470..908e17d2dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,37 @@ -FROM node:latest AS builder -WORKDIR /app -COPY ./package.json ./ -RUN npm install -COPY . . +# Multi-stage build for the dfx-api NestJS service. +# +# Built and pushed by .github/workflows/dfx-api-{dev,prd}.yaml as +# dfxswiss/dfx-api:{beta,latest} (linux/arm64). + +FROM node:20-alpine AS builder + +# node-gyp needs Python + a C/C++ toolchain to build native modules +RUN apk add --no-cache python3 make g++ + +USER node +WORKDIR /home/node + +ADD --chown=node:node package.json . +ADD --chown=node:node package-lock.json . +RUN npm ci + +ADD --chown=node:node . . RUN npm run build +# Drop dev deps in-place after the build so the runtime stage can copy +# the already-compiled native modules without needing python3 + g++. +RUN npm prune --omit=dev + + +FROM node:20-alpine + +USER node +WORKDIR /home/node + +COPY --from=builder /home/node/package.json /home/node/package-lock.json ./ +COPY --from=builder /home/node/node_modules ./node_modules +COPY --from=builder /home/node/dist ./dist +COPY --from=builder /home/node/migration ./migration + +EXPOSE 3000 -FROM node:latest -WORKDIR /app -COPY --from=builder /app ./ -EXPOSE 3000:3000 -CMD [ "npm", "run", "start" ] \ No newline at end of file +CMD ["node", "dist/main.js"]