



























The container ecosystem experienced a shift when Broadcom acquired VMware, subsequently implementing monetization strategies across the Bitnami portfolio. As detailed in my previous analysis of Broadcom's Bitnami monetization impact, these change altered how organizations access trusted container images.
The monetization changes mean organizations previously pulling images like bitnami/redis or bitnami/postgresql without restrictions now face authentication requirements and usage limitations. While Bitnami offers commercial solutions for production environments, some teams need alternatives for development, testing, or learning purposes.
The solution involves:
This guide is for educational and development purposes. Building your own container images introduces complexity and responsibility that many organizations may not be prepared to handle. Consider these factors:
When This Approach Makes Sense:
Recommended Alternatives:
This guide demonstrates the technical feasibility of building custom Bitnami images using GitHub Actions and AWS ECR, plus how to update your Helm charts to consume these self-hosted images. Use this knowledge responsibly and consider the trade-offs carefully.
Create a dedicated repository for your container images with this structure:
container-images/
├── containers/bitnami/ # Bitnami container definitions
│ ├── nginx/
│ ├── redis/
│ ├── postgresql/
│ └── ...
├── .github/workflows/ # GitHub Actions workflows
└── README.md
Before building images, provision ECR repositories for each application you'll host:
# Create ECR repositories for common applications
aws ecr create-repository --repository-name acmeorg-bitnami-redis --region us-east-1
aws ecr create-repository --repository-name acmeorg-bitnami-nginx --region us-east-1
aws ecr create-repository --repository-name acmeorg-bitnami-postgresql --region us-east-1
❗For Infrastructure as Code approaches, use tools like Terraform or AWS CDK to manage these repositories.
This is straightforward. Just go inside the bitnami container folder and the tool you want to build image for. Assume we want to build an image for Redis. Enter the folder:
containers/bitnami/redis/8.2/debian-12
Now just run:
docker buildx build --platform linux/arm64 -t bitnami-redis . --load
Because I’m building on Apple Silicon (ARM64), I use the --platform flag to avoid accidental mismatches. This guarantees the image is built for the correct architecture expected by my Kubernetes cluster.
Now you can test the REDIS:
docker run --rm bitnami-redis redis-server --version
Output:
redis 21:11:53.26 INFO ==>
Redis server v=8.2.1 sha=00000000:1 malloc=jemalloc-5.3.0 bits=64 build=6242b285f6fb7236
Create a flexible workflow that handles multiple image types and versions. In the following example, I've written a workflow that is assuming a role in AWS. It pushes the images to the pre-created repositories in the previous step.
name: Build and Push Container Image to ECR
on:
workflow_dispatch:
inputs:
image_type:
description: 'Type of image to build'
required: true
type: choice
options:
- 'bitnami'
default: 'bitnami'
image_name:
description: 'Image name (e.g., nginx, redis, postgresql)'
required: true
type: string
image_version:
description: 'Image version (e.g., 1.29, 8.2, latest)'
required: true
type: string
default: 'latest'
os_flavor:
description: 'Operating system flavor'
required: true
type: choice
options:
- 'debian-12'
default: 'debian-12'
aws_region:
description: 'AWS region'
required: true
type: string
default: 'us-east-1'
env:
AWS_REGION: ${{ inputs.aws_region }}
ORG_PREFIX: "acmeorg"
permissions:
id-token: write
contents: read
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
role-session-name: GitHubActions-ECR-Push
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Determine build context and Dockerfile path
id: build-context
run: |
IMAGE_TYPE="${{ inputs.image_type }}"
IMAGE_NAME="${{ inputs.image_name }}"
IMAGE_VERSION="${{ inputs.image_version }}"
OS_FLAVOR="${{ inputs.os_flavor }}"
if [ "$IMAGE_TYPE" == "bitnami" ]; then
BUILD_CONTEXT="containers/bitnami/${IMAGE_NAME}/${IMAGE_VERSION}/${OS_FLAVOR}"
DOCKERFILE_PATH="${BUILD_CONTEXT}/Dockerfile"
FULL_IMAGE_NAME="bitnami-${IMAGE_NAME}"
ECR_REPOSITORY="${{ env.ORG_PREFIX }}-bitnami-${IMAGE_NAME}"
ECR_REPOSITORY="${ECR_REPOSITORY,,}"
elif [ "$IMAGE_TYPE" == "custom" ]; then
BUILD_CONTEXT="containers/custom/${IMAGE_NAME}/${IMAGE_VERSION}/${OS_FLAVOR}"
DOCKERFILE_PATH="${BUILD_CONTEXT}/Dockerfile"
FULL_IMAGE_NAME="${IMAGE_NAME}"
ECR_REPOSITORY="${{ env.ORG_PREFIX }}-custom-${IMAGE_NAME}"
ECR_REPOSITORY="${ECR_REPOSITORY,,}"
fi
# Verify Dockerfile exists
if [ ! -f "$DOCKERFILE_PATH" ]; then
echo "Dockerfile not found at: $DOCKERFILE_PATH"
echo "Available paths:"
find . -name "Dockerfile" -path "./containers/${IMAGE_TYPE}/${IMAGE_NAME}/*" | head -10
exit 1
fi
echo "build-context=$BUILD_CONTEXT" >> $GITHUB_OUTPUT
echo "dockerfile-path=$DOCKERFILE_PATH" >> $GITHUB_OUTPUT
echo "full-image-name=$FULL_IMAGE_NAME" >> $GITHUB_OUTPUT
echo "ecr-repository=$ECR_REPOSITORY" >> $GITHUB_OUTPUT
- name: Verify ECR repository exists
run: |
ECR_REPOSITORY="${{ steps.build-context.outputs.ecr-repository }}"
if ! aws ecr describe-repositories --repository-names "$ECR_REPOSITORY" --region ${{ env.AWS_REGION }} >/dev/null 2>&1; then
echo "ECR repository '$ECR_REPOSITORY' does not exist in region ${{ env.AWS_REGION }}"
echo "Please create the repository first using AWS CLI or Console"
exit 1
else
echo "ECR repository $ECR_REPOSITORY exists"
fi
- name: Generate image tags
id: tags
run: |
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
ECR_REPOSITORY="${{ steps.build-context.outputs.ecr-repository }}"
IMAGE_VERSION="${{ inputs.image_version }}"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
GIT_SHA=$(git rev-parse --short HEAD)
# Generate tags
TAGS="${ECR_REGISTRY}/${ECR_REPOSITORY}:${IMAGE_VERSION}"
TAGS="${TAGS},${ECR_REGISTRY}/${ECR_REPOSITORY}:${IMAGE_VERSION}-${TIMESTAMP}"
TAGS="${TAGS},${ECR_REGISTRY}/${ECR_REPOSITORY}:${IMAGE_VERSION}-${GIT_SHA}"
echo "tags=$TAGS" >> $GITHUB_OUTPUT
echo "primary-tag=${ECR_REGISTRY}/${ECR_REPOSITORY}:${IMAGE_VERSION}" >> $GITHUB_OUTPUT
- name: Check if image exists
run: |
ECR_REGISTRY="${{ steps.login-ecr.outputs.registry }}"
ECR_REPOSITORY="${{ steps.build-context.outputs.ecr-repository }}"
IMAGE_VERSION="${{ inputs.image_version }}"
if aws ecr describe-images --repository-name "$ECR_REPOSITORY" --image-ids imageTag="$IMAGE_VERSION" --region ${{ env.AWS_REGION }} >/dev/null 2>&1; then
echo "Image $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_VERSION already exists. Skipping build."
exit 0
else
echo "Image does not exist, proceeding with build."
fi
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ${{ steps.build-context.outputs.build-context }}
file: ${{ steps.build-context.outputs.dockerfile-path }}
push: true
tags: ${{ steps.tags.outputs.tags }}
platforms: linux/amd64
cache-from: type=gha
cache-to: type=gha,mode=max
labels: |
org.opencontainers.image.title=${{ steps.build-context.outputs.full-image-name }}
org.opencontainers.image.version=${{ inputs.image_version }}
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
- name: Output image details
run: |
echo "Successfully built and pushed image!"
echo "Primary tag: ${{ steps.tags.outputs.primary-tag }}"
echo "Pull command: docker pull ${{ steps.tags.outputs.primary-tag }}"
The workflow supports both Bitnami and you could also add a custom image type, allowing you to extend beyond Bitnami's catalog as needed. Each build creates multiple tags including timestamped and Git SHA variants for precise version tracking.
It utilizes GitHub Actions cache to accelerate subsequent builds of the same image. I've also added a check for ECR repository existence and prevents duplicate builds of existing image versions.
You can extend this by implementing the Semantic Release and use tags instead. It's totally up to you.
To add a new application from Bitnami's catalog:
# Clone Bitnami's containers repository
git clone https://github.com/bitnami/containers.git bitnami-source
cd bitnami-source
# Copy specific application (e.g., Redis)
cp -r bitnami/redis ../containers/bitnami/
# Clean up
cd ..
rm -rf bitnami-source
Ensure the copied application follows Bitnami's standard structure:
containers/bitnami/redis/
├── 8.2/
│ └── debian-12/
│ ├── Dockerfile
│ ├── prebuildfs/
│ └── rootfs/
├── docker-compose.yml
└── README.md
Most Bitnami Helm charts reference multiple container images. For Redis, the Chart.yaml typically includes:
annotations:
images: |
- name: kubectl
image: bitnami/kubectl:1.33.3
- name: redis
image: bitnami/redis:8.2.0
- name: redis-exporter
image: bitnami/redis-exporter:1.74.0
- name: redis-sentinel
image: bitnami/redis-sentinel:8.0.3
You don't need to build every referenced image. Focus on the components you actually use in your deployment.
Update your values.yaml to reference your custom registry:
# Primary Redis configuration
image:
registry: 123456789012.dkr.ecr.us-east-1.amazonaws.com
repository: acmeorg-bitnami-redis
tag: 8.2.0
digest: ""
# Redis Sentinel (if enabled)
sentinel:
enabled: false # Disable if not needed
# If enabled:
# image:
# registry: 123456789012.dkr.ecr.us-east-1.amazonaws.com
# repository: acmeorg-bitnami-redis-sentinel
# tag: 8.0.3
# Redis Exporter (if metrics enabled)
metrics:
enabled: false # Disable if not needed
# If enabled:
# image:
# registry: 123456789012.dkr.ecr.us-east-1.amazonaws.com
# repository: acmeorg-bitnami-redis-exporter
# tag: 1.74.0
# kubectl image (used for init containers)
kubectl:
image:
registry: 123456789012.dkr.ecr.us-east-1.amazonaws.com
repository: acmeorg-bitnami-kubectl
tag: 1.33.3
❗In the value file, you need to enable the allowInsecureImages: true
global:
imageRegistry: ""
## E.g.
## imagePullSecrets:
## - myRegistryKeySecretName
##
imagePullSecrets: []
defaultStorageClass: ""
storageClass: ""
## Security parameters
##
security:
## @param global.security.allowInsecureImages Allows skipping image verification
allowInsecureImages: true <<<<< MAKE SURE YOU HAVE THIS
Deploy Redis using your custom images:
# Add Bitnami Helm repository
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# Deploy with custom values
helm install my-redis bitnami/redis \
--values values.yaml \
--namespace redis \
--create-namespace
For some environments you can set ARM64 (like AWS Graviton instances), just modify the workflow to build multi-platform images:
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
platforms: linux/amd64,linux/arm64
# ... other configuration
Integrate container scanning into your pipeline:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ steps.tags.outputs.primary-tag }}
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
Create scheduled workflows to check for new Bitnami releases:
name: Check for Updates
on:
schedule:
- cron: '0 6 * * 1' # Weekly on Mondays
jobs:
check-updates:
runs-on: ubuntu-latest
steps:
- name: Check Bitnami repository for updates
run: |
# Script to compare your versions with upstream
# Create issues or PRs for detected updates
Building your own Bitnami images is a technical exercise that requires careful consideration of the trade-offs involved. While this guide demonstrates the technical feasibility, remember that Bitnami does not recommend this approach for production environments.
Key Takeaways:
The GitHub Actions workflow presented here provides an idea for those who choose this path. Whether you use this for learning, development environments, or as part of a larger container strategy, approach it with full understanding of the responsibilities involved.
Organizations should carefully evaluate their specific needs, compliance requirements, and operational capabilities before implementing self-hosted container registries. For many use cases, Bitnami's commercial offerings or other officially supported alternatives is more appropriate.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。