diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..124d061 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +# Keep the Docker build context minimal. _site/ is the only thing the image +# actually needs (it's built on the CI runner before `docker build`). +.git +.github +node_modules +_tmp +.cache +.DS_Store +*.md +!README.md +.vscode diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e9636e2 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,81 @@ +name: release + +on: + pull_request: + push: + branches: [main] + +# Only one push-to-ECR at a time per branch; queueing avoids racy tag pushes +# if two commits land back to back. +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Checkout/Install pusher/actions + uses: actions/checkout@v4 + with: + repository: pusher/actions + token: ${{ secrets.PUSHER_CI_GITHUB_PRIVATE_TOKEN }} + path: .github/actions + + - name: Define Common Env + id: common + uses: ./.github/actions/setup-common + + - name: Set Env Vars + run: | + echo "VERSION=${{ steps.common.outputs.version }}" >> $GITHUB_ENV + echo "SHORT_SHA=${{ steps.common.outputs.short_sha }}" >> $GITHUB_ENV + echo "DATE=${{ steps.common.outputs.date }}" >> $GITHUB_ENV + echo "LONG_DATE=${{ steps.common.outputs.long_date }}" >> $GITHUB_ENV + echo "NAME=docs" >> $GITHUB_ENV + + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build static site + env: + BUILD_ENV: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'production' || 'preview' }} + run: yarn build + + - name: Update Algolia index + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + env: + ALGOLIA_UPDATE_KEY: ${{ secrets.ALGOLIA_UPDATE_KEY }} + BUILD_ENV: production + run: yarn update:algolia + + - name: Build Docker image + run: | + docker build -t ${NAME}:${VERSION} . + echo "[BUILT] ${NAME}:${VERSION}" + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.PUSHERINOS_AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.PUSHERINOS_AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Push image to Amazon ECR + run: | + echo "${{ steps.login-ecr.outputs.registry }}" + docker tag ${NAME}:${VERSION} ${{ steps.login-ecr.outputs.registry }}/pusher/${NAME}:${VERSION} + docker push ${{ steps.login-ecr.outputs.registry }}/pusher/${NAME}:${VERSION} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3c9e56b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# Build-time assets (_site/) are produced by the GitHub Actions runner before +# `docker build` runs. This image is a thin static server. +# +# Using nginxinc/nginx-unprivileged so the master process runs as the non-root +# `nginx` user (uid 101) and listens on :8080 — matches the k8s security +# context used for the rest of our web workloads. +# +# Build locally: +# yarn install && yarn build && docker build -t docs:dev . +# docker run --rm -p 8080:8080 docs:dev +# open http://localhost:8080/docs/ + +FROM nginxinc/nginx-unprivileged:1.27-alpine + +COPY docker/nginx.conf /etc/nginx/conf.d/default.conf +COPY _site /usr/share/nginx/html + +EXPOSE 8080 diff --git a/README.md b/README.md index 76e89da..0efd07e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ permalink: docs/README/ An [Eleventy] powered static site using our custom [Tachyons] build with [Postcss] for styling. -It’s deployed and hosted by [Vercel] when the `main` branch changes using their [Github integration] - https://pusher-docs.vercel.app +It's built and served from our own EKS cluster (`eks-general`). On every push to `main`, GitHub Actions (`.github/workflows/release.yml`) builds the static site, pushes a Docker image to ECR (`008815156580.dkr.ecr.us-east-1.amazonaws.com/pusher/docs`), and Flux deploys it to the `docs` Service in the `internal` namespace. Public traffic reaches it via CloudFront → the `pusher-sites` nginx proxy → this pod. + +See the migration plan in `pusher/engineering-manual` for the full setup. ## Running locally @@ -43,11 +45,19 @@ yarn run css ### Search -Search is powered by Algolia, on every production build a refreshed index of all content is sent to them. +Search is powered by Algolia; on every `main` production build, `yarn update:algolia` pushes a refreshed index. The primary search experience is client-side JS (see `js/modules/search.mjs`). Users with JavaScript disabled see a short fallback message — no server-side rendering is offered. + +Required secret for the Algolia push: `ALGOLIA_UPDATE_KEY`, set as a GitHub Actions secret on this repo. -For users without JS there is a fallback page which is powered by Vercel’s serverless functions. +### Building a production-like image locally -If you need to debug this you can run the project with `vercel dev` and it will hot reload any changes. +```bash +yarn install +yarn build +docker build -t docs:dev . +docker run --rm -p 8080:8080 docs:dev +open http://localhost:8080/docs/ +``` ## How to add / update new pages @@ -226,8 +236,6 @@ Contributions welcome! [eleventy]: https://www.11ty.io [tachyons]: http://tachyons.io/ [postcss]: https://postcss.org -[vercel]: https://vercel.co/ -[github integration]: https://vercel.com/docs/git-integrations [markdown]: https://www.markdownguide.org/ [yarn]: https://yarnpkg.com/ [browsersync]: https://www.browsersync.io/ diff --git a/_data/env.js b/_data/env.js index 0455ba3..81984c4 100644 --- a/_data/env.js +++ b/_data/env.js @@ -1,4 +1,14 @@ +// BUILD_ENV is set by the release workflow: +// "production" on main pushes +// "preview" on pull requests +// unset in local dev (treat as non-production) +// +// Kept named `VERCEL_ENV` historically; the new pipeline sets `BUILD_ENV` +// but we read both so local tools that still export `VERCEL_ENV` keep +// working during the transition. +const env = process.env.BUILD_ENV || process.env.VERCEL_ENV; + module.exports = { - includeAnalytics: process.env.VERCEL_ENV === "production", + includeAnalytics: env === "production", pusherJSVersion: "8.3.0", }; diff --git a/_includes/partials/top-nav.njk b/_includes/partials/top-nav.njk index ef2cbee..5e30b33 100644 --- a/_includes/partials/top-nav.njk +++ b/_includes/partials/top-nav.njk @@ -63,11 +63,14 @@