add Docker and CI/CD pipeline with ledo
Some checks failed
Docker - build image / 🏗️ Docker builder (latest from master) 🏗️ (push) Failing after 17s

Configure Next.js static export with nginx serving, Dockerfile
(multi-stage build), docker-compose for prod/dev, Gitea Actions
pipelines for build-on-push and tag-based releases using ledo tool.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 23:49:15 +01:00
parent afb939f629
commit 3438f8d405
11 changed files with 252 additions and 1 deletions

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
node_modules
.next
.git
.gitea
.automancer
docker
*.md
.env*
.DS_Store

View File

@@ -0,0 +1,27 @@
name: Docker - build image
run-name: ${{ gitea.actor }} builds image for project 🏗️
on:
push:
branches:
- "main"
jobs:
builder:
name: 🏗️ Docker builder (latest from master) 🏗️
runs-on: dind
steps:
- name: "[docker] registry login"
uses: docker/login-action@v2
with:
registry: git.cynarski.pl
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: "[code] repository checkout"
uses: actions/checkout@v3
with:
submodules: recursive
- name: "[ledo] Image build"
run: ledo image build
- name: "[ledo] Image push"
run: ledo image push
- name: "[docker] system prune"
run: docker system prune -af --volumes

View File

@@ -0,0 +1,35 @@
name: Docker - build image
run-name: ${{ gitea.actor }} builds docker image for project 🏗️
on:
push:
tags:
- "v*"
jobs:
builder:
name: 🏗️ Docker builder release tag 🏗️
runs-on: dind
steps:
- name: "[docker] registry login"
uses: docker/login-action@v2
with:
registry: git.cynarski.pl
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: "[code] repository checkout"
uses: actions/checkout@v3
with:
submodules: recursive
- name: checkout submodule
run: |
git submodule init
git submodule update
- name: "[ledo] Image build"
run: |
ledo image build
- name: "[ledo] Image retag and push"
run: |
export VERSION=$(echo $GITHUB_REF | cut -d '/' -f 3)
ledo image retag latest $VERSION
ledo image push $VERSION
- name: "[docker] system prune"
run: docker system prune -af --volumes

11
.ledo.yml Normal file
View File

@@ -0,0 +1,11 @@
runtime: docker
docker:
registry: git.cynarski.pl
namespace: automancer
name: site
main_service: site
shell: /bin/bash
modes:
base: docker/docker-compose.yml
dev: docker/docker-compose.yml docker/docker-compose.dev.yml
test: docker/docker-compose.yml docker/docker-compose.test.yml

35
Dockerfile Normal file
View File

@@ -0,0 +1,35 @@
# syntax=docker/dockerfile:1.7
############################
# 1) Dependencies
############################
FROM node:20-alpine AS deps
WORKDIR /app
RUN apk add --no-cache libc6-compat
COPY package.json package-lock.json* ./
RUN npm ci
############################
# 2) Build stage
############################
FROM node:20-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
############################
# 3) Production stage (nginx)
############################
FROM nginx:1.27-alpine AS production
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/out /usr/share/nginx/html
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -0,0 +1,17 @@
version: "3.7"
services:
site:
build:
context: ../
target: build
volumes:
- "../:/app"
- "/app/node_modules"
- "/app/.next"
ports:
- "3000:3000"
command: npm run dev
environment:
- NODE_ENV=development
networks:
- network-automancer-dev

11
docker/docker-compose.yml Normal file
View File

@@ -0,0 +1,11 @@
version: "3.7"
services:
site:
image: git.cynarski.pl/automancer/site:latest
ports:
- "8080:8080"
networks:
- network-automancer-dev
networks:
network-automancer-dev: {}

39
docker/docker-entrypoint.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/bin/bash
set -eo pipefail
shopt -s nullglob
#
# H E L P E R F U N C T I O N S
#
##################################
declare -i term_width=80
h1() {
declare border padding text
border='\e[1;34m'"$(printf '=%.0s' $(seq 1 "$term_width"))"'\e[0m'
padding="$(printf ' %.0s' $(seq 1 $(((term_width - $(wc -m <<<"$*")) / 2))))"
text="\\e[1m$*\\e[0m"
echo -e "$border"
echo -e "${padding}${text}${padding}"
echo -e "$border"
}
h2() {
printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "$*"
}
#
# M A I N F U N C T I O N S
#
#################################
h1 "Project init"
###
### Your code here
###
h1 "End of init"
exec "$@"

29
docker/nginx.conf Normal file
View File

@@ -0,0 +1,29 @@
server {
listen 8080;
server_name _;
root /usr/share/nginx/html;
index index.html;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
# Static assets: cache aggressively
location ~* \.(?:css|js|mjs|map|png|jpg|jpeg|gif|svg|ico|webp|woff2|woff|ttf)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000, immutable";
try_files $uri =404;
}
# HTML: no cache
location ~* \.html$ {
add_header Cache-Control "no-cache";
try_files $uri =404;
}
# Next.js static export: try file, then file.html, then 404
location / {
try_files $uri $uri.html $uri/ /404.html;
}
}

38
docker/test-entrypoint.sh Executable file
View File

@@ -0,0 +1,38 @@
#!/bin/bash
set -eo pipefail
shopt -s nullglob
#
# H E L P E R F U N C T I O N S
#
##################################
declare -i term_width=80
h1() {
declare border padding text
border='\e[1;34m'"$(printf '=%.0s' $(seq 1 "$term_width"))"'\e[0m'
padding="$(printf ' %.0s' $(seq 1 $(((term_width - $(wc -m <<<"$*")) / 2))))"
text="\\e[1m$*\\e[0m"
echo -e "$border"
echo -e "${padding}${text}${padding}"
echo -e "$border"
}
h2() {
printf '\e[1;33m==>\e[37;1m %s\e[0m\n' "$*"
}
#
# M A I N F U N C T I O N S
#
#################################
h1 "Project test init"
###
### Your code here
###
h1 "End of test init"
exec "$@"

View File

@@ -1,7 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
output: "export",
};
export default nextConfig;