diff --git a/qa/gems/gitlab-cng/lib/gitlab/cng/commands/create.rb b/qa/gems/gitlab-cng/lib/gitlab/cng/commands/create.rb
index 01375754069b93a5bcb137e6913ca44d5c49b701..732ea2ceaaeccae80fae608ab2e1f7f1531db994 100644
--- a/qa/gems/gitlab-cng/lib/gitlab/cng/commands/create.rb
+++ b/qa/gems/gitlab-cng/lib/gitlab/cng/commands/create.rb
@@ -8,33 +8,8 @@ module Commands
       # Create command composed of subcommands that create various resources needed for CNG deployment
       #
       class Create < Command
-        desc "cluster", "Create kind cluster for local deployments"
-        option :name,
-          desc: "Cluster name",
-          default: "gitlab",
-          type: :string,
-          aliases: "-n"
-        option :ci,
-          desc: "Use CI specific configuration",
-          default: false,
-          type: :boolean,
-          aliases: "-c"
-        option :docker_hostname,
-          desc: "Custom docker hostname if remote docker instance is used, like docker-in-docker",
-          type: :string,
-          aliases: "-d"
-        option :host_http_port,
-          desc: "Extra port mapping for Gitlab HTTP port",
-          type: :numeric,
-          default: 80
-        option :host_ssh_port,
-          desc: "Extra port mapping for Gitlab ssh port",
-          type: :numeric,
-          default: 22
-        def cluster
-          Kind::Cluster.new(**symbolized_options).create
-        end
-
+        # TODO: without separate cluster creation command, create subcommands are somewhat redundant,
+        # consider removing
         desc "deployment [TYPE]", "Create specific type of deployment"
         subcommand "deployment", Subcommands::Deployment
       end
diff --git a/qa/gems/gitlab-cng/lib/gitlab/cng/commands/destroy.rb b/qa/gems/gitlab-cng/lib/gitlab/cng/commands/destroy.rb
index f65c6c82ff6bccfdded47273e2d087adfcaab824..2619f60a5824ca0cf29e28c6c28e54c566229d61 100644
--- a/qa/gems/gitlab-cng/lib/gitlab/cng/commands/destroy.rb
+++ b/qa/gems/gitlab-cng/lib/gitlab/cng/commands/destroy.rb
@@ -6,17 +6,12 @@ module Commands
       # Destroy command consisting of cleanup for cluster and deployments
       #
       class Destroy < Command
-        desc "cluster", "Destroy kind cluster"
-        option :name,
-          desc: "Cluster name",
-          default: "gitlab",
-          type: :string,
-          aliases: "-n"
+        desc "cluster", "Destroy kind cluster created for kind type deployments"
         def cluster
-          delete = TTY::Prompt.new.yes?("Are you sure you want to delete cluster #{options[:name]}?")
+          delete = TTY::Prompt.new.yes?("Are you sure you want to delete cluster #{Kind::Cluster::CLUSTER_NAME}?")
           return unless delete
 
-          Kind::Cluster.destroy(options[:name])
+          Kind::Cluster.destroy
         end
 
         desc "deployment [NAME]", "Destroy specific deployment and all it's resources, " \
@@ -35,6 +30,11 @@ def cluster
           desc: "Timeout for helm release uninstall",
           default: "10m",
           type: :string
+        option :with_cluster,
+          desc: "Destroy kind cluster that was created for the deployment, " \
+            "only applicable for deployment type 'kind'",
+          default: false,
+          type: :boolean
         def deployment(name = Subcommands::Deployment::DEFAULT_HELM_RELEASE_NAME)
           prompt = TTY::Prompt.new
           delete = prompt.yes?("Are you sure you want to delete deployment '#{name}'?")
@@ -52,6 +52,8 @@ def deployment(name = Subcommands::Deployment::DEFAULT_HELM_RELEASE_NAME)
             cleanup_configuration: cleanup_configuration,
             timeout: options[:timeout]
           )
+
+          Kind::Cluster.destroy if options[:with_cluster]
         end
       end
     end
