Skip to content

Development Docker Build #583

Development Docker Build

Development Docker Build #583

name: Development Docker Build
on:
schedule:
- cron: '15 0 * * *'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
image: ghcr.io/dragonflydb/dragonfly-dev
GCS_IMAGE: us-central1-docker.pkg.dev/dragonflydb-public/dragonfly-registry/dragonfly-dev
jobs:
build_and_tag:
if: github.repository == 'dragonflydb/dragonfly'
name: Build and Push ${{matrix.flavor}} ${{ matrix.os.arch }} image
strategy:
matrix:
flavor: [alpine,ubuntu,distroless]
os:
- image: ubuntu-24.04
arch: amd64
- image: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.os.image }}
permissions:
contents: read
packages: write
id-token: write
steps:
- name: checkout
uses: actions/checkout@v6
with:
fetch-depth: 1
submodules: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to Registries
uses: ./.github/actions/multi-registry-docker-login
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v3
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: Configure AWS Credentials
if: github.repository_owner == 'dragonflydb' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ secrets.AWS_CI_S3_ROLE_ARN }}
aws-region: us-east-1
- name: Get Build Information
id: build_info
run: |
echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Docker meta
id: metadata
uses: docker/metadata-action@v6
with:
images: |
${{ env.image }}
${{ env.GCS_IMAGE }}
tags: |
type=sha,enable=true,prefix=${{ matrix.flavor}}-,suffix=-${{ matrix.os.arch }},format=short
labels: |
org.opencontainers.image.vendor=DragonflyDB LTD
org.opencontainers.image.title=Dragonfly Development Image
org.opencontainers.image.description=The fastest in-memory store
- name: Build image
id: build
uses: docker/build-push-action@v7
with:
context: .
push: true
provenance: false # Prevent pushing a docker manifest
tags: |
${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
file: tools/packaging/Dockerfile.${{ matrix.flavor }}-dev
cache-from: type=gha,scope=tagged${{ matrix.flavor }}
cache-to: type=gha,scope=tagged${{ matrix.flavor }},mode=max
load: true # Load the build images into the local docker.
- name: Test Image
run: |
echo ${{ steps.build.outputs.digest }}
image_tags=(${{ steps.metadata.outputs.tags }})
# install redis-tools
sudo apt-get update && sudo apt-get install redis-tools -y
for image_tag in "${image_tags[@]}"; do
echo "Testing image: ${image_tag}"
docker image inspect ${image_tag}
echo "Testing ${{ matrix.flavor }} image"
# docker run with port-forwarding
docker run -d -p 6379:6379 ${image_tag}
sleep 5
redis-cli -h localhost ping | grep -q "PONG" || exit 1
docker stop $(docker ps -q --filter ancestor=${image_tag})
done
- name: Extract and Upload Binaries
if: matrix.flavor == 'ubuntu' # Only run once per flavor
run: |
# Get the image tag
image_tags=(${{ steps.metadata.outputs.tags }})
image_tag=${image_tags[0]}
# Extract version from the image
echo "Extracting version from image..."
VERSION=$(docker run --rm ${image_tag} dragonfly --version | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g" | head -n1 | cut -d' ' -f2 | cut -d'-' -f1)
# Check if version starts with a release version (v*.*.*)
if [[ ! $VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then
# Get the latest release version to use as prefix
LATEST_RELEASE=$(curl -s https://api.github.com/repos/dragonflydb/dragonfly/releases/latest | jq -r .tag_name)
VERSION="${LATEST_RELEASE}+${VERSION}"
fi
echo "Dragonfly version: $VERSION"
echo "Extracting binary from ${image_tag} for ${{ matrix.os.arch }}"
# Create a temporary container and copy the binary
container_id=$(docker create ${image_tag})
docker cp ${container_id}:/usr/local/bin/dragonfly ./dragonfly
docker rm ${container_id}
# Create a tar archive
if [[ "${{ matrix.os.arch }}" == "arm64" ]]; then
arch_name="aarch64"
else
arch_name="x86_64"
fi
tar_name="dragonfly-${arch_name}-dbgsym.tar.gz"
tar czf ${tar_name} dragonfly
# Upload to GCS
echo "Uploading ${tar_name} to GCS"
gcloud storage cp "$tar_name" "gs://${{ secrets.STAGING_BINARY_BUCKET }}/dragonfly/$VERSION/$tar_name"
# Upload to AWS
echo "Uploading ${tar_name} to AWS"
aws s3 cp "$tar_name" "s3://${{ secrets.STAGING_BINARY_BUCKET }}/dragonfly/$VERSION/$tar_name"
# Cleanup
rm -f dragonfly ${tar_name}
outputs:
# matrix jobs outputs override each other, but we use the same sha
# for all images, so we can use the same output name.
sha: ${{ steps.build_info.outputs.short_sha }}
merge_manifest:
if: github.repository == 'dragonflydb/dragonfly'
needs: [build_and_tag]
runs-on: ubuntu-latest
strategy:
matrix:
flavor: [alpine,ubuntu,distroless]
steps:
- name: checkout
uses: actions/checkout@v6
- name: Login to Registries
uses: ./.github/actions/multi-registry-docker-login
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
- name: Merge and Push
run: |
# Function to create and push manifests for a given registry
create_and_push_manifests() {
local registry=$1
local flavor=$2
local sha=$3
# Create and push the manifest like dragonfly-dev:alpine-<sha>
local sha_tag="${registry}:${flavor}-${sha}"
docker manifest create ${sha_tag} --amend ${sha_tag}-amd64 --amend ${sha_tag}-arm64
docker manifest push ${sha_tag}
# Create and push the manifest like dragonfly-dev:alpine
local flavor_tag="${registry}:${flavor}"
docker manifest create ${flavor_tag} --amend ${sha_tag}-amd64 --amend ${sha_tag}-arm64
docker manifest push ${flavor_tag}
}
# GitHub Container Registry manifests
create_and_push_manifests "${{ env.image }}" "${{ matrix.flavor }}" "${{ needs.build_and_tag.outputs.sha }}"
# Google Artifact Registry manifests
create_and_push_manifests "${{ env.GCS_IMAGE }}" "${{ matrix.flavor }}" "${{ needs.build_and_tag.outputs.sha }}"