xiaohongshu
xiaohongshu
flyway-backend-docker
Setup backend project with Flyway SQL migrations, tini init system, and MySQL integration testing. Modifies existing Dockerfile from backend-docker skill.
Full skill instructions
This skill configures a backend project to use Flyway for SQL schema management. It modifies an existing Dockerfile (created by the backend-docker skill) to add tini as init system and Flyway migrations that run before the application starts.
Invoke this skill when ANY of these conditions are true:
# Check for existing Dockerfile (from backend-docker skill)
ls ${BACKEND_PATH}/Dockerfile
If Dockerfile does not exist, invoke the backend-docker skill first.
Create the ./sql directory with the AGENTS.md file:
mkdir -p ${BACKEND_PATH}/sql
Create ${BACKEND_PATH}/sql/AGENTS.md:
# SQL Migrations Directory
This folder contains Flyway SQL migration files.
## IMPORTANT: Agent Rules
**DO NOT** modify or delete any existing files in this folder.
**ONLY** add new migration files following the Flyway naming convention:
- `V{version}__{description}.sql` for versioned migrations
- `U{version}__{description}.sql` for undo migrations (optional)
- `R__{description}.sql` for repeatable migrations
### Naming Convention Examples
- `V1__create_users_table.sql`
- `V2__add_email_to_users.sql`
- `V3__create_orders_table.sql`
- `R__refresh_views.sql`
### Why This Restriction?
Flyway tracks applied migrations by checksum. Modifying an already-applied migration will cause:
- Migration failures
- Checksum mismatch errors
- Database inconsistency
If you need to change existing schema, create a NEW migration file with the next version number.
Create ${BACKEND_PATH}/sql/V1__hello_world.sql:
-- Flyway Hello World Migration
-- This validates that Flyway is correctly configured
CREATE TABLE IF NOT EXISTS flyway_hello_world (
id INT AUTO_INCREMENT PRIMARY KEY,
message VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO flyway_hello_world (message) VALUES ('Hello from Flyway!');
Create ${BACKEND_PATH}/docker-entrypoint.sh:
#!/bin/sh
set -e
echo "=== Running Flyway migrations ==="
# Wait for database to be ready
until nc -z -v -w30 ${DB_HOST:-db} ${DB_PORT:-3306}
do
echo "Waiting for database connection at ${DB_HOST:-db}:${DB_PORT:-3306}..."
sleep 2
done
echo "Database is up - running migrations"
# Run Flyway migrations
flyway -url="jdbc:mysql://${DB_HOST:-db}:${DB_PORT:-3306}/${DB_NAME:-app}?allowPublicKeyRetrieval=true&useSSL=false" \
-user=${DB_USER:-root} \
-password=${DB_PASSWORD:-root} \
-locations=filesystem:/app/sql \
-connectRetries=5 \
migrate
echo "=== Flyway migrations complete ==="
echo "=== Starting application ==="
# Execute the main command (passed as arguments)
exec "$@"
Read the existing Dockerfile and apply these modifications:
For Debian/Ubuntu-based images (python:*-slim, etc.), add after existing apt-get install:
# Install tini, flyway dependencies, and netcat for health checks
RUN apt-get update && apt-get install -y --no-install-recommends \
tini \
curl \
netcat-openbsd \
default-jre-headless \
&& rm -rf /var/lib/apt/lists/*
For Alpine-based images (node:-alpine, golang:-alpine, etc.), add:
# Install tini and dependencies for flyway
RUN apk add --no-cache tini openjdk17-jre-headless curl bash netcat-openbsd
Add after the dependency installation:
# Install Flyway
ENV FLYWAY_VERSION=10.22.0
RUN mkdir -p /tmp/flyway && \
curl -fSL --retry 3 --retry-delay 5 \
"https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/${FLYWAY_VERSION}/flyway-commandline-${FLYWAY_VERSION}-linux-x64.tar.gz" \
-o /tmp/flyway/flyway.tar.gz && \
tar -xzf /tmp/flyway/flyway.tar.gz -C /opt && \
ln -s /opt/flyway-${FLYWAY_VERSION}/flyway /usr/local/bin/flyway && \
rm -rf /tmp/flyway
Note: For Alpine images, use linux-alpine-x64.tar.gz instead of linux-x64.tar.gz.
Add before COPY . .:
# Copy SQL migrations
COPY sql/ /app/sql/
# Copy entrypoint
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
Replace the existing CMD with ENTRYPOINT + CMD pattern:
For Debian-based images:
ENTRYPOINT ["/usr/bin/tini", "--", "/docker-entrypoint.sh"]
CMD ["<original-cmd>"]
For Alpine-based images:
ENTRYPOINT ["/sbin/tini", "--", "/docker-entrypoint.sh"]
CMD ["<original-cmd>"]
Where <original-cmd> is the original CMD from the Dockerfile (e.g., python -m uvicorn app.main:app --host 0.0.0.0 --port 8000).
Create ${BACKEND_PATH}/docker-compose.yml:
services:
db:
image: mysql:8.0
container_name: flyway-test-db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: app
MYSQL_USER: appuser
MYSQL_PASSWORD: apppassword
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
interval: 5s
timeout: 5s
retries: 10
start_period: 30s
app:
build: .
container_name: flyway-test-app
environment:
DB_HOST: db
DB_PORT: 3306
DB_NAME: app
DB_USER: root
DB_PASSWORD: root
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
volumes:
mysql_data:
Create ${BACKEND_PATH}/test-flyway-integration.sh:
#!/bin/bash
set -e
echo "=== Flyway Integration Test ==="
# Cleanup any existing containers
docker compose down -v 2>/dev/null || true
# Start MySQL
echo "Starting MySQL container..."
docker compose up -d db
# Wait for MySQL to be healthy
echo "Waiting for MySQL to be ready..."
timeout=90
while [ $timeout -gt 0 ]; do
if docker compose exec -T db mysqladmin ping -h localhost -u root -proot 2>/dev/null; then
echo "MySQL is ready!"
break
fi
echo "Waiting... ($timeout seconds remaining)"
sleep 2
timeout=$((timeout - 2))
done
if [ $timeout -le 0 ]; then
echo "ERROR: MySQL failed to start within timeout"
docker compose logs db
docker compose down -v
exit 1
fi
# Build and start app (which runs Flyway migrations)
echo "Building and starting app container..."
docker compose up -d --build app
# Wait for app to start and run migrations
echo "Waiting for app to start..."
sleep 15
# Check if app is running
if ! docker compose ps app | grep -q "Up"; then
echo "ERROR: App container failed to start"
docker compose logs app
docker compose down -v
exit 1
fi
# Verify Flyway migration was applied
echo "Verifying Flyway migration..."
RESULT=$(docker compose exec -T db mysql -u root -proot -D app -e "SELECT message FROM flyway_hello_world LIMIT 1;" 2>/dev/null)
if echo "$RESULT" | grep -q "Hello from Flyway!"; then
echo "SUCCESS: Flyway migration applied correctly!"
echo "Found message: Hello from Flyway!"
else
echo "ERROR: Flyway migration verification failed"
echo "Query result: $RESULT"
docker compose logs app
docker compose down -v
exit 1
fi
# Cleanup
echo "Cleaning up..."
docker compose down -v
echo "=== Integration Test PASSED ==="
Run the integration test:
cd ${BACKEND_PATH}
chmod +x test-flyway-integration.sh docker-entrypoint.sh
./test-flyway-integration.sh
Expected output:
flyway_hello_world table contains "Hello from Flyway!"| Variable | Default | Description |
|---|---|---|
| DB_HOST | db | Database hostname |
| DB_PORT | 3306 | Database port |
| DB_NAME | app | Database name |
| DB_USER | root | Database user |
| DB_PASSWORD | root | Database password |
To add a new migration:
# Create new migration file
touch sql/V2__create_users_table.sql
IMPORTANT: Never modify existing migration files. Always create new versioned migrations.
DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORDdocker compose logs app/sbin/tini, Debian uses /usr/bin/tinidocker-entrypoint.shxiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience