Skip to content

Community Edition using Docker

This page describes how to install Community Edition (CE) using Docker, to run on your x86_64 machine, laptop or server.

Prerequisites

  • Docker must be installed on your machine or server (version 4.32.0 or later). Please download it from the Docker page.
  • Minimum free memory: 16GB.
  • Minimum storage for docker: 100GB.
  • K9S installed on your machine (optional but recommended).

Special Steps needed to start WSL for Windows Machines

Windows machines require WSL to run the CE container. Please follow the steps given below to setup WSL:

Step 1: Install WSL

Open PowerShell as Administrator and run the following command to install WSL:

wsl --install

Step 2: Choose a Distribution

After installing WSL, choose a Linux distribution from the Microsoft Store. Some popular choices are Ubuntu, Debian, and Kali Linux. For example, to install Ubuntu, run:

wsl --install -d Ubuntu

Step 3: Set WSL2 as default

wsl --set-default-version 2

Step 4: Start the WSL shell in your local machine

wsl

There is a possibility you may encounter kernel issues with WSL, which can be resolved by updating the kernel using the installer listed on the Official Microsoft page for WSL 2 kernel update.

Try running the ./ybdce start script mentioned below.

YBDCE

ybdce script
sh
#!/bin/bash

K8SVER="1.29.2"
DATA_DIR="`pwd`/local_data"
NODE_NAME="ybd-ce"
KUBECTL="docker exec $NODE_NAME k0s kubectl"
DOCKER_ON_MAC="false"
UPGRADE_MODE=false
# will help in upgrade if we do not want to check the OS again
ACTION=start
VERBOSE="false"
VOLUME_NAME_LFS_ALT="local_data"
VOLUME_NAME="ybd-storage"
VOLUME_NAME_RFS="ybd-storage_rfs"
VOLUME_NAME_LFS="ybd-storage_lfs"
RESTART='false'
POD_NAME='ybinst-i0-0'
NAMESPACE='ybdcens'
CE_VERSION=1.0
PASSWORD=""

# Determine the OS and CPU variant
cpu_arch=$(uname -m)
if [ "$cpu_arch" == "arm64" ]; then
    arch="arm64"
elif [ "$cpu_arch" == "x86_64" ]; then
    arch="amd64"
fi

IMAGE_NAME="yellowbrickdata/ybd-ce-k0s-$arch:stable"

# Detect the operating system and set DOCKER_ON_MAC
case "$OSTYPE" in
  darwin*)
    DOCKER_ON_MAC=true
    ;;  # macOS
  msys*)
    DOCKER_ON_MAC=true
    ;;  # Windows
  linux*)
    DOCKER_ON_MAC=false
    ;; # Linux
  *)
    echo "Unknown OS type: $OSTYPE"
    DOCKER_ON_MAC=false
    ;;
esac

# Function to display general help message
ybdce_usage() {
    echo "Usage: $0 [COMMAND] [OPTIONS]"
    echo
    echo "COMMAND:"
    echo "      start                   Start ybd ce."
    echo "      stop                    Stop ybd ce."
    echo "      upgrade                 Upgrade ybd ce."
    echo "      diags                   Get the logs from the docker container."
    echo "      help                    Display this help message."
    echo "      logs                    Collect logs from ybdce."
}

# Function to display start command help message
ybdce_start_usage() {
    echo "Usage: $0 start [-d true|false] [-i image_name] [-v] [-h|--help]"
    echo
    echo "Options:"
    echo "  -d          Set Docker on Mac to true or false"
    echo "  -i          Specify the image name"
    echo "  -v          Enable verbose mode"
    echo "  -p          Specify a password for ybdce initial user"
    echo "  -h, --help  Display this help message and exit"
}

# Function to display stop command help message
ybdce_stop_usage() {
    echo "Usage: $0 stop [-f|--full-clean] [-r|--remove-container] [-h|--help]"
    echo
    echo "Options:"
    echo "  -f, --full-clean         Delete container and the Docker volumes"
    echo "  -r, --remove-container   Delete container"
    echo "  -h, --help               Display this help message"
}

ybdce_upgrade_usage() {
    echo "Usage: $0 upgrade [-d true|false] [-i image_name] [-v] [-h|--help]"
    echo
    echo "Options:"
    echo "  -d          Set Docker on Mac to true or false"
    echo "  -i          Specify the image name"
    echo "  -v          Enable verbose mode"
    echo "  -h, --help  Display this help message and exit"
}

ybdce_logs_usage() {
    echo "Collect logs for ybdce."
    echo "Options:"
    echo "  -n          Specify a name for this logs. The package will be ybdce-logs-<name>.tgz"
}

# Function to print verbose logs and append to a file with a date timestamp
vlog() {
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local message="[$timestamp] $1"

    if [ "$VERBOSE" = true ]; then
        echo "$message"
    fi

    echo "$message" >> "ybdce-diags.txt"
}

container_resume(){
    while true; do
        # if the container is up and running
        if [ $(docker ps --filter "name=^/${NODE_NAME}$" --format '{{.Names}}') ]; then
            vlog "Container is up and running"
            return 1
        else
            echo "Container is still waiting to spin up. Restarting it now"
            docker start ${NODE_NAME}
        fi
        sleep 5
    done
}

node_ready() {
    local node_name node_ready
    node_name=$1
    # making sure the container has not errored out
    container_resume
    sleep 5
    if [ -z ${node_name} ]; then
        vlog "A node name must be specified to check if it's ready" >&2
        return 1
    fi
    k0s_ready=$(docker exec $NODE_NAME k0s status)
    node_ready=$(${KUBECTL} get node ${node_name} -o jsonpath='{.status.conditions[3].status}')
    if [ $? != 0 ]; then
        return 3
    fi
    if [ ${node_ready} == True ]; then
        vlog "node ${node_name} is ready."
        return 0
    else
        return 1
    fi
}

create_volumes(){
    # Check if Docker volume exists and create it if it doesn't
    VOLUME_NAME="ybd-storage"
    VOLUME_NAME_RFS="ybd-storage_rfs"
    VOLUME_NAME_LFS="ybd-storage_lfs"
    if ! docker volume ls --format '{{ .Name }}' | grep -qw $VOLUME_NAME; then
        vlog "Docker volume $VOLUME_NAME does not exist. Creating..."
        docker volume create $VOLUME_NAME
        docker volume create $VOLUME_NAME_RFS
        if [[ ${DOCKER_ON_MAC} == "true" ]]; then
            MNT_DIR=/host_mnt$DATA_DIR
            docker volume create --driver local -o o=bind -o type=none -o device=$MNT_DIR $VOLUME_NAME_LFS 2>&1
        else
            VOLUME_NAME_LFS=$DATA_DIR
        fi
    else
        vlog "Docker volume $VOLUME_NAME already exists."
    fi
}

create_container(){
    # creating the container
        docker run -d --name $NODE_NAME --hostname $NODE_NAME --privileged -v $VOLUME_NAME_RFS:/var/lib/k0s --cgroupns=host -v $VOLUME_NAME:/mnt/ \
            -e PASSWORD="$PASSWORD" \
            -v $VOLUME_NAME_LFS:/local_data/ -v /sys/fs/cgroup:/sys/fs/cgroup:rw -p 7443:6443 -p 5432:5432 -p 8443:443 $IMAGE_NAME 2>&1
        if [ $? -ne 0 ]; then
            vlog "Failed to run the Docker container. Please check the docker image."
            exit 1
        else
            vlog "Docker container started successfully."
        fi
}

