From 00bd1f08dad19d9ac0e2ba9c07864225e6d6ff38 Mon Sep 17 00:00:00 2001 From: Frank Hamand Date: Thu, 25 May 2023 09:44:05 +0100 Subject: [PATCH 1/2] Add docker build workflow --- .github/workflows/docker-api.yaml | 51 +++++++++++++ .github/workflows/docker-frontend.yaml | 72 +++++++++++++++++++ docker-compose.yml | 12 ++-- frontend/.node-version | 1 + frontend/Dockerfile | 12 +--- frontend/Dockerfile.dev | 14 ++++ frontend/package.json | 1 + frontend/src/Layout.tsx | 2 +- frontend/src/pages/DiskUsage/DiskUsage.tsx | 2 +- frontend/src/pages/Errors/Errors.tsx | 2 +- frontend/src/pages/Logs/Logs.tsx | 4 +- frontend/src/pages/Operations/Operations.tsx | 6 +- frontend/src/pages/Overview/Overview.tsx | 2 +- .../src/pages/QueryEditor/QueryEditor.tsx | 3 +- .../pages/RunningQueries/RunningQueries.tsx | 4 +- .../src/pages/SchemaStats/SchemaStats.tsx | 4 +- .../src/pages/SchemaStats/SchemaTable.tsx | 4 +- .../pages/SlowQueries/ExampleQueriesTab.tsx | 2 +- frontend/src/pages/SlowQueries/ExplainTab.tsx | 2 +- frontend/src/pages/SlowQueries/MetricsTab.tsx | 2 +- .../pages/SlowQueries/NormalizedQueryTab.tsx | 2 +- .../src/pages/SlowQueries/SlowQueries.tsx | 6 +- housewatch/clickhouse/client.py | 6 +- 23 files changed, 176 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/docker-api.yaml create mode 100644 .github/workflows/docker-frontend.yaml create mode 100644 frontend/.node-version create mode 100644 frontend/Dockerfile.dev diff --git a/.github/workflows/docker-api.yaml b/.github/workflows/docker-api.yaml new file mode 100644 index 0000000..17b8363 --- /dev/null +++ b/.github/workflows/docker-api.yaml @@ -0,0 +1,51 @@ +name: API Docker build + +on: + push: + +jobs: + docker: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: + - + uses: actions/checkout@v3 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: arm64 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Docker image metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ghcr.io/${{ github.repository }}/api + tags: | + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} + type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }} + type=ref,event=pr + type=sha + - + name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/docker-frontend.yaml b/.github/workflows/docker-frontend.yaml new file mode 100644 index 0000000..58fff33 --- /dev/null +++ b/.github/workflows/docker-frontend.yaml @@ -0,0 +1,72 @@ +name: Frontend Docker build + +on: + push: + +jobs: + docker: + runs-on: ubuntu-latest + defaults: + run: + working-directory: 'frontend' + + permissions: + contents: read + packages: write + + steps: + - + uses: actions/checkout@v3 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: arm64 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Docker image metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ghcr.io/${{ github.repository }}/frontend + tags: | + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} + type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }} + type=ref,event=pr + type=sha + - + name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version-file: frontend/.node-version + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - + name: Install dependencies + run: npm install + + - + name: Build + run: npm run build + env: + NODE_OPTIONS: --openssl-legacy-provider + + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: frontend/ + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/docker-compose.yml b/docker-compose.yml index a2dc303..59c7da8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,14 @@ version: '3' services: + web: + build: + context: frontend/ + dockerfile: Dockerfile.dev + command: ["npm", "run", "start"] + ports: + - "3000:3000" + app: build: . environment: @@ -23,10 +31,6 @@ services: - .:/code ports: - '8000:8000' - web: - build: ./frontend - ports: - - "3000:3000" redis: image: redis:6.2.7-alpine diff --git a/frontend/.node-version b/frontend/.node-version new file mode 100644 index 0000000..bd45cd7 --- /dev/null +++ b/frontend/.node-version @@ -0,0 +1 @@ +20.4.0 diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 360cdf0..4a2b9bc 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,13 +1,7 @@ -FROM node:16.20.0 +FROM alpine:latest WORKDIR /frontend -COPY . . +COPY build/ build/ -RUN npm install -RUN npm run build -RUN npm install -g serve - -EXPOSE 3000 - -CMD ["serve", "-s", "build"] \ No newline at end of file +CMD ["echo", "Serve the files from /frontend/build, don't run this container directly"] diff --git a/frontend/Dockerfile.dev b/frontend/Dockerfile.dev new file mode 100644 index 0000000..8c63fcd --- /dev/null +++ b/frontend/Dockerfile.dev @@ -0,0 +1,14 @@ +FROM node:20 + +WORKDIR /frontend + +COPY . . + +ENV NODE_OPTIONS --openssl-legacy-provider +RUN npm install +RUN npm run build +RUN npm install -g serve + +EXPOSE 3000 + +CMD ["serve", "-s", "build"] diff --git a/frontend/package.json b/frontend/package.json index bfb982b..6b0d1ef 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -36,6 +36,7 @@ "react-app/jest" ] }, + "proxy": "http://localhost:8000", "browserslist": { "production": [ ">0.2%", diff --git a/frontend/src/Layout.tsx b/frontend/src/Layout.tsx index 2555891..2edabf8 100644 --- a/frontend/src/Layout.tsx +++ b/frontend/src/Layout.tsx @@ -51,7 +51,7 @@ export default function AppLayout(): JSX.Element { const [hostname, setHostname] = useState('') const fetchHostname = async () => { - const response = await fetch(`http://localhost:8000/api/analyze/hostname`) + const response = await fetch(`/api/analyze/hostname`) const responseJson = await response.json() setHostname(responseJson.hostname) } diff --git a/frontend/src/pages/DiskUsage/DiskUsage.tsx b/frontend/src/pages/DiskUsage/DiskUsage.tsx index 26ead48..dd98f03 100644 --- a/frontend/src/pages/DiskUsage/DiskUsage.tsx +++ b/frontend/src/pages/DiskUsage/DiskUsage.tsx @@ -13,7 +13,7 @@ export function DiskUsage(): JSX.Element { const loadData = async () => { try { - const res = await fetch('http://localhost:8000/api/analyze/cluster_overview') + const res = await fetch('/api/analyze/cluster_overview') const resJson = await res.json() setClusterOverviewData(resJson) } catch { diff --git a/frontend/src/pages/Errors/Errors.tsx b/frontend/src/pages/Errors/Errors.tsx index fa49c35..3ac760c 100644 --- a/frontend/src/pages/Errors/Errors.tsx +++ b/frontend/src/pages/Errors/Errors.tsx @@ -32,7 +32,7 @@ export default function CollapsibleTable() { const loadData = async () => { try { - const res = await fetch('http://localhost:8000/api/analyze/errors') + const res = await fetch('/api/analyze/errors') const resJson = await res.json() const slowQueriesData = resJson.map((error: ErrorData, idx: number) => ({ key: idx, ...error })) diff --git a/frontend/src/pages/Logs/Logs.tsx b/frontend/src/pages/Logs/Logs.tsx index fa2b34e..e8cb373 100644 --- a/frontend/src/pages/Logs/Logs.tsx +++ b/frontend/src/pages/Logs/Logs.tsx @@ -38,7 +38,7 @@ export default function Logs() { }, ] - const url = 'http://localhost:8000/api/analyze/logs' + const url = '/api/analyze/logs' const fetchLogs = async (messageIlike = '') => { setLoadingLogs(true) @@ -60,7 +60,7 @@ export default function Logs() { const fetchLogsFrequency = async (messageIlike = '') => { setLoadingLogsFrequency(true) - const res = await fetch('http://localhost:8000/api/analyze/logs_frequency', { + const res = await fetch('/api/analyze/logs_frequency', { method: 'POST', body: JSON.stringify({ message_ilike: messageIlike }), headers: { diff --git a/frontend/src/pages/Operations/Operations.tsx b/frontend/src/pages/Operations/Operations.tsx index 95d6414..6032831 100644 --- a/frontend/src/pages/Operations/Operations.tsx +++ b/frontend/src/pages/Operations/Operations.tsx @@ -77,7 +77,7 @@ export function OperationsList(): JSX.Element { const [operations, setOperations] = useState([]) const fetchAndUpdateOperationsIfNeeded = async () => { - const response = await fetch('http://localhost:8000/api/async_migrations') + const response = await fetch('/api/async_migrations') const responseJson = await response.json() const results = responseJson.results if (JSON.stringify(results) !== JSON.stringify(operations)) { @@ -86,7 +86,7 @@ export function OperationsList(): JSX.Element { } const triggerOperation = async (id) => { - await fetch(`http://localhost:8000/api/async_migrations/${id}/trigger`, { method: 'POST' }) + await fetch(`/api/async_migrations/${id}/trigger`, { method: 'POST' }) await fetchAndUpdateOperationsIfNeeded() } @@ -174,7 +174,7 @@ export function CreateNewOperation(): JSX.Element { operationData[key] = value } - const res = await fetch('http://localhost:8000/api/async_migrations', { + const res = await fetch('/api/async_migrations', { method: 'POST', body: JSON.stringify(operationData), headers: { diff --git a/frontend/src/pages/Overview/Overview.tsx b/frontend/src/pages/Overview/Overview.tsx index c80c076..4cb04fa 100644 --- a/frontend/src/pages/Overview/Overview.tsx +++ b/frontend/src/pages/Overview/Overview.tsx @@ -26,7 +26,7 @@ export default function Overview() { const loadData = async () => { try { - const res = await fetch('http://localhost:8000/api/analyze/query_graphs') + const res = await fetch('/api/analyze/query_graphs') const resJson = await res.json() const execution_count = resJson.execution_count const memory_usage = resJson.memory_usage diff --git a/frontend/src/pages/QueryEditor/QueryEditor.tsx b/frontend/src/pages/QueryEditor/QueryEditor.tsx index db6ef87..6060ee4 100644 --- a/frontend/src/pages/QueryEditor/QueryEditor.tsx +++ b/frontend/src/pages/QueryEditor/QueryEditor.tsx @@ -68,8 +68,7 @@ export default function QueryEditor() { setRunningQueryId(queryId) try { setData([]) - setError('') - const res = await fetch('http://localhost:8000/api/analyze/query', { + const res = await fetch('/api/analyze/query', { method: 'POST', body: JSON.stringify({ sql, query_id: queryId }), headers: { diff --git a/frontend/src/pages/RunningQueries/RunningQueries.tsx b/frontend/src/pages/RunningQueries/RunningQueries.tsx index e7c8ea1..ef42a3a 100644 --- a/frontend/src/pages/RunningQueries/RunningQueries.tsx +++ b/frontend/src/pages/RunningQueries/RunningQueries.tsx @@ -21,7 +21,7 @@ function KillQueryButton({ queryId }: any) { const killQuery = async () => { setIsLoading(true) try { - const res = await fetch(`http://localhost:8000/api/analyze/${queryId}/kill_query`, { + const res = await fetch(`/api/analyze/${queryId}/kill_query`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', @@ -97,7 +97,7 @@ export default function RunningQueries() { async () => { setRunningQueries([]) setLoadingRunningQueries(true) - const res = await fetch('http://localhost:8000/api/analyze/running_queries') + const res = await fetch('/api/analyze/running_queries') const resJson = await res.json() setRunningQueries(resJson) setLoadingRunningQueries(false) diff --git a/frontend/src/pages/SchemaStats/SchemaStats.tsx b/frontend/src/pages/SchemaStats/SchemaStats.tsx index 5ca3c56..8ce1406 100644 --- a/frontend/src/pages/SchemaStats/SchemaStats.tsx +++ b/frontend/src/pages/SchemaStats/SchemaStats.tsx @@ -45,12 +45,12 @@ export default function Schema() { const loadData = async () => { try { - const res = await fetch('http://localhost:8000/api/analyze/tables') + const res = await fetch('/api/analyze/tables') const resJson = await res.json() const filteredRes = resJson.filter((r: { total_bytes: number }) => r.total_bytes > 0) const filteredResUrls = filteredRes - .map((fr: { name: string }) => `http://localhost:8000/api/analyze/${fr.name}/schema`) + .map((fr: { name: string }) => `/api/analyze/${fr.name}/schema`) .slice(0, 1) const nestedRes = await Promise.all( diff --git a/frontend/src/pages/SchemaStats/SchemaTable.tsx b/frontend/src/pages/SchemaStats/SchemaTable.tsx index d53d8b5..c577547 100644 --- a/frontend/src/pages/SchemaStats/SchemaTable.tsx +++ b/frontend/src/pages/SchemaStats/SchemaTable.tsx @@ -50,7 +50,7 @@ function TableTreeMap({ schema, dataIndex }) { export function ColumnsData({ table }: { table: string }): JSX.Element { const [schema, setSchema] = React.useState([]) - const url = `http://localhost:8000/api/analyze/${table}/schema` + const url = `/api/analyze/${table}/schema` useEffect @@ -91,7 +91,7 @@ export function PartsData({ table }: { table: string }): JSX.Element { const loadData = async () => { try { - const res = await fetch(`http://localhost:8000/api/analyze/${table}/parts`) + const res = await fetch(`/api/analyze/${table}/parts`) const resJson = await res.json() setPartData(resJson) } catch { diff --git a/frontend/src/pages/SlowQueries/ExampleQueriesTab.tsx b/frontend/src/pages/SlowQueries/ExampleQueriesTab.tsx index 8825943..9bf731a 100644 --- a/frontend/src/pages/SlowQueries/ExampleQueriesTab.tsx +++ b/frontend/src/pages/SlowQueries/ExampleQueriesTab.tsx @@ -14,7 +14,7 @@ export default function ExampleQueriesTab({ query_hash }: { query_hash: string } const loadData = async () => { try { - const res = await fetch(`http://localhost:8000/api/analyze/${query_hash}/query_examples`) + const res = await fetch(`/api/analyze/${query_hash}/query_examples`) const resJson = await res.json() setData(resJson) } catch { diff --git a/frontend/src/pages/SlowQueries/ExplainTab.tsx b/frontend/src/pages/SlowQueries/ExplainTab.tsx index ab479f7..6be3fc2 100644 --- a/frontend/src/pages/SlowQueries/ExplainTab.tsx +++ b/frontend/src/pages/SlowQueries/ExplainTab.tsx @@ -14,7 +14,7 @@ export default function ExplainTab({ query_hash }: { query_hash: string }) { const loadData = async () => { try { - const res = await fetch(`http://localhost:8000/api/analyze/${query_hash}/query_explain`) + const res = await fetch(`/api/analyze/${query_hash}/query_explain`) const resJson = await res.json() setData(resJson) } catch { diff --git a/frontend/src/pages/SlowQueries/MetricsTab.tsx b/frontend/src/pages/SlowQueries/MetricsTab.tsx index c036fb4..dc3d83d 100644 --- a/frontend/src/pages/SlowQueries/MetricsTab.tsx +++ b/frontend/src/pages/SlowQueries/MetricsTab.tsx @@ -12,7 +12,7 @@ export default function MetricsTab({ query_hash }: { query_hash: string }) { const loadData = async () => { try { - const res = await fetch(`http://localhost:8000/api/analyze/${query_hash}/query_metrics`) + const res = await fetch(`/api/analyze/${query_hash}/query_metrics`) const resJson = await res.json() setData(resJson) } catch { diff --git a/frontend/src/pages/SlowQueries/NormalizedQueryTab.tsx b/frontend/src/pages/SlowQueries/NormalizedQueryTab.tsx index 8ea255c..a2eae15 100644 --- a/frontend/src/pages/SlowQueries/NormalizedQueryTab.tsx +++ b/frontend/src/pages/SlowQueries/NormalizedQueryTab.tsx @@ -15,7 +15,7 @@ export default function NormalizedQueryTab({ query_hash }: { query_hash: string const loadData = async () => { try { - const res = await fetch(`http://localhost:8000/api/analyze/${query_hash}/query_normalized`) + const res = await fetch(`/api/analyze/${query_hash}/query_normalized`) const resJson = await res.json() setData(resJson) } catch { diff --git a/frontend/src/pages/SlowQueries/SlowQueries.tsx b/frontend/src/pages/SlowQueries/SlowQueries.tsx index 5ddf23e..7d9938b 100644 --- a/frontend/src/pages/SlowQueries/SlowQueries.tsx +++ b/frontend/src/pages/SlowQueries/SlowQueries.tsx @@ -76,7 +76,7 @@ export default function CollapsibleTable() { setSlowQueries([]) setLoadingSlowQueries(true) try { - const res = await fetch(`http://localhost:8000/api/analyze/slow_queries?time_range=${timeRange}`) + const res = await fetch(`/api/analyze/slow_queries?time_range=${timeRange}`) const resJson = await res.json() const slowQueriesData = resJson.map((error: SlowQueryData, idx: number) => ({ key: idx, ...error })) setSlowQueries(slowQueriesData) @@ -99,8 +99,8 @@ export default function CollapsibleTable() { placeholder="system.query_log" optionFilterProp="children" options={[ - { label: 'Last week', value: '-1w' }, - { label: 'Last two weeks', value: '-2w' }, + { label: 'Last week', value: '-1w' }, + { label: 'Last two weeks', value: '-2w' }, { label: 'Last month', value: '-1m' }, { label: 'Last three months', value: '-3m' } ]} diff --git a/housewatch/clickhouse/client.py b/housewatch/clickhouse/client.py index 419865c..582fe7a 100644 --- a/housewatch/clickhouse/client.py +++ b/housewatch/clickhouse/client.py @@ -10,9 +10,9 @@ def str_to_bool(s: str) -> bool: return str(s).lower() in ("y", "yes", "t", "true", "on", "1") ch_host = os.getenv("CLICKHOUSE_HOST", "localhost") -ch_verify = os.getenv("CLICKHOUSE_VERIFY", True) +ch_verify = os.getenv("CLICKHOUSE_VERIFY", "true").lower() not in ("false", "0") ch_ca = os.getenv("CLICKHOUSE_CA", None) -ch_secure = os.getenv("CLICKHOUSE_SECURE", True) +ch_secure = os.getenv("CLICKHOUSE_SECURE", "true").lower() not in ("false", "0") pool = ChPool( host=ch_host, @@ -36,7 +36,7 @@ def run_query( ): final_query = query % (params or {}) if substitute_params else query query_hash = "" - + if use_cache: query_hash = hashlib.sha256(final_query.encode("utf-8")).hexdigest() cached_result = cache.get(query_hash) From bbe3bf931f9db61348ceb1fc56e0a5a28d89b1f0 Mon Sep 17 00:00:00 2001 From: Frank Hamand Date: Thu, 25 May 2023 14:59:52 +0100 Subject: [PATCH 2/2] Add helm chart --- .gitignore | 1 - charts/housewatch/.helmignore | 23 +++++++ charts/housewatch/Chart.yaml | 6 ++ charts/housewatch/templates/_helpers.tpl | 62 +++++++++++++++++ .../templates/deployment-nginx.yaml | 55 ++++++++++++++++ .../housewatch/templates/deployment-web.yaml | 66 +++++++++++++++++++ .../templates/deployment-worker.yaml | 50 ++++++++++++++ .../housewatch/templates/nginx-configmap.yaml | 33 ++++++++++ charts/housewatch/templates/redis.yaml | 32 +++++++++ charts/housewatch/templates/service.yaml | 52 +++++++++++++++ charts/housewatch/values.yaml | 59 +++++++++++++++++ docker-compose.yml | 4 ++ 12 files changed, 442 insertions(+), 1 deletion(-) create mode 100644 charts/housewatch/.helmignore create mode 100644 charts/housewatch/Chart.yaml create mode 100644 charts/housewatch/templates/_helpers.tpl create mode 100644 charts/housewatch/templates/deployment-nginx.yaml create mode 100644 charts/housewatch/templates/deployment-web.yaml create mode 100644 charts/housewatch/templates/deployment-worker.yaml create mode 100644 charts/housewatch/templates/nginx-configmap.yaml create mode 100644 charts/housewatch/templates/redis.yaml create mode 100644 charts/housewatch/templates/service.yaml create mode 100644 charts/housewatch/values.yaml diff --git a/.gitignore b/.gitignore index 4a5879d..bd4c8a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ env/ -charts __pycache__/ node_modules housewatch.sqlite3 diff --git a/charts/housewatch/.helmignore b/charts/housewatch/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/housewatch/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/housewatch/Chart.yaml b/charts/housewatch/Chart.yaml new file mode 100644 index 0000000..20c54be --- /dev/null +++ b/charts/housewatch/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: housewatch +description: Open source tool for monitoring and managing ClickHouse clusters +type: application +version: 0.1.0 +appVersion: "0.1.0" diff --git a/charts/housewatch/templates/_helpers.tpl b/charts/housewatch/templates/_helpers.tpl new file mode 100644 index 0000000..9c724fe --- /dev/null +++ b/charts/housewatch/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "housewatch.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "housewatch.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "housewatch.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "housewatch.labels" -}} +helm.sh/chart: {{ include "housewatch.chart" . }} +{{ include "housewatch.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "housewatch.selectorLabels" -}} +app.kubernetes.io/name: {{ include "housewatch.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "housewatch.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "housewatch.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/housewatch/templates/deployment-nginx.yaml b/charts/housewatch/templates/deployment-nginx.yaml new file mode 100644 index 0000000..9ad2ca5 --- /dev/null +++ b/charts/housewatch/templates/deployment-nginx.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "housewatch.fullname" . }}-nginx + labels: + {{- include "housewatch.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "housewatch.selectorLabels" . | nindent 6 }} + app.kubernetes.io/service: nginx + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "housewatch.selectorLabels" . | nindent 8 }} + app.kubernetes.io/service: nginx + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: frontend + emptyDir: {} + - name: nginx-config + configMap: + name: {{ include "housewatch.fullname" . }}-nginx + initContainers: + - name: frontend-copy + image: "{{ .Values.image.frontendRepository }}:{{ .Values.image.tag }}" + command: [sh, -cex] + args: + - cp -r /frontend/build/* /http/ + volumeMounts: + - mountPath: /http + name: frontend + containers: + - name: nginx + image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag }}" + ports: + - name: http + containerPort: 80 + protocol: TCP + volumeMounts: + - mountPath: /http + name: frontend + - mountPath: /etc/nginx/nginx.conf + name: nginx-config + subPath: nginx.conf + resources: + {{- toYaml .Values.nginx.resources | nindent 12 }} diff --git a/charts/housewatch/templates/deployment-web.yaml b/charts/housewatch/templates/deployment-web.yaml new file mode 100644 index 0000000..3da6d3c --- /dev/null +++ b/charts/housewatch/templates/deployment-web.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "housewatch.fullname" . }} + labels: + {{- include "housewatch.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "housewatch.selectorLabels" . | nindent 6 }} + app.kubernetes.io/service: web + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "housewatch.selectorLabels" . | nindent 8 }} + app.kubernetes.io/service: web + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: web + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + command: ["bash", "-c"] + args: + - | + python manage.py migrate + python manage.py runserver 0.0.0.0:8000 + ports: + - name: api + containerPort: 8000 + protocol: TCP + env: + - name: REDIS_URL + value: redis://{{ include "housewatch.fullname" . }}-redis:6379 + - name: CLICKHOUSE_HOST + value: "{{ .Values.clickhouse.host }}" + - name: CLICKHOUSE_DATABASE + value: "{{ .Values.clickhouse.database }}" + - name: CLICKHOUSE_USER + value: "{{ .Values.clickhouse.user }}" + - name: CLICKHOUSE_PASSWORD + value: "{{ .Values.clickhouse.password }}" + - name: CLICKHOUSE_CLUSTER + value: {{ .Values.clickhouse.cluster }} + - name: CLICKHOUSE_SECURE + value: "{{ .Values.clickhouse.secure }}" + - name: CLICKHOUSE_VERIFY + value: "{{ .Values.clickhouse.verify }}" + - name: CLICKHOUSE_CA + value: "{{ .Values.clickhouse.ca }}" + livenessProbe: + httpGet: + path: / + port: api + readinessProbe: + httpGet: + path: / + port: api + resources: + {{- toYaml .Values.web.resources | nindent 12 }} diff --git a/charts/housewatch/templates/deployment-worker.yaml b/charts/housewatch/templates/deployment-worker.yaml new file mode 100644 index 0000000..ed81e92 --- /dev/null +++ b/charts/housewatch/templates/deployment-worker.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "housewatch.fullname" . }}-worker + labels: + {{- include "housewatch.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "housewatch.selectorLabels" . | nindent 6 }} + app.kubernetes.io/service: worker + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "housewatch.selectorLabels" . | nindent 8 }} + app.kubernetes.io/service: worker + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: worker + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + command: ["./bin/celery"] + env: + - name: REDIS_URL + value: redis://{{ include "housewatch.fullname" . }}-redis:6379 + - name: CLICKHOUSE_HOST + value: "{{ .Values.clickhouse.host }}" + - name: CLICKHOUSE_DATABASE + value: "{{ .Values.clickhouse.database }}" + - name: CLICKHOUSE_USER + value: "{{ .Values.clickhouse.user }}" + - name: CLICKHOUSE_PASSWORD + value: "{{ .Values.clickhouse.password }}" + - name: CLICKHOUSE_CLUSTER + value: "{{ .Values.clickhouse.cluster }}" + - name: CLICKHOUSE_SECURE + value: "{{ .Values.clickhouse.secure }}" + - name: CLICKHOUSE_VERIFY + value: "{{ .Values.clickhouse.verify }}" + - name: CLICKHOUSE_CA + value: "{{ .Values.clickhouse.ca }}" + resources: + {{- toYaml .Values.worker.resources | nindent 12 }} diff --git a/charts/housewatch/templates/nginx-configmap.yaml b/charts/housewatch/templates/nginx-configmap.yaml new file mode 100644 index 0000000..c1e6623 --- /dev/null +++ b/charts/housewatch/templates/nginx-configmap.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "housewatch.fullname" . }}-nginx +data: + nginx.conf: | + events { + worker_connections 1024; + } + http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + keepalive_timeout 65; + + server { + listen 80; + + location / { + root /http; + try_files $uri $uri/ /index.html =404; + } + + location /api { + proxy_pass http://{{ include "housewatch.fullname" . }}-api:8000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + } + } + } diff --git a/charts/housewatch/templates/redis.yaml b/charts/housewatch/templates/redis.yaml new file mode 100644 index 0000000..3ad0aaa --- /dev/null +++ b/charts/housewatch/templates/redis.yaml @@ -0,0 +1,32 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "housewatch.fullname" . }}-redis + labels: + {{- include "housewatch.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "housewatch.selectorLabels" . | nindent 6 }} + app.kubernetes.io/service: redis + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "housewatch.selectorLabels" . | nindent 8 }} + app.kubernetes.io/service: redis + spec: + containers: + - name: redis + image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: redis + containerPort: 6379 + protocol: TCP + resources: + {{- toYaml .Values.redis.resources | nindent 12 }} diff --git a/charts/housewatch/templates/service.yaml b/charts/housewatch/templates/service.yaml new file mode 100644 index 0000000..b1116db --- /dev/null +++ b/charts/housewatch/templates/service.yaml @@ -0,0 +1,52 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "housewatch.fullname" . }} + annotations: + {{- toYaml .Values.service.annotations | nindent 4 }} + labels: + {{- include "housewatch.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + {{- include "housewatch.selectorLabels" . | nindent 4 }} + app.kubernetes.io/service: nginx +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "housewatch.fullname" . }}-api + labels: + {{- include "housewatch.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: 8000 + targetPort: api + protocol: TCP + name: api + selector: + {{- include "housewatch.selectorLabels" . | nindent 4 }} + app.kubernetes.io/service: web +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "housewatch.fullname" . }}-redis + labels: + {{- include "housewatch.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: 6379 + targetPort: 6379 + protocol: TCP + name: redis + selector: + {{- include "housewatch.selectorLabels" . | nindent 4 }} + app.kubernetes.io/service: redis diff --git a/charts/housewatch/values.yaml b/charts/housewatch/values.yaml new file mode 100644 index 0000000..19733b2 --- /dev/null +++ b/charts/housewatch/values.yaml @@ -0,0 +1,59 @@ +image: + repository: ghcr.io/posthog/housewatch/api + frontendRepository: ghcr.io/posthog/housewatch/frontend + tag: sha-4cbdf5e + +nginx: + image: + repository: nginx + tag: stable + +clickhouse: + user: default + host: clickhouse + database: default + secure: "false" + verify: "false" + ca: "" + +imagePullSecrets: +- name: dockerconfigjson-ghcr-io + +service: + annotations: {} + +web: + resources: + requests: + cpu: 100m + memory: 500Mi + limits: + memory: 500Mi + +frontend: + resources: + requests: + cpu: 500m + memory: 2Gi + limits: + memory: 2Gi + +worker: + resources: + requests: + cpu: 100m + memory: 1500Mi + limits: + memory: 1500Mi + +redis: + image: + repository: redis + tag: 6.2.7-alpine + + resources: + requests: + cpu: 100m + memory: 1Gi + limits: + memory: 1Gi diff --git a/docker-compose.yml b/docker-compose.yml index 59c7da8..2f8dc47 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,8 +29,12 @@ services: python manage.py runserver 0.0.0.0:8000 volumes: - .:/code +<<<<<<< HEAD ports: - '8000:8000' +======= + network_mode: "service:web" +>>>>>>> 0921a8c (Add helm chart) redis: image: redis:6.2.7-alpine