Skip to content

Commit

Permalink
feat: initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
pcfreak30 committed Nov 12, 2024
1 parent f8f0a75 commit 4fa8e04
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 0 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Build and Publish Docker Image

on:
push:
branches:
- develop
tags:
- 'v*'
pull_request:
branches:
- develop

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23.2'

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
29 changes: 29 additions & 0 deletions Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
# Global Caddy configuration
admin off

# Logging
log {
level INFO
output file /var/log/caddy/access.log
}
}

# Metrics exporter with authentication and SSL
:8080 {
# Basic authentication for metrics
basicauth /* {
{$METRICS_USERNAME} {$METRICS_PASSWORD}
}

# Proxy to metrics exporter
reverse_proxy localhost:9104 {
transport http {
tls_insecure_skip_verify
}
}

tls {
challenge http
}
}
57 changes: 57 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
ARG MYSQL_VERSION=8
ARG METRICS_EXPORTER_VERSION=develop
ARG MYSQL_MANAGER_VERSION=develop
ARG CADDY_VERSION=2.7.6

# Disable Percona Telemetry
ARG PERCONA_TELEMETRY_DISABLE=1

# Use the official Renterd image as base
FROM ghcr.io/lumeweb/akash-metrics-exporter:${METRICS_EXPORTER_VERSION} AS metrics-exporter
FROM ghcr.io/lumeweb/mysql-manager:${MYSQL_MANAGER_VERSION} AS mysql-manager
FROM caddy:${CADDY_VERSION} AS caddy

FROM percona:${MYSQL_VERSION}


# Switch to root to perform installations
USER root

# Install system dependencies
RUN percona-release enable pxb-80 && yum install percona-xtrabackup-80 lz4 zstd

# Copy the built executables from the builder stages
COPY --from=metrics-exporter /usr/bin/metrics-exporter /usr/bin/akash-metrics-exporter
COPY --from=caddy /usr/bin/caddy /usr/bin/caddy
COPY --from=mysql-manager /usr/bin/mysql-manager /usr/bin/mysql-manager

VOLUME [ "/data" ]

# Create log directory for Caddy
RUN mkdir -p /var/log/caddy

# Copy configuration files
COPY Caddyfile /etc/caddy/Caddyfile
COPY entrypoint.sh /entrypoint.sh
COPY cluster.sh /docker-entrypoint-initdb.d/cluster.sh
RUN chmod +x /entrypoint.sh

RUN rm /docker-entrypoint.sh

# Set environment variables with defaults
ENV METRICS_PORT=9104
ENV METRICS_USERNAME=admin
ENV METRICS_PASSWORD=
ENV METRICS_TLS_ENABLED=false

# Expose ports
EXPOSE 443 444 8080 3306 33060

# Switch back to original user
USER 1000

# Define volumes
VOLUME ["/var/lib/mysql", "/var/log/mysql"]

# Use entrypoint
ENTRYPOINT ["/entrypoint.sh"]
84 changes: 84 additions & 0 deletions cluster.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/bin/bash
set -eo pipefail

# Check if we need clustering
if [[ -z "${REPL_USER}" ]] || [[ -z "${REPL_PASSWORD}" ]] || [[ ( "${IS_SLAVE}" = "1" && -z "${MASTER_HOST}" ) ]]; then
echo "Clustering not configured, using standalone setup"
# Write basic MySQL config without replication
cat > /etc/my.cnf.d/mysql.cnf << EOF
[mysqld]
# Performance settings
innodb_buffer_pool_size=${INNODB_BUFFER_POOL_SIZE:-1G}
innodb_flush_log_at_trx_commit=1
EOF
exit 0
fi

echo "Configuring replication..."

# Setup MySQL replication config
cat > /etc/my.cnf.d/replication.cnf << EOF
[mysqld]
# Required settings
server-id=${SERVER_ID:-1}
gtid_mode=ON
enforce_gtid_consistency=ON
log_bin=/var/log/mysql/mysql-bin.log
log_slave_updates=1
binlog_format=ROW
# Crash-safe replication
sync_binlog=1
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log=/var/log/mysql/mysql-relay-bin
innodb_flush_log_at_trx_commit=1
# Performance settings
innodb_buffer_pool_size=${INNODB_BUFFER_POOL_SIZE:-1G}
EOF

# If this is a slave, wait for master and configure replication
if [ "${IS_SLAVE}" = "1" ] && [ -n "${MASTER_HOST}" ]; then
echo "Configuring as slave, waiting for master ${MASTER_HOST}..."

# Wait for master to be available
until mysqladmin ping -h"${MASTER_HOST}" -u"root" -p"${MYSQL_ROOT_PASSWORD}" --silent; do
echo "Waiting for master..."
sleep 5
done

# Configure replication
mysql -u root -p"${MYSQL_ROOT_PASSWORD}" << EOF
CHANGE MASTER TO
MASTER_HOST='${MASTER_HOST}',
MASTER_USER='${REPL_USER}',
MASTER_PASSWORD='${REPL_PASSWORD}',
MASTER_AUTO_POSITION=1;
START SLAVE;
EOF
echo "Slave configuration complete"
fi

# For master, create replication user if it doesn't exist
if [ "${IS_SLAVE}" != "1" ]; then
echo "Configuring as master..."
mysql -u root -p"${MYSQL_ROOT_PASSWORD}" << EOF
CREATE USER IF NOT EXISTS '${REPL_USER}'@'%' IDENTIFIED BY '${REPL_PASSWORD}';
GRANT REPLICATION SLAVE ON *.* TO '${REPL_USER}'@'%';
FLUSH PRIVILEGES;
EOF
echo "Master configuration complete"
fi

# Environment variables:
# Required for clustering:
# - REPL_USER
# - REPL_PASSWORD
# - SERVER_ID
# - IS_SLAVE (1 for slave, anything else for master)
# - MASTER_HOST (required for slave)
# Required for all:
# - MYSQL_ROOT_PASSWORD
# Optional:
# - INNODB_BUFFER_POOL_SIZE
23 changes: 23 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh
set -e

# Load environment variables
export METRICS_USERNAME=${METRICS_USERNAME:-admin}
export METRICS_PASSWORD=${METRICS_PASSWORD}
export METRICS_PORT=${METRICS_PORT:-9104}
export METRICS_TLS_ENABLED=${METRICS_TLS_ENABLED:-false}
export DOMAIN_NAME=${DOMAIN_NAME:-renterd.example.com}

if [ -z "$METRICS_PASSWORD" ]; then
METRICS_PASSWORD=$(openssl rand -base64 12)
echo "Generated metrics password: $METRICS_PASSWORD"
fi

# Start metrics exporter in background
/app/metrics-exporter &

# Start Caddy with authentication and SSL
caddy run --config /etc/caddy/Caddyfile &

# Start MySQL
/ps-entrypoint.sh mysqld
89 changes: 89 additions & 0 deletions ps-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/bin/bash
set -eo pipefail
shopt -s nullglob

# Helpers for config file handling
file_env() {
local var="$1"
local fileVar="${var}_FILE"
local def="${2:-}"
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
exit 1
fi
local val="$def"
if [ "${!var:-}" ]; then
val="${!var}"
elif [ "${!fileVar:-}" ]; then
val="$(< "${!fileVar}")"
fi
export "$var"="$val"
unset "$fileVar"
}

if [ "$1" = 'mysqld' ]; then
# We need to initialize the DB if it's empty
DATADIR="/var/lib/mysql"

if [ ! -d "$DATADIR/mysql" ]; then
file_env 'MYSQL_ROOT_PASSWORD'
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" ]; then
echo >&2 'error: database is uninitialized and password option is not specified'
exit 1
fi

mkdir -p "$DATADIR"

echo 'Initializing database'
mysqld --initialize-insecure --datadir="$DATADIR"
echo 'Database initialized'

# Start MySQL temporarily to do initial setup
mysqld --skip-networking --datadir="$DATADIR" &
pid="$!"

mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="/var/run/mysqld/mysqld.sock" --password="" )

# Wait for MySQL to be ready
for i in {120..0}; do
if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then
break
fi
sleep 1
done
if [ "$i" = 0 ]; then
echo >&2 'MySQL init process failed.'
exit 1
fi

# Set root password and permissions
"${mysql[@]}" <<-EOSQL
SET @@SESSION.SQL_LOG_BIN=0;
DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'mysql.infoschema', 'mysql.session', 'root') OR host NOT IN ('localhost') ;
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
FLUSH PRIVILEGES ;
EOSQL

# Run any initialization scripts
for f in /docker-entrypoint-initdb.d/*; do
case "$f" in
*.sh) echo "$0: running $f"; . "$f" ;;
*.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
*) echo "$0: ignoring $f" ;;
esac
done

if ! kill -s TERM "$pid" || ! wait "$pid"; then
echo >&2 'MySQL init process failed.'
exit 1
fi
fi

# Hand over to mysqld
mysql-manager &
exec mysqld
else
exec "$@"
fi

0 comments on commit 4fa8e04

Please sign in to comment.