Deployment added.
This commit is contained in:
@@ -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
@@ -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"]
|
||||||
|
|||||||
@@ -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)")
|
||||||
@@ -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 }}
|
||||||
@@ -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 %}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Hops n Grains Microbrewery
|
||||||
|
hosts: monoco
|
||||||
|
become: true
|
||||||
|
vars_files:
|
||||||
|
- vars/default.yml
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- network
|
||||||
|
- hops
|
||||||
|
- caddy
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
collections:
|
||||||
|
- name: community.docker
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
caddy_container: caddy
|
||||||
|
caddy_caddyfile_path: /var/lib/caddy/conf/Caddyfile
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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 }}"
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure Docker network exists
|
||||||
|
community.docker.docker_network:
|
||||||
|
name: "{{ docker_network }}"
|
||||||
|
state: present
|
||||||
|
connected:
|
||||||
|
- "{{ caddy_container }}"
|
||||||
|
appends: true
|
||||||
@@ -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!
|
||||||
@@ -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,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Data directory for PocketBase
|
# Data directory for PocketBase
|
||||||
|
|||||||
Reference in New Issue
Block a user