mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-03-14 10:01:52 +00:00
chore: introduce docker release pipeline (#4618)
* chore: introduce docker release pipeline The whole flow is reimplemented using native arm64/amd64 runners. Signed-off-by: Roman Gershman <roman@dragonflydb.io> * Update .github/workflows/docker-release2.yml Co-authored-by: Kostas Kyrimis <kostas@dragonflydb.io> Signed-off-by: Roman Gershman <romange@gmail.com> * chore: comments --------- Signed-off-by: Roman Gershman <roman@dragonflydb.io> Signed-off-by: Roman Gershman <romange@gmail.com> Co-authored-by: Kostas Kyrimis <kostas@dragonflydb.io>
This commit is contained in:
25
.github/actions/test-docker/action.yml
vendored
Normal file
25
.github/actions/test-docker/action.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Test Docker Image
|
||||
|
||||
inputs:
|
||||
image_id:
|
||||
required: true
|
||||
type: string
|
||||
name:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Test Image
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Testing ${{ inputs.name }} image"
|
||||
docker pull ${{inputs.image_id}}
|
||||
docker image inspect ${{inputs.image_id}}
|
||||
|
||||
# docker run with port-forwarding
|
||||
docker run --name test -d -p 6379:6379 ${{inputs.image_id}}
|
||||
until [ "`docker inspect -f {{.State.Health.Status}} test`"=="healthy" ]; do
|
||||
sleep 0.1;
|
||||
done;
|
124
.github/workflows/docker-release.yml
vendored
124
.github/workflows/docker-release.yml
vendored
@ -1,124 +0,0 @@
|
||||
name: docker release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
TAG_NAME:
|
||||
description: 'Tag name that the major tag will point to'
|
||||
required: true
|
||||
PRERELEASE:
|
||||
description: 'Whether this is a prerelease'
|
||||
type: boolean
|
||||
required: true
|
||||
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
||||
IS_PRERELEASE: ${{ github.event.release.prerelease || github.event.inputs.PRERELEASE }}
|
||||
|
||||
jobs:
|
||||
# This workaround is needed, as it's not possible to reference env.FOOBAR directly at this stage
|
||||
# - for ex. https://github.com/actions/runner/issues/1189
|
||||
release-container-prereq:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
tag: ${{ steps.release-param.outputs.tag }}
|
||||
tag_latest: ${{ steps.release-param.outputs.tag_latest }}
|
||||
steps:
|
||||
- id: release-param
|
||||
run: |
|
||||
# If env.IS_PRERELEASE is true, set tag to alpha and do not enable tag_latest
|
||||
# If env.IS_PRERELEASE is not true (aka false), don't set an extra tag and enable tag_latest
|
||||
echo "tag=${{ env.IS_PRERELEASE == 'true' && 'alpha' }}" >> $GITHUB_OUTPUT
|
||||
echo "tag_latest=${{ env.IS_PRERELEASE == 'true' && 'false' || 'true' }}" >> $GITHUB_OUTPUT
|
||||
|
||||
release-container:
|
||||
needs: release-container-prereq
|
||||
uses: ./.github/workflows/reusable-container-workflow.yaml
|
||||
with:
|
||||
build_type: prod
|
||||
tag: ${{ needs.release-container-prereq.outputs.tag }}
|
||||
tag_latest: ${{ needs.release-container-prereq.outputs.tag_latest == 'true' }}
|
||||
image: ghcr.io/${{ github.repository }}
|
||||
registry: ghcr.io
|
||||
registry_username: ${{ github.repository_owner }}
|
||||
fetch_release: true
|
||||
release_version: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
||||
secrets:
|
||||
registry_password: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release:
|
||||
needs: [release-container-prereq, release-container]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: print_env
|
||||
run: env
|
||||
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install helm
|
||||
uses: azure/setup-helm@v4
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
|
||||
- name: Configure Git
|
||||
if: env.IS_PRERELEASE != 'true'
|
||||
run: |
|
||||
git config user.name "$GITHUB_ACTOR"
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Update helm chart
|
||||
if: env.IS_PRERELEASE != 'true'
|
||||
run: |
|
||||
git checkout main
|
||||
sed -Ei \
|
||||
-e 's/^(version\:) .*/\1 '${{ env.TAG_NAME }}'/g' \
|
||||
-e 's/^(appVersion\:) .*/\1 "'${{ env.TAG_NAME }}'"/g' \
|
||||
contrib/charts/dragonfly/Chart.yaml
|
||||
|
||||
go test ./contrib/charts/dragonfly/... -update
|
||||
|
||||
git commit \
|
||||
-m 'chore(helm-chart): update to ${{ env.TAG_NAME }}' \
|
||||
contrib/charts/dragonfly/Chart.yaml \
|
||||
contrib/charts/dragonfly/ci || true
|
||||
|
||||
- name: Push Helm chart as OCI to Github
|
||||
if: env.IS_PRERELEASE != 'true'
|
||||
run: |
|
||||
echo "${{ secrets.GITHUB_TOKEN }}" | \
|
||||
helm registry login -u ${{ github.actor }} --password-stdin ghcr.io
|
||||
|
||||
helm package contrib/charts/dragonfly
|
||||
|
||||
helm push dragonfly-${{ env.TAG_NAME }}.tgz oci://ghcr.io/${{ github.repository }}/helm
|
||||
|
||||
- name: GitHub Push
|
||||
uses: CasperWA/push-protected@v2
|
||||
with:
|
||||
token: ${{ secrets.DRAGONFLY_TOKEN }}
|
||||
branch: main
|
||||
|
||||
- name: Discord notification
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
uses: Ilshidur/action-discord@0c4b27844ba47cb1c7bee539c8eead5284ce9fa9
|
||||
with:
|
||||
args: 'DragonflyDB version [${{ env.TAG_NAME }}](https://github.com/dragonflydb/dragonfly/releases/tag/${{ env.TAG_NAME }}) has been released 🎉'
|
||||
|
||||
- name: Re-build Docs
|
||||
if: env.IS_PRERELEASE != 'true'
|
||||
run: |
|
||||
curl -s -X POST '${{ secrets.VERCEL_DOCS_WEBHOOK }}'
|
160
.github/workflows/docker-release2.yml
vendored
Normal file
160
.github/workflows/docker-release2.yml
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
name: Docker Release-v2
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
TAG_NAME:
|
||||
description: 'Tag name that the major tag will point to'
|
||||
required: true
|
||||
PRERELEASE:
|
||||
description: 'Whether this is a prerelease'
|
||||
type: boolean
|
||||
required: true
|
||||
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
||||
IS_PRERELEASE: ${{ github.event.release.prerelease || github.event.inputs.PRERELEASE }}
|
||||
IMAGE: ghcr.io/dragonflydb/dragonfly
|
||||
|
||||
jobs:
|
||||
build_and_tag:
|
||||
name: Build and Push ${{matrix.flavor}} ${{ matrix.os.arch }} image
|
||||
strategy:
|
||||
matrix:
|
||||
flavor: [ubuntu]
|
||||
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@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
- name: Set up Docker Build
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Fetch release asset
|
||||
uses: dsaltares/fetch-gh-release-asset@1.1.2
|
||||
with:
|
||||
version: "tags/${{ env.TAG_NAME }}"
|
||||
regex: true
|
||||
file: "dragonfly-.*\\.tar\\.gz"
|
||||
target: 'releases/'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract artifacts
|
||||
run: |
|
||||
echo "Event prerelease ${{ github.event.release.prerelease }}"
|
||||
echo "Input prerelease ${{ github.event.inputs.PRERELEASE }}"
|
||||
ls -l
|
||||
ls -l releases
|
||||
for f in releases/*.tar.gz; do tar xvfz $f -C releases; done
|
||||
rm releases/*.tar.gz
|
||||
|
||||
- name: Docker meta
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.IMAGE }}
|
||||
flavor: |
|
||||
latest=false
|
||||
prefix=${{ matrix.flavor}}-
|
||||
suffix=-${{ matrix.os.arch }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}},enable=true,value=${{ env.TAG_NAME }}
|
||||
type=semver,pattern={{raw}},enable=true,value=${{ env.TAG_NAME }}
|
||||
type=ref,event=pr
|
||||
labels: |
|
||||
org.opencontainers.image.vendor=DragonflyDB LTD
|
||||
org.opencontainers.image.title=Dragonfly Production Image
|
||||
org.opencontainers.image.description=The fastest in-memory store
|
||||
|
||||
- name: Build image
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
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 }}-prod
|
||||
cache-from: type=gha,scope=prod-${{ matrix.flavor }}
|
||||
cache-to: type=gha,scope=prod-${{ matrix.flavor }},mode=max
|
||||
load: true # Load the build images into the local docker.
|
||||
|
||||
- name: Test Image
|
||||
uses: ./.github/actions/test-docker
|
||||
timeout-minutes: 1
|
||||
with:
|
||||
image_id: ${{ env.IMAGE }}@${{ steps.build.outputs.digest }}
|
||||
name: ${{ matrix.flavor }}-${{ matrix.os.arch }}
|
||||
|
||||
- id: output-sha
|
||||
run: |
|
||||
echo "sha_${{ matrix.os.arch }}=${{ steps.build.outputs.digest }}" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
sha_amd: ${{ steps.output-sha.outputs.sha_amd64 }}
|
||||
sha_arm: ${{ steps.output-sha.outputs.sha_arm64 }}
|
||||
|
||||
merge_manifest:
|
||||
needs: [build_and_tag]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
flavor: [ubuntu]
|
||||
steps:
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Merge and Push
|
||||
run: |
|
||||
sha_amd=${{ env.IMAGE }}@${{ needs.build_and_tag.outputs.sha_amd }}
|
||||
sha_arm=${{ env.IMAGE }}@${{ needs.build_and_tag.outputs.sha_arm }}
|
||||
echo "shas: $sha_amd $sha_arm"
|
||||
|
||||
if [[ "${{ env.IS_PRERELEASE }}" == 'true' ]]; then
|
||||
# Create and push the manifest like dragonfly:alpha-ubuntu
|
||||
tag="${{ env.IMAGE }}:alpha-${{ matrix.flavor }}"
|
||||
docker manifest create ${tag} --amend ${sha_amd} --amend ${sha_arm}
|
||||
docker manifest push ${tag}
|
||||
elif [[ "${{matrix.flavor}}" == 'ubuntu' ]]; then
|
||||
tag="${{ env.IMAGE }}:latest"
|
||||
# Create and push the manifest like dragonfly:latest
|
||||
docker manifest create ${tag} --amend ${sha_amd} --amend ${sha_arm}
|
||||
docker manifest push ${tag}
|
||||
fi
|
||||
|
||||
# Create and push the manifest like dragonfly:v1.26.4
|
||||
tag=${{ env.IMAGE }}:${{ env.TAG_NAME }}
|
||||
docker manifest create ${tag} --amend ${sha_amd} --amend ${sha_arm}
|
||||
docker manifest push ${tag}
|
205
.github/workflows/reusable-container-workflow.yaml
vendored
205
.github/workflows/reusable-container-workflow.yaml
vendored
@ -1,205 +0,0 @@
|
||||
name: Reusable Container Build Workflow
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
# Which suffix to look for with the Dockerfile. Can be dev or prod
|
||||
build_type:
|
||||
required: true
|
||||
type: string
|
||||
# For example 'alpha', for pre-release or weekly builds
|
||||
tag:
|
||||
required: false
|
||||
type: string
|
||||
# Is this a final release? Then we set this to true, so the 'latest' tag is updated
|
||||
tag_latest:
|
||||
required: false
|
||||
type: boolean
|
||||
# The container image dragonflydb/dragonfly
|
||||
image:
|
||||
required: true
|
||||
type: string
|
||||
# ghcr.io / hub.docker.com / quay.io / you name it
|
||||
registry:
|
||||
required: true
|
||||
type: string
|
||||
# Username used to login to the registry
|
||||
registry_username:
|
||||
required: true
|
||||
type: string
|
||||
# Do we have to fetch release assets? Then set this to true.
|
||||
# Not required for build_type == dev, as they entirely build from source
|
||||
# But for build_type == prod, as they're based on the release assets
|
||||
fetch_release:
|
||||
required: false
|
||||
type: boolean
|
||||
# Which version are we fetching? Should be identical to the release version.
|
||||
# For example v0.12.0
|
||||
release_version:
|
||||
required: false
|
||||
type: string
|
||||
secrets:
|
||||
# Password used to login to the registry
|
||||
registry_password:
|
||||
required: true
|
||||
# Github Personal Access Token used to fetch assets from a release
|
||||
GH_TOKEN:
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
container-build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- flavor: alpine
|
||||
dockerfile: tools/packaging/Dockerfile.alpine
|
||||
tag_main: false
|
||||
- flavor: ubuntu
|
||||
dockerfile: tools/packaging/Dockerfile.ubuntu
|
||||
tag_main: true
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
|
||||
- if: inputs.fetch_release
|
||||
name: Fetch release asset
|
||||
uses: dsaltares/fetch-gh-release-asset@1.1.2
|
||||
with:
|
||||
version: "tags/${{ inputs.release_version }}"
|
||||
regex: true
|
||||
file: "dragonfly-.*\\.tar\\.gz"
|
||||
target: 'releases/'
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- if: inputs.fetch_release
|
||||
name: Extract artifacts
|
||||
run: |
|
||||
echo "Event prerelease ${{ github.event.release.prerelease }}"
|
||||
echo "Input prerelease ${{ github.event.inputs.PRERELEASE }}"
|
||||
ls -l
|
||||
ls -l releases
|
||||
for f in releases/*.tar.gz; do tar xvfz $f -C releases; done
|
||||
rm releases/*.tar.gz
|
||||
|
||||
- name: Set up QEMU
|
||||
id: qemu
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: arm64,amd64
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ inputs.registry }}
|
||||
username: ${{ inputs.registry_username }}
|
||||
password: ${{ secrets.registry_password }}
|
||||
|
||||
- name: Docker meta
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ inputs.image }}
|
||||
tags: |
|
||||
# will set tag 'latest' for ubuntu build on production push
|
||||
# inputs.tag_latest will be true on when triggered by docker-release.yml
|
||||
# matrix.tag_main will only be true for ubuntu flavor
|
||||
type=raw,value=latest,enable=${{ matrix.tag_main && inputs.tag_latest }}
|
||||
|
||||
# set a tag like 'alpine' or 'ubuntu', if we're setting 'latest' during this build as well
|
||||
type=raw,value=${{ matrix.flavor }},enable=${{ inputs.tag_latest }}
|
||||
|
||||
# will set tag like 'alpha' for ubuntu build, if inputs.tag is not empty
|
||||
# but will set the non-flavored tag only, if matrix.tag_main is true
|
||||
type=raw,value=${{ inputs.tag }},enable=${{ inputs.tag != 'false' && matrix.tag_main }}
|
||||
|
||||
# will set tag like 'alpha-(ubuntu|alpine)', if inputs.tag is not empty
|
||||
type=raw,value=${{ inputs.tag }}-${{ matrix.flavor }},enable=${{ inputs.tag != 'false' }}
|
||||
|
||||
# will set tag like 'v0.12.0' for ubuntu build, if inputs.release_version is not empty
|
||||
# but will set the non-flavored tag only, if matrix.tag_main is true
|
||||
type=raw,value=${{ inputs.release_version }},enable=${{ matrix.tag_main && inputs.release_version != '' }}
|
||||
|
||||
# will set tag like 'v0.12.0-(ubuntu|alpine)', if inputs.release_version is not empty
|
||||
type=raw,value=${{ inputs.release_version }}-${{ matrix.flavor }},enable=${{ inputs.release_version != '' }}
|
||||
|
||||
# build is broken based on platforms as load: true is not supported with multi-platform builds
|
||||
- if: ${{ hashFiles(format('{0}-{1}', matrix.dockerfile, inputs.build_type)) }}
|
||||
name: Build release image for amd64
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
build-args: |
|
||||
QEMU_CPU=max,pauth-impdef=on
|
||||
push: false
|
||||
tags: |
|
||||
${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
file: ${{ matrix.dockerfile }}-${{ inputs.build_type }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
# only load AMD64 image for testing
|
||||
load: true
|
||||
|
||||
- if: ${{ hashFiles(format('{0}-{1}', matrix.dockerfile, inputs.build_type)) }}
|
||||
name: Build release image for arm64
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64
|
||||
build-args: |
|
||||
QEMU_CPU=max,pauth-impdef=on
|
||||
push: false
|
||||
tags: |
|
||||
${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
file: ${{ matrix.dockerfile }}-${{ inputs.build_type }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- if: ${{ hashFiles(format('{0}-{1}', matrix.dockerfile, inputs.build_type)) }}
|
||||
name: Test Docker run
|
||||
run: |
|
||||
# docker run with port-forwarding
|
||||
# install redis-tools
|
||||
sudo apt-get install redis-tools -y
|
||||
tag="${{ steps.metadata.outputs.tags }}"
|
||||
# use the first tag if multiple tags are provided
|
||||
if [[ $(echo "${tag}" | wc -l) -gt 1 ]]; then
|
||||
echo "Multiple tags provided, using the first one"
|
||||
tag=$(echo "${tag}" | head -n 1)
|
||||
fi
|
||||
echo "Testing ${tag}"
|
||||
docker run -d -p 6379:6379 ${tag}
|
||||
sleep 5
|
||||
# ping with redis-cli and expect PONG
|
||||
if [[ $(redis-cli -h localhost ping) != "PONG" ]]; then
|
||||
echo "Redis ping failed"
|
||||
exit 1
|
||||
else
|
||||
echo "Redis ping succeeded"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
- if: ${{ hashFiles(format('{0}-{1}', matrix.dockerfile, inputs.build_type)) }}
|
||||
name: Push release image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
QEMU_CPU=max,pauth-impdef=on
|
||||
tags: |
|
||||
${{ steps.metadata.outputs.tags }}
|
||||
labels: ${{ steps.metadata.outputs.labels }}
|
||||
file: ${{ matrix.dockerfile }}-${{ inputs.build_type }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
@ -1,5 +1,5 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM ghcr.io/romange/ubuntu-dev:20 as builder
|
||||
FROM ghcr.io/romange/ubuntu-dev:20 AS builder
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
|
Reference in New Issue
Block a user