Skip to content

Commit

Permalink
Add meet.bluedot.org
Browse files Browse the repository at this point in the history
  • Loading branch information
domdomegg committed Apr 21, 2024
1 parent 3e68c03 commit 411c87e
Show file tree
Hide file tree
Showing 65 changed files with 2,693 additions and 42 deletions.
39 changes: 36 additions & 3 deletions .github/workflows/ci_cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ jobs:
infra:
paths:
- 'apps/infra/**'
meet:
paths:
- 'apps/meet/**'
miniextensions-proxy:
paths:
- 'apps/miniextensions-proxy/**'
Expand All @@ -63,7 +66,7 @@ jobs:
if: ${{ github.ref == 'refs/heads/master' && needs.ci.outputs.should_skip != 'true' || !fromJSON(needs.ci.outputs.paths_result).infra.should_skip }}
runs-on: ubuntu-latest
concurrency:
group: ${{ github.job }}
group: cd_infra
timeout-minutes: 10
steps:
- name: Checkout ${{ github.sha }}
Expand Down Expand Up @@ -94,7 +97,7 @@ jobs:
if: ${{ github.ref == 'refs/heads/master' && needs.ci.outputs.should_skip != 'true' || !fromJSON(needs.ci.outputs.paths_result).frontend-example.should_skip }}
runs-on: ubuntu-latest
concurrency:
group: ${{ github.job }}
group: cd_frontend-example
timeout-minutes: 10
steps:
- name: Checkout ${{ github.sha }}
Expand All @@ -119,12 +122,42 @@ jobs:
- name: Deploy
run: npm run deploy:prod --workspace apps/frontend-example

cd_meet:
needs: ci
if: ${{ github.ref == 'refs/heads/master' && needs.ci.outputs.should_skip != 'true' || !fromJSON(needs.ci.outputs.paths_result).meet.should_skip }}
runs-on: ubuntu-latest
concurrency:
group: cd_meet
timeout-minutes: 10
steps:
- name: Checkout ${{ github.sha }}
uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org/
- name: Install NPM dependencies
run: npm ci

- name: Configure for deployment
run: |
docker login https://sjc.vultrcr.com/bluedot -u dbaa58f3-01f1-4fcc-9c14-93cc28f524e0 -p $VULTR_CONTAINER_REGISTRY_PASSWORD
mkdir -p ~/.kube
echo "$K8S_KUBECONFIG" > ~/.kube/config
env:
K8S_KUBECONFIG: ${{ secrets.K8S_KUBECONFIG }}
VULTR_CONTAINER_REGISTRY_PASSWORD: ${{ secrets.VULTR_CONTAINER_REGISTRY_PASSWORD }}
- name: Deploy
run: npm run deploy:prod --workspace apps/meet

cd_miniextensions-proxy:
needs: ci
if: ${{ github.ref == 'refs/heads/master' && needs.ci.outputs.should_skip != 'true' || !fromJSON(needs.ci.outputs.paths_result).miniextensions-proxy.should_skip }}
runs-on: ubuntu-latest
concurrency:
group: ${{ github.job }}
group: cd_miniextensions-proxy
timeout-minutes: 10
steps:
- name: Checkout ${{ github.sha }}
Expand Down
1 change: 0 additions & 1 deletion apps/backend/src/db/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Pool } from 'pg';
import { Kysely, PostgresDialect } from 'kysely';
// All these ignores are to allow this to pass in CI, where we don't have a database to generate the files with
// If we do more with backend, we should fix this properly by having CI spin up a database
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line import/extensions
import Database from './generated/Database';
Expand Down
10 changes: 8 additions & 2 deletions apps/frontend-example/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import dynamic from 'next/dynamic';
import '../globals.css';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import dynamic from 'next/dynamic';

const App: React.FC<AppProps> = ({ Component, pageProps }: AppProps) => {
return (
<Component {...pageProps} />
<>
<Head>
<title>frontend-example</title>
</Head>
<Component {...pageProps} />
</>
);
};