start_controlplane() {
    # call the function to create volumes
    create_volumes
    # if we are in upgrade mode
    if [[ $UPGRADE_MODE == true ]]; then
        # checking if container exists
        if [ $(docker ps -a --filter "name=^/${NODE_NAME}$" --format '{{.Names}}') ]; then
            echo "Container ${NODE_NAME} exists."
            echo "Do you want to stop the container and conitnue upgrading (y/n)?"
            read -r REPLY
            if [[ $REPLY == y ]]; then
                ybdce_stop -r
                echo "Proceeding with the upgrade"
            else
                UPGRADE_MODE=false
                echo "Nothing will be done. Exiting upgrade."
                exit 0
            fi
        else
            vlog "Container ${NODE_NAME} does not exist. Proceeding to create it now."
        fi
        create_container
    else
        # Check if container exists
        if [ $(docker ps -a --filter "name=^/${NODE_NAME}$" --format '{{.Names}}') ]; then
            vlog "Container ${NODE_NAME} exists."
            # Check if container is not running
            if [ $(docker ps --filter "name=^/${NODE_NAME}$" --format '{{.Names}}') ]; then
            vlog "Container ${NODE_NAME} is running. Please use the upgrade option to upgrade your image."
            exit 1
            else
            vlog "Container ${NODE_NAME} is not running. Restarting it now."
            container_resume
            RESTART=true
            fi
        else
            vlog "Container ${NODE_NAME} does not exist. Creating it now."
            create_container
        fi
    fi
}

# progress bar in green
show_progress() {
    local duration=$1
    local pid=$2
    local elapsed=0
    local bar_length=50
    local max_elapsed=45  # Maximum duration before restarting the bar if duration is zero
    local green=$(tput setaf 2)  # Set text color to green
    local reset=$(tput sgr0)     # Reset text color
    while true; do
        if [[ $duration -ne 0 ]]; then
            while [ $elapsed -le $duration ]; do
                local progress=$(( ($elapsed * $bar_length) / $duration ))
                local remainder=$(( $bar_length - $progress ))
                printf "\r["
                for ((i = 0; i < $progress; i++)); do printf "${green}-"; done
                for ((i = 0; i < $remainder; i++)); do printf " "; done
                printf "] %d%%" $(( ($elapsed * 100) / $duration ))
                sleep 1
                elapsed=$(( elapsed + 1 ))
            done
            break
        else
            # Progress bar that restarts if duration is zero
            local effective_elapsed=$((elapsed % max_elapsed))
            local progress=$(( (effective_elapsed * bar_length) / max_elapsed ))
            local remainder=$(( bar_length - progress ))
            printf "\r["
            for ((i = 0; i < progress; i++)); do printf "${green}-"; done
            for ((i = 0; i < remainder; i++)); do printf " "; done
            printf "] %d seconds elapsed" $elapsed
        fi
        sleep 1
        elapsed=$(( elapsed + 1 ))
        if [[ -n "$pid" ]]; then
            if ! ps -p $pid > /dev/null 2>&1; then
                break
            fi
        fi
    done
    printf "${reset}\n"
}

