Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 125 additions & 6 deletions .github/workflows/cache-base-image.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
name: Update base OS image
run-name: Updating the base OS and install necessary extra packages
run-name: Updating the base OS and install necessary extra packages (multiplatform)

# This workflow builds the pgEdge base test image with full reproducibility metadata:
# - Captures build timestamp, git commit SHA, branch, and Rocky Linux version
# - Embeds build information in /etc/pgedge/build-info.txt within the image
# - Tags images with both :latest and :${GIT_COMMIT} for version tracking
# - Adds OCI labels for standard metadata inspection
# - Prints all build metadata to workflow output for issue reproduction

on:
workflow_dispatch:
inputs:
image_name:
description: 'Base image name (without registry/owner prefix)'
required: false
default: 'base-test-image'
type: string
image_tag:
description: 'Additional custom tag (besides :latest and :<commit-sha>)'
required: false
default: ''
type: string

permissions:
contents: read
Expand Down Expand Up @@ -32,9 +50,40 @@ jobs:
env:
OWNER: '${{ github.repository_owner }}'

- name: Set up Docker
# Capture build metadata for reproducibility
- name: Capture build metadata
id: meta
run: |
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> ${GITHUB_ENV}
echo "GIT_COMMIT=$(git rev-parse HEAD)" >> ${GITHUB_ENV}
echo "GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> ${GITHUB_ENV}
echo "ROCKYLINUX_VERSION=$(docker run --rm rockylinux:9 cat /etc/rocky-release)" >> ${GITHUB_ENV}
echo "IMAGE_NAME=${{ inputs.image_name || 'base-test-image' }}" >> ${GITHUB_ENV}

# Print build information
echo "========================================="
echo "pgEdge Base Image Build Information"
echo "========================================="
echo "Image Name: ${{ inputs.image_name || 'base-test-image' }}"
echo "Custom Tag: ${{ inputs.image_tag }}"
echo "Build Date: $(date -u +'%Y-%m-%dT%H:%M:%SZ')"
echo "Git Commit: $(git rev-parse HEAD)"
echo "Git Branch: $(git rev-parse --abbrev-ref HEAD)"
echo "Rocky Linux: $(docker run --rm rockylinux:9 cat /etc/rocky-release)"
echo "Platforms: linux/amd64, linux/arm64"
echo "========================================="

# Set up QEMU for multiplatform builds
- name: Set up QEMU
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3
with:
platforms: linux/amd64,linux/arm64

- name: Set up Docker Buildx
# Codacy wants us to use full commit SHA. This is for v3
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
with:
platforms: linux/amd64,linux/arm64

# Login to GHCR
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
Expand All @@ -43,15 +92,85 @@ jobs:
username: $OWNER_LC
password: ${{ secrets.GITHUB_TOKEN }}

# Prepare cached version of the base image
- name: Build and push base system image
# Prepare cached version of the base image with build metadata
- name: Build and push multiplatform base system image
uses: docker/build-push-action@c382f710d39a5bb4e430307530a720f50c2d3318
with:
context: .
file: tests/docker/Dockerfile-base.el9
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ env.OWNER_LC }}/base-test-image:latest
tags: |
ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:latest
ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:${{ env.GIT_COMMIT }}
${{ inputs.image_tag && format('ghcr.io/{0}/{1}:{2}', env.OWNER_LC, env.IMAGE_NAME, inputs.image_tag) || '' }}
build-args: |
BUILD_DATE=${{ env.BUILD_DATE }}
GIT_COMMIT=${{ env.GIT_COMMIT }}
GIT_BRANCH=${{ env.GIT_BRANCH }}
ROCKYLINUX_VERSION=${{ env.ROCKYLINUX_VERSION }}
cache-from: type=gha,scope=base
cache-to: type=gha,mode=max,scope=base
provenance: false
sbom: false

# Verify multiplatform manifest
- name: Inspect multiplatform manifest
run: |
docker buildx imagetools inspect ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:latest

# Verify and display build information from the image
- name: Display build information
run: |
echo ""
echo "========================================="
echo "Multiplatform Image Built Successfully!"
echo "========================================="
echo "Image Name: ${{ env.IMAGE_NAME }}"
echo "Platforms: linux/amd64, linux/arm64"
echo ""
echo "Image Tags:"
echo " - ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:latest"
echo " - ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:${{ env.GIT_COMMIT }}"
if [ -n "${{ inputs.image_tag }}" ]; then
echo " - ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:${{ inputs.image_tag }}"
fi
echo ""
echo "To pull this specific build:"
echo " docker pull ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:${{ env.GIT_COMMIT }}"
echo ""
echo "Docker will automatically select the correct architecture:"
echo " - linux/amd64 for Intel/AMD systems"
echo " - linux/arm64 for Apple Silicon Macs (M1/M2/M3/M4)"
echo ""
echo "To view build info from the image:"
echo " docker run --rm ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:latest cat /etc/pgedge/build-info.txt"
echo ""
echo "To inspect image labels:"
echo " docker inspect ghcr.io/${{ env.OWNER_LC }}/${{ env.IMAGE_NAME }}:latest | jq '.[0].Config.Labels'"
echo "========================================="