Expand Down
2 changes: 1 addition & 1 deletion apps/frontend-example/tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default {
dark: '#002199',
darker: '#00114D',
},
agisf: {
aisf: {
lighter: '#E6B3FF',
light: '#D680FF',
normal: '#C64EFF',
Expand Down
8 changes: 6 additions & 2 deletions apps/infra/Pulumi.prod.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
encryptionsalt: v1:1DwWI+bI55I=:v1:tpqziDy1t6GntGld:l3IA3E6yuXwTfNlPX8Lxe59IqDG7QA==
config:
infra:airtablePat:
secure: v1:xxnGOjci0H2TTfIY:p5/SIY+vels8uuUTUCJYRW3JIIYJNF9Jmr1m8usCqYgjU073BMKjQ+uq3dUb42f1iNeOs0A124ZIzDjxv9f1cJNaOd8gfvAxQf1oA1WC/A/CqnHyoNFIG6zpE1C0gNtu+u8=
infra:alertsSlackBotToken:
secure: v1:KHo0xEvyljpu6RQu:FxDE6U4NfjkQTTCE+yLJKpF2tnjiNqGM4eWfgnSMgD+3RKyicTHqUuVKYyEQdNYj9YZkokYeD6X0eB277AYJHQUV3ZhbrrO/vA==
infra:containerRegistryDockerConfigJson:
secure: v1:lycjX7rEaALQ9R/z:sZY2d07ja/BvKImmficAenAbHtUZ/fRgnq1VUrD9whc4PEwv8RM952po7asuECsQHPF7/nSAheMWH4dk2n039ylID933zQ9lMSh9AbDP5hsw6Td+X+KSwyYBZlSx6RdYfzAf8F7dRk6Rd+varZXql+rKpwfhpcXoEd9OMHR/niMQIBOQk5mUqc/m2FUMkWptCYMJpfYUQu4x9oqA52hG39Ojbdr7NDf+ZiedXWIJFmniCTdOZRNUWDgnkXI2fGkPI0yr1O8cr68aS2WmrvtVYDfheaKJZd9kZ4avug==
infra:dbPassword:
secure: v1:ERZRodNiiPzZWbC2:sG0lmdI7kUxxeD3krcFFzUg/SOa4bsXBwigCyoh8xAZvNFFopFPeSAR+TMUyrfE/YHt+XDHHKFuAm319k2j+gL+aYYtP3g83PhTOojEQSJI=
infra:meetZoomClientSecret:
secure: v1:jPYJIQX1CoHF/Zmm:KTKen2BLFJ2UpCuIOXE5kdUh0OynxG/UbVbTD4h0Ft5X2UFFRYPp1iSVGd8Rxd+o
vultr:apiKey:
secure: v1:V4H9p6vQNMJM4KEQ:G/T2vskLJtn5ZtO9Ry7TfstCV0lwGmCQIwb6twGs9j9VJq5FWG249dYKg/RuJFOXl6eDZg==
25 changes: 24 additions & 1 deletion apps/infra/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,30 @@ aws_secret_access_key=

Get `passphrase.prod.txt` from 1Password.

## Manual connections
## Tasks

### Adding a new service

TODO

### Adding a secret

We manage secrets with [Pulumi secrets](https://www.pulumi.com/learn/building-with-pulumi/secrets/). In general, we pass in secrets via Pulumi as environment variables to containers.

To add a secret, run:

```bash
# key should be a camelCase identifier e.g. meetZoomClientSecret
npm run config:secret <key>
```

It'll prompt you for a value, and then update [Pulumi.prod.yaml](./Pulumi.prod.yaml).

If you want to use your secret as an environment variable, add it to the `toK8s` array in [secrets.ts](./src/k8s/secrets.ts). You can then use it as `envVarSources.key` in other files.

If you want to use your secret 'raw', import config from [config.ts](./src/config.ts) and then call `config.requireSecret('key')`.

### Connecting with kubectl

```bash
PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi stack output --show-secrets k8sConfig > kubeconfig.json
Expand Down
5 changes: 1 addition & 4 deletions apps/infra/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Config } from '@pulumi/pulumi';

const config = new Config();
export const config = new Config();

export const vultrRegion = config.get('vultrRegion') || 'ams';

Expand All @@ -10,6 +10,3 @@ export const k8sNodeCount = config.getNumber('k8sNodeCount') || 1;
// VPS plan to use for K8s cluster nodes.
// See https://www.vultr.com/api/#tag/plans/operation/list-plans
export const k8sVpsPlan = config.get('k8sVpsPlan') || 'vc2-1c-2gb';

export const containerRegistryDockerConfigJson = config.requireSecret('containerRegistryDockerConfigJson');
export const dbPassword = config.requireSecret('dbPassword');
13 changes: 0 additions & 13 deletions apps/infra/src/k8s/containerRegistry.ts

This file was deleted.

2 changes: 1 addition & 1 deletion apps/infra/src/k8s/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import './containerRegistry';
import './secrets';
import './ingress';
import './certManager';
import './services';
36 changes: 36 additions & 0 deletions apps/infra/src/k8s/secrets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as k8s from '@pulumi/kubernetes';
import { core } from '@pulumi/kubernetes/types/input';
import { provider } from './provider';
import { config } from '../config';

// These Pulumi secrets will be converted to K8s secrets automatically
const toK8s = [
'airtablePat',
'alertsSlackBotToken',
'meetZoomClientSecret',
] as const;

export const envVarSources = toK8s.reduce((obj, key) => {
const resource = new k8s.core.v1.Secret(`${key.toLowerCase()}-secret`, {
metadata: {
name: `${key.toLowerCase()}-secret`,
},
stringData: {
value: config.requireSecret(key),
},
}, { provider });

// eslint-disable-next-line no-param-reassign
obj[key] = { secretKeyRef: { name: resource.metadata.name, key: 'value' } };
return obj;
}, {} as Record<typeof toK8s[number], core.v1.EnvVarSource>);

export const containerRegistrySecret = new k8s.core.v1.Secret('vultr-cr-secret', {
metadata: {
name: 'vultr-cr-credentials',
},
data: {
'.dockerconfigjson': config.requireSecret('containerRegistryDockerConfigJson'),
},
type: 'kubernetes.io/dockerconfigjson',
}, { provider });
21 changes: 20 additions & 1 deletion apps/infra/src/k8s/serviceDefinitions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { core } from '@pulumi/kubernetes/types/input';
import { containerRegistrySecret } from './containerRegistry';
import { containerRegistrySecret, envVarSources } from './secrets';

// TODO: pin the external versions
export const services: ServiceDefinition[] = [
Expand Down Expand Up @@ -38,6 +38,25 @@ export const services: ServiceDefinition[] = [
},
hosts: ['forms.bluedot.org'],
},
{
name: 'bluedot-meet',
targetPort: 8080,
spec: {
containers: [{
name: 'bluedot-meet',
image: 'sjc.vultrcr.com/bluedot/bluedot-meet:latest',
env: [
{ name: 'AIRTABLE_PERSONAL_ACCESS_TOKEN', valueFrom: envVarSources.airtablePat },
{ name: 'NEXT_PUBLIC_ZOOM_CLIENT_ID', value: 'lX1NBglbQWO2ERYSS1xdfA' },
{ name: 'ZOOM_CLIENT_SECRET', valueFrom: envVarSources.meetZoomClientSecret },
{ name: 'ALERTS_SLACK_CHANNEL_ID', value: 'C04SAGM4FN1' /* #tech-prod-alerts */ },
{ name: 'ALERTS_SLACK_BOT_TOKEN', valueFrom: envVarSources.alertsSlackBotToken },
],
}],
imagePullSecrets: [{ name: containerRegistrySecret.metadata.name }],
},
hosts: ['meet.bluedot.org'],
},
// {
// name: 'bluedot-bubble-proxy',
// targetPort: 80,
Expand Down
13 changes: 13 additions & 0 deletions apps/meet/.env.local.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Airtable: https://support.airtable.com/docs/creating-and-using-api-keys-and-access-tokens
AIRTABLE_PERSONAL_ACCESS_TOKEN=

# Zoom
NEXT_PUBLIC_ZOOM_CLIENT_ID=lX1NBglbQWO2ERYSS1xdfA
ZOOM_CLIENT_SECRET=

# BlueDot Impact Slack, #tech-dev-alerts
ALERTS_SLACK_CHANNEL_ID=C04SFUECECU
# For (local) BlueBot see https://airtable.com/appnNmNoNMB6crg6I/tbllthJ2YSPDsKWCt/viwfjWLvplq6Xw93D/recqurdJTPWzm5y4W
# For (prod) BlueBot see https://api.slack.com/apps/A04PV2GAQRY/install-on-team
# Starts 'xoxb-'
ALERTS_SLACK_BOT_TOKEN=
10 changes: 10 additions & 0 deletions apps/meet/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Airtable
AIRTABLE_PERSONAL_ACCESS_TOKEN=FAKE_TOKEN

# Zoom
NEXT_PUBLIC_ZOOM_CLIENT_ID=FAKE_CLIENT_ID
ZOOM_CLIENT_SECRET=FAKE_CLIENT_SECRET

# Slack
ALERTS_SLACK_CHANNEL_ID=C04SFUECECU
ALERTS_SLACK_BOT_TOKEN=FAKE_TOKEN
25 changes: 25 additions & 0 deletions apps/meet/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM node:lts-alpine@sha256:7e227295e96f5b00aa79555ae166f50610940d888fc2e321cf36304cbd17d7d6 AS base

RUN apk update && apk add --no-cache dumb-init

WORKDIR /app

ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown node:node .next

ARG APP_NAME
ENV APP_NAME=${APP_NAME}

COPY --chown=node:node .next/standalone ./
COPY --chown=node:node public ./apps/${APP_NAME}/public
COPY --chown=node:node .next/static ./apps/${APP_NAME}/.next/static

USER node

EXPOSE 8080

CMD HOSTNAME="0.0.0.0" PORT="8080" dumb-init node ./apps/${APP_NAME}/server.js
5 changes: 5 additions & 0 deletions apps/meet/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
41 changes: 41 additions & 0 deletions apps/meet/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/** @type {import('next').NextConfig} */
module.exports = {
transpilePackages: ['@bluedot/ui'],
reactStrictMode: true,
output: 'standalone',

// We already run eslint as a separate step
eslint: {
ignoreDuringBuilds: true,
},

poweredByHeader: false,
headers: async () => {
return [
// See https://developers.zoom.us/docs/meeting-sdk/web/sharedarraybuffer/
{
source: '/',
headers: [
{
key: 'Cross-Origin-Embedder-Policy',
value: 'require-corp',
},
{
key: 'Cross-Origin-Opener-Policy',
value: 'same-origin',
},
],
},
{
source: '/:path*',
headers: [
{
key: 'X-Bluedot-Version',
// eslint-disable-next-line turbo/no-undeclared-env-vars
value: process.env.VERSION_TAG || 'unknown',
},
],
},
];
},
};
Loading

0 comments on commit 411c87e

Please sign in to comment.