ybdce_start(){
    echo ""
    vlog "Running in Verbose Mode..."
    vlog "DOCKER ON MAC = $DOCKER_ON_MAC"
    vlog "Upgrade Mode = $UPGRADE_MODE"
    vlog "IMAGE = $IMAGE_NAME"
    mkdir -p ${DATA_DIR}
    # Start the controplane with the configuration provided
    echo "Starting install of Yellowbrick Community Edition v$CE_VERSION"
    echo "------------------------------------------------------"
    echo ""
    echo "Executing Step 1/4: Infrastructure"
    start_controlplane
    vlog "Waiting for Infrastructure to Initailize"
    # wait for control plane to start before moving ahead
    echo "Executing Step 2/4: System Intialization"
    duration=30  # Total time for the progress bar (in seconds)
    echo "-- This can take multiple minutes to complete --"
    show_progress $duration
    while true; do
        if node_ready $NODE_NAME; then
            break
        else
            vlog "Waiting for System to become Ready"
        fi
        sleep 5 # Wait for 5 seconds before checking again
    done
    while [ "$RESTART" = true ]; do
        status=$(docker exec "$NODE_NAME" k0s kubectl get pod "$POD_NAME" -n "$NAMESPACE" | grep "$POD_NAME" | awk '{print $3}')
        if [ "$status" = "Unknown" ]; then
            break
        fi
        sleep 0.1
    done
    echo "Executing Step 3/4: Pod Status Check"
    vlog "Checking if the pod is up and running"
    # Loop untill we can make sure the pod ybinst-i0-0 is up and running
    while [ "$RESTART" = true ]; do
        # Check if the status of each container in the pod
        READY_STATUS=$(docker exec $NODE_NAME k0s kubectl get pod $POD_NAME -n $NAMESPACE -o custom-columns="READY:.status.containerStatuses[*].ready" --no-headers)
        vlog "Running status of each container = $READY_STATUS"
        # Count the number of "true" values in the READY_STATUS to get the number of running containers
        RUNNING_CONTAINERS=$(echo $READY_STATUS | grep -o "true" | wc -l | xargs)
        # Check if the status is "Running"
        if [ "$RUNNING_CONTAINERS" = "3" ]; then
            break
        else
            vlog "Pod $POD_NAME is not fully running. Waiting..."
        fi
        sleep 10
    done
    vlog "Pod $POD_NAME is running."
    # Export the kubeconfig to allow local access for the pods
    docker exec $NODE_NAME cat /var/lib/k0s/pki/admin.conf > ybd_ce_config
    if [[ "$OSTYPE" == "darwin"* ]]; then
        sed -i '' 's|localhost:6443|localhost:7443|g' ybd_ce_config
    else
        sed -i 's|localhost:6443|localhost:7443|g' ybd_ce_config
    fi

    chmod 0600 ybd_ce_config
    vlog "kubeconfig is saved as ybd_ce_config"
    echo "Executing Step 4/4: Service and Cluster Check"
    vlog "------Checking if the Service is Up. This will take a few minutes initially------"
    if [ "$VERBOSE" == true ]; then
        docker exec $NODE_NAME /opt/community_edition/check_service.sh -v
        vlog "------YBD service is up. Configuring the worker------"
        docker exec $NODE_NAME /opt/community_edition/check_cluster_availability.sh -v
    else
        (docker exec $NODE_NAME /opt/community_edition/check_service.sh) &
        pid=$!
        show_progress 0 $pid
        wait $pid
        vlog "------YBD service is up. Configuring the worker------"
        docker exec $NODE_NAME /opt/community_edition/check_cluster_availability.sh
    fi
    echo ""
    echo "The Cluster is up and running with the following settings:"
    echo ""
    get_password
    echo ""
    ybdce_get_diags ybdce_install_diags
    docker cp $NODE_NAME:/opt/community_edition/ybdce-diags.txt temp_1.txt && cat temp_1.txt >> ybdce-diags.txt && rm -f temp_1.txt
}

# Function to get the password from the logs
get_password() {
    logs=$(docker logs ybd-ce 2>&1)

    # URL and link text
    URL="https://localhost:8443/"
    LINK_TEXT="Yellowbrick UI:"
    # Print Markdown link
    echo "$LINK_TEXT ($URL)"

   # Echo the username for the instance
    echo "Username    : 'ybdadmin'"

    # Filter the logs for the desired string
    password=$(echo "$logs" | grep "YB instance generated password:")
    echo "Password    : $password"
}

# Function to display a warning message
display_warning() {
    echo "Warning: This would delete Docker volumes: $VOLUME_NAME $VOLUME_NAME_RFS $VOLUME_NAME_LFS $VOLUME_NAME_LFS_ALT"
}
# Function to display a warning message
delete_container() {
    echo "Deleting Docker container: $NODE_NAME"
    docker rm -f $NODE_NAME
    rm -f ybd_ce_config
}
# Function to delete the Docker volume
delete_volume() {
    echo "Deleting Docker volume: $VOLUME_NAME"
    docker volume rm -f $VOLUME_NAME $VOLUME_NAME_RFS $VOLUME_NAME_LFS $VOLUME_NAME_LFS_ALT
}

