From e544275f20a9b3f310ba834a90aa6a7ff089e04e Mon Sep 17 00:00:00 2001 From: Vladimir Cryptohog Rogojin Date: Thu, 20 Mar 2025 23:46:03 +0200 Subject: [PATCH 1/2] Add Docker implementation for Alpha node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit includes: - Multi-stage Dockerfile with proper RandomX dependency handling - Docker Compose configuration for easy deployment - Comprehensive test scripts for container validation - Documentation for Docker setup and usage - Deployment automation script - CLAUDE.md with build commands and coding guidelines 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CLAUDE.md | 31 +++++ docker/Dockerfile | 65 ++++++++++ docker/README.md | 201 ++++++++++++++++++++++++++++++ docker/alpha.conf.default | 21 ++++ docker/config/alpha.conf.example | 34 +++++ docker/deploy.sh | 148 ++++++++++++++++++++++ docker/docker-compose.yml | 18 +++ docker/entrypoint.sh | 38 ++++++ docker/tests/README.md | 156 +++++++++++++++++++++++ docker/tests/check_sync_status.sh | 54 ++++++++ docker/tests/start_and_monitor.sh | 55 ++++++++ docker/tests/test_container.sh | 48 +++++++ 12 files changed, 869 insertions(+) create mode 100644 CLAUDE.md create mode 100644 docker/Dockerfile create mode 100644 docker/README.md create mode 100644 docker/alpha.conf.default create mode 100644 docker/config/alpha.conf.example create mode 100755 docker/deploy.sh create mode 100644 docker/docker-compose.yml create mode 100644 docker/entrypoint.sh create mode 100644 docker/tests/README.md create mode 100755 docker/tests/check_sync_status.sh create mode 100755 docker/tests/start_and_monitor.sh create mode 100755 docker/tests/test_container.sh diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0ca4cf4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,31 @@ +# Alpha Project Guidelines + +## Build Commands +- Basic build: `./autogen.sh && ./configure && make` +- With GUI: `./autogen.sh && make -C depends && ./configure --prefix=$PWD/depends/x86_64-pc-linux-gnu --program-transform-name='s/bitcoin/alpha/g' && make && make install` +- Without GUI: `./autogen.sh && make -C depends NO_QT=1 && ./configure --without-gui --prefix=$PWD/depends/x86_64-pc-linux-gnu --program-transform-name='s/bitcoin/alpha/g' && make && make install` +- Debug build: `./configure --enable-debug && make` + +## Test Commands +- All unit tests: `make check` +- Single unit test: `src/test/test_bitcoin --run_test=getarg_tests/doubledash` +- All functional tests: `test/functional/test_runner.py` +- Single functional test: `test/functional/feature_rbf.py` +- Test coverage: `./configure --enable-lcov && make && make cov` + +## Lint Commands +- Run all lint checks: `ci/lint_run_all.sh` +- Run clang-tidy: `bear --config src/.bear-tidy-config -- make -j $(nproc) && cd ./src/ && run-clang-tidy -j $(nproc)` + +## Code Style +- C++: 4-space indentation, braces on new lines for functions/classes +- Variables: `snake_case`, class members with `m_` prefix, constants in `ALL_CAPS`, globals with `g_` prefix +- Class/methods: `UpperCamelCase` for classes, no `C` prefix +- Commit messages: 50 chars title + blank line + description +- PR titles: Prefix with component (consensus, doc, qt, wallet, etc.) +- Python: Follow PEP-8, use f-strings, include docstrings +- Include guards: `BITCOIN_FOO_BAR_H` format +- Imports: No `using namespace` in global scope +- Error handling: Use `assert`/`Assert` for assumptions, `CHECK_NONFATAL` for recoverable errors +- Use init lists for member initialization: `int x{0};` instead of `int x = 0;` +- Always use full namespace specifiers for function calls \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..e69cace --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,65 @@ +FROM ubuntu:22.04 AS builder + +# Set environment variables +ENV DEBIAN_FRONTEND=noninteractive + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 \ + libssl-dev libevent-dev libboost-system-dev libboost-filesystem-dev \ + libboost-chrono-dev libboost-test-dev libboost-thread-dev \ + libminiupnpc-dev libzmq3-dev libdb-dev libdb++-dev git \ + cmake bison \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /alpha + +# Copy the source code +COPY . . + +# Build Dependencies and Alpha +RUN ./autogen.sh +RUN make -C depends NO_QT=1 -j$(nproc) +RUN ./configure --without-gui --prefix=$PWD/depends/x86_64-pc-linux-gnu --program-transform-name='s/bitcoin/alpha/g' +RUN make -j$(nproc) +RUN make install + +# Second stage: create minimal runtime image +FROM ubuntu:22.04 + +# Install runtime dependencies +RUN apt-get update && apt-get install -y \ + libboost-system1.74.0 libboost-filesystem1.74.0 libboost-thread1.74.0 \ + libboost-chrono1.74.0 libevent-2.1-7 libzmq5 libminiupnpc17 \ + && rm -rf /var/lib/apt/lists/* + +# Update library path +RUN ldconfig /usr/local/lib + +# Copy binaries from builder stage +COPY --from=builder /alpha/depends/x86_64-pc-linux-gnu/bin/alphad /usr/local/bin/ +COPY --from=builder /alpha/depends/x86_64-pc-linux-gnu/bin/alpha-cli /usr/local/bin/ + +# Copy required libraries +COPY --from=builder /alpha/depends/x86_64-pc-linux-gnu/lib/librandomx.* /usr/local/lib/ + +# Configure library paths +RUN echo "/usr/local/lib" > /etc/ld.so.conf.d/local.conf && ldconfig + +# Create directory for alpha config and data +RUN mkdir -p /etc/alpha /root/.alpha + +# Copy the default configuration file from the docker directory +COPY docker/alpha.conf.default /etc/alpha/alpha.conf.default +COPY docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +# Expose ports - P2P and RPC +EXPOSE 7933 8589 + +# This directory was already created above + +# Set entrypoint +ENTRYPOINT ["/entrypoint.sh"] +CMD ["alphad"] \ No newline at end of file diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..3a5e571 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,201 @@ +# Alpha Node Docker Implementation + +This document explains how to build and run the Alpha node in a Docker container. + +## Overview + +The Docker implementation provides: +- A multi-stage build process that minimizes container size +- Proper handling of RandomX dependency +- Volume mounting for persistent blockchain data +- Configuration customization options +- Automated test scripts for validation + +## Quick Start + +To build and run the Alpha node container: + +```bash +# Build the Docker image +docker compose -f docker/docker-compose.yml build + +# Start the container +docker compose -f docker/docker-compose.yml up -d + +# Check the logs +docker compose -f docker/docker-compose.yml logs -f +``` + +## Directory Structure + +- `Dockerfile` - Multi-stage build definition +- `docker-compose.yml` - Service definition with volume configuration +- `entrypoint.sh` - Container startup script +- `alpha.conf.default` - Default node configuration +- `config/` - Directory for custom configuration (optional) +- `tests/` - Test scripts for verification and monitoring + +## Configuration + +The Alpha node supports flexible configuration using a layered approach: + +1. A default configuration (`/etc/alpha/alpha.conf.default`) is embedded in the Docker image +2. You can override it by providing your own config when running the container + +### Using a Custom Configuration File + +You have multiple options for using a custom configuration: + +#### Option 1: Bind Mount a Configuration File + +```bash +docker run -d --name alpha-node \ + -p 8589:8589 \ + -p 7933:7933 \ + -v alpha-data:/root/.alpha \ + -v $(pwd)/your-alpha.conf:/config/alpha.conf:ro \ + alpha-node +``` + +#### Option 2: Using Docker Compose with Custom Config + +1. Copy the example config in the `config` directory: + +```bash +cd docker +cp config/alpha.conf.example config/alpha.conf +``` + +2. Edit `config/alpha.conf` with your preferred settings + +3. Run using docker-compose: + +```bash +docker compose -f docker/docker-compose.yml up -d +``` + +The configuration will be automatically detected and used. + +## Persistent Storage + +The docker-compose configuration already includes persistent storage. The blockchain data is stored in a named volume `alpha-data` that persists when the container is destroyed and recreated. + +## Exposed Ports + +- **8589** - RPC port (for API access) +- **7933** - P2P port (for network communication) + +## Testing and Monitoring + +Several test scripts are provided in the `tests/` directory: + +- `test_container.sh` - Verifies the container is working properly +- `start_and_monitor.sh` - Automates starting and monitoring the node +- `check_sync_status.sh` - Checks blockchain synchronization status + +Example usage: +```bash +cd docker/tests +./start_and_monitor.sh +./test_container.sh +./check_sync_status.sh +``` + +## Running alpha-cli in the Container + +### Method 1: Execute Commands Directly + +```bash +docker exec -it alpha-node alpha-cli getblockcount +``` + +### Method 2: Interactive Shell + +```bash +docker exec -it alpha-node bash +``` + +Then from within the container: +```bash +alpha-cli getblockcount +``` + +### Method 3: Using Docker Compose + +```bash +docker compose -f docker/docker-compose.yml exec alpha alpha-cli getblockcount +``` + +## RPC Access from Outside the Container + +To access the RPC interface from outside, ensure: + +1. Your alpha.conf contains these settings: +``` +rpcallowip=0.0.0.0/0 +rpcbind=0.0.0.0 +rpcuser=your_username +rpcpassword=your_secure_password +``` + +2. The port is published as shown above (8589) + +3. Use RPC with appropriate credentials: +```bash +curl --user your_username:your_secure_password \ + --data-binary '{"jsonrpc":"1.0","method":"getblockcount","params":[]}' \ + -H 'content-type: text/plain;' http://localhost:8589/ +``` + +## Container Structure + +- `/root/.alpha`: Data directory (mount point for persistent data) +- `/config`: Mount point for custom configuration +- `/etc/alpha/alpha.conf.default`: Default configuration file +- `/entrypoint.sh`: Startup script that manages configuration priorities + +## Default Configuration + +The default configuration in `docker/alpha.conf.default` includes: + +``` +rpcuser=user +rpcpassword=password +chain=alpha +server=1 +rpcbind=0.0.0.0 +rpcport=8589 +txindex=1 +``` + +## Troubleshooting + +### Common Issues + +1. **RandomX Dependency Issues** + - The container includes proper linking for the RandomX library + - Verify library presence with: `docker exec alpha-node ls -la /usr/local/lib/librandomx*` + +2. **Binary Name Mismatches** + - The Dockerfile handles renaming between bitcoind/alphad appropriately + - Verify binary names with: `docker exec alpha-node which alphad alpha-cli` + +3. **Permission Problems** + - If you encounter permission issues with mounted volumes: + ```bash + sudo chown -R 1000:1000 ./config + ``` + +4. **Connection Issues** + - Ensure ports 8589 and 7933 are accessible on your host + - Check firewall settings if connecting remotely + +## Security Considerations + +- The example RPC settings allow connections from anywhere. In production, use specific IP addresses in `rpcallowip`. +- Always use strong passwords for RPC access +- Consider using a reverse proxy with TLS for public-facing nodes +- For production environments, consider additional security measures: + - Use a non-root user in the container + - Implement proper firewall rules + - Set strong RPC credentials \ No newline at end of file diff --git a/docker/alpha.conf.default b/docker/alpha.conf.default new file mode 100644 index 0000000..5a9bb6e --- /dev/null +++ b/docker/alpha.conf.default @@ -0,0 +1,21 @@ +# Default configuration file with daemon mode enabled and exposed RPC port 8589 with default user:password +rpcuser=user +rpcpassword=password +chain=alpha +daemon=0 +debug=0 +txindex=1 + +[alpha] +adddnsseed= + +[alphatestnet] +adddnsseed= + +randomxfastmode=1 + +server=1 +rpcbind=0.0.0.0 +rpcbind=::/0 +rpcport=8589 +txindex=1 diff --git a/docker/config/alpha.conf.example b/docker/config/alpha.conf.example new file mode 100644 index 0000000..a93f804 --- /dev/null +++ b/docker/config/alpha.conf.example @@ -0,0 +1,34 @@ +# Example custom Alpha configuration file +# Rename to alpha.conf to activate these settings + +# Network-related settings +listen=1 +bind=0.0.0.0 +port=7933 + +# RPC settings (for API access) +rpcbind=0.0.0.0 +rpcallowip=0.0.0.0/0 +rpcuser=alpha_user +rpcpassword=change_this_to_a_secure_password +rpcport=8589 + +# Reduce disk usage +#prune=550 +#txindex=0 + +# Performance tuning +dbcache=1000 +maxmempool=300 + +# Debug options +#debug=net +logtimestamps=1 +logips=1 + +# Logging +printtoconsole=1 + +# ZMQ notifications +#zmqpubhashtx=tcp://0.0.0.0:7934 +#zmqpubhashblock=tcp://0.0.0.0:7934 \ No newline at end of file diff --git a/docker/deploy.sh b/docker/deploy.sh new file mode 100755 index 0000000..3e7f3a1 --- /dev/null +++ b/docker/deploy.sh @@ -0,0 +1,148 @@ +#!/bin/bash + +# Alpha Node Docker Deployment Script +# This script automates the deployment of an Alpha node via Docker + +set -e + +# Configuration +COMPOSE_FILE="docker-compose.yml" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_DIR="${SCRIPT_DIR}/config" +EXAMPLE_CONFIG="${CONFIG_DIR}/alpha.conf.example" +CUSTOM_CONFIG="${CONFIG_DIR}/alpha.conf" +LOG_FILE="/tmp/alpha_deploy.log" + +# Header +echo "========================================" +echo " Alpha Node Docker Deployment Tool " +echo "========================================" +echo "" + +# Function to log messages +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}" +} + +# Create log file +touch "${LOG_FILE}" +log "Starting Alpha node deployment" + +# Check Docker installation +if ! command -v docker &> /dev/null; then + log "❌ Error: Docker is not installed" + echo "Please install Docker first: https://docs.docker.com/get-docker/" + exit 1 +fi + +if ! command -v docker compose &> /dev/null; then + log "❌ Error: Docker Compose is not installed" + echo "Please install Docker Compose first: https://docs.docker.com/compose/install/" + exit 1 +fi + +log "✅ Docker and Docker Compose are installed" + +# Check if we're in the right directory +if [ ! -f "${SCRIPT_DIR}/${COMPOSE_FILE}" ]; then + log "❌ Error: ${COMPOSE_FILE} not found in ${SCRIPT_DIR}" + exit 1 +fi + +# Check if custom config exists or offer to create it +if [ ! -f "${CUSTOM_CONFIG}" ]; then + echo "No custom configuration found at ${CUSTOM_CONFIG}" + echo "Would you like to:" + echo "1) Use default configuration" + echo "2) Create custom configuration from example" + read -p "Enter choice (1-2): " config_choice + + if [ "$config_choice" == "2" ]; then + if [ -f "${EXAMPLE_CONFIG}" ]; then + cp "${EXAMPLE_CONFIG}" "${CUSTOM_CONFIG}" + log "Created custom configuration from example" + echo "Please edit ${CUSTOM_CONFIG} with your preferred settings" + read -p "Press Enter when ready to continue..." + else + log "❌ Error: Example configuration not found at ${EXAMPLE_CONFIG}" + exit 1 + fi + else + log "Using default configuration" + fi +fi + +# Check if container is already running +if docker ps --format '{{.Names}}' | grep -q "alpha-node"; then + echo "Alpha node is already running." + echo "Would you like to:" + echo "1) Stop and recreate it" + echo "2) Leave it running and exit" + read -p "Enter choice (1-2): " container_choice + + if [ "$container_choice" == "1" ]; then + log "Stopping existing Alpha node container" + docker compose -f "${SCRIPT_DIR}/${COMPOSE_FILE}" down + else + log "Leaving existing container running" + echo "Exiting deployment script" + exit 0 + fi +fi + +# Build and start the container +log "Building Alpha node container" +echo "This may take a while..." +docker compose -f "${SCRIPT_DIR}/${COMPOSE_FILE}" build + +log "Starting Alpha node container" +docker compose -f "${SCRIPT_DIR}/${COMPOSE_FILE}" up -d + +# Verify container is running +if ! docker ps --format '{{.Names}}' | grep -q "alpha-node"; then + log "❌ Error: Failed to start Alpha node container" + echo "Please check logs with: docker compose -f ${SCRIPT_DIR}/${COMPOSE_FILE} logs" + exit 1 +fi + +log "✅ Alpha node container started successfully" + +# Wait for node to respond +echo "Waiting for Alpha node to initialize..." +attempts=0 +max_attempts=30 +success=false + +while [ $attempts -lt $max_attempts ]; do + if docker exec alpha-node alpha-cli getblockcount &>/dev/null; then + success=true + block_count=$(docker exec alpha-node alpha-cli getblockcount) + log "✅ Alpha node is responsive at block height: ${block_count}" + break + fi + + attempts=$((attempts + 1)) + echo -n "." + sleep 5 +done + +echo "" + +if [ "$success" != "true" ]; then + log "⚠️ Alpha node did not respond within expected timeframe" + echo "The node may still be initializing. Check status with:" + echo "docker exec alpha-node alpha-cli getblockcount" +else + echo "Container information:" + docker ps --format "ID: {{.ID}}\nName: {{.Names}}\nStatus: {{.Status}}\nPorts: {{.Ports}}" | grep -A3 "alpha-node" + + echo "" + echo "Node is running! Use the following commands to interact with it:" + echo " View logs: docker compose -f ${SCRIPT_DIR}/${COMPOSE_FILE} logs -f" + echo " Stop node: docker compose -f ${SCRIPT_DIR}/${COMPOSE_FILE} down" + echo " Run CLI: docker exec -it alpha-node alpha-cli getinfo" + echo "" + echo "Run tests: cd ${SCRIPT_DIR}/tests && ./test_container.sh" +fi + +log "Deployment script completed" \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..426c2c1 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,18 @@ +services: + alpha: + build: + context: .. + dockerfile: docker/Dockerfile + container_name: alpha-node + volumes: + - alpha-data:/root/.alpha + # Mount custom configuration if available + - ./config:/config:ro + ports: + - "8589:8589" # RPC port + - "7933:7933" # P2P port + restart: unless-stopped + +volumes: + alpha-data: + # This volume persists blockchain data between container restarts \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..1a1cacc --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + +# Function to handle configuration +setup_config() { + # Default location for config + CONFIG_DIR="/root/.alpha" + mkdir -p $CONFIG_DIR + + # Check for mounted config file + if [ -f "/config/alpha.conf" ]; then + echo "Using mounted configuration from /config/alpha.conf" + cp /config/alpha.conf $CONFIG_DIR/alpha.conf + # Check for local config file + elif [ -f "/etc/alpha/alpha.conf" ]; then + echo "Using local configuration from /etc/alpha/alpha.conf" + cp /etc/alpha/alpha.conf $CONFIG_DIR/alpha.conf + # Use default config file + else + echo "Using default configuration file" + cp /etc/alpha/alpha.conf.default $CONFIG_DIR/alpha.conf + fi +} + +# Handle configuration +setup_config + +# First argument is alphad or alpha-cli +if [ "$1" = "alphad" ]; then + echo "Starting Alpha daemon..." + exec alphad -conf=/root/.alpha/alpha.conf "${@:2}" +elif [ "$1" = "alpha-cli" ]; then + echo "Running Alpha CLI command..." + exec alpha-cli -conf=/root/.alpha/alpha.conf "${@:2}" +else + # Assume any other command is to be executed directly + exec "$@" +fi \ No newline at end of file diff --git a/docker/tests/README.md b/docker/tests/README.md new file mode 100644 index 0000000..2433b91 --- /dev/null +++ b/docker/tests/README.md @@ -0,0 +1,156 @@ +# Alpha Node Docker Test Scripts + +This directory contains utility scripts for testing and monitoring the Alpha node Docker container. These scripts help verify the correct operation of the container and monitor its performance. + +## Available Scripts + +### 1. `test_container.sh` + +A comprehensive test suite that verifies the Alpha node container is working correctly. It checks: +- If the container is running +- If required ports are open +- If the alpha-cli tool is functioning properly +- If the node can respond to basic queries + +**Usage:** +```bash +./test_container.sh +``` + +**Output:** +``` +Starting Alpha node container test... +✅ Container alpha-node is running +✅ Ports 8589 (RPC) and 7933 (P2P) are open +✅ alpha-cli is working properly +✅ Node info can be retrieved +✅ All tests passed successfully! +``` + +### 2. `start_and_monitor.sh` + +Automates the startup process and monitors the Alpha node until it's fully initialized. This script: +- Stops any existing Alpha node container +- Starts a fresh container using Docker Compose +- Waits for the node to initialize +- Reports on block height and node information +- Creates a log file at `/tmp/alpha_node_monitor.log` + +**Usage:** +```bash +./start_and_monitor.sh +``` + +**Output:** +``` +Starting Alpha node with Docker Compose... +Waiting for node to start (max 120 seconds)... +Waiting for node to be ready... (10s elapsed) +Waiting for node to be ready... (20s elapsed) +Node is running! Current block height: 197000 + +===== Alpha Node Information ===== +{ + "version": 260100, + "blocks": 197000, + "connections": 8, + "difficulty": 123456.78, + ... +} +================================== + +Node is running and ready to use! +To run tests: ./test_container.sh +To stop node: docker compose -f /home/vrogojin/Projects/alpha/docker/docker-compose.yml down +To view logs: docker compose -f /home/vrogojin/Projects/alpha/docker/docker-compose.yml logs -f +``` + +### 3. `check_sync_status.sh` + +Checks the blockchain synchronization status of a running Alpha node container. This script: +- Retrieves and displays current block height +- Shows synchronization progress as percentage +- Reports on connection count +- Shows mempool transaction count +- Displays container uptime + +**Usage:** +```bash +./check_sync_status.sh +``` + +**Output:** +``` +Checking Alpha node synchronization status... +Current Status: +Block Height: 197000 +Headers: 197000 +Sync Progress: 100.00% +✅ Node is fully synchronized with the network +Connections: 8 +Mempool Transactions: 12 +Container Uptime: 2d 5h 37m +``` + +## Integration with CI/CD + +These scripts can be integrated into CI/CD pipelines for automated testing: + +```yaml +# Example GitLab CI configuration +test_alpha_node: + stage: test + script: + - cd docker/tests + - ./start_and_monitor.sh + - ./test_container.sh + - ./check_sync_status.sh + artifacts: + paths: + - /tmp/alpha_node_monitor.log +``` + +## Customizing the Scripts + +You can customize these scripts by modifying the following variables: + +### In `test_container.sh`: +- `CONTAINER_NAME`: The name of the Alpha node container +- `RPC_PORT`: The port used for RPC connections +- `P2P_PORT`: The port used for P2P connections + +### In `start_and_monitor.sh`: +- `COMPOSE_FILE`: Path to the docker-compose.yml file +- `LOG_FILE`: Path where logs will be stored +- `MAX_STARTUP_TIME`: Maximum time to wait for the node to start +- `CHECK_INTERVAL`: Time between status checks + +### In `check_sync_status.sh`: +- `CONTAINER_NAME`: The name of the Alpha node container + +## Troubleshooting + +If the scripts fail, check the following: + +1. Make sure the container is running: + ```bash + docker ps | grep alpha-node + ``` + +2. Check container logs for errors: + ```bash + docker logs alpha-node + ``` + +3. Ensure docker-compose.yml path is correct in `start_and_monitor.sh` + +4. Verify the Docker daemon is running: + ```bash + systemctl status docker + ``` + +5. Ensure your user has permission to run Docker commands: + ```bash + sudo usermod -aG docker $USER + ``` + (Log out and log back in after running this command) \ No newline at end of file diff --git a/docker/tests/check_sync_status.sh b/docker/tests/check_sync_status.sh new file mode 100755 index 0000000..ed2b042 --- /dev/null +++ b/docker/tests/check_sync_status.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Check if the Alpha node is in sync with the network +# Usage: ./check_sync_status.sh + +CONTAINER_NAME="alpha-node" + +echo "Checking Alpha node synchronization status..." + +# Get current blockchain info +if ! blockchain_info=$(docker exec ${CONTAINER_NAME} alpha-cli getblockchaininfo 2>/dev/null); then + echo "❌ Error: Cannot retrieve blockchain info" + exit 1 +fi + +# Extract relevant information +current_height=$(echo "${blockchain_info}" | grep "\"blocks\"" | awk '{print $2}' | sed 's/,//') +headers=$(echo "${blockchain_info}" | grep "\"headers\"" | awk '{print $2}' | sed 's/,//') +verification_progress=$(echo "${blockchain_info}" | grep "\"verificationprogress\"" | awk '{print $2}' | sed 's/,//') + +# Convert verification progress to percentage +sync_percent=$(echo "${verification_progress} * 100" | bc -l | xargs printf "%.2f") + +echo "Current Status:" +echo "Block Height: ${current_height}" +echo "Headers: ${headers}" +echo "Sync Progress: ${sync_percent}%" + +# Check if node is synced +if [[ $(echo "${verification_progress} > 0.9999" | bc -l) -eq 1 && ${current_height} -eq ${headers} ]]; then + echo "✅ Node is fully synchronized with the network" +else + remaining_blocks=$((headers - current_height)) + echo "⏳ Node is still synchronizing (${remaining_blocks} blocks remaining)" +fi + +# Get network information +connection_count=$(docker exec ${CONTAINER_NAME} alpha-cli getconnectioncount 2>/dev/null || echo "unknown") +echo "Connections: ${connection_count}" + +# Get memory pool information +mempool_info=$(docker exec ${CONTAINER_NAME} alpha-cli getmempoolinfo 2>/dev/null) +tx_count=$(echo "${mempool_info}" | grep "\"size\"" | awk '{print $2}' | sed 's/,//') +echo "Mempool Transactions: ${tx_count}" + +# Simple uptime check +uptime=$(docker inspect --format='{{.State.StartedAt}}' ${CONTAINER_NAME} | xargs date +%s -d) +now=$(date +%s) +uptime_seconds=$((now - uptime)) +uptime_days=$((uptime_seconds / 86400)) +uptime_hours=$(( (uptime_seconds % 86400) / 3600 )) +uptime_minutes=$(( (uptime_seconds % 3600) / 60 )) + +echo "Container Uptime: ${uptime_days}d ${uptime_hours}h ${uptime_minutes}m" \ No newline at end of file diff --git a/docker/tests/start_and_monitor.sh b/docker/tests/start_and_monitor.sh new file mode 100755 index 0000000..00393a9 --- /dev/null +++ b/docker/tests/start_and_monitor.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +set -e + +# Configuration +COMPOSE_FILE="/home/vrogojin/Projects/alpha/docker/docker-compose.yml" +LOG_FILE="/tmp/alpha_node_monitor.log" +MAX_STARTUP_TIME=120 # Maximum time to wait for node to start (seconds) +CHECK_INTERVAL=10 # Time between status checks (seconds) + +echo "Starting Alpha node with Docker Compose..." +echo "$(date): Starting container" >> ${LOG_FILE} + +# Make sure any previous instance is stopped +docker compose -f ${COMPOSE_FILE} down 2>/dev/null || true + +# Start the container +docker compose -f ${COMPOSE_FILE} up -d + +echo "Waiting for node to start (max ${MAX_STARTUP_TIME} seconds)..." + +# Wait for the node to fully start +start_time=$(date +%s) +while true; do + current_time=$(date +%s) + elapsed=$((current_time - start_time)) + + if [ ${elapsed} -gt ${MAX_STARTUP_TIME} ]; then + echo "Error: Startup timed out after ${MAX_STARTUP_TIME} seconds" + echo "$(date): Startup timed out after ${MAX_STARTUP_TIME} seconds" >> ${LOG_FILE} + docker compose -f ${COMPOSE_FILE} logs + exit 1 + fi + + # Check if container is running and service is ready + if docker exec alpha-node alpha-cli getblockcount &>/dev/null; then + block_count=$(docker exec alpha-node alpha-cli getblockcount) + echo "Node is running! Current block height: ${block_count}" + echo "$(date): Node started successfully. Block height: ${block_count}" >> ${LOG_FILE} + break + fi + + echo "Waiting for node to be ready... (${elapsed}s elapsed)" + sleep ${CHECK_INTERVAL} +done + +# Display node information +echo "===== Alpha Node Information =====" +docker exec alpha-node alpha-cli getinfo | grep -v "\"privatekeys\|\"walletname\|\"hdmasterkeyid\|\"keypoololdest\|\"paytxfee\|\"relayfee" +echo "==================================" + +echo "Node is running and ready to use!" +echo "To run tests: ./test_container.sh" +echo "To stop node: docker compose -f ${COMPOSE_FILE} down" +echo "To view logs: docker compose -f ${COMPOSE_FILE} logs -f" \ No newline at end of file diff --git a/docker/tests/test_container.sh b/docker/tests/test_container.sh new file mode 100755 index 0000000..02ce8bc --- /dev/null +++ b/docker/tests/test_container.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +set -e + +CONTAINER_NAME="alpha-node" +RPC_PORT=8589 +P2P_PORT=7933 + +echo "Starting Alpha node container test..." + +# Check if container exists and is running +if ! docker ps -f "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "${CONTAINER_NAME}"; then + echo "❌ Error: Container ${CONTAINER_NAME} is not running" + exit 1 +fi + +echo "✅ Container ${CONTAINER_NAME} is running" + +# Check if ports are open +if ! docker exec ${CONTAINER_NAME} netstat -tuln | grep -q "${RPC_PORT}"; then + echo "❌ Error: RPC port ${RPC_PORT} is not listening" + exit 1 +fi + +if ! docker exec ${CONTAINER_NAME} netstat -tuln | grep -q "${P2P_PORT}"; then + echo "❌ Error: P2P port ${P2P_PORT} is not listening" + exit 1 +fi + +echo "✅ Ports ${RPC_PORT} (RPC) and ${P2P_PORT} (P2P) are open" + +# Check if alpha-cli is working +if ! docker exec ${CONTAINER_NAME} alpha-cli -version &> /dev/null; then + echo "❌ Error: alpha-cli command not working" + exit 1 +fi + +echo "✅ alpha-cli is working properly" + +# Check if the node can get info +if ! docker exec ${CONTAINER_NAME} alpha-cli getinfo &> /dev/null; then + echo "❌ Error: Cannot get node information" + exit 1 +fi + +echo "✅ Node info can be retrieved" + +echo "✅ All tests passed successfully!" From 47abd3a81c705e6d772073fc3c010f100e686009 Mon Sep 17 00:00:00 2001 From: Vladimir Cryptohog Rogojin Date: Thu, 20 Mar 2025 23:51:05 +0200 Subject: [PATCH 2/2] Add GitHub Actions workflow for Docker image publishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds: - GitHub Actions workflow for automated Docker image builds on release - Manual publishing script for Docker images - Documentation for the CI/CD process - Updates to README with instructions for using pre-built images 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/README.md | 63 ++++++++++++++++++ .github/workflows/docker-publish.yml | 71 ++++++++++++++++++++ docker/README.md | 49 +++++++++++++- docker/publish-image.sh | 98 ++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/README.md create mode 100644 .github/workflows/docker-publish.yml create mode 100755 docker/publish-image.sh diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..9b49432 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,63 @@ +# GitHub Actions Workflows for Alpha + +This directory contains GitHub Actions workflows for automating tasks in the Alpha project. + +## Docker Image Publishing + +The `docker-publish.yml` workflow automatically builds and publishes Docker images to GitHub Container Registry (ghcr.io) when: + +1. A new GitHub Release is published +2. The workflow is manually triggered + +### How It Works + +When a new release is created: + +1. GitHub Actions checks out the code +2. Sets up Docker Buildx for multi-platform builds +3. Logs in to GitHub Container Registry using the built-in GITHUB_TOKEN +4. Builds the Docker image using the Dockerfile in the docker/ directory +5. Tags the image with both the release version and 'latest' +6. Pushes the image to ghcr.io/{owner}/alpha +7. Updates the container description with the contents of docker/README.md + +### Manual Triggering + +You can manually trigger a build by: + +1. Going to the "Actions" tab in GitHub +2. Selecting "Build and Publish Docker Image" workflow +3. Clicking "Run workflow" +4. Optionally specifying a tag (leave empty for 'latest') + +### Image Access + +The published images will be available at: + +``` +ghcr.io/{owner}/alpha:latest +ghcr.io/{owner}/alpha:{tag} +``` + +Where `{owner}` is your GitHub username or organization name, and `{tag}` is the release version. + +### Local Building and Publishing + +You can also build and push the Docker image locally using the provided script: + +```bash +./docker/publish-image.sh [tag] +``` + +This script will: + +1. Build the Docker image locally +2. Tag it with both the specified tag and 'latest' +3. Push it to GitHub Container Registry (if you're logged in) + +### Required Permissions + +For the workflow to function properly: + +1. The repository must have "Read and write permissions" for "Workflow permissions" in Settings → Actions → General +2. If using organization packages, the repository must have package write access configured in the organization settings \ No newline at end of file diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..57558fc --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,71 @@ +name: Build and Publish Docker Image + +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: 'Tag to build (leave empty for latest)' + required: false + default: '' + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set tag variables + id: vars + run: | + if [[ "${{ github.event_name }}" == "release" ]]; then + VERSION=${{ github.event.release.tag_name }} + elif [[ -n "${{ github.event.inputs.tag }}" ]]; then + VERSION=${{ github.event.inputs.tag }} + else + VERSION=latest + fi + echo "VERSION=${VERSION}" >> $GITHUB_ENV + REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') + echo "IMAGE_NAME=ghcr.io/${REPO_LOWER}/alpha" >> $GITHUB_ENV + + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + file: ./docker/Dockerfile + push: true + tags: | + ${{ env.IMAGE_NAME }}:${{ env.VERSION }} + ${{ env.IMAGE_NAME }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Update Docker Hub description + uses: peter-evans/dockerhub-description@v3 + if: github.event_name == 'release' + with: + registry: ghcr.io + repository: ${{ github.repository_owner }}/alpha + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + short-description: "Alpha cryptocurrency node" + readme-filepath: ./docker/README.md \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index 3a5e571..e6e7bed 100644 --- a/docker/README.md +++ b/docker/README.md @@ -13,6 +13,21 @@ The Docker implementation provides: ## Quick Start +### Option 1: Using pre-built image from GitHub Container Registry + +```bash +# Pull the image (replace {owner} with the GitHub username or organization) +docker pull ghcr.io/{owner}/alpha:latest + +# Run the container +docker run -d --name alpha-node \ + -p 8589:8589 -p 7933:7933 \ + -v alpha-data:/root/.alpha \ + ghcr.io/{owner}/alpha:latest +``` + +### Option 2: Building locally + To build and run the Alpha node container: ```bash @@ -26,6 +41,13 @@ docker compose -f docker/docker-compose.yml up -d docker compose -f docker/docker-compose.yml logs -f ``` +### Option 3: Using the deployment script + +```bash +# Run the deployment script +./docker/deploy.sh +``` + ## Directory Structure - `Dockerfile` - Multi-stage build definition @@ -198,4 +220,29 @@ txindex=1 - For production environments, consider additional security measures: - Use a non-root user in the container - Implement proper firewall rules - - Set strong RPC credentials \ No newline at end of file + - Set strong RPC credentials + +## Automated Builds + +This project uses GitHub Actions to automatically build and publish Docker images to GitHub Container Registry (ghcr.io) when new releases are created. + +### How to Use Published Images + +Once a release is created, the Docker image will be available at: + +``` +ghcr.io/{owner}/alpha:latest +ghcr.io/{owner}/alpha:{tag} +``` + +Where `{owner}` is the GitHub username or organization name, and `{tag}` is the release version. + +### Manual Image Publishing + +You can manually build and publish the Docker image using: + +```bash +./docker/publish-image.sh [tag] +``` + +For more information about the CI/CD process, see the `.github/workflows/README.md` file. \ No newline at end of file diff --git a/docker/publish-image.sh b/docker/publish-image.sh new file mode 100755 index 0000000..0789d9c --- /dev/null +++ b/docker/publish-image.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +# Script to manually build and push the Alpha node Docker image to GitHub Container Registry +# Usage: ./publish-image.sh [tag] + +set -e + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +IMAGE_NAME="alpha" +TAG="${1:-latest}" + +# Detect GitHub repository if in a Git repo +if git -C "${PROJECT_ROOT}" remote -v &>/dev/null; then + GITHUB_REPO=$(git -C "${PROJECT_ROOT}" remote get-url origin | sed -n 's/.*github.com[:/]\([^/]*\/[^.]*\)\(\.git\)\?$/\1/p' | tr '[:upper:]' '[:lower:]') + if [ -n "${GITHUB_REPO}" ]; then + FULL_IMAGE_NAME="ghcr.io/${GITHUB_REPO}/${IMAGE_NAME}" + else + echo "Cannot detect GitHub repository from Git remote URL." + echo "Using local image name: ${IMAGE_NAME}" + FULL_IMAGE_NAME="${IMAGE_NAME}" + fi +else + echo "Not a Git repository or no remotes configured." + echo "Using local image name: ${IMAGE_NAME}" + FULL_IMAGE_NAME="${IMAGE_NAME}" +fi + +echo "========================================" +echo " Alpha Node Docker Image Publisher " +echo "========================================" +echo "" +echo "Building and publishing Docker image for Alpha node" +echo "Image: ${FULL_IMAGE_NAME}:${TAG}" +echo "" + +# Check Docker installation +if ! command -v docker &>/dev/null; then + echo "❌ Error: Docker is not installed" + echo "Please install Docker first: https://docs.docker.com/get-docker/" + exit 1 +fi + +# Check if user is logged in to GitHub Container Registry +if [[ "${FULL_IMAGE_NAME}" == ghcr.io/* ]]; then + if ! docker info | grep -q "ghcr.io"; then + echo "⚠️ You don't appear to be logged in to GitHub Container Registry" + echo "To login, run:" + echo " echo \${GITHUB_PAT} | docker login ghcr.io -u USERNAME --password-stdin" + echo "" + read -p "Continue anyway? [y/N] " -n 1 -r + echo "" + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi + fi +fi + +# Build the Docker image +echo "Building Docker image..." +docker build -t "${FULL_IMAGE_NAME}:${TAG}" -f "${SCRIPT_DIR}/Dockerfile" "${PROJECT_ROOT}" + +# Tag as latest if not already +if [ "${TAG}" != "latest" ]; then + echo "Tagging as latest as well..." + docker tag "${FULL_IMAGE_NAME}:${TAG}" "${FULL_IMAGE_NAME}:latest" +fi + +# Ask for confirmation before pushing +if [[ "${FULL_IMAGE_NAME}" == ghcr.io/* ]]; then + echo "" + echo "Ready to push the following tags to GitHub Container Registry:" + echo " ${FULL_IMAGE_NAME}:${TAG}" + echo " ${FULL_IMAGE_NAME}:latest" + echo "" + read -p "Push these images? [y/N] " -n 1 -r + echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "Pushing images to GitHub Container Registry..." + docker push "${FULL_IMAGE_NAME}:${TAG}" + docker push "${FULL_IMAGE_NAME}:latest" + echo "✅ Images pushed successfully!" + else + echo "Push cancelled. Images are built locally only." + fi +else + echo "" + echo "Local image built successfully:" + echo " ${FULL_IMAGE_NAME}:${TAG}" +fi + +echo "" +echo "To run this image:" +echo " docker run -d --name alpha-node \\" +echo " -p 8589:8589 -p 7933:7933 \\" +echo " -v alpha-data:/root/.alpha \\" +echo " ${FULL_IMAGE_NAME}:${TAG}" \ No newline at end of file