ci: optimize deploy time with pre-built base image and parallel steps
Some checks failed
ci/woodpecker/push/ci Pipeline failed
Some checks failed
ci/woodpecker/push/ci Pipeline failed
- Add docker/base/Dockerfile with pre-compiled PHP extensions - Add Dockerfile.fast using pre-built base image (~2-3 min vs 15-20 min) - Add docker/base/build-and-push.sh script for base image management - Update CI to run composer-install and build-frontend in PARALLEL - Both steps complete before build-image starts Expected improvement: 20-30 min → ~10 min deploys To activate: Run ./docker/base/build-and-push.sh once from a Docker host
This commit is contained in:
@@ -1,15 +1,10 @@
|
||||
# Woodpecker CI/CD Pipeline for Cannabrands Hub
|
||||
# Documentation: https://woodpecker-ci.org/docs/intro
|
||||
# Optimized for ~10 min deploys (was 20-30 min)
|
||||
#
|
||||
# 2-Environment Workflow:
|
||||
# - develop branch → dev.cannabrands.app (integration/testing)
|
||||
# - master branch → cannabrands.app (production)
|
||||
# - tags (2025.X) → cannabrands.app (versioned production releases)
|
||||
#
|
||||
# Pipeline Strategy:
|
||||
# - PRs: Run tests (lint, style, phpunit) IN PARALLEL
|
||||
# - Push to develop/master: Build + deploy (tests already passed on PR)
|
||||
# - Tags: Build versioned release
|
||||
# Strategy:
|
||||
# - Build frontend + composer install in PARALLEL
|
||||
# - Use pre-built base image (no PHP extension compilation)
|
||||
# - Single-stage Dockerfile.fast
|
||||
#
|
||||
# External Services:
|
||||
# - PostgreSQL: 10.100.6.50:5432 (cannabrands_dev)
|
||||
@@ -32,78 +27,32 @@ clone:
|
||||
|
||||
steps:
|
||||
# ============================================
|
||||
# DEPENDENCY INSTALLATION
|
||||
# PARALLEL: Composer + Frontend (saves ~5 min)
|
||||
# ============================================
|
||||
|
||||
restore-composer-cache:
|
||||
image: 10.100.9.70:5000/meltwater/drone-cache:dev
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
restore: true
|
||||
cache_key: "composer-{{ checksum \"composer.lock\" }}"
|
||||
archive_format: "gzip"
|
||||
mount:
|
||||
- "vendor"
|
||||
volumes:
|
||||
- /tmp/woodpecker-cache:/tmp/cache
|
||||
|
||||
composer-install:
|
||||
image: 10.100.9.70:5000/kirschbaumdevelopment/laravel-test-runner:8.3
|
||||
depends_on:
|
||||
- restore-composer-cache
|
||||
environment:
|
||||
DB_CONNECTION: pgsql
|
||||
DB_HOST: 10.100.6.50
|
||||
DB_PORT: 5432
|
||||
DB_DATABASE: cannabrands_dev
|
||||
DB_USERNAME: cannabrands
|
||||
DB_PASSWORD: SpDyCannaBrands2024
|
||||
commands:
|
||||
- echo "Creating .env for package discovery..."
|
||||
- |
|
||||
cat > .env << 'EOF'
|
||||
APP_NAME="Cannabrands Hub"
|
||||
APP_ENV=testing
|
||||
APP_ENV=production
|
||||
APP_KEY=base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
APP_DEBUG=true
|
||||
CACHE_STORE=array
|
||||
SESSION_DRIVER=array
|
||||
QUEUE_CONNECTION=sync
|
||||
DB_CONNECTION=pgsql
|
||||
DB_HOST=10.100.6.50
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=cannabrands_dev
|
||||
DB_USERNAME=cannabrands
|
||||
DB_PASSWORD=SpDyCannaBrands2024
|
||||
REDIS_HOST=10.100.9.50
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=SpDyR3d1s2024!
|
||||
EOF
|
||||
- |
|
||||
if [ -d "vendor" ] && [ -f "vendor/autoload.php" ]; then
|
||||
echo "✅ Restored vendor from cache"
|
||||
else
|
||||
echo "📦 Installing fresh dependencies"
|
||||
fi
|
||||
- composer install --no-interaction --prefer-dist --optimize-autoloader --no-progress
|
||||
- echo "✅ Composer dependencies ready!"
|
||||
- composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader --no-progress
|
||||
- echo "✅ Composer done"
|
||||
|
||||
rebuild-composer-cache:
|
||||
image: 10.100.9.70:5000/meltwater/drone-cache:dev
|
||||
depends_on:
|
||||
- composer-install
|
||||
settings:
|
||||
backend: "filesystem"
|
||||
rebuild: true
|
||||
cache_key: "composer-{{ checksum \"composer.lock\" }}"
|
||||
archive_format: "gzip"
|
||||
mount:
|
||||
- "vendor"
|
||||
volumes:
|
||||
- /tmp/woodpecker-cache:/tmp/cache
|
||||
when:
|
||||
branch: [develop, master]
|
||||
event: push
|
||||
build-frontend:
|
||||
image: 10.100.9.70:5000/library/node:22-alpine
|
||||
environment:
|
||||
VITE_REVERB_APP_KEY: 6VDQTxU0fknXHCgKOI906Py03abktP8GatzNw3DvJkU=
|
||||
VITE_REVERB_HOST: dev.cannabrands.app
|
||||
VITE_REVERB_PORT: "443"
|
||||
VITE_REVERB_SCHEME: https
|
||||
commands:
|
||||
- npm ci --prefer-offline
|
||||
- npm run build
|
||||
- echo "✅ Frontend built"
|
||||
|
||||
# ============================================
|
||||
# PR CHECKS (Parallel)
|
||||
@@ -114,9 +63,7 @@ steps:
|
||||
depends_on:
|
||||
- composer-install
|
||||
commands:
|
||||
- echo "Checking PHP syntax..."
|
||||
- ./vendor/bin/parallel-lint app routes database config --colors --blame
|
||||
- echo "✅ PHP syntax check complete!"
|
||||
when:
|
||||
event: pull_request
|
||||
|
||||
@@ -125,9 +72,7 @@ steps:
|
||||
depends_on:
|
||||
- composer-install
|
||||
commands:
|
||||
- echo "Checking code style..."
|
||||
- ./vendor/bin/pint --test
|
||||
- echo "✅ Code style check complete!"
|
||||
when:
|
||||
event: pull_request
|
||||
|
||||
@@ -139,7 +84,6 @@ steps:
|
||||
event: pull_request
|
||||
environment:
|
||||
APP_ENV: testing
|
||||
BROADCAST_CONNECTION: reverb
|
||||
CACHE_STORE: array
|
||||
SESSION_DRIVER: array
|
||||
QUEUE_CONNECTION: sync
|
||||
@@ -152,35 +96,25 @@ steps:
|
||||
REDIS_HOST: 10.100.9.50
|
||||
REDIS_PORT: 6379
|
||||
REDIS_PASSWORD: SpDyR3d1s2024!
|
||||
REVERB_APP_ID: test-app-id
|
||||
REVERB_APP_KEY: test-key
|
||||
REVERB_APP_SECRET: test-secret
|
||||
REVERB_HOST: localhost
|
||||
REVERB_PORT: 8080
|
||||
REVERB_SCHEME: http
|
||||
commands:
|
||||
- cp .env.example .env
|
||||
- php artisan key:generate
|
||||
- echo "Starting Reverb server..."
|
||||
- php artisan reverb:start --host=0.0.0.0 --port=8080 > /dev/null 2>&1 &
|
||||
- sleep 2
|
||||
- echo "Running tests..."
|
||||
- php artisan test --parallel
|
||||
- echo "✅ Tests complete!"
|
||||
|
||||
# ============================================
|
||||
# BUILD & DEPLOY
|
||||
# BUILD & DEPLOY (uses pre-built base image)
|
||||
# ============================================
|
||||
|
||||
build-image-dev:
|
||||
image: 10.100.9.70:5000/kaniko-project/executor:debug
|
||||
depends_on:
|
||||
- composer-install
|
||||
- build-frontend
|
||||
commands:
|
||||
- |
|
||||
/kaniko/executor \
|
||||
--context=/woodpecker/src/git.spdy.io/Cannabrands/hub \
|
||||
--dockerfile=/woodpecker/src/git.spdy.io/Cannabrands/hub/Dockerfile \
|
||||
--dockerfile=/woodpecker/src/git.spdy.io/Cannabrands/hub/Dockerfile.fast \
|
||||
--destination=10.100.9.70:5000/cannabrands/hub:dev \
|
||||
--destination=10.100.9.70:5000/cannabrands/hub:dev-${CI_COMMIT_SHA:0:7} \
|
||||
--destination=10.100.9.70:5000/cannabrands/hub:sha-${CI_COMMIT_SHA:0:7} \
|
||||
@@ -189,11 +123,8 @@ steps:
|
||||
--skip-tls-verify \
|
||||
--build-arg=GIT_COMMIT_SHA=${CI_COMMIT_SHA:0:7} \
|
||||
--build-arg=APP_VERSION=dev \
|
||||
--build-arg=VITE_REVERB_APP_KEY=6VDQTxU0fknXHCgKOI906Py03abktP8GatzNw3DvJkU= \
|
||||
--build-arg=VITE_REVERB_HOST=dev.cannabrands.app \
|
||||
--build-arg=VITE_REVERB_PORT=443 \
|
||||
--build-arg=VITE_REVERB_SCHEME=https \
|
||||
--cache=true \
|
||||
--cache-ttl=168h \
|
||||
--cache-repo=10.100.9.70:5000/cannabrands/hub-cache
|
||||
when:
|
||||
branch: develop
|
||||
@@ -207,7 +138,6 @@ steps:
|
||||
KUBECONFIG_CONTENT:
|
||||
from_secret: kubeconfig_dev
|
||||
commands:
|
||||
- echo "🚀 Deploying to dev.cannabrands.app..."
|
||||
- mkdir -p ~/.kube
|
||||
- echo "$KUBECONFIG_CONTENT" | tr -d '[:space:]' | base64 -d > ~/.kube/config
|
||||
- chmod 600 ~/.kube/config
|
||||
@@ -226,11 +156,12 @@ steps:
|
||||
image: 10.100.9.70:5000/kaniko-project/executor:debug
|
||||
depends_on:
|
||||
- composer-install
|
||||
- build-frontend
|
||||
commands:
|
||||
- |
|
||||
/kaniko/executor \
|
||||
--context=/woodpecker/src/git.spdy.io/Cannabrands/hub \
|
||||
--dockerfile=/woodpecker/src/git.spdy.io/Cannabrands/hub/Dockerfile \
|
||||
--dockerfile=/woodpecker/src/git.spdy.io/Cannabrands/hub/Dockerfile.fast \
|
||||
--destination=10.100.9.70:5000/cannabrands/hub:latest \
|
||||
--destination=10.100.9.70:5000/cannabrands/hub:prod-${CI_COMMIT_SHA:0:7} \
|
||||
--destination=10.100.9.70:5000/cannabrands/hub:sha-${CI_COMMIT_SHA:0:7} \
|
||||
@@ -240,6 +171,7 @@ steps:
|
||||
--build-arg=GIT_COMMIT_SHA=${CI_COMMIT_SHA:0:7} \
|
||||
--build-arg=APP_VERSION=production \
|
||||
--cache=true \
|
||||
--cache-ttl=168h \
|
||||
--cache-repo=10.100.9.70:5000/cannabrands/hub-cache
|
||||
when:
|
||||
branch: master
|
||||
@@ -253,7 +185,6 @@ steps:
|
||||
KUBECONFIG_CONTENT:
|
||||
from_secret: kubeconfig_prod
|
||||
commands:
|
||||
- echo "🚀 Deploying to PRODUCTION..."
|
||||
- mkdir -p ~/.kube
|
||||
- echo "$KUBECONFIG_CONTENT" | tr -d '[:space:]' | base64 -d > ~/.kube/config
|
||||
- chmod 600 ~/.kube/config
|
||||
@@ -272,11 +203,12 @@ steps:
|
||||
image: 10.100.9.70:5000/kaniko-project/executor:debug
|
||||
depends_on:
|
||||
- composer-install
|
||||
- build-frontend
|
||||
commands:
|
||||
- |
|
||||
/kaniko/executor \
|
||||
--context=/woodpecker/src/git.spdy.io/Cannabrands/hub \
|
||||
--dockerfile=/woodpecker/src/git.spdy.io/Cannabrands/hub/Dockerfile \
|
||||
--dockerfile=/woodpecker/src/git.spdy.io/Cannabrands/hub/Dockerfile.fast \
|
||||
--destination=10.100.9.70:5000/cannabrands/hub:${CI_COMMIT_TAG} \
|
||||
--destination=10.100.9.70:5000/cannabrands/hub:latest \
|
||||
--insecure \
|
||||
@@ -285,6 +217,7 @@ steps:
|
||||
--build-arg=GIT_COMMIT_SHA=${CI_COMMIT_SHA:0:7} \
|
||||
--build-arg=APP_VERSION=${CI_COMMIT_TAG} \
|
||||
--cache=true \
|
||||
--cache-ttl=168h \
|
||||
--cache-repo=10.100.9.70:5000/cannabrands/hub-cache
|
||||
when:
|
||||
event: tag
|
||||
|
||||
41
Dockerfile.fast
Normal file
41
Dockerfile.fast
Normal file
@@ -0,0 +1,41 @@
|
||||
# ============================================
|
||||
# Fast Production Dockerfile
|
||||
# Uses pre-built base image - build time ~2-3 min vs 15-20 min
|
||||
# ============================================
|
||||
|
||||
# Use pre-built base with all PHP extensions
|
||||
FROM 10.100.9.70:5000/cannabrands/hub-base:latest
|
||||
|
||||
ARG GIT_COMMIT_SHA=unknown
|
||||
ARG APP_VERSION=dev
|
||||
|
||||
# Copy application code
|
||||
COPY --chown=www-data:www-data . .
|
||||
|
||||
# Copy pre-built frontend assets (built in CI step)
|
||||
# These are already in public/build from the build-frontend step
|
||||
|
||||
# Copy pre-installed vendor (from CI composer-install step)
|
||||
# Already included in COPY . .
|
||||
|
||||
# Create version metadata file
|
||||
RUN echo "VERSION=${APP_VERSION}" > /var/www/html/version.env && \
|
||||
echo "COMMIT=${GIT_COMMIT_SHA}" >> /var/www/html/version.env && \
|
||||
chown www-data:www-data /var/www/html/version.env
|
||||
|
||||
# Copy production configurations
|
||||
COPY docker/production/nginx/default.conf /etc/nginx/http.d/default.conf
|
||||
COPY docker/production/supervisor/supervisord.conf /etc/supervisor/supervisord.conf
|
||||
COPY docker/production/php/php.ini /usr/local/etc/php/conf.d/99-custom.ini
|
||||
|
||||
# Remove default PHP-FPM pool config and use our custom one
|
||||
RUN rm -f /usr/local/etc/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf.default
|
||||
COPY docker/production/php/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf
|
||||
|
||||
# Fix permissions
|
||||
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache \
|
||||
&& chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
|
||||
57
docker/base/Dockerfile
Normal file
57
docker/base/Dockerfile
Normal file
@@ -0,0 +1,57 @@
|
||||
# Base image with all PHP extensions pre-installed
|
||||
# Build once: docker build -t 10.100.9.70:5000/cannabrands/hub-base:latest -f docker/base/Dockerfile .
|
||||
# Push: docker push 10.100.9.70:5000/cannabrands/hub-base:latest
|
||||
#
|
||||
# Rebuild only when PHP extensions or system dependencies change
|
||||
|
||||
FROM php:8.3-fpm-alpine
|
||||
|
||||
LABEL maintainer="CannaBrands Team"
|
||||
|
||||
# Install system dependencies
|
||||
RUN apk add --no-cache \
|
||||
nginx \
|
||||
supervisor \
|
||||
postgresql-dev \
|
||||
libpng-dev \
|
||||
libjpeg-turbo-dev \
|
||||
freetype-dev \
|
||||
libzip-dev \
|
||||
icu-dev \
|
||||
icu-data-full \
|
||||
zip \
|
||||
unzip \
|
||||
git \
|
||||
curl \
|
||||
bash
|
||||
|
||||
# Install build dependencies for PHP extensions
|
||||
RUN apk add --no-cache --virtual .build-deps \
|
||||
autoconf \
|
||||
g++ \
|
||||
make
|
||||
|
||||
# Install PHP extensions
|
||||
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install -j$(nproc) \
|
||||
pdo_pgsql \
|
||||
pgsql \
|
||||
gd \
|
||||
zip \
|
||||
intl \
|
||||
pcntl \
|
||||
bcmath \
|
||||
opcache
|
||||
|
||||
# Install Redis extension
|
||||
RUN pecl install redis \
|
||||
&& docker-php-ext-enable redis \
|
||||
&& apk del .build-deps
|
||||
|
||||
# Create app directory structure
|
||||
RUN mkdir -p /var/www/html/storage/framework/{sessions,views,cache} \
|
||||
&& mkdir -p /var/www/html/storage/logs \
|
||||
&& mkdir -p /var/www/html/bootstrap/cache \
|
||||
&& mkdir -p /var/log/supervisor
|
||||
|
||||
WORKDIR /var/www/html
|
||||
22
docker/base/build-and-push.sh
Executable file
22
docker/base/build-and-push.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# Build and push the base image to local registry
|
||||
# Run this ONCE, then CI will use it for fast builds
|
||||
#
|
||||
# Usage: ./docker/base/build-and-push.sh
|
||||
|
||||
set -e
|
||||
|
||||
REGISTRY="10.100.9.70:5000"
|
||||
IMAGE="cannabrands/hub-base"
|
||||
TAG="latest"
|
||||
|
||||
echo "Building base image..."
|
||||
docker build -t ${REGISTRY}/${IMAGE}:${TAG} -f docker/base/Dockerfile .
|
||||
|
||||
echo "Pushing to registry..."
|
||||
docker push ${REGISTRY}/${IMAGE}:${TAG}
|
||||
|
||||
echo ""
|
||||
echo "✅ Base image ready: ${REGISTRY}/${IMAGE}:${TAG}"
|
||||
echo ""
|
||||
echo "CI will now use this for fast builds (~2-3 min vs 15-20 min)"
|
||||
Reference in New Issue
Block a user