ybdce_stop(){
    # stopping the container
    docker stop $NODE_NAME
    # Check if any argument is passed
    if [ "$#" -eq 1 ]; then
        case $1 in
            -f|--full-clean)
                display_warning
                delete_container
                delete_volume
                ;;
            -r|--remove-container)
                delete_container
                ;;
            -h|--help)
                ybdce_stop_usage
                exit 0
                ;;
            *)
                echo "Invalid option: $1"
                ybdce_stop_usage
                exit 1
                ;;
        esac
    else
        echo "Not deleting the container."
        echo "Not deleting the volumes."
    fi
}

ybdce_upgrade(){
    vlog "Running upgrade script"
    UPGRADE_MODE=true
    ybdce_start
    ybdce_get_diags ybdce_upgrade_diags
    docker cp $NODE_NAME:/opt/community_edition/ybdce-diags.txt temp_1.txt && cat temp_1.txt >> ybdce-diags.txt && rm -f temp_1.txt
}

ybdce_get_diags(){
    diags_name=$1
    local timestamp=$(date '+%Y-%m-%d_%H-%M-%S')
    echo "Creating full diagnostics"
    docker logs -t $NODE_NAME >> ${diags_name}-${timestamp}.txt 2>&1
    echo "The diags are stored in the current directory with the name '${diags_name}-${timestamp}.txt'"
}

# Main function call logic
ACTION=$1
shift || true
case $ACTION in
    diags)
        ybdce_get_diags ybdce_diags
        exit 0
        ;;
    start)
        for arg in "$@"; do
            case $arg in
                --help)
                    ybdce_start_usage
                    exit 0
                    ;;
            esac
        done
        while getopts ":d:i:p:hv" opt; do
            case ${opt} in
                d)
                    DOCKER_ON_MAC="$OPTARG"
                    ;;
                i)
                    IMAGE_NAME="$OPTARG"
                    ;;
                h)
                    ybdce_start_usage
                    exit 0
                    ;;
                p)
                    PASSWORD="$OPTARG"
                    ;;
                v)
                    VERBOSE=true
                    ;;
                :)
                    echo "Option -$OPTARG requires an argument." >&2
                    ybdce_start_usage
                    exit 0
                    ;;
                \?)
                    echo "Invalid option: -$OPTARG" >&2
                    ybdce_start_usage
                    exit 1
                    ;;
            esac
        done
        ybdce_start
        exit 0
        ;;
    stop)
        for arg in "$@"; do
            case $arg in
                --help)
                    ybdce_stop_usage
                    exit 0
                    ;;
                --full-clean)
                    ybdce_stop -f
                    exit 0
                    ;;
                --remove-container)
                    ybdce_stop -f
                    exit 0
                    ;;
            esac
        done
        while getopts ":frh" opt; do
            case ${opt} in
                f)
                    ybdce_stop -f
                    exit 0
                    ;;
                r)
                    ybdce_stop -r
                    exit 0
                    ;;
                h)
                    ybdce_stop_usage
                    exit 0
                    ;;
                :)
                    echo "Option -$OPTARG requires an argument." >&2
                    ybdce_stop_usage
                    exit 1
                    ;;
                \?)
                    echo "Invalid option: -$OPTARG" >&2
                    ybdce_stop_usage
                    exit 1
                    ;;
            esac
        done
        ybdce_stop
        exit 0
        ;;
    upgrade)
        for arg in "$@"; do
            case $arg in
                --help)
                    ybdce_upgrade_usage
                    exit 0
                    ;;
            esac
        done
        while getopts ":d:i:hv" opt; do
            case ${opt} in
                d)
                    DOCKER_ON_MAC="$OPTARG"
                    ;;
                i)
                    IMAGE_NAME="$OPTARG"
                    ;;
                h)
                    ybdce_upgrade_usage
                    exit 0
                    ;;
                v)
                    VERBOSE=true
                    ;;
                :)
                    echo "Option -$OPTARG requires an argument." >&2
                    ybdce_upgrade_usage
                    exit 0
                    ;;
                \?)
                    echo "Invalid option: -$OPTARG" >&2
                    ybdce_upgrade_usage
                    exit 1
                    ;;
            esac
        done
        ybdce_upgrade
        exit 0
        ;;
    logs)
        for arg in "$@"; do
            case $arg in
                --help)
                    ybdce_logs_usage
                    exit 0
                    ;;
            esac
        done
        while getopts ":n:" opt; do
            case ${opt} in
                n)
                    NAME="$OPTARG"
                    ;;
                \?)
                    echo "Invalid option: -$OPTARG" >&2
                    ybdce_logs_usage
                    exit 1
                    ;;
            esac
        done
        if ! docker container inspect ybd-ce &>/dev/null; then
            echo "YBD CE doesn't exist. Use `$0 start` to start." >&2
        fi
        NAME=${NAME:-$(date +%Y%m%d%H%M%S%3N)}
        docker exec ybd-ce bash /collect_logs.sh -o /tmp -p -n $NAME && docker cp ybd-ce:/tmp/ybdce-logs-$NAME.tgz ./
        echo "ybdce-logs-$NAME.tgz is created."
        exit 0
        ;;
    config)
    get_password
    exit 0
    ;;
    help|-h|--help)
        ybdce_usage
        exit 0
        ;;
    "")
        ybdce_usage
        exit 0
        ;;
    *)
        echo "Unsupported action. '$ACTION'"
        exit 1
        ;;
