From f4cd3b3e24daefb4e7c5d98a0e2335e6745b0bda Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Tue, 21 Oct 2025 12:36:49 +0200 Subject: [PATCH 01/17] Add apiserver port to firewalld --- src/rpm/postinstall.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpm/postinstall.sh b/src/rpm/postinstall.sh index 3dbcf0c1..221e27c1 100755 --- a/src/rpm/postinstall.sh +++ b/src/rpm/postinstall.sh @@ -40,6 +40,7 @@ dnf install -y firewalld systemd-resolved \ jq bash-completion firewall-offline-cmd --zone=trusted --add-source=10.42.0.0/16 firewall-offline-cmd --zone=trusted --add-source=169.254.169.1 +firewall-offline-cmd --zone=public --add-port=6443/tcp # With kindnet present: # - No need for openvswitch service which is enabled by default once MicroShift From b2d9b978733cd39745638f30d4ab1a552e7c507c Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Tue, 21 Oct 2025 14:59:17 +0200 Subject: [PATCH 02/17] Add firewall settings and sysctls for multinode --- src/rpm/postinstall.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/rpm/postinstall.sh b/src/rpm/postinstall.sh index 221e27c1..4dbcb0e8 100755 --- a/src/rpm/postinstall.sh +++ b/src/rpm/postinstall.sh @@ -40,7 +40,16 @@ dnf install -y firewalld systemd-resolved \ jq bash-completion firewall-offline-cmd --zone=trusted --add-source=10.42.0.0/16 firewall-offline-cmd --zone=trusted --add-source=169.254.169.1 +# Multinode clusters require connectivity on both apiserver and etcd firewall-offline-cmd --zone=public --add-port=6443/tcp +firewall-offline-cmd --zone=public --add-port=2379/tcp +firewall-offline-cmd --zone=public --add-port=2380/tcp + +# Configure limits for cAdvisor and kubelet +cat > /etc/sysctl.d/99-microshift.conf < Date: Mon, 27 Oct 2025 10:47:17 +0100 Subject: [PATCH 03/17] Add multinode builder gh workflow --- .github/actions/build/action.yaml | 21 +++++++++++++++------ .github/workflows/builders.yaml | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/.github/actions/build/action.yaml b/.github/actions/build/action.yaml index 81c5ed61..c2b6a733 100644 --- a/.github/actions/build/action.yaml +++ b/.github/actions/build/action.yaml @@ -30,6 +30,11 @@ inputs: required: false default: 0 type: integer + multinode: + description: Build and test the multinode container image + required: false + default: 0 + type: integer build: type: choice description: Types of artifacts to build @@ -80,6 +85,7 @@ runs: make_opts=() [ "${{ inputs.isolated-network }}" = "1" ] && make_opts+=("EMBED_CONTAINER_IMAGES=1") [ "${{ inputs.ovnk-networking }}" = "1" ] && make_opts+=("WITH_KINDNET=0") + [ "${{ inputs.multinode }}" = "1" ] && make_opts+=("WITH_MULTINODE=1") make image \ BOOTC_IMAGE_URL=${{ inputs.bootc-image-url }} \ @@ -111,12 +117,15 @@ runs: done fi - # Wait until the MicroShift service is ready and healthy - make run-ready - make run-healthy - - # Stop the MicroShift container - make stop + # Start-stop test with readiness check + if [ "${{ inputs.multinode }}" = "1" ]; then + make multinode-create + make multinode-delete + else + make run-ready + make run-healthy + make stop + fi # Uncomment this to enable tmate-debug on failure # - name: Pause and open tmate debug session diff --git a/.github/workflows/builders.yaml b/.github/workflows/builders.yaml index 98472be0..678a021f 100644 --- a/.github/workflows/builders.yaml +++ b/.github/workflows/builders.yaml @@ -115,3 +115,21 @@ jobs: isolated-network: 1 ovnk-networking: 1 build: bootc-image + + multinode-bootc: + runs-on: ubuntu-24.04 + steps: + - name: Check out MicroShift upstream repository + uses: actions/checkout@v4 + + - name: Detect OKD version tag + id: detect-okd-version + uses: ./.github/actions/okd-version + + - name: Run the build action + uses: ./.github/actions/build + with: + ushift-branch: main + okd-version-tag: ${{ steps.detect-okd-version.outputs.okd-version-tag }} + multinode: 1 + build: bootc-image From d702f38d1c8af66d07b892c318296d2de755668f Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Mon, 27 Oct 2025 18:10:56 +0100 Subject: [PATCH 04/17] Add cluster_manager.sh --- src/cluster_manager.sh | 391 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100755 src/cluster_manager.sh diff --git a/src/cluster_manager.sh b/src/cluster_manager.sh new file mode 100755 index 00000000..7bb9a89b --- /dev/null +++ b/src/cluster_manager.sh @@ -0,0 +1,391 @@ +#!/bin/bash +# MicroShift Cluster Manager +# Primitive functions for managing MicroShift clusters + +set -euo pipefail + +# Configuration - These variables can be overridden by the environment +# They are used throughout the script for single-node and multi-node cluster management +USHIFT_MULTINODE_CLUSTER="${USHIFT_MULTINODE_CLUSTER:-microshift-okd-multinode}" +NODE_BASE_NAME="${NODE_BASE_NAME:-microshift-okd-}" +USHIFT_IMAGE="${USHIFT_IMAGE:-microshift-okd}" +LVM_DISK="${LVM_DISK:-/var/lib/microshift-okd/lvmdisk.image}" +LVM_VOLSIZE="${LVM_VOLSIZE:-1G}" +VG_NAME="${VG_NAME:-vg-${USHIFT_MULTINODE_CLUSTER}}" +ISOLATED_NETWORK="${ISOLATED_NETWORK:-0}" + +_is_cluster_created() { + if sudo podman container exists "${NODE_BASE_NAME}1"; then + return 0 + fi + return 1 +} + +_is_container_created() { + local -r name="${1}" + if sudo podman container exists "${name}"; then + return 0 + fi + return 1 +} + +_create_topolvm_backend() { + if [ -f "${LVM_DISK}" ]; then + echo "INFO: '${LVM_DISK}' exists, reusing" + return 0 + fi + + sudo mkdir -p "$(dirname "${LVM_DISK}")" + sudo truncate --size="${LVM_VOLSIZE}" "${LVM_DISK}" + local -r device_name="$(sudo losetup --find --show --nooverlap "${LVM_DISK}")" + sudo vgcreate -f -y "${VG_NAME}" "${device_name}" +} + +# Delete TopoLVM backend +_delete_topolvm_backend() { + if [ -f "${LVM_DISK}" ]; then + echo "Deleting TopoLVM backend: ${LVM_DISK}" + sudo lvremove -y "${VG_NAME}" || true + sudo vgremove -y "${VG_NAME}" || true + local -r device_name="$(sudo losetup -j "${LVM_DISK}" | cut -d: -f1)" + [ -n "${device_name}" ] && sudo losetup -d "${device_name}" || true + sudo rm -rf "$(dirname "${LVM_DISK}")" + fi +} + +_create_podman_network() { + local -r name="${1}" + if ! sudo podman network exists "${name}"; then + echo "Creating podman network: ${name}" + sudo podman network create "${name}" + else + echo "Podman network '${name}' already exists" + fi +} + +_get_subnet() { + local -r network_name="${1}" + local -r subnet_with_mask=$(sudo podman network inspect "${network_name}" --format '{{range .}}{{range .Subnets}}{{.Subnet}}{{end}}{{end}}') + if [ -z "$subnet_with_mask" ]; then + echo "ERROR: Could not determine subnet for network '${network_name}'." >&2 + exit 1 + fi + local -r subnet="${subnet_with_mask%%/*}" + echo "$subnet" +} + +_get_ip_address() { + local -r subnet="${1}" + local -r node_id="${2}" + echo "$subnet" | awk -F. -v new="$node_id" 'NF==4{$4=new+10; printf "%s.%s.%s.%s", $1,$2,$3,$4} NF!=4{print $0}' +} + +_add_node() { + local -r name="${1}" + local -r network_name="${2}" + local -r ip_address="${3}" + + local vol_opts="--tty --volume /dev:/dev" + for device in input snd dri; do + [ -d "/dev/${device}" ] && vol_opts="${vol_opts} --tmpfs /dev/${device}" + done + + local network_opts="--network ${network_name}" + if [ "${ISOLATED_NETWORK}" = "0" ]; then + network_opts="${network_opts} --ip ${ip_address}" + fi + + # shellcheck disable=SC2086 + sudo podman run --privileged -d \ + --ulimit nofile=524288:524288 \ + ${vol_opts} \ + ${network_opts} \ + --tmpfs /var/lib/containers \ + --name "${name}" \ + --hostname "${name}" \ + "${USHIFT_IMAGE}" + + return $? +} + + +_join_node() { + local -r name="${1}" + local -r primary_name="${NODE_BASE_NAME}1" + local -r src_kubeconfig="/var/lib/microshift/resources/kubeadmin/${primary_name}/kubeconfig" + local -r tmp_kubeconfig="/tmp/kubeconfig.${primary_name}" + + sudo podman cp "${primary_name}:${src_kubeconfig}" "${tmp_kubeconfig}" + local -r dest_kubeconfig="kubeconfig" + sudo podman cp "${tmp_kubeconfig}" "${name}:${dest_kubeconfig}" + sudo rm -f "${tmp_kubeconfig}" + + sudo podman exec -i "${name}" bash -c "\ + systemctl stop microshift kubepods.slice crio && \ + microshift add-node --kubeconfig=${dest_kubeconfig} --learner=false > add-node.log 2>&1" + + return $? +} + + +_wait_node_ready() { + local -r name="${1}" + for _ in $(seq 100); do + state=$(sudo podman exec -i "${name}" systemctl show --property=SubState --value greenboot-healthcheck 2>/dev/null || echo "unknown") + if [ "${state}" = "exited" ]; then + return 0 + fi + sleep 5 + done + return 1 +} + + +_get_cluster_containers() { + sudo podman ps -a --format '{{.Names}}' | grep -E "^${NODE_BASE_NAME}[0-9]+$" || true +} + + +_get_running_containers() { + sudo podman ps --format '{{.Names}}' | grep -E "^${NODE_BASE_NAME}[0-9]+$" || true +} + + +cluster_create() { + local -r container_name="${NODE_BASE_NAME}1" + echo "Creating cluster: ${container_name}" + + if _is_container_created "${container_name}"; then + echo "ERROR: Container '${container_name}' already exists" >&2 + exit 1 + fi + + sudo modprobe openvswitch || true + _create_topolvm_backend + _create_podman_network "${USHIFT_MULTINODE_CLUSTER}" + + local -r subnet=$(_get_subnet "${USHIFT_MULTINODE_CLUSTER}") + local network_name="${USHIFT_MULTINODE_CLUSTER}" + if [ "${ISOLATED_NETWORK}" = "1" ]; then + network_name="none" + fi + + local -r node_name="${NODE_BASE_NAME}1" + local -r ip_address=$(_get_ip_address "$subnet" "1") + if ! _add_node "${node_name}" "${network_name}" "${ip_address}"; then + echo "ERROR: failed to create node: $node_name" >&2 + exit 1 + fi + + if [ "${ISOLATED_NETWORK}" = "1" ] ; then \ + echo "Configuring isolated network for node: ${node_name}" + sudo podman cp ./src/config_isolated_net.sh "${node_name}:/tmp/config_isolated_net.sh" && \ + sudo podman exec -i "${node_name}" /tmp/config_isolated_net.sh && \ + sudo podman exec -i "${node_name}" rm -vf /tmp/config_isolated_net.sh ; \ + fi + + echo "Cluster created successfully" +} + + +cluster_add_node() { + if ! _is_cluster_created; then + echo "ERROR: Cluster is not created" >&2 + exit 1 + fi + if [ "${ISOLATED_NETWORK}" = "1" ]; then + echo "ERROR: Network type is isolated" >&2 + exit 1 + fi + + local last_id=0 + + for node in $(_get_cluster_containers); do + node_num="${node##*"${NODE_BASE_NAME}"}" + if [[ "${node_num}" =~ ^[0-9]+$ ]] && [ "${node_num}" -gt "${last_id}" ]; then + last_id="${node_num}" + fi + done + + local -r subnet=$(_get_subnet "${USHIFT_MULTINODE_CLUSTER}") + local -r node_id=$((last_id + 1)) + local -r node_name="${NODE_BASE_NAME}${node_id}" + local -r ip_address=$(_get_ip_address "$subnet" "$node_id") + + cluster_healthy + + echo "Creating node: ${node_name}" + if ! _add_node "${node_name}" "${USHIFT_MULTINODE_CLUSTER}" "${ip_address}"; then + echo "ERROR: failed to create node: ${node_name}" >&2 + exit 1 + fi + echo "Joining node to the cluster: ${node_name}" + if ! _join_node "${node_name}"; then + echo "ERROR: failed to join node to the cluster: ${node_name}. Check logs with 'sudo podman exec ${node_name} cat add-node.log'" >&2 + exit 1 + fi + + echo "Node added successfully" + return 0 +} + + +cluster_start() { + local -r containers=$(_get_cluster_containers) + + if [ -z "${containers}" ]; then + echo "ERROR: No cluster containers found" >&2 + exit 1 + fi + + echo "Starting cluster" + for container in ${containers}; do + echo "Starting container: ${container}" + sudo podman start "${container}" || true + done +} + + +cluster_stop() { + local -r containers=$(_get_running_containers) + + if [ -z "${containers}" ]; then + echo "No running cluster containers" + return 0 + fi + + echo "Stopping cluster" + for container in ${containers}; do + echo "Stopping container: ${container}" + sudo podman stop --time 0 "${container}" || true + done +} + + +cluster_destroy() { + local containers + containers=$(_get_cluster_containers) + for container in ${containers}; do + echo "Stopping container: ${container}" + sudo podman stop --time 0 "${container}" || true + echo "Removing container: ${container}" + sudo podman rm -f "${container}" || true + done + + if sudo podman network exists "${USHIFT_MULTINODE_CLUSTER}"; then + echo "Removing podman network: ${USHIFT_MULTINODE_CLUSTER}" + sudo podman network rm "${USHIFT_MULTINODE_CLUSTER}" || true + fi + + sudo rmmod openvswitch || true + _delete_topolvm_backend + + echo "Cluster destroyed successfully" +} + + +cluster_ready() { + local -r containers=$(_get_running_containers) + if [ -z "${containers}" ]; then + echo "No running nodes found" + exit 1 + fi + for container in ${containers}; do + echo "Checking readiness of container: ${container}" + state=$(sudo podman exec -i "${container}" systemctl show --property=SubState --value microshift.service 2>/dev/null || echo "unknown") + if [ "${state}" != "running" ]; then + echo "Node ${container} is not ready." + exit 1 + fi + done + echo "All nodes running." +} + +cluster_healthy() { + local -r containers=$(_get_running_containers) + for container in ${containers}; do + echo "Checking health of container: ${container}" + state=$(sudo podman exec -i "${container}" systemctl show --property=SubState --value greenboot-healthcheck 2>/dev/null || echo "unknown") + if [ "${state}" != "exited" ]; then + echo "Node ${container} is not healthy." + exit 1 + fi + done + echo "All nodes healthy." +} + + +cluster_status() { + if ! _is_cluster_created && ! _container_exists "${USHIFT_IMAGE}"; then + echo "Cluster is not initialized" + exit 1 + fi + + local -r running_containers=$(_get_running_containers) + + if [ -z "${running_containers}" ]; then + echo "Cluster is down. No cluster nodes are running." + return 0 + fi + + local -r created_containers=$(_get_cluster_containers) + for container in ${created_containers}; do + if ! echo "${running_containers}" | grep -q "${container}"; then + echo "Node ${container} is not running." + fi + done + + local -r first_container=$(echo "${running_containers}" | head -n1) + echo "Cluster is running." + sudo podman exec -i "${first_container}" oc --kubeconfig=/var/lib/microshift/resources/kubeadmin/kubeconfig get nodes,pods -A -o wide 2>/dev/null || echo "Unable to retrieve cluster status" + return 0 +} + +main() { + case "${1:-}" in + create) + shift + cluster_create + ;; + add-node) + shift + cluster_add_node + ;; + start) + shift + cluster_start + ;; + stop) + shift + cluster_stop + ;; + delete) + shift + cluster_destroy + ;; + ready) + shift + cluster_ready + ;; + healthy) + shift + cluster_healthy + ;; + status) + shift + cluster_status + ;; + *) + echo "Usage: $0 {create|add-node|start|stop|delete|ready|healthy|status}" + exit 1 + ;; + esac +} + +# Ensure script is running from project root directory (where Makefile exists) +if [ ! -f "./Makefile" ]; then + echo "ERROR: Please run this script from the project root directory (where Makefile is located)" >&2 + exit 1 +fi + +main "$@" From a1f09a4491f0ea927d06d1b3ee56c9581bcfea57 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Tue, 28 Oct 2025 12:25:07 +0100 Subject: [PATCH 05/17] Use cluster_manager.sh in Makefile targets --- Makefile | 64 +++++++++++++++++++++----------------------------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index cd1952b0..eb9e83ac 100644 --- a/Makefile +++ b/Makefile @@ -105,36 +105,32 @@ image: # which is less efficient than the default driver .PHONY: run run: - @echo "Running the MicroShift container" - sudo modprobe openvswitch - $(MAKE) _topolvm_create + @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh create - NETWORK_OPTS="" ; \ - if [ "${ISOLATED_NETWORK}" = "1" ] ; then \ - NETWORK_OPTS="--network none" ; \ - fi ; \ - VOL_OPTS="--tty --volume /dev:/dev" ; \ - for device in input snd dri; do \ - [ -d "/dev/$${device}" ] && VOL_OPTS="$${VOL_OPTS} --tmpfs /dev/$${device}" ; \ - done ; \ - sudo podman run --privileged --rm -d \ - --replace \ - $${NETWORK_OPTS} \ - $${VOL_OPTS} \ - --tmpfs /var/lib/containers \ - --name "${USHIFT_IMAGE}" \ - --hostname 127.0.0.1.nip.io \ - "${USHIFT_IMAGE}" ; \ - $(MAKE) _isolated_network_config +.PHONY: add-node +add-node: + @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh add-node + +.PHONY: start +start: + @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh start + +.PHONY: stop +stop: + @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh stop + +.PHONY: delete +delete: + @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh delete .PHONY: run-ready run-ready: @echo "Waiting 5m for the MicroShift service to be ready" @for _ in $$(seq 60); do \ - if sudo podman exec -i "${USHIFT_IMAGE}" systemctl -q is-active microshift.service ; then \ + if USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh ready ; then \ printf "\nOK\n" && exit 0; \ fi ; \ - echo -n "." && sleep 5 ; \ + sleep 5 ; \ done ; \ printf "\nFAILED\n" && exit 1 @@ -142,31 +138,19 @@ run-ready: run-healthy: @echo "Waiting 15m for the MicroShift service to be healthy" @for _ in $$(seq 60); do \ - state=$$(sudo podman exec -i "${USHIFT_IMAGE}" systemctl show --property=SubState --value greenboot-healthcheck) ; \ - if [ "$${state}" = "exited" ] ; then \ + if USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh healthy ; then \ printf "\nOK\n" && exit 0; \ fi ; \ - echo -n "." && sleep 15 ; \ + sleep 5 ; \ done ; \ - printf "\nThe state of the greenboot-healthcheck service is '$${state}'" && \ printf "\nFAILED\n" && exit 1 -.PHONY: login -login: - @echo "Logging into the MicroShift container" - sudo podman exec -it "${USHIFT_IMAGE}" bash -l - -.PHONY: stop -stop: - @echo "Stopping the MicroShift container" - sudo podman stop --time 0 "${USHIFT_IMAGE}" || true +.PHONY: run-status +run-status: + @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh status .PHONY: clean -clean: - @echo "Cleaning up the MicroShift container and the TopoLVM CSI backend" - $(MAKE) stop - sudo rmmod openvswitch || true - $(MAKE) _topolvm_delete +clean: delete .PHONY: clean-all clean-all: From 8be57393d461226f9094bb3fd897cf54a0aeb2e1 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Tue, 28 Oct 2025 12:27:40 +0100 Subject: [PATCH 06/17] Update workflow to support multinode --- .github/actions/build/action.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/actions/build/action.yaml b/.github/actions/build/action.yaml index c2b6a733..0ea47387 100644 --- a/.github/actions/build/action.yaml +++ b/.github/actions/build/action.yaml @@ -118,14 +118,12 @@ runs: fi # Start-stop test with readiness check + make run-ready if [ "${{ inputs.multinode }}" = "1" ]; then - make multinode-create - make multinode-delete - else - make run-ready - make run-healthy - make stop + make add-node fi + make run-healthy + make stop # Uncomment this to enable tmate-debug on failure # - name: Pause and open tmate debug session From 6e42be40ba8fd57d724a7cb3d7a9bae11710c5a3 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Tue, 28 Oct 2025 16:13:42 +0100 Subject: [PATCH 07/17] Update build action to support multinode --- .github/actions/build/action.yaml | 8 ++++---- .github/workflows/builders.yaml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/build/action.yaml b/.github/actions/build/action.yaml index 0ea47387..79de52ae 100644 --- a/.github/actions/build/action.yaml +++ b/.github/actions/build/action.yaml @@ -30,8 +30,8 @@ inputs: required: false default: 0 type: integer - multinode: - description: Build and test the multinode container image + multi-node: + description: Include a second node in the test cluster required: false default: 0 type: integer @@ -85,7 +85,6 @@ runs: make_opts=() [ "${{ inputs.isolated-network }}" = "1" ] && make_opts+=("EMBED_CONTAINER_IMAGES=1") [ "${{ inputs.ovnk-networking }}" = "1" ] && make_opts+=("WITH_KINDNET=0") - [ "${{ inputs.multinode }}" = "1" ] && make_opts+=("WITH_MULTINODE=1") make image \ BOOTC_IMAGE_URL=${{ inputs.bootc-image-url }} \ @@ -119,7 +118,8 @@ runs: # Start-stop test with readiness check make run-ready - if [ "${{ inputs.multinode }}" = "1" ]; then + make run-healthy + if [ "${{ inputs.multi-node }}" = "1" ]; then make add-node fi make run-healthy diff --git a/.github/workflows/builders.yaml b/.github/workflows/builders.yaml index 678a021f..6816b6b5 100644 --- a/.github/workflows/builders.yaml +++ b/.github/workflows/builders.yaml @@ -116,7 +116,7 @@ jobs: ovnk-networking: 1 build: bootc-image - multinode-bootc: + multi-node-bootc: runs-on: ubuntu-24.04 steps: - name: Check out MicroShift upstream repository @@ -131,5 +131,5 @@ jobs: with: ushift-branch: main okd-version-tag: ${{ steps.detect-okd-version.outputs.okd-version-tag }} - multinode: 1 + multi-node: 1 build: bootc-image From f53eca669ebccff31d00b9ecb499f43ae0baab81 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Tue, 28 Oct 2025 16:33:16 +0100 Subject: [PATCH 08/17] Update quickstart action --- .github/actions/quick-start-clean/action.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/actions/quick-start-clean/action.yaml b/.github/actions/quick-start-clean/action.yaml index 49e25237..627e665f 100644 --- a/.github/actions/quick-start-clean/action.yaml +++ b/.github/actions/quick-start-clean/action.yaml @@ -18,8 +18,14 @@ runs: sudo IMAGE_REF=${{ inputs.image-ref }} bash -xeuo pipefail < ./src/quickstart.sh # Wait until the MicroShift service is ready and healthy - make run-ready - make run-healthy + for _ in $(seq 100); do + state=$(sudo podman exec -i microshift-okd systemctl show --property=SubState --value greenboot-healthcheck 2>/dev/null || echo "unknown") + if [ "${state}" = "exited" ]; then + exit 0 + fi + sleep 10 + done + exit 1 - name: Run the quick clean script shell: bash From a0b32fba08fcdf58862176935891948570ef74eb Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Tue, 28 Oct 2025 17:59:30 +0100 Subject: [PATCH 09/17] Clean up Makefiles unused targets --- Makefile | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/Makefile b/Makefile index eb9e83ac..ce31574d 100644 --- a/Makefile +++ b/Makefile @@ -165,15 +165,6 @@ check: _hadolint _shellcheck # # Define the private targets # -# The configurations for the isolated network are done inside the container -.PHONY: _isolated_network_config -_isolated_network_config: - if [ "${ISOLATED_NETWORK}" = "1" ] ; then \ - sudo podman cp ./src/config_isolated_net.sh "${USHIFT_IMAGE}:/tmp/config_isolated_net.sh" && \ - sudo podman exec -i "${USHIFT_IMAGE}" /tmp/config_isolated_net.sh && \ - sudo podman exec -i "${USHIFT_IMAGE}" rm -vf /tmp/config_isolated_net.sh ; \ - fi - .PHONY: _topolvm_create _topolvm_create: if [ ! -f "${LVM_DISK}" ] ; then \ @@ -184,16 +175,7 @@ _topolvm_create: sudo vgcreate -f -y "${VG_NAME}" "$${DEVICE_NAME}" ; \ fi -.PHONY: _topolvm_delete -_topolvm_delete: - if [ -f "${LVM_DISK}" ] ; then \ - echo "Deleting the TopoLVM CSI backend" ; \ - sudo lvremove -y "${VG_NAME}" || true ; \ - sudo vgremove -y "${VG_NAME}" || true ; \ - DEVICE_NAME="$$(sudo losetup -j "${LVM_DISK}" | cut -d: -f1)" ; \ - [ -n "$${DEVICE_NAME}" ] && sudo losetup -d $${DEVICE_NAME} || true ; \ - sudo rm -rf "$$(dirname "${LVM_DISK}")" ; \ - fi + # When run inside a container, the file contents are redirected via stdin and # the output of errors does not contain the file path. Work around this issue From e53a8acdc4fe0d31a9ec43b105141eb78aaa1f99 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Tue, 28 Oct 2025 18:04:08 +0100 Subject: [PATCH 10/17] Nits --- src/cluster_manager.sh | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/cluster_manager.sh b/src/cluster_manager.sh index 7bb9a89b..e86f62e6 100755 --- a/src/cluster_manager.sh +++ b/src/cluster_manager.sh @@ -128,19 +128,6 @@ _join_node() { } -_wait_node_ready() { - local -r name="${1}" - for _ in $(seq 100); do - state=$(sudo podman exec -i "${name}" systemctl show --property=SubState --value greenboot-healthcheck 2>/dev/null || echo "unknown") - if [ "${state}" = "exited" ]; then - return 0 - fi - sleep 5 - done - return 1 -} - - _get_cluster_containers() { sudo podman ps -a --format '{{.Names}}' | grep -E "^${NODE_BASE_NAME}[0-9]+$" || true } @@ -177,12 +164,12 @@ cluster_create() { exit 1 fi - if [ "${ISOLATED_NETWORK}" = "1" ] ; then \ + if [ "${ISOLATED_NETWORK}" = "1" ] ; then echo "Configuring isolated network for node: ${node_name}" - sudo podman cp ./src/config_isolated_net.sh "${node_name}:/tmp/config_isolated_net.sh" && \ - sudo podman exec -i "${node_name}" /tmp/config_isolated_net.sh && \ - sudo podman exec -i "${node_name}" rm -vf /tmp/config_isolated_net.sh ; \ - fi + sudo podman cp ./src/config_isolated_net.sh "${node_name}:/tmp/config_isolated_net.sh" + sudo podman exec -i "${node_name}" /tmp/config_isolated_net.sh + sudo podman exec -i "${node_name}" rm -vf /tmp/config_isolated_net.sh + fi echo "Cluster created successfully" } @@ -302,7 +289,18 @@ cluster_ready() { } cluster_healthy() { + if ! _is_cluster_created ; then + echo "Cluster is not initialized" + exit 1 + fi + local -r containers=$(_get_running_containers) + + if [ -z "${containers}" ]; then + echo "Cluster is down. No cluster nodes are running." + return 0 + fi + for container in ${containers}; do echo "Checking health of container: ${container}" state=$(sudo podman exec -i "${container}" systemctl show --property=SubState --value greenboot-healthcheck 2>/dev/null || echo "unknown") @@ -316,7 +314,7 @@ cluster_healthy() { cluster_status() { - if ! _is_cluster_created && ! _container_exists "${USHIFT_IMAGE}"; then + if ! _is_cluster_created ; then echo "Cluster is not initialized" exit 1 fi From f30c6e398ecfce06dcd6c470460f2554c84e69a3 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Wed, 29 Oct 2025 09:05:21 +0100 Subject: [PATCH 11/17] Add debug logging to cluster manager --- src/cluster_manager.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/cluster_manager.sh b/src/cluster_manager.sh index e86f62e6..f4479553 100755 --- a/src/cluster_manager.sh +++ b/src/cluster_manager.sh @@ -171,7 +171,8 @@ cluster_create() { sudo podman exec -i "${node_name}" rm -vf /tmp/config_isolated_net.sh fi - echo "Cluster created successfully" + echo "Cluster created successfully. To access the node container, run:" + echo " sudo podman exec -it ${node_name} /bin/bash" } @@ -208,11 +209,18 @@ cluster_add_node() { fi echo "Joining node to the cluster: ${node_name}" if ! _join_node "${node_name}"; then - echo "ERROR: failed to join node to the cluster: ${node_name}. Check logs with 'sudo podman exec ${node_name} cat add-node.log'" >&2 + echo "ERROR: failed to join node to the cluster: ${node_name}" >&2 + echo "=== Add-node log content ===" >&2 + if sudo podman exec -i "${node_name}" test -f add-node.log; then + sudo podman exec -i "${node_name}" cat add-node.log >&2 + else + echo "WARNING: add-node.log not found in ${node_name}" >&2 + fi exit 1 fi - echo "Node added successfully" + echo "Node added successfully. To access the new node container, run:" + echo " sudo podman exec -it ${node_name} /bin/bash" return 0 } From b71f43c3cbf1587069d2fdf35bc1e807c476cae9 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Wed, 29 Oct 2025 09:20:15 +0100 Subject: [PATCH 12/17] Remove delete target from Makefile --- Makefile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index ce31574d..75a1d2ba 100644 --- a/Makefile +++ b/Makefile @@ -119,10 +119,6 @@ start: stop: @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh stop -.PHONY: delete -delete: - @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh delete - .PHONY: run-ready run-ready: @echo "Waiting 5m for the MicroShift service to be ready" @@ -150,7 +146,8 @@ run-status: @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh status .PHONY: clean -clean: delete +clean: + @USHIFT_IMAGE=${USHIFT_IMAGE} ISOLATED_NETWORK=${ISOLATED_NETWORK} LVM_DISK=${LVM_DISK} LVM_VOLSIZE=${LVM_VOLSIZE} VG_NAME=${VG_NAME} ./src/cluster_manager.sh delete .PHONY: clean-all clean-all: From 70df340a426d9740221d188cc54a42075c4fee46 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Wed, 29 Oct 2025 09:40:48 +0100 Subject: [PATCH 13/17] Update makefile usage --- Makefile | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 75a1d2ba..4b0d5784 100644 --- a/Makefile +++ b/Makefile @@ -30,19 +30,21 @@ VG_NAME := myvg1 # .PHONY: all all: - @echo "make " + @echo "make " @echo " rpm: build the MicroShift RPMs" @echo " image: build the MicroShift bootc container image" - @echo " run: run the MicroShift bootc container" - @echo " login: login to the MicroShift bootc container" - @echo " stop: stop the MicroShift bootc container" - @echo " clean: clean up the MicroShift container and the LVM backend" + @echo " run: create and run a MicroShift cluster (1 node) in a bootc container" + @echo " add-node: add a new node to the MicroShift cluster in a bootc container" + @echo " start: start the MicroShift cluster that was already created" + @echo " stop: stop the MicroShift cluster" + @echo " clean: clean up the MicroShift cluster and the LVM backend" @echo " check: run the presubmit checks" @echo "" @echo "Sub-targets:" @echo " rpm-to-deb: convert the MicroShift RPMs to Debian packages" - @echo " run-ready: wait until the MicroShift service is ready" - @echo " run-healthy: wait until the MicroShift service is healthy" + @echo " run-ready: wait until the MicroShift service is ready across the cluster" + @echo " run-healthy: wait until the MicroShift service is healthy across the cluster" + @echo " run-status: show the status of the MicroShift cluster" @echo " clean-all: perform a full cleanup, including the container images" @echo "" From 2cf2fdd486c5eaa7b88019f5704d945feea07afe Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Wed, 29 Oct 2025 10:04:51 +0100 Subject: [PATCH 14/17] Add second node to most presubmits --- .github/actions/build/action.yaml | 12 +++++++----- .github/workflows/builders.yaml | 21 +++------------------ 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/.github/actions/build/action.yaml b/.github/actions/build/action.yaml index 79de52ae..70a697f7 100644 --- a/.github/actions/build/action.yaml +++ b/.github/actions/build/action.yaml @@ -30,10 +30,10 @@ inputs: required: false default: 0 type: integer - multi-node: - description: Include a second node in the test cluster + node-count: + description: Number of nodes in the MicroShift cluster required: false - default: 0 + default: 1 type: integer build: type: choice @@ -119,9 +119,11 @@ runs: # Start-stop test with readiness check make run-ready make run-healthy - if [ "${{ inputs.multi-node }}" = "1" ]; then + + for i in $(seq 2 ${{ inputs.node-count }}); do make add-node - fi + done + make run-healthy make stop diff --git a/.github/workflows/builders.yaml b/.github/workflows/builders.yaml index 6816b6b5..ae0660f7 100644 --- a/.github/workflows/builders.yaml +++ b/.github/workflows/builders.yaml @@ -23,6 +23,7 @@ jobs: bootc-image-url: quay.io/centos-bootc/centos-bootc bootc-image-tag: stream9 build: bootc-image + node-count: 2 centos10-bootc: runs-on: ubuntu-24.04 @@ -42,6 +43,7 @@ jobs: bootc-image-url: quay.io/centos-bootc/centos-bootc bootc-image-tag: stream10 build: bootc-image + node-count: 2 fedora-bootc: runs-on: ubuntu-24.04 @@ -61,6 +63,7 @@ jobs: bootc-image-url: registry.fedoraproject.org/fedora-bootc bootc-image-tag: latest build: bootc-image + node-count: 2 ubuntu-rpm2deb: runs-on: ubuntu-24.04 @@ -115,21 +118,3 @@ jobs: isolated-network: 1 ovnk-networking: 1 build: bootc-image - - multi-node-bootc: - runs-on: ubuntu-24.04 - steps: - - name: Check out MicroShift upstream repository - uses: actions/checkout@v4 - - - name: Detect OKD version tag - id: detect-okd-version - uses: ./.github/actions/okd-version - - - name: Run the build action - uses: ./.github/actions/build - with: - ushift-branch: main - okd-version-tag: ${{ steps.detect-okd-version.outputs.okd-version-tag }} - multi-node: 1 - build: bootc-image From d5ade0907605f9470db3d79069d1f71f08721ca7 Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Wed, 29 Oct 2025 10:39:59 +0100 Subject: [PATCH 15/17] Remove topolvm_create makefile target --- .github/actions/build-deb/action.yaml | 2 +- Makefile | 11 ----------- src/cluster_manager.sh | 18 +++++++++++++----- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/.github/actions/build-deb/action.yaml b/.github/actions/build-deb/action.yaml index 41376bce..fb5ef5c5 100644 --- a/.github/actions/build-deb/action.yaml +++ b/.github/actions/build-deb/action.yaml @@ -51,7 +51,7 @@ runs: - name: Start the MicroShift service shell: bash run: | - make _topolvm_create + ./src/cluster_manager.sh topolvm-create || exit 1 sudo systemctl start --no-block microshift.service - name: Run a test to verify that MicroShift is functioning properly diff --git a/Makefile b/Makefile index 4b0d5784..34d3e197 100644 --- a/Makefile +++ b/Makefile @@ -164,17 +164,6 @@ check: _hadolint _shellcheck # # Define the private targets # -.PHONY: _topolvm_create -_topolvm_create: - if [ ! -f "${LVM_DISK}" ] ; then \ - echo "Creating the TopoLVM CSI backend" ; \ - sudo mkdir -p "$$(dirname "${LVM_DISK}")" ; \ - sudo truncate --size="${LVM_VOLSIZE}" "${LVM_DISK}" ; \ - DEVICE_NAME="$$(sudo losetup --find --show --nooverlap "${LVM_DISK}")" && \ - sudo vgcreate -f -y "${VG_NAME}" "$${DEVICE_NAME}" ; \ - fi - - # When run inside a container, the file contents are redirected via stdin and # the output of errors does not contain the file path. Work around this issue diff --git a/src/cluster_manager.sh b/src/cluster_manager.sh index f4479553..620bc88f 100755 --- a/src/cluster_manager.sh +++ b/src/cluster_manager.sh @@ -29,7 +29,7 @@ _is_container_created() { return 1 } -_create_topolvm_backend() { +create_topolvm_backend() { if [ -f "${LVM_DISK}" ]; then echo "INFO: '${LVM_DISK}' exists, reusing" return 0 @@ -42,7 +42,7 @@ _create_topolvm_backend() { } # Delete TopoLVM backend -_delete_topolvm_backend() { +delete_topolvm_backend() { if [ -f "${LVM_DISK}" ]; then echo "Deleting TopoLVM backend: ${LVM_DISK}" sudo lvremove -y "${VG_NAME}" || true @@ -148,7 +148,7 @@ cluster_create() { fi sudo modprobe openvswitch || true - _create_topolvm_backend + create_topolvm_backend _create_podman_network "${USHIFT_MULTINODE_CLUSTER}" local -r subnet=$(_get_subnet "${USHIFT_MULTINODE_CLUSTER}") @@ -273,7 +273,7 @@ cluster_destroy() { fi sudo rmmod openvswitch || true - _delete_topolvm_backend + delete_topolvm_backend echo "Cluster destroyed successfully" } @@ -381,8 +381,16 @@ main() { shift cluster_status ;; + topolvm-create) + shift + create_topolvm_backend + ;; + topolvm-delete) + shift + delete_topolvm_backend + ;; *) - echo "Usage: $0 {create|add-node|start|stop|delete|ready|healthy|status}" + echo "Usage: $0 {create|add-node|start|stop|delete|ready|healthy|status|topolvm-create|topolvm-delete}" exit 1 ;; esac From 1a922679f29e3def2a0b220b2a9297627e6bcb9d Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Wed, 29 Oct 2025 13:53:13 +0100 Subject: [PATCH 16/17] Nits in cluster_manager.sh --- src/cluster_manager.sh | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/cluster_manager.sh b/src/cluster_manager.sh index 620bc88f..dd28cb18 100755 --- a/src/cluster_manager.sh +++ b/src/cluster_manager.sh @@ -1,6 +1,6 @@ #!/bin/bash # MicroShift Cluster Manager -# Primitive functions for managing MicroShift clusters +# Basic functions for managing MicroShift clusters set -euo pipefail @@ -11,7 +11,7 @@ NODE_BASE_NAME="${NODE_BASE_NAME:-microshift-okd-}" USHIFT_IMAGE="${USHIFT_IMAGE:-microshift-okd}" LVM_DISK="${LVM_DISK:-/var/lib/microshift-okd/lvmdisk.image}" LVM_VOLSIZE="${LVM_VOLSIZE:-1G}" -VG_NAME="${VG_NAME:-vg-${USHIFT_MULTINODE_CLUSTER}}" +VG_NAME="${VG_NAME:-myvg1}" ISOLATED_NETWORK="${ISOLATED_NETWORK:-0}" _is_cluster_created() { @@ -172,7 +172,7 @@ cluster_create() { fi echo "Cluster created successfully. To access the node container, run:" - echo " sudo podman exec -it ${node_name} /bin/bash" + echo " sudo podman exec -it ${node_name} /bin/bash -l" } @@ -186,15 +186,7 @@ cluster_add_node() { exit 1 fi - local last_id=0 - - for node in $(_get_cluster_containers); do - node_num="${node##*"${NODE_BASE_NAME}"}" - if [[ "${node_num}" =~ ^[0-9]+$ ]] && [ "${node_num}" -gt "${last_id}" ]; then - last_id="${node_num}" - fi - done - + local -r last_id=$(_get_cluster_containers | wc -l) local -r subnet=$(_get_subnet "${USHIFT_MULTINODE_CLUSTER}") local -r node_id=$((last_id + 1)) local -r node_name="${NODE_BASE_NAME}${node_id}" @@ -220,7 +212,7 @@ cluster_add_node() { fi echo "Node added successfully. To access the new node container, run:" - echo " sudo podman exec -it ${node_name} /bin/bash" + echo " sudo podman exec -it ${node_name} /bin/bash -l" return 0 } @@ -286,7 +278,7 @@ cluster_ready() { exit 1 fi for container in ${containers}; do - echo "Checking readiness of container: ${container}" + echo "Checking readiness of node: ${container}" state=$(sudo podman exec -i "${container}" systemctl show --property=SubState --value microshift.service 2>/dev/null || echo "unknown") if [ "${state}" != "running" ]; then echo "Node ${container} is not ready." @@ -306,11 +298,11 @@ cluster_healthy() { if [ -z "${containers}" ]; then echo "Cluster is down. No cluster nodes are running." - return 0 + exit 1 fi for container in ${containers}; do - echo "Checking health of container: ${container}" + echo "Checking health of node: ${container}" state=$(sudo podman exec -i "${container}" systemctl show --property=SubState --value greenboot-healthcheck 2>/dev/null || echo "unknown") if [ "${state}" != "exited" ]; then echo "Node ${container} is not healthy." @@ -343,7 +335,7 @@ cluster_status() { local -r first_container=$(echo "${running_containers}" | head -n1) echo "Cluster is running." - sudo podman exec -i "${first_container}" oc --kubeconfig=/var/lib/microshift/resources/kubeadmin/kubeconfig get nodes,pods -A -o wide 2>/dev/null || echo "Unable to retrieve cluster status" + sudo podman exec -i "${first_container}" oc get nodes,pods -A -o wide 2>/dev/null || echo "Unable to retrieve cluster status" return 0 } From 607c15a961f44391063b8a3bf8d3fcc7897be92a Mon Sep 17 00:00:00 2001 From: Pablo Acevedo Montserrat Date: Wed, 29 Oct 2025 15:46:05 +0100 Subject: [PATCH 17/17] Update run.md docs --- docs/run.md | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/docs/run.md b/docs/run.md index a832d306..26750161 100644 --- a/docs/run.md +++ b/docs/run.md @@ -98,14 +98,17 @@ The following options can be specified in the make command line using the `NAME= | Name | Required | Default | Comments |-------------------|----------|----------|--------- -| LVM_VOLUME_SIZE | no | 1G | TopoLVM CSI backend volume +| LVM_VOLSIZE | no | 1G | TopoLVM CSI backend volume | ISOLATED_NETWORK | no | 0 | Use `--network none` podman option +This step creates a single-node MicroShift cluster. The cluster can be extended using `make add-node` to add one node at a time. + This step includes: * Loading the `openvswitch` module required when OVN-K CNI driver is used when compiled with the non-default `WITH_KINDNET=0` image build option. -* Preparing a 1GB TopoLVM CSI backend on the host to be used by MicroShift when +* Preparing a TopoLVM CSI backend (default 1GB, configurable via `LVM_VOLSIZE`) on the host to be used by MicroShift when compiled with the default `WITH_TOPOLVM=1` image build option. +* Creating a podman network for easier multi-node cluster support with name resolution. ```bash make run @@ -124,20 +127,29 @@ make run ### Container Login -Log into the container by running the following command. +Log into the container by running the following command. The commands for doing so are displayed as +part of the summary from `make run` and `make add-node`. +For example, the first node in a cluster is named `microshift-okd-1`: ```bash -make login +sudo podman exec -it microshift-okd-1 /bin/bash -l ``` Verify that all the MicroShift services are up and running successfully. - ```bash export KUBECONFIG=/var/lib/microshift/resources/kubeadmin/kubeconfig oc get nodes oc get pods -A ``` +### Start the Container + +If you have stopped the MicroShift cluster, you can start it again using the following command. + +```bash +make start +``` + ### Stop the Container Run the following command to stop the MicroShift Bootc container. @@ -146,6 +158,31 @@ Run the following command to stop the MicroShift Bootc container. make stop ``` +### Add Node to Cluster + +To create a multi-node cluster, you can add additional nodes after creating the initial cluster with `make run`. + +```bash +make add-node +``` + +> Note: The `add-node` target requires a non-isolated network (`ISOLATED_NETWORK=0`). Each additional node will be automatically joined to the cluster. + +### Check Cluster Status + +Run the following commands to check the status of your MicroShift cluster. + +```bash +# Wait until the MicroShift service is ready (checks all nodes) +make run-ready + +# Wait until the MicroShift service is healthy (checks all nodes) +make run-healthy + +# Show current cluster status including nodes and pods +make run-status +``` + ## Cleanup ### RPM