Deployment added.

This commit is contained in:
2026-09-02 17:45:38 +00:00
parent 1a9c69fc9d
commit c078745bc0
15 changed files with 235 additions and 18 deletions
+1
View File
@@ -23,6 +23,7 @@ backend/pocketbase.exe
.env.local .env.local
.env.*.local .env.*.local
!.env.example !.env.example
!ansible/files/.env
# IDEs & System files # IDEs & System files
.vscode/ .vscode/
+25 -17
View File
@@ -1,18 +1,19 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Stage 1: Install frontend dependencies # Stage 1: Install frontend dependencies (Native execution on host architecture)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
FROM node:lts-trixie-slim AS deps FROM --platform=$BUILDPLATFORM node:22-bookworm-slim AS deps
WORKDIR /app/frontend WORKDIR /app/frontend
COPY frontend/package.json frontend/package-lock.json* ./ COPY frontend/package.json frontend/package-lock.json* ./
RUN npm ci RUN --mount=type=cache,target=/root/.npm \
npm ci
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Stage 2: Build the TanStack Start frontend # Stage 2: Build the TanStack Start frontend (Native execution on host architecture)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
FROM node:lts-trixie-slim AS builder FROM --platform=$BUILDPLATFORM node:22-bookworm-slim AS builder
WORKDIR /app/frontend WORKDIR /app/frontend
COPY --from=deps /app/frontend/node_modules ./node_modules COPY --from=deps /app/frontend/node_modules ./node_modules
@@ -22,25 +23,28 @@ ENV NODE_ENV=production
RUN npm run build RUN npm run build
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Stage 3: Fetch PocketBase binary for target architecture # Stage 3: Fetch PocketBase binary for target architecture (Native host downloader)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
FROM alpine:3.20 AS pb-downloader FROM --platform=$BUILDPLATFORM alpine:3.20 AS pb-downloader
ARG TARGETARCH=amd64 ARG TARGETARCH
ARG PB_VERSION=0.40.2 ARG PB_VERSION=0.40.2
RUN apk add --no-cache curl unzip ca-certificates \ RUN apk add --no-cache curl unzip ca-certificates \
&& PB_ARCH="${TARGETARCH}" \ && case "${TARGETARCH}" in \
&& if [ "$TARGETARCH" = "x86_64" ]; then PB_ARCH="amd64"; fi \ amd64) PB_ARCH="amd64" ;; \
&& if [ "$TARGETARCH" = "aarch64" ]; then PB_ARCH="arm64"; fi \ arm64) PB_ARCH="arm64" ;; \
arm) PB_ARCH="armv7" ;; \
*) echo "Unsupported target architecture: ${TARGETARCH}" >&2; exit 1 ;; \
esac \
&& curl -fsSL -o /tmp/pb.zip "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_${PB_ARCH}.zip" \ && curl -fsSL -o /tmp/pb.zip "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_${PB_ARCH}.zip" \
&& unzip /tmp/pb.zip -d /app \ && unzip /tmp/pb.zip -d /app \
&& chmod +x /app/pocketbase \ && chmod +x /app/pocketbase \
&& rm -f /tmp/pb.zip && rm -f /tmp/pb.zip
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Stage 4: Production runner # Stage 4: Production runner (Target architecture)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
FROM node:lts-trixie-slim AS runner FROM node:22-bookworm-slim AS runner
LABEL maintainer="Amritanshu <docker@tanshu.com>" LABEL maintainer="Amritanshu <docker@tanshu.com>"
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
@@ -62,10 +66,10 @@ COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN chmod +x /app/docker-entrypoint.sh RUN chmod +x /app/docker-entrypoint.sh
# Environment variables # Environment variables
ENV NODE_ENV=production ENV NODE_ENV=production \
ENV PORT=3000 PORT=3000 \
ENV HOST=0.0.0.0 HOST=0.0.0.0 \
ENV PB_DATA_DIR=/app/pb_data PB_DATA_DIR=/app/pb_data
# Persistent data volume for PocketBase SQLite database and file storage # Persistent data volume for PocketBase SQLite database and file storage
VOLUME ["/app/pb_data"] VOLUME ["/app/pb_data"]
@@ -74,4 +78,8 @@ VOLUME ["/app/pb_data"]
# Port 8090: PocketBase REST API & Admin UI # Port 8090: PocketBase REST API & Admin UI
EXPOSE 3000 8090 EXPOSE 3000 8090
# Health check for both PocketBase and frontend server
HEALTHCHECK --interval=15s --timeout=3s --start-period=5s --retries=3 \
CMD curl -fsS http://127.0.0.1:8090/api/health > /dev/null && curl -fsS http://127.0.0.1:3000 > /dev/null || exit 1
ENTRYPOINT ["/app/docker-entrypoint.sh"] ENTRYPOINT ["/app/docker-entrypoint.sh"]
+36
View File
@@ -0,0 +1,36 @@
.PHONY: build-production
build-production: ## Build the production docker image and push to private registry
@docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag registry.tanshu.com/hops:latest \
$(if $(filter-out latest,$(TAG)),--tag registry.tanshu.com/hops:$(TAG)) \
--push \
--pull \
git@git.tanshu.com:tanshu/hops.git
.PHONY: build-check
build-check: ## Multi-arch build without push (compile check)
@docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag hops:test \
--pull \
--progress=plain \
git@git.tanshu.com:tanshu/hops.git
.PHONY: build-check-local
build-check-local: ## Multi-arch build without push (compile check)
@git archive --format=tar HEAD | docker buildx build \
--platform linux/amd64 \
--tag hops:test \
--pull \
--progress=plain \
--load \
-
# .PHONY: deploy
# deploy: ## Build, upload to registry, and trigger Ansible deployment
# @./deploy.sh --deploy $(if $(TAG),$(TAG))
# .PHONY: ansible-deploy
# ansible-deploy: ## Run Ansible playbook directly
# @cd ansible && ansible-playbook -i hosts playbook.yml $(if $(TAG),-e "tag=$(TAG)")
+6
View File
@@ -0,0 +1,6 @@
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
PB_DATA_DIR=/app/pb_data
PB_ADMIN_EMAIL={{ pb_admin_email }}
PB_ADMIN_PASSWORD={{ pb_admin_password }}
+20
View File
@@ -0,0 +1,20 @@
{{ host }}{% if apex_host is defined and apex_host %}, {{ apex_host }}{% endif %} {
# PocketBase Admin UI and REST API
handle /_/* {
reverse_proxy {{ container_name }}:8090
}
handle /api/* {
reverse_proxy {{ container_name }}:8090
}
# TanStack Start Frontend Application
handle {
reverse_proxy {{ container_name }}:3000
}
}
{% if admin_host is defined and admin_host %}
{{ admin_host }} {
reverse_proxy {{ container_name }}:8090
}
{% endif %}
+11
View File
@@ -0,0 +1,11 @@
---
- name: Deploy Hops n Grains Microbrewery
hosts: monoco
become: true
vars_files:
- vars/default.yml
roles:
- network
- hops
- caddy
+3
View File
@@ -0,0 +1,3 @@
---
collections:
- name: community.docker
+3
View File
@@ -0,0 +1,3 @@
---
caddy_container: caddy
caddy_caddyfile_path: /var/lib/caddy/conf/Caddyfile
+5
View File
@@ -0,0 +1,5 @@
---
- name: Reload Caddy configuration
ansible.builtin.command: "docker exec -w /etc/caddy {{ caddy_container }} caddy reload"
listen: "Reload Caddy"
changed_when: true
+26
View File
@@ -0,0 +1,26 @@
---
- name: Read snippet from template file
ansible.builtin.set_fact:
caddy_snippet_block: "{{ lookup('template', 'files/Caddyfile.j2') }}"
- name: Read current Caddyfile
ansible.builtin.slurp:
path: "{{ caddy_caddyfile_path }}"
register: caddy_caddyfile_raw
- name: Decode Caddyfile content
ansible.builtin.set_fact:
caddy_caddyfile_content: "{{ caddy_caddyfile_raw['content'] | b64decode }}"
- name: Check if snippet already exists
ansible.builtin.set_fact:
caddy_snippet_present: "{{ caddy_snippet_block in caddy_caddyfile_content }}"
- name: Add or update snippet in Caddyfile
ansible.builtin.blockinfile:
path: "{{ caddy_caddyfile_path }}"
marker: "# {mark} Ansible managed Caddy snippet for {{ host }}"
block: "{{ caddy_snippet_block }}"
create: true
mode: "0644"
notify: Reload Caddy configuration
+43
View File
@@ -0,0 +1,43 @@
---
- name: Log in to private Docker registry
community.docker.docker_login:
registry: "{{ registry }}"
username: "{{ username }}"
password: "{{ password }}"
- name: Pull Hops n Grains image
community.docker.docker_image:
name: "{{ image_name }}"
source: pull
state: present
force_source: true
- name: Ensure Host Directory exists
ansible.builtin.file:
path: "{{ host_data_path }}"
state: directory
mode: "0755"
- name: Ensure PocketBase data directory exists
ansible.builtin.file:
path: "{{ host_data_path }}/pb_data"
state: directory
mode: "0755"
- name: Upload the .env file
ansible.builtin.template:
src: "files/.env"
dest: "{{ host_data_path }}/.env"
mode: "0600"
- name: Create and run Hops n Grains container
community.docker.docker_container:
name: "{{ container_name }}"
image: "{{ image_name }}"
state: started
restart_policy: "unless-stopped"
env_file: "{{ host_data_path }}/.env"
volumes:
- "{{ host_data_path }}/pb_data:/app/pb_data"
networks:
- name: "{{ docker_network }}"
+8
View File
@@ -0,0 +1,8 @@
---
- name: Ensure Docker network exists
community.docker.docker_network:
name: "{{ docker_network }}"
state: present
connected:
- "{{ caddy_container }}"
appends: true
+28
View File
@@ -0,0 +1,28 @@
---
registry: registry.tanshu.com
username: ta-registry
password: ff28a01f00c0f39315d94cd9dcb1e554968dba25676a8ea5f2be34e96a9a099f
title: hops
tag: latest
image_name: "{{ registry }}/hops:{{ tag }}"
app_name: hops
host_directory: "{{ app_name }}"
host_data_path: "/var/lib/{{ host_directory }}"
container_name: "{{ app_name }}"
docker_network: "{{ app_name }}_net"
# Public host for frontend & PocketBase routing
host: www.hopsngrains.com
apex_host: hopsngrains.com
admin_host: admin.hopsngrains.com
# Caddy configuration
caddy_container: caddy
caddy_caddyfile_path: /var/lib/caddy/conf/Caddyfile
# PocketBase Initial Superuser Credentials
pb_admin_email: admin@hopsngrains.com
pb_admin_password: HopsPassword1234!
Executable
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" || exit ; pwd -P )
cd "$parent_path" || exit
echo "========================================================"
echo " Building & Uploading Docker Image"
echo "========================================================"
current_version="${1:-latest}"
make build-production TAG="$current_version"
echo ""
echo "========================================================"
echo " Executing Ansible Deployment"
echo "========================================================"
cd "$parent_path/ansible" || exit
ansible-playbook playbook.yml -e "tag=$current_version"
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
set -e set -e
# Data directory for PocketBase # Data directory for PocketBase