esac

If you encounter issues with the formatting of the ./ybdce script, you can convert it to an acceptable format and then re-run it as follows:

sudo apt-get install dos2unix
dos2unix ./ybdce

Instructions for YBDCE script

The CE image can be pulled automatically for your OS, so there is no need to provide images explicitly. However, if you want to work with a specific image, you can pass it as an option with -i.

The Community Edition Images can be found at the yellowbrickdata dockerhub page.

Access all available commands for ybdce by running the following command:

% ./ybdce
Usage: ./ybdce [COMMAND] [OPTIONS]
COMMAND:
      start                   Start ybd ce.
      stop                    Stop ybd ce.
      upgrade                 Upgrade ybd ce.
      help                    Display this help message.

To start CE and install the container, use the following command:

% ./ybdce start -h
Usage: ./ybdce start [-d true|false] [-i image_name] [-v] [-h|--help]
Options:
  -d          Set Docker on Mac to true or false
  -i          Specify the image name
  -v          Enable verbose mode
  -h, --help  Display this help message and exit

For example, to start a simple CE installation, use the following command:

./ybdce start

You do not need to explicitely pass the -d option as the script auto detects the OS and sets the -d value accordingly. By default, -d is set to off.

The start script performs the following tasks:

  1. Creates volumes, sets up the pods, and the ybd-ce container.

  2. Auto detects the available memory and switches between a medium-v1 and a large-v1 configuration with appropriate WLM Resource Pools. The switch occurs at 16GB of memory.

  3. Checks if the service endpoint is up.

  4. Ensures that the cluster is running.

  5. Outputs the password for the UI, which can be accessed at localhost:8443 with the username ybadmin.

Note: Other options supported for the start script are stop and upgrade. Their syntax and usage can be found by running:

./ybdce stop -h or ./ybdce upgrade -h

To monitor the state of kubernetes cluster being spun up in the backend, you can use K9S with the following command:

k9s --kubeconfig ./ybd_ce_config

You can access YBSQL using the following command or by using the tools container and pointing it to the CE instance running on your machine by passing -h localhost

docker exec -it ybd-ce k0s kubectl exec -it -n ybdcens ybinst-i0-0 -c ybinst-pg -- ybsql yellowbrick

The instructions for using the tools container can be found on the YBTools Docker Installation Page.

You can also try using local LOAD TABLE by placing files in the local_data directory. A default location called default_mount_loc has been created for you to use.

For details on Advanced Docker Usage, click here.