diff --git a/qa/gems/gitlab-cng/lib/gitlab/cng/commands/subcommands/deployment.rb b/qa/gems/gitlab-cng/lib/gitlab/cng/commands/subcommands/deployment.rb
index ce5de1fec883fb37cacbf61ba73792ea8dc4d7d2..ada2fe3afecee3a7b6f65129ce95cbbc1cc77b47 100644
--- a/qa/gems/gitlab-cng/lib/gitlab/cng/commands/subcommands/deployment.rb
+++ b/qa/gems/gitlab-cng/lib/gitlab/cng/commands/subcommands/deployment.rb
@@ -96,9 +96,9 @@ def kind(name = DEFAULT_HELM_RELEASE_NAME)
             return print_deploy_args("kind") if options[:print_deploy_args] && options[:ci]
 
             if options[:create_cluster]
-              invoke(Commands::Create, :cluster, [], **symbolized_options.slice(
+              Kind::Cluster.new(**symbolized_options.slice(
                 :docker_hostname, :ci, :host_http_port, :host_ssh_port
-              ))
+              )).create
             end
 
             configuration_args = symbolized_options.slice(
diff --git a/qa/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/kind.rb b/qa/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/kind.rb
index b84fecde4d9d243ce30fa0f64d6000cd92681d9d..96887a6e449b49873ce48c6b3fb11ba0dc276766 100644
--- a/qa/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/kind.rb
+++ b/qa/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/kind.rb
@@ -83,8 +83,8 @@ def values
                   service: {
                     type: "NodePort",
                     nodePorts: {
-                      "gitlab-shell": Cng::Kind::Cluster::SSH_PORT,
-                      http: Cng::Kind::Cluster::HTTP_PORT
+                      "gitlab-shell": Cng::Kind::Cluster.host_port_mapping(host_ssh_port),
+                      http: Cng::Kind::Cluster.host_port_mapping(host_http_port)
                     }
                   }
                 }
diff --git a/qa/gems/gitlab-cng/lib/gitlab/cng/lib/kind/cluster.rb b/qa/gems/gitlab-cng/lib/gitlab/cng/lib/kind/cluster.rb
index ea8062f8d9cfd2b9a7691ee1e35a790f00d2d2f4..52b49999036a6831420fdd5a8b1344bf60a99925 100644
--- a/qa/gems/gitlab-cng/lib/gitlab/cng/lib/kind/cluster.rb
+++ b/qa/gems/gitlab-cng/lib/gitlab/cng/lib/kind/cluster.rb
@@ -14,29 +14,50 @@ class Cluster
         extend Helpers::Output
         extend Helpers::Shell
 
-        HTTP_PORT = 32080
-        SSH_PORT = 32022
+        CLUSTER_NAME = "gitlab"
 
         METRICS_CHART_NAME = "metrics-server"
         METRICS_CHART_URL = "https://kubernetes-sigs.github.io/metrics-server/"
         METRICS_CHART_VERSION = "^3.12"
 
