**Describe the solution you'd like**

We already can run clickhouse-server without configured ZooKeeper (the tables will start in read-only mode)
and with configured ZooKeeper, if it starts to be inaccessible at runtime (the tables will be read-only until the session is re-established).

Let's also make it possible to start up when ZooKeeper is unavailable.

**Additional context**

If that will be very hard to implement, we can consider other options:
- lazy attaching of the tables after sever start-up;
- a maintenance mode when the tables are not attached at start-up and require manual ATTACH queries.
const String &, const String & detached_replica_name, const String & detached_zookeeper_path, ContextPtr local_context)
{
    bool keep_shared = false;
    zkutil::ZooKeeperPtr zookeeper = local_context->getZooKeeper();
    NameSet files_not_to_remove;
    fs::path checksums = fs::path(path) / IMergeTreeDataPart::FILE_FOR_REFERENCES_CHECK;
    if (disk->exists(checksums))
    {
        if (disk->getRefCount(checksums) == 0)
        {
            String id = disk->getUniqueId(checksums);
            bool can_remove = false;
            std::tie(can_remove, files_not_to_remove) = StorageReplicatedMergeTree::unlockSharedDataByID(id, table_uuid, part_name,
                detached_replica_name, toString(disk->getDataSourceDescription().type), zookeeper, local_context->getReplicatedMergeTreeSettings(), &Poco::Logger::get("StorageReplicatedMergeTree"),
                detached_zookeeper_path);
            keep_shared = !can_remove;
        }
        else
            keep_shared = true;
    }
    disk->removeSharedRecursive(path, keep_shared, files_not_to_remove);
    return keep_shared;
}
void StorageReplicatedMergeTree::createAndStoreFreezeMetadata(DiskPtr disk, DataPartPtr, String backup_part_path) const