diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c03ec6b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +node_modules +dist +.git +.github +*.md +!README.md +.gitignore +.vscode +*.log +*.tgz +tests +coverage +.nyc_output + diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..63cf43f --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,68 @@ +name: Build and Publish Docker Image + +on: + push: + branches: + - master + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build TypeScript + run: npm run build + + - name: Run tests + run: npm test + + build-and-push: + needs: build-and-test + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,prefix= + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + diff --git a/Dockerfile b/Dockerfile index 1cfe4dc..f12db2f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,47 @@ +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install all dependencies (including devDependencies for build) +RUN npm ci --ignore-scripts + +# Copy source code +COPY . . + +# Build TypeScript +RUN npm run build + +# Production stage FROM node:20-alpine +WORKDIR /app + RUN apk --no-cache add curl -RUN yarn global add --ignore-optional taskforce-connector pm2@5.2.0 && yarn cache clean +# Install pm2 globally for process management +RUN npm install -g pm2 + +# Copy package files +COPY package*.json ./ + +# Install production dependencies only (skip prepare script) +RUN npm ci --omit=dev --ignore-scripts + +# Copy built files from builder +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/app.js ./app.js -CMD pm2-runtime taskforce -- -n "${TASKFORCE_CONNECTION}" --team "${TASKFORCE_TEAM}" `([ "$REDIS_USE_TLS" == "1" ] && echo --tls)` +# Run with pm2-runtime for resilience (auto-restart on crash) +# Shell form needed for environment variable expansion +CMD pm2-runtime --name taskforce node -- app.js -n "${TASKFORCE_CONNECTION}" --team "${TASKFORCE_TEAM}" +# Healthcheck uses pm2 process name - must match --name above HEALTHCHECK --interval=30s --timeout=30s \ - --start-period=5s --retries=3 CMD curl -f http://localhost || exit 1 + --start-period=5s --retries=3 CMD pm2 list | grep -q taskforce || exit 1 -LABEL org.opencontainers.image.source="https://github.com/taskforcesh/taskforce-connector" +LABEL org.opencontainers.image.source="https://github.com/serenityapp/taskforce-connector" +LABEL org.opencontainers.image.description="Patched for AWS MemoryDB TLS compatibility"