# And we have a base image. Check: https://github.com/pgedge/spock/pkgs/container/base-test-image
# ==============================================================================
# Build Complete!
# ==============================================================================
# The base image is available at:
# https://github.com/pgedge/spock/pkgs/container/<image-name>
#
# Workflow Inputs (configurable through Actions UI):
# - image_name: Base image name (default: 'base-test-image')
# - image_tag: Optional custom tag in addition to :latest and :<commit-sha>
#
# Each build includes comprehensive reproducibility metadata:
# 1. /etc/pgedge/build-info.txt - Embedded build information file
# 2. OCI image labels with build timestamp, commit SHA, and branch
# 3. Commit-specific tag (:<commit-sha>) for immutable references
# 4. Optional custom tag (:<custom-tag>) if provided
# 5. Workflow output with all build parameters
#
# To reproduce any build:
# 1. Check workflow output or image labels for git commit SHA
# 2. Checkout that commit: git checkout <sha>
# 3. Run the docker build command shown in /etc/pgedge/build-info.txt
#
# Documentation: tests/docker/Dockerfile-base.md
# ==============================================================================
1 change: 0 additions & 1 deletion .github/workflows/spockbench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
pull_request:
types: [opened, synchronize, reopened]


permissions:
contents: read

Expand Down
216 changes: 135 additions & 81 deletions tests/docker/Dockerfile-base.el9
Original file line number Diff line number Diff line change
@@ -1,94 +1,148 @@
# ##############################################################################
#
# Base test image for pgEdge Spock development and testing.
# syntax=docker/dockerfile:1

# ==============================================================================
# Base Test Image for pgEdge Products Development and Testing
# ==============================================================================
#
# This image includes:
# - Rocky Linux 9 base with development tools
# - PostgreSQL build dependencies (LLVM, ICU, SSL, etc.)
# - Testing tools (Perl Test::More, SSH)
# - pgedge user with sudo access
# Description:
# This image provides a Rocky Linux 9 base with all necessary dependencies
# for building and testing PostgreSQL extensions, specifically pgEdge Spock.
#
# Built and published to: ghcr.io/pgedge/base-test-image:latest
# Included Components:
# - Rocky Linux 9 base OS with development tools
# - PostgreSQL build dependencies (compilers, libraries, etc.)
# - Testing frameworks (Perl Test::More)
# - SSH server for testing connectivity
# - pgedge user with sudo privileges
#
# ##############################################################################
# Build Target: ghcr.io/pgedge/base-test-image:latest
# ==============================================================================

# Use the latest Rocky Linux 9 base image
FROM rockylinux:9

# Update system and install base development tools
RUN dnf -y update && \
# Define build arguments for customization and reproducibility
ARG PGEDGE_USER=pgedge
ARG BUILD_DATE
ARG GIT_COMMIT
ARG GIT_BRANCH
ARG ROCKYLINUX_VERSION

# Set metadata labels for reproducibility
LABEL org.opencontainers.image.title="pgEdge Dev Base Test Image" \
org.opencontainers.image.description="Base image for pgEdge development and testing" \
org.opencontainers.image.vendor="pgEdge" \
org.opencontainers.image.maintainer="andrei.lepikhov@pgedge.com" \
org.opencontainers.image.licenses="BSD" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${GIT_COMMIT}" \
org.opencontainers.image.source="https://github.com/pgedge/spock" \
com.pgedge.base-os.version="${ROCKYLINUX_VERSION}" \
com.pgedge.git.branch="${GIT_BRANCH}"

# ==============================================================================
# Build Information for Reproducibility
# ==============================================================================
RUN set -eux && \
mkdir -p /etc/pgedge && \
printf "pgEdge Base Test Image Build Information\n" > /etc/pgedge/build-info.txt && \
printf "=========================================\n\n" >> /etc/pgedge/build-info.txt && \
printf "Build Date: %s\n" "${BUILD_DATE:-unknown}" >> /etc/pgedge/build-info.txt && \
printf "Git Commit: %s\n" "${GIT_COMMIT:-unknown}" >> /etc/pgedge/build-info.txt && \
printf "Git Branch: %s\n" "${GIT_BRANCH:-unknown}" >> /etc/pgedge/build-info.txt && \
printf "Rocky Linux: %s\n" "${ROCKYLINUX_VERSION:-unknown}" >> /etc/pgedge/build-info.txt && \
printf "\nTo reproduce this exact build:\n" >> /etc/pgedge/build-info.txt && \
printf " git clone https://github.com/pgedge/spock.git\n" >> /etc/pgedge/build-info.txt && \
printf " git checkout %s\n" "${GIT_COMMIT:-unknown}" >> /etc/pgedge/build-info.txt && \
printf " docker build -f tests/docker/Dockerfile-base.el9 \\\\\n" >> /etc/pgedge/build-info.txt && \
printf " --build-arg BUILD_DATE=%s \\\\\n" "${BUILD_DATE:-unknown}" >> /etc/pgedge/build-info.txt && \
printf " --build-arg GIT_COMMIT=%s \\\\\n" "${GIT_COMMIT:-unknown}" >> /etc/pgedge/build-info.txt && \
printf " --build-arg GIT_BRANCH=%s .\n" "${GIT_BRANCH:-unknown}" >> /etc/pgedge/build-info.txt && \
printf "\n" >> /etc/pgedge/build-info.txt && \
cat /etc/pgedge/build-info.txt

