This example package can be used as a starting point for creating projects with Microcluster. This package contains:
- A Microcluster daemon command (
microd) and a control command (microctl) - Examples for the built-in Microcluster API
- Examples of how Microcluster can be extended with additional listeners with user-defined endpoints and schema versions
- How to build and run the package
- Tutorial
-
Gomust be installed on your system.-
If snaps are available on your system, you can install Go by running:
sudo snap install go --classic -
If you cannot use snaps, follow the installation instructions from Go.dev.
-
-
Run the following commands to install the remaining required packages:
sudo apt-get update sudo apt-get install --no-install-recommends -y \ shellcheck \ pkg-config \ autoconf \ automake \ libtool \ make \ libuv1-dev \ libsqlite3-dev \ liblz4-dev
After Go is installed, ensure that the CGO_ENABLED environment variable is persistently set to 1, which allows Go programs to interface with C libraries:
go env -w CGO_ENABLED=1Additional variables must be set in your shell to ensure that Dqlite dependencies can be loaded during the build:
| ENVIRONMENT VARIABLE | VALUE |
|---|---|
| CGO_CFLAGS | -I$HOME/go/deps/dqlite/include/ |
| CGO_LDFLAGS | -L$HOME/go/deps/dqlite/.libs/ |
| LD_LIBRARY_PATH | $HOME/go/deps/dqlite/.libs/ |
| CGO_LDFLAGS_ALLOW | (-Wl,-wrap,pthread_create)|(-Wl,-z,now) |
If you are using bash as your shell, you can set the above as persistent variables with the following commands:
cat << EOF >> ~/.bashrc
export CGO_CFLAGS="-I$HOME/go/deps/dqlite/include/"
export CGO_LDFLAGS="-L$HOME/go/deps/dqlite/.libs/"
export LD_LIBRARY_PATH="$HOME/go/deps/dqlite/.libs/"
export CGO_LDFLAGS_ALLOW="(-Wl,-wrap,pthread_create)|(-Wl,-z,now)"
EOF
source ~/.bashrcClone this repository to your system, then run the following command from the repository's root directory:
make depsThis installs required dependencies, including Dqlite.
If the previous command is successful, then build the example package by running:
make -C exampleAfter a successful build, test the microctl and microd commands by running:
microctl --help
microd --helpIf either command returns a not found error, confirm that the microctl and microd have been generated. Typically, they are generated in the ~/go/bin/ directory. If this directory is not defined in your system path, you must add it.
If you're using bash, you can add it by running:
echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.bashrc
source ~/.bashrcThe microd command starts the Microcluster daemon, and microctl controls it.
Note: These commands are not a core component of the Microcluster library; they are included in this example package to demonstrate how you can create similar commands for your own implementation.
Use the microd command along with the --state-dir <path/to/state/directory> flag to start a Microcluster daemon with a running control socket and no database.
You must specify its state directory, the path where the daemon's information is stored. If the state directory does not exist at the path you provide, microd creates the directory.
View the microd --help documentation for other options, or view the tutorial for example usage.
Use the microctl command to control the Microcluster. View microctl --help for options, or view the tutorial for example usage.
This tutorial walks you through using the example package to start up a Microcluster and interact with it.
Ensure that your system meets the prerequisites in the how-to guide above, then build the package.
The commands below start three Microcluster daemons in the background, creating state directories for each and waiting for the daemon to be ready to process requests. Each daemon's PID is stored in a shell variable (proc1, proc2, and proc3) for later use.
Run:
microd --state-dir /tmp/mc1 & proc1=$!
microd --state-dir /tmp/mc2 & proc2=$!
microd --state-dir /tmp/mc3 & proc3=$!You should see three "Microcluster database is uninitialized" warnings. Don't worry; this is expected.
Run the following command to bootstrap the first Microcluster member, which starts a new cluster:
microctl --state-dir /tmp/mc1 init mc1 127.0.0.1:9001 --bootstrapYou might see a warning that "The 'missing_extension' is not registered". Disregard this warning.
To confirm creation of the cluster, run the following command:
microctl --state-dir /tmp/mc1 cluster listYou should see a table that displays a single cluster member with the name of mc1 and an address of 127.0.0.1:9001, along with its role, fingerprint, and status. Ensure that the status is ONLINE before you proceed.
To generate and use join tokens for the second and third Microcluster members, using the names mc2 and mc3, run:
token=$(microctl --state-dir /tmp/mc1 tokens add mc2)
microctl --state-dir /tmp/mc2 init mc2 127.0.0.1:9002 --token "$token"
token=$(microctl --state-dir /tmp/mc1 tokens add mc3)
microctl --state-dir /tmp/mc3 init mc3 127.0.0.1:9003 --token "$token"Note: Each token can only be used once, because they are deleted from the cluster after use.
To confirm that the second and third Microcluster members have joined the cluster, view the cluster list again.
You have created three Microcluster daemons, used one to bootstrap a new cluster, then joined the other two daemons to that cluster. Next, remove the mc3 cluster member:
microctl --state-dir /tmp/mc1 cluster remove mc3Note: When using cluster remove, for the --state-dir argument, you can use the state directory for any online cluster member. This includes the state directory of the cluster member being removed.
The microctl command includes an option to execute an SQL query against the cluster's Dqlite database.
Run the following command to view all available tables:
microctl --state-dir /tmp/mc1 sql "SELECT name FROM sqlite_master WHERE type='table';"Expected output:
+----------------------+
| name |
+----------------------+
| sqlite_sequence |
| schemas |
| core_cluster_members |
| core_token_records |
| extended_table |
| some_other_table |
+----------------------+
Try querying data from the core_cluster_members table:
microctl --state-dir /tmp/mc1 sql "SELECT name,address,heartbeat FROM core_cluster_members"Expected output:
+------+----------------+--------------------------------+
| name | address | heartbeat |
+------+----------------+--------------------------------+
| mc1 | 127.0.0.1:9001 | 2025-03-20T17:52:03.101704405Z |
| mc2 | 127.0.0.1:9002 | 2025-03-20T17:52:03.125658611Z |
+------+----------------+--------------------------------+
Finally, perform an SQL query on an extended schema table called extended_table:
microctl --state-dir /tmp/mc1 sql "insert into extended_table (key, value) values ('some_key', 'some_value')"Expected output:
Rows affected: 1
View the updated table:
microctl --state-dir /tmp/mc1 sql "select * from extended_table"Expected output:
+----+----------+------------+
| id | key | value |
+----+----------+------------+
| 1 | some_key | some_value |
+----+----------+------------+
Run:
microctl --state-dir /tmp/mc2 extended 127.0.0.1:9001Expected output:
cluster member at address "127.0.0.1:9002" received message "Testing 1 2 3..." from cluster member at address "127.0.0.1:9001"
This demonstrates using the extended API to communicate between mc1 (127.0.0.1:9001) and mc2 (127.0.0.1:9002).
To shut down the Microcluster, stop the daemons using the PID variables defined in Step 2:
kill $proc1 $proc2 $proc3If you are done using the example package, or you want to start the tutorial over from the beginning, also remove the /tmp/mc1, /tmp/mc2, and /tmp/mc3 directories:
rm -rf /tmp/mc*