Automating ECR repository and image setup for Sisense offline installations [Linux]
This script automates repository creation and image upload when using Amazon ECR as the private docker repository for a Sisense offline installation. It is designed to simplify the setup process in air-gapped environments by handling all necessary ECR interactions from the command line.
Use this script instead of step 6 in Installing Sisense in an Offline (Air-Gapped) Environment
Step-by-Step Guide:
This guide explains how to use the push_to_ecr.sh script to manage container images between a local Linux environment and Amazon Elastic Container Registry (ECR).
1. Meet the Prerequisites
Before running the script, you must ensure your environment is set up correctly.
- Install AWS CLI: The AWS Command Line Interface (aws) must be installed and configured with valid IAM credentials.
The user or role needs permissions for ECR (ecr:*) and STS (sts:GetCallerIdentity).
See here for more details on installing AWS CLI. - Install containerd: The ctr command-line tool must be installed on your system.
- Set User Permissions for ctr: The script needs to run ctr without sudo. To allow this, you must add your user to the group that owns the containerd socket.
- First, find the group name by running this command. The group is often named Docker or root.
ls -l /run/containerd/containerd.sock
- Next, add your user to that group. Replace GROUP_NAME with the actual group name you found.
# Replace 'GROUP_NAME' with the actual group name sudo usermod -aG GROUP_NAME $(whoami)
- Finally, log out and log back in. This is a mandatory step for the new group membership to take effect.
- First, find the group name by running this command. The group is often named Docker or root.
2. Save the Script
Save the following script code as push_to_ecr.sh on your Linux machine.
Note: If your ECR registry is not in the us-east-2 region, update the AWS_REGION variable in the script below to match your region.
(Bash Code)
#!/bin/bash
# ==============================================================================
# Standalone Script to Push Local Container Images to Amazon ECR
#
# Description:
# This script can push local .tar image files to ECR, create the ECR
# repositories without pushing, or list all existing repositories.
#
# ==============================================================================
# --- Configuration ---
set -e
set -u
set -o pipefail
# --- User-configurable variables ---
AWS_REGION="us-east-2"
# --- Helper Functions ---
usage() {
echo "Usage: $0 [command] [path_to_images_directory]"
echo
echo "Commands:"
echo " (no command) Default action. Pushes all images from the directory."
echo " --create-repos-only, -c Scans the directory and creates ECR repos if they don't exist. Does not push."
echo " --list-repos, -l Lists all repositories in your ECR registry for the configured region."
echo " --help, -h Displays this help message."
}
list_all_repos() {
echo "INFO: Listing all ECR repositories in region ${AWS_REGION}..."
aws ecr describe-repositories --region "${AWS_REGION}" --query "repositories[].repositoryName" --output text | tr '\t' '\n'
}
create_repos_only() {
local images_dir="$1"
echo "INFO: Starting 'create repos only' mode."
echo "INFO: Scanning image directory: ${images_dir}"
if [ ! -d "$images_dir" ]; then echo "ERROR: Images directory '${images_dir}' not found."; exit 1; fi
for image_tar_file in "$images_dir"/*.tar; do
if [ ! -f "$image_tar_file" ]; then echo "WARNING: No .tar files found in '${images_dir}'. Exiting."; exit 0; fi
echo "=============================================================================="
echo "INFO: Processing file for repository name: ${image_tar_file}"
local original_image_name
original_image_name=$(ctr -n=k8s.io images import "$image_tar_file" | awk 'NR==1{print $2}')
if [ -z "$original_image_name" ]; then echo "ERROR: Failed to import image from ${image_tar_file}." >&2; continue; fi
ctr -n=k8s.io images rm "${original_image_name}" > /dev/null 2>&1 || true
local base_repo_name
base_repo_name=$(echo "$original_image_name" | awk -F: '{print $1}' | rev | cut -d'/' -f 1 | rev)
if [[ $original_image_name == *"bitnami"* ]]; then base_repo_name="bitnami/${base_repo_name}"; fi
base_repo_name="sisense/${base_repo_name}"
echo "INFO: Derived repository name: ${base_repo_name}"
echo "INFO: Checking if ECR repository exists..."
if ! aws ecr describe-repositories --region "${AWS_REGION}" --repository-names "${base_repo_name}" > /dev/null 2>&1; then
echo "INFO: Repository does not exist. Creating it now..."
aws ecr create-repository --repository-name "${base_repo_name}" --region "${AWS_REGION}" --image-scanning-configuration scanOnPush=true > /dev/null
echo "INFO: Repository '${base_repo_name}' created successfully."
else
echo "INFO: Repository already exists."
fi
done
}
push_images() {
local images_dir="$1"
echo "INFO: Starting ECR image push process."
echo "INFO: Using image directory: ${images_dir}"
local ECR_TOKEN
ECR_TOKEN=$(aws ecr get-login-password --region "${AWS_REGION}")
if [ -z "$ECR_TOKEN" ]; then echo "ERROR: Failed to get ECR authentication token."; exit 1; fi
if [ ! -d "$images_dir" ]; then echo "ERROR: Images directory '${images_dir}' not found."; exit 1; fi
for image_tar_file in "$images_dir"/*.tar; do
if [ ! -f "$image_tar_file" ]; then echo "WARNING: No .tar files found in '${images_dir}'. Exiting."; exit 0; fi
echo "=============================================================================="
echo "INFO: Processing image file: ${image_tar_file}"
local original_image_name
original_image_name=$(ctr -n=k8s.io images import "$image_tar_file" | awk 'NR==1{print $2}')
if [ -z "$original_image_name" ]; then echo "ERROR: Failed to import image from ${image_tar_file}."; continue; fi
echo "INFO: Imported as: ${original_image_name}"
local base_repo_name tag new_ecr_image_name
base_repo_name=$(echo "$original_image_name" | awk -F: '{print $1}' | rev | cut -d'/' -f 1 | rev)
tag=$(echo "$original_image_name" | awk -F: '{print $2}')
if [[ $original_image_name == *"bitnami"* ]]; then base_repo_name="bitnami/${base_repo_name}"; fi
base_repo_name="sisense/${base_repo_name}"
new_ecr_image_name="${REGISTRY_SERVER}/${base_repo_name}:${tag}"
echo "INFO: New ECR tag will be: ${new_ecr_image_name}"
echo "INFO: Checking if ECR repository '${base_repo_name}' exists..."
if ! aws ecr describe-repositories --region "${AWS_REGION}" --repository-names "${base_repo_name}" > /dev/null 2>&1; then
echo "INFO: Repository does not exist. Creating it now..."
aws ecr create-repository --repository-name "${base_repo_name}" --region "${AWS_REGION}" --image-scanning-configuration scanOnPush=true > /dev/null
echo "INFO: Repository '${base_repo_name}' created successfully."
else
echo "INFO: Repository already exists."
fi
echo "INFO: Ensuring no old tag exists..."
ctr -n=k8s.io images rm "${new_ecr_image_name}" > /dev/null 2>&1 || true
echo "INFO: Tagging image..."
ctr -n=k8s.io images tag "${original_image_name}" "${new_ecr_image_name}"
echo "INFO: Pushing image to ECR..."
ctr -n=k8s.io images push --user "AWS:${ECR_TOKEN}" "${new_ecr_image_name}"
echo "SUCCESS: Successfully pushed ${new_ecr_image_name}"
done
}
# --- Main Execution Logic ---
if ! command -v aws &> /dev/null; then echo "ERROR: AWS CLI ('aws') could not be found."; exit 1; fi
if ! command -v ctr &> /dev/null; then echo "ERROR: containerd CLI ('ctr') could not be found."; exit 1; fi
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
if [ -z "$AWS_ACCOUNT_ID" ]; then echo "ERROR: Could not get AWS Account ID."; exit 1; fi
REGISTRY_SERVER="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
COMMAND=${1:-push}
IMAGES_DIR=""
if [[ "$COMMAND" == --* || "$COMMAND" == -* ]]; then
IMAGES_DIR=${2:-./images}
else
IMAGES_DIR=${1:-./images}
COMMAND="push"
fi
case "$COMMAND" in
--create-repos-only|-c) create_repos_only "$IMAGES_DIR" ;;
--list-repos|-l) list_all_repos ;;
--help|-h) usage ;;
push) push_images "$IMAGES_DIR" ;;
*)
if [ -d "$COMMAND" ]; then
push_images "$COMMAND"
else
echo "ERROR: Unknown command '$COMMAND'."
usage
exit 1
fi
;;
esac
echo "=============================================================================="
echo "INFO: Script finished."
3. Make the Script Executable
Open a terminal and run chmod to give the script execution permissions.
chmod +x push_to_ecr.sh
4. Using the Script's Commands
The script is now ready to use. Here are the primary commands:
- Push Images (Default Action): This command will scan the <sisense installation directory>/images directory, import each .tar file, create the corresponding ECR repository if it doesn't exist, and push the image.
./push_to_ecr.sh <sisense installation directory>/images
(Example Output)
INFO: Starting ECR image push process.
INFO: Using image directory: ./images/
==============================================================================
INFO: Processing image file: ./images//ghcr.io_kedacore_keda-admission-webhooks_2.13.1.tar
INFO: Imported as: ghcr.io/kedacore/keda-admission-webhooks:2.13.1
INFO: New ECR tag will be: 111213707889.dkr.ecr.us-east-2.amazonaws.com/sisense/keda-admission-webhooks:2.13.1
INFO: Checking if ECR repository 'sisense/keda-admission-webhooks' exists...
INFO: Repository already exists.
INFO: Ensuring no old tag exists...
INFO: Tagging image...
111213707889.dkr.ecr.us-east-2.amazonaws.com/sisense/keda-admission-webhooks:2.13.1
INFO: Pushing image to ECR...
manifest-2.13.1@sha256:3dbfbbe3214671a728a080f21211114127b565594872374f2f0c09d3c836f2a2: done |++++++++++++++++++++++++++++++++++++++|
config-sha256:3076d7a3f36e43ec91f449536582b77c57a6ba8b4dd381bd3765d5de2205b03d: done |++++++++++++++++++++++++++++++++++++++|
elapsed: 0.3 s total: 3.8 Ki (12.7 KiB/s)
SUCCESS: Successfully pushed 111213707889.dkr.ecr.us-east-2.amazonaws.com/sisense/keda-admission-webhooks:2.13.1
==============================================================================
INFO: Processing image file: ./images//ghcr.io_kedacore_keda-metrics-apiserver_2.13.1.tar
INFO: Imported as: ghcr.io/kedacore/keda-metrics-apiserver:2.13.1
INFO: New ECR tag will be: 111213707889.dkr.ecr.us-east-2.amazonaws.com/sisense/keda-metrics-apiserver:2.13.1
INFO: Checking if ECR repository 'sisense/keda-metrics-apiserver' exists...
INFO: Repository already exists.
INFO: Ensuring no old tag exists...
INFO: Tagging image...
111213707889.dkr.ecr.us-east-2.amazonaws.com/sisense/keda-metrics-apiserver:2.13.1
INFO: Pushing image to ECR...
manifest-2.13.1@sha256:9bd61a6a3f7daf0a4e81dbbb4ac49daaca0f75f6479c099377076b59d7ff7849: done |++++++++++++++++++++++++++++++++++++++|
config-sha256:5469bb8aaadc54c641b19041e8f9faf69c54b38ed561fec51b94c646556aa288: done |++++++++++++++++++++++++++++++++++++++|
elapsed: 0.3 s total: 3.8 Ki (12.7 KiB/s)
SUCCESS: Successfully pushed 111213707889.dkr.ecr.us-east-2.amazonaws.com/sisense/keda-metrics-apiserver:2.13.1
==============================================================================
- Create Repositories Only: Use this command to pre-populate ECR with all the necessary repositories without pushing the images. This is useful for setting up an environment ahead of time.
./push_to_ecr.sh --create-repos-only <sisense installation directory>/images
(Example Output)
INFO: Starting 'create repos only' mode.
INFO: Scanning image directory: ./images/
==============================================================================
INFO: Processing file for repository name: ./images//quay.io_sisense_connectors_L2024.1.0.85.tar
INFO: Derived repository name: sisense/connectors
INFO: Checking if ECR repository exists...
INFO: Repository already exists.
==============================================================================
INFO: Processing file for repository name: ./images//quay.io_sisense_develop_ai-integration_L2025.2.0.240.tar
INFO: Derived repository name: sisense/ai-integration
INFO: Checking if ECR repository exists...
INFO: Repository does not exist. Creating it now...
INFO: Repository 'sisense/ai-integration' created successfully.
==============================================================================
- List Existing Repositories: This command provides a clean, newline-separated list of all ECR repositories in your configured AWS region.
./push_to_ecr.sh --list-repos
(Example Output)
INFO: Listing all ECR repositories in region us-east-2...
sisense/external-provisioner
sisense/external-resizer
sisense/aws-fsx-csi-driver
sisense/prometheus
sisense/connectors
sisense/ai-integration
sisense/bitnami/rabbitmq
sisense/build-connector
sisense/compute-service
sisense/customcode
sisense/dgraph
sisense/filebrowser
sisense/fluent-bit
sisense/git
sisense/grafana
sisense/infusion-service
sisense/infusion-slack
sisense/intelligence
sisense/jobs
sisense/knowledgegraph
sisense/migration
sisense/monetdb
sisense/nlq-rt
sisense/query
sisense/secret-service
sisense/storage
sisense/thanos
sisense/translation
sisense/utils
sisense/keda-admission-webhooks
sisense/keda-metrics-apiserver
sisense/keda
sisense/livenessprobe
sisense/node-driver-registrar
sisense/prometheus-config-reloader
sisense/bitnami/minideb
sisense/ai-services
sisense/configuration
sisense/exporting
sisense/infusion-teams
sisense/k8s-sidecar
sisense/kube-state-metrics
sisense/logrotate
sisense/model-graphql
sisense/monitoring
sisense/nlq-compile
sisense/oxygen
sisense/reporting
sisense/usage
sisense/csi-node-driver-registrar
sisense/csi-resizer
sisense/nfsplugin
sisense/api-gateway
sisense/bitnami/mongodb-exporter
sisense/bitnami/zookeeper
sisense/build
sisense/busybox
sisense/external-plugins
sisense/formula-management
sisense/jinja-init
sisense/kube-webhook-certgen
sisense/management
sisense/nlq-duckling
sisense/plugins
sisense/prometheus-operator
sisense/quest
sisense/csi-snapshotter
sisense/alertmanager
sisense/analyticalengine
sisense/bats
sisense/bitnami/mongodb
sisense/bitnami/os-shell
sisense/exporter-xlsx
sisense/fluentd
sisense/galaxy
sisense/identity
sisense/maintenance
sisense/node-exporter
sisense/pivot2-be
sisense/provisioner
sisense/sysinfo_sender
sisense/utilsbox
sisense/warehouse
sisense/controller
sisense/csi-provisioner
==============================================================================
INFO: Script finished.
Conclusion:
After this process is complete and all images have been successfully pushed to your ECR registry, you can proceed with the Sisense installation from step 7 onwards in the official documentation.
Note: When you configure your config.yaml file, the docker_registry parameter should be set to ${YOUR_DOCKER_REGISTRY}/sisense, where ${YOUR_DOCKER_REGISTRY} is your ECR server address (e.g., 1234567890abcde.dkr.ecr.us-east-2.amazonaws.com).
Disclaimer: This post outlines a potential custom workaround for a specific use case or provides instructions regarding a specific task. The solution may not work in all scenarios or Sisense versions, so we strongly recommend testing it in your environment before deployment. If you need further assistance with this, please let us know.