# ==============================================================================
# System Update and Base Development Tools Installation
# ==============================================================================
RUN set -eux && \
dnf -y upgrade && \
dnf -y install sudo && \
dnf -y groupinstall "Development Tools"

# Create pgedge user with sudo privileges
RUN useradd -m pgedge -s /bin/bash && \
echo pgedge:asdf | chpasswd && \
echo "pgedge ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/pgedge && \
chmod 0440 /etc/sudoers.d/pgedge && \
chown -R pgedge:pgedge /home/pgedge
dnf -y groupinstall "Development Tools" && \
dnf clean all && \
rm -rf /var/cache/dnf/*

# Install PostgreSQL build dependencies and testing tools
# Note: List inlined to avoid requiring build context with external files
RUN dnf install --allowerasing --enablerepo=crb -y \
bison \
clang \
curl \
cyrus-sasl-gssapi \
dnsutils \
flex \
jansson-devel \
krb5-devel \
libicu-devel \
libpq \
libpq-devel \
libuuid \
libuuid-devel \
libxslt \
libxslt-devel \
llvm \
llvm-devel \
lz4 \
lz4-devel \
nc \
openldap \
openldap-devel \
openssh-clients \
openssh-server \
openssl-devel \
pam-devel \
perl \
perl-App-cpanminus \
perl-devel \
perl-IPC-Run \
pkgconfig \
procps \
python3 \
python3-devel \
sudo \
systemd-devel \
unzip \
uuid \
uuid-devel \
vim \
zlib \
zlib-devel && \
dnf clean all
# ==============================================================================
# User Creation and Configuration
# ==============================================================================
RUN set -eux && \
useradd -m -s /bin/bash ${PGEDGE_USER} && \
echo "${PGEDGE_USER}:asdf" | chpasswd && \
echo "${PGEDGE_USER} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/${PGEDGE_USER} && \
chmod 0440 /etc/sudoers.d/${PGEDGE_USER} && \
chown -R ${PGEDGE_USER}:${PGEDGE_USER} /home/${PGEDGE_USER}

# Install Perl testing dependencies
RUN cpanm Test::More
# ==============================================================================
# PostgreSQL Build Dependencies and Testing Tools
# ==============================================================================
# Install all required packages in a single RUN to minimize layers
RUN set -eux && \
dnf install --allowerasing --enablerepo=crb -y \
bind-utils \
bison \
clang \
curl \
cyrus-sasl-gssapi \
flex \
gcc \
git \
jansson-devel \
krb5-devel \
libicu-devel \
libpq \
libpq-devel \
libuuid-devel \
libxml2-devel \
libxslt-devel \
llvm \
llvm-devel \
lz4-devel \
make \
nc \
openldap-devel \
openssh-clients \
openssh-server \
openssl-devel \
pam-devel \
perl \
perl-devel \
perl-IPC-Run \
perl-Test-Simple \
pkgconfig \
procps \
python3 \
python3-devel \
readline-devel \
systemd-devel \
unzip \
uuid-devel \
zlib-devel \
libzstd-devel && \
dnf clean all && \
rm -rf /var/cache/dnf/* /tmp/* /var/tmp/*

# Setup SSH for pgedge user (not root!)
# This allows SSH-based testing as the pgedge user
USER pgedge
RUN mkdir -p ~/.ssh && \
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519 && \
cat ~/.ssh/*.pub >> ~/.ssh/authorized_keys && \
# ==============================================================================
# SSH Configuration for Testing
# ==============================================================================
# Switch to pgedge user for SSH setup (security best practice)
USER ${PGEDGE_USER}
RUN set -eux && \
mkdir -p ~/.ssh && \
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519 -C "${PGEDGE_USER}@localhost" && \
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys && \
chmod 700 ~/.ssh && \
chmod 600 ~/.ssh/authorized_keys

# Set default working directory
WORKDIR /home/pgedge
chmod 600 ~/.ssh/authorized_keys ~/.ssh/id_ed25519

# Metadata
LABEL maintainer="andrei.lepikhov@pgedge.com"
LABEL description="Base image for pgEdge Spock PostgreSQL extension development and testing"
# ==============================================================================
# Working Directory and Final Setup
# ==============================================================================
WORKDIR /home/${PGEDGE_USER}
Loading