-        # Destroy kind cluster
-        #
-        # @param [String] name
-        # @return [void]
-        def self.destroy(name)
-          log("Destroying cluster '#{name}'", :info, bright: true)
-          return log("Cluster not found, skipping!", :warn) unless execute_shell(%w[kind get clusters]).include?(name)
+        class << self
+          # Destroy kind cluster
+          #
+          # @param [String] name
+          # @return [void]
+          def destroy
+            log("Destroying cluster '#{CLUSTER_NAME}'", :info, bright: true)
+
+            unless execute_shell(%w[kind get clusters]).include?(CLUSTER_NAME)
+              return log("Cluster not found, skipping!", :warn)
+            end
+
+            Helpers::Spinner.spin("destroying cluster") do
+              puts execute_shell(%W[kind delete cluster --name #{CLUSTER_NAME}])
+            end
+          end
+
+          # Get configured port mapping
+          #
+          # @param [Integer] port
+          # @return [Integer]
+          def host_port_mapping(port)
+            yml = YAML.safe_load(File.read(kind_config_file))
 
-          Helpers::Spinner.spin("destroying cluster") do
-            puts execute_shell(%W[kind delete cluster --name #{name}])
+            yml["nodes"].first["extraPortMappings"].find { |mapping| mapping["hostPort"] == port }["containerPort"]
+          end
+
+          # Kind cluster configuration file
+          #
+          # @return [String]
+          def kind_config_file
+            File.join(Helpers::Utils.tmp_dir, "kind-config.yml")
           end
         end
 
-        def initialize(ci:, name:, host_http_port:, host_ssh_port:, docker_hostname: nil)
+        def initialize(ci:, host_http_port:, host_ssh_port:, docker_hostname: nil)
           @ci = ci
-          @name = name
+          @name = CLUSTER_NAME
           @host_http_port = host_http_port
           @host_ssh_port = host_ssh_port
           @docker_hostname = ci ? docker_hostname || "docker" : docker_hostname
@@ -126,14 +147,12 @@ def cluster_exists?
           execute_shell(%w[kind get clusters]).include?(name)
         end
 
-        # Create temporary kind config file
+        # Create kind config file
         #
         # @param [String] config_yml
         # @return [String]
         def tmp_config_file(config_yml)
-          File.join(Helpers::Utils.tmp_dir, "kind-config.yml").tap do |path|
-            File.write(path, config_yml)
-          end
+          self.class.kind_config_file.tap { |path| File.write(path, config_yml) }
         end
 
         # Temporary ci specific kind configuration file
@@ -159,10 +178,10 @@ def ci_config
                       certSANs:
                         - "#{docker_hostname}"
                 extraPortMappings:
-                  - containerPort: #{HTTP_PORT}
+                  - containerPort: #{http_port}
                     hostPort: #{host_http_port}
                     listenAddress: "0.0.0.0"
-                  - containerPort: #{SSH_PORT}
+                  - containerPort: #{ssh_port}
                     hostPort: #{host_ssh_port}
                     listenAddress: "0.0.0.0"
           YML
@@ -193,16 +212,30 @@ def default_config
                       - "<%= docker_hostname %>"
             <% end -%>
               extraPortMappings:
-                - containerPort: #{HTTP_PORT}
+                - containerPort: #{http_port}
                   hostPort: #{host_http_port}
                   listenAddress: "0.0.0.0"
-                - containerPort: #{SSH_PORT}
+                - containerPort: #{ssh_port}
                   hostPort: #{host_ssh_port}
                   listenAddress: "0.0.0.0"
           YML
 
           tmp_config_file(template.result(binding))
         end
+
+        # Random http port to expose outside cluster
+        #
+        # @return [Integer]
+        def http_port
+          @http_port ||= rand(30000..31000)
+        end
+
+        # Random ssh port to expose outside cluster
+        #
+        # @return [Integer]
+        def ssh_port
+          @ssh_port ||= rand(31001..32000)
+        end
       end
     end
   end
diff --git a/qa/gems/gitlab-cng/spec/integration/gitlab/cng/cli_spec.rb b/qa/gems/gitlab-cng/spec/integration/gitlab/cng/cli_spec.rb
index 1727d7f8d41fb99e60645c13e5fcab8fafc1ee8a..de907c0051de9852f990d67afa0358ad756a29f4 100644
--- a/qa/gems/gitlab-cng/spec/integration/gitlab/cng/cli_spec.rb
+++ b/qa/gems/gitlab-cng/spec/integration/gitlab/cng/cli_spec.rb
@@ -45,11 +45,6 @@
   end
 
   describe "create command" do
-    context "with cluster subcommand" do
-      it_behaves_like "command with help", %w[create help cluster], /Create kind cluster for local deployments/
-      it_behaves_like "executable command", Gitlab::Cng::Commands::Create, %w[create cluster]
-    end
-
     context "with deployment subcommand" do
       context "with kind deployment" do
         it_behaves_like "command with help", %w[create deployment help kind],
diff --git a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/create_spec.rb b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/create_spec.rb
deleted file mode 100644
index b394e5147385c91620b5c8a2d3283be8ff5f6349..0000000000000000000000000000000000000000
--- a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/create_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Gitlab::Cng::Commands::Create do
-  include_context "with command testing helper"
-
-  let(:kind_cluster) { instance_double(Gitlab::Cng::Kind::Cluster, create: nil) }
-
-  before do
-    allow(Gitlab::Cng::Kind::Cluster).to receive(:new).and_return(kind_cluster)
-  end
-
-  describe "cluster command" do
-    let(:command_name) { "cluster" }
-
-    it "defines cluster command" do
-      expect_command_to_include_attributes(command_name, {
-        description: "Create kind cluster for local deployments",
-        name: command_name,
-        usage: command_name
-      })
-    end
-
-    it "invokes kind cluster creation with correct arguments" do
-      invoke_command(command_name, [], { ci: true, name: "test-cluster" })
-
-      expect(kind_cluster).to have_received(:create)
-      expect(Gitlab::Cng::Kind::Cluster).to have_received(:new).with({
-        ci: true,
-        name: "test-cluster",
-        host_http_port: 80,
-        host_ssh_port: 22
-      })
-    end
-  end
-end
diff --git a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/destroy_spec.rb b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/destroy_spec.rb
index bdf3a3ab02c9c2f391aa60f3c55d8139e84e9ade..b12843759f830eb91ea552307672c0e8d44febdb 100644
--- a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/destroy_spec.rb
+++ b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/destroy_spec.rb
@@ -15,17 +15,16 @@
 
     it "defines cluster command" do
       expect_command_to_include_attributes(command_name, {
-        description: "Destroy kind cluster",
-        name: command_name,
+        description: "Destroy kind cluster created for kind type deployments",
         usage: command_name
       })
     end
 
     context "with accepted prompt" do
       it "invokes kind cluster deletion" do
-        invoke_command(command_name, [], { name: "test-cluster" })
+        invoke_command(command_name, [])
 
-        expect(Gitlab::Cng::Kind::Cluster).to have_received(:destroy).with("test-cluster")
+        expect(Gitlab::Cng::Kind::Cluster).to have_received(:destroy)
       end
     end
 
@@ -33,7 +32,7 @@
       let(:prompt_response) { false }
 
       it "skips cluster deletion" do
-        invoke_command(command_name, [], { name: "test-cluster" })
+        invoke_command(command_name, [])
 
         expect(Gitlab::Cng::Kind::Cluster).not_to have_received(:destroy)
       end
diff --git a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/subcommands/deployment_spec.rb b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/subcommands/deployment_spec.rb
index 482b517bccb089e6bb13e3d4d7e81baad1b37115..01bee2a58c957a1437871b659be3763fdce70e4a 100644
--- a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/subcommands/deployment_spec.rb
+++ b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/commands/subcommands/deployment_spec.rb
@@ -34,7 +34,7 @@
       })
     end
 
-    it "invokes kind cluster creation with correct arguments" do
+    it "invokes kind deployment creation with correct arguments" do
       invoke_command(command_name, [], {
         namespace: "gitlab",
         ci: false
@@ -61,14 +61,13 @@
       expect(installation_instance).to have_received(:create)
     end
 
-    it "create kind cluster before deployment" do
+    it "creates kind cluster before deployment" do
       invoke_command(command_name, [], {
         namespace: "gitlab",
         ci: true
       })
 
-      expect(Gitlab::Cng::Kind::Cluster).to have_received(:new)
-        .with(name: "gitlab", ci: true, host_http_port: 80, host_ssh_port: 22)
+      expect(Gitlab::Cng::Kind::Cluster).to have_received(:new).with(ci: true, host_http_port: 80, host_ssh_port: 22)
       expect(cluster_instance).to have_received(:create)
     end
 
diff --git a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/kind_spec.rb b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/kind_spec.rb
index 4a7489da95505b5aacb62fc228a5a9330db3f39a..f815b0b9a27492101c1fd05b3ef8d2d8002167b4 100644
--- a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/kind_spec.rb
+++ b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/kind_spec.rb
@@ -14,8 +14,17 @@
   end
 
   let(:kubeclient) { instance_double(Gitlab::Cng::Kubectl::Client, create_resource: "", execute: "") }
+  let(:port_mappings) do
+    {
+      80 => 32080,
+      22 => 32222
+    }
+  end
 
   before do
+    allow(Gitlab::Cng::Kind::Cluster).to receive(:host_port_mapping).and_return(port_mappings[22])
+    allow(Gitlab::Cng::Kind::Cluster).to receive(:host_port_mapping).with(80).and_return(port_mappings[80])
+
     allow(Gitlab::Cng::Kubectl::Client).to receive(:new).and_return(kubeclient)
   end
 
@@ -97,8 +106,8 @@
           service: {
             type: "NodePort",
             nodePorts: {
-              "gitlab-shell": 32022,
-              http: 32080
+              "gitlab-shell": port_mappings[22],
+              http: port_mappings[80]
             }
           }
         }
diff --git a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/kind/cluster_spec.rb b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/kind/cluster_spec.rb
index d365febd9138b19a35d3bcc0869888f8fb986d3f..3144f8d73b6ae029d1b6cbf1b7188b72a49b593c 100644
--- a/qa/gems/gitlab-cng/spec/unit/gitlab/cng/kind/cluster_spec.rb
+++ b/qa/gems/gitlab-cng/spec/unit/gitlab/cng/kind/cluster_spec.rb
@@ -5,10 +5,9 @@
     subject(:cluster) do
       described_class.new(
         ci: ci,
-        name: name,
         docker_hostname: docker_hostname,
-        host_http_port: 32080,
-        host_ssh_port: 32022
+        host_http_port: 80,
+        host_ssh_port: 22
       )
     end
 
@@ -19,6 +18,8 @@
     let(:command_status) { instance_double(Process::Status, success?: true) }
     let(:clusters) { "kind" }
     let(:helm) { instance_double(Gitlab::Cng::Helm::Client, add_helm_chart: nil, upgrade: nil) }
+    let(:http_container_port) { 30080 }
+    let(:ssh_container_port) { 31022 }
 
     before do
       allow(Gitlab::Cng::Helpers::Utils).to receive(:tmp_dir).and_return("/tmp")
@@ -37,6 +38,9 @@
         "--wait", "30s",
         "--config", tmp_config_path
       ]).and_return(["", command_status])
+
+      allow(cluster).to receive(:rand).with(30000..31000).and_return(http_container_port)
+      allow(cluster).to receive(:rand).with(31001..32000).and_return(ssh_container_port)
     end
 
     context "with ci specific setup" do
@@ -63,11 +67,11 @@
                     certSANs:
                       - "#{docker_hostname}"
               extraPortMappings:
-                - containerPort: 32080
-                  hostPort: 32080
+                - containerPort: #{http_container_port}
+                  hostPort: 80
                   listenAddress: "0.0.0.0"
-                - containerPort: 32022
-                  hostPort: 32022
+                - containerPort: #{ssh_container_port}
+                  hostPort: 22
                   listenAddress: "0.0.0.0"
         YML
       end
@@ -117,11 +121,11 @@
                   kubeletExtraArgs:
                     node-labels: "ingress-ready=true"
             extraPortMappings:
-              - containerPort: 32080
-                hostPort: 32080
+              - containerPort: #{http_container_port}
+                hostPort: 80
                 listenAddress: "0.0.0.0"
-              - containerPort: 32022
-                hostPort: 32022
+              - containerPort: #{ssh_container_port}
+                hostPort: 22
                 listenAddress: "0.0.0.0"
         YML
       end
@@ -152,7 +156,7 @@
     end
   end
 
-  describe "with cleanup" do
+  describe "#destroy" do
     subject(:cluster) { described_class }
 
     before do
@@ -166,7 +170,7 @@
       end
 
       it "deletes cluster" do
-        expect { cluster.destroy("gitlab") }.to output(/Destroying cluster 'gitlab'/).to_stdout
+        expect { cluster.destroy }.to output(/Destroying cluster 'gitlab'/).to_stdout
         expect(cluster).to have_received(:execute_shell).with(%w[kind delete cluster --name gitlab])
       end
     end
@@ -177,11 +181,52 @@
       end
 
       it "deletes cluster" do
-        expect { cluster.destroy("gitlab") }.to output(
+        expect { cluster.destroy }.to output(
           match(/Destroying cluster 'gitlab'/).and(match(/Cluster not found, skipping!/))
         ).to_stdout
         expect(cluster).not_to have_received(:execute_shell).with(%w[kind delete cluster --name gitlab])
       end
     end
   end
+
+  describe "#host_port_mapping" do
+    let(:http_container_port) { 32080 }
+    let(:ssh_container_port) { 32022 }
+
+    before do
+      allow(File).to receive(:read).with(File.join(Gitlab::Cng::Helpers::Utils.tmp_dir, "kind-config.yml")).and_return(
+        <<~YML
+          apiVersion: kind.x-k8s.io/v1alpha4
+          kind: Cluster
+          networking:
+            apiServerAddress: "0.0.0.0"
+          nodes:
+            - role: control-plane
+              kubeadmConfigPatches:
+                - |
+                  kind: InitConfiguration
+                  nodeRegistration:
+                    kubeletExtraArgs:
+                      node-labels: "ingress-ready=true"
+                - |
+                  kind: ClusterConfiguration
+                  apiServer:
+                    certSANs:
+                      - "test"
+              extraPortMappings:
+                - containerPort: #{http_container_port}
+                  hostPort: 80
+                  listenAddress: "0.0.0.0"
+                - containerPort: #{ssh_container_port}
+                  hostPort: 22
+                  listenAddress: "0.0.0.0"
+        YML
+      )
+    end
+
+    it "return correct port mappings" do
+      expect(described_class.host_port_mapping(80)).to eq(http_container_port)
+      expect(described_class.host_port_mapping(22)).to eq(ssh_container_port)
+    end
+  end
 end