diff --git a/.gitlab/ci/test-on-cng/main.gitlab-ci.yml b/.gitlab/ci/test-on-cng/main.gitlab-ci.yml
index 0c07556322c37afc80bed59915451d12de16484d..f038407116daef601503362b39b0d5d4e8730c37 100644
--- a/.gitlab/ci/test-on-cng/main.gitlab-ci.yml
+++ b/.gitlab/ci/test-on-cng/main.gitlab-ci.yml
@@ -51,7 +51,14 @@ workflow:
     - source scripts/utils.sh
     - source scripts/rspec_helpers.sh
     - cd qa && bundle install
-    - bundle exec cng create deployment --gitlab-domain "${GITLAB_DOMAIN}" --ci --with-cluster ${EXTRA_DEPLOY_VALUES}
+    - |
+      bundle exec cng create deployment kind \
+        --gitlab-domain "${GITLAB_DOMAIN}" \
+        --timeout 5m \
+        --admin-password "${GITLAB_ADMIN_PASSWORD}" \
+        --admin-token "${GITLAB_QA_ADMIN_ACCESS_TOKEN}" \
+        --ci \
+        ${EXTRA_DEPLOY_VALUES}
   script:
     - export QA_COMMAND="bundle exec bin/qa ${QA_SCENARIO:=Test::Instance::All} $QA_GITLAB_URL -- --force-color --order random --format documentation"
     - echo "Running - '$QA_COMMAND'"
diff --git a/gems/gitlab-cng/lib/gitlab/cng/commands/create.rb b/gems/gitlab-cng/lib/gitlab/cng/commands/create.rb
index 56ff6cc54fea10a0682620905c3d24b23d05f3b1..01375754069b93a5bcb137e6913ca44d5c49b701 100644
--- a/gems/gitlab-cng/lib/gitlab/cng/commands/create.rb
+++ b/gems/gitlab-cng/lib/gitlab/cng/commands/create.rb
@@ -1,14 +1,13 @@
 # frozen_string_literal: true
 
+require_relative "subcommands/deployment"
+
 module Gitlab
   module Cng
     module Commands
       # Create command composed of subcommands that create various resources needed for CNG deployment
       #
       class Create < Command
-        # @return [Array] configurations that are used for kind cluster deployments
-        KIND_CLUSTER_CONFIGURATIONS = %w[kind].freeze
-
         desc "cluster", "Create kind cluster for local deployments"
         option :name,
           desc: "Cluster name",
@@ -24,52 +23,20 @@ class Create < Command
           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
 
-        desc "deployment [NAME]", "Create CNG deployment from official GitLab Helm chart"
-        long_desc <<~LONGDESC
-          This command installs a GitLab chart archive and performs all additional pre-install and post-install setup.
-          Argument NAME is helm install name and defaults to "gitlab".
-          Deployment has several optional environment variables it can read before performing chart install:
-            QA_EE_LICENSE|EE_LICENSE - gitlab test license, if present, will be added to deployment,
-        LONGDESC
-        option :configuration,
-          desc: "Deployment configuration",
-          default: "kind",
-          type: :string,
-          aliases: "-c",
-          enum: ["kind"]
-        option :namespace,
-          desc: "Deployment namespace",
-          default: "gitlab",
-          type: :string,
-          aliases: "-n"
-        option :set,
-          desc: "Optional helm chart values (can specify multiple or separate values with commas: key1=val1,key2=val2)",
-          type: :string,
-          repeatable: true
-        option :ci,
-          desc: "Use CI specific configuration",
-          default: false,
-          type: :boolean
-        option :gitlab_domain,
-          desc: "Domain for deployed app. Defaults to (your host IP).nip.io",
-          type: :string
-        option :with_cluster,
-          desc: "Create kind cluster for local deployments. \
-            Only valid for configurations designed to run against local kind cluster",
-          type: :boolean
-        def deployment(name = "gitlab")
-          if options[:with_cluster] && KIND_CLUSTER_CONFIGURATIONS.include?(options[:configuration])
-            invoke :cluster, [], ci: options[:ci]
-          end
-
-          Deployment::Installation
-            .new(name, **symbolized_options.slice(:configuration, :namespace, :set, :ci, :gitlab_domain))
-            .create
-        end
+        desc "deployment [TYPE]", "Create specific type of deployment"
+        subcommand "deployment", Subcommands::Deployment
       end
     end
   end
diff --git a/gems/gitlab-cng/lib/gitlab/cng/commands/subcommands/deployment.rb b/gems/gitlab-cng/lib/gitlab/cng/commands/subcommands/deployment.rb
new file mode 100644
index 0000000000000000000000000000000000000000..90f403fa5ac6fe5ed48d00dbfcb36403b680608a
--- /dev/null
+++ b/gems/gitlab-cng/lib/gitlab/cng/commands/subcommands/deployment.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require "socket"
+
+module Gitlab
+  module Cng
+    module Commands
+      module Subcommands
+        # Different deployment type subcommands
+        #
+        # Each public method defines a specific deployment type.
+        # Each deployment method must call {Deployment::Installaton#create} where installation instance is initialized
+        #   with appropriate configuration class which encapsulates optional deployment hooks and specific helm values
+        #
+        class Deployment < Command
+          class << self
+            # Add common deployment options for each deployment command defined as public method
+            #
+            # @param [String] name
+            # @return [void]
+            def method_added(name)
+              option :namespace,
+                desc: "Deployment namespace",
+                default: "gitlab",
+                type: :string,
+                aliases: "-n"
+              option :set,
+                desc: "Optional helm chart values " \
+                      "(can specify multiple or separate values with commas: key1=val1,key2=val2)",
+                type: :string,
+                repeatable: true
+              option :ci,
+                desc: "Use CI specific configuration",
+                default: false,
+                type: :boolean
+              option :timeout,
+                desc: "Timeout for deployment",
+                default: "10m",
+                type: :string
+
+              super(name)
+            end
+          end
+
+          desc "kind [NAME]", "Create CNG deployment against local kind k8s cluster where NAME is deployment name"
+          option :create_cluster,
+            desc: "Create kind cluster for local deployments before creating deployment",
+            type: :boolean,
+            default: true
+          option :docker_hostname,
+            desc: "Custom docker hostname if remote docker instance is used, like docker-in-docker, " \
+                  "only applicable when --create-cluster is true",
+            type: :string
+          option :gitlab_domain,
+            desc: "Domain for deployed app, default to (your host IP).nip.io",
+            type: :string
+          option :admin_password,
+            desc: "Admin password for gitlab, defaults to password commonly used across development environments",
+            type: :string,
+            default: "5iveL!fe"
+          option :admin_token,
+            desc: "Admin token for gitlab, defaults to value used in gitlab development seed data",
+            type: :string,
+            default: "ypCa3Dzb23o5nvsixwPA"
+          option :host_http_port,
+            desc: "Host HTTP port for gitlab",
+            type: :numeric,
+            default: 80
+          option :host_ssh_port,
+            desc: "Host ssh port for gitlab",
+            type: :numeric,
+            default: 22
+          def kind(name = "gitlab")
+            if options[:create_cluster]
+              invoke(Commands::Create, :cluster, [], **symbolized_options.slice(
+                :docker_hostname, :ci, :host_http_port, :host_ssh_port
+              ))
+            end
+
+            configuration_args = symbolized_options.slice(
+              :namespace,
+              :ci,
+              :gitlab_domain,
+              :admin_password,
+              :admin_token,
+              :host_http_port,
+              :host_ssh_port
+            )
+
+            installation(name, Cng::Deployment::Configurations::Kind.new(**configuration_args)).create
+          end
+
+          private
+
+          # Installation instance
+          #
+          # @param [String] name
+          # @param [Deployment::Configurations::Base] configuration
+          # @return [Deployment::Installation]
+          def installation(name, configuration)
+            Cng::Deployment::Installation.new(
+              name, configuration: configuration,
+              **symbolized_options.slice(:namespace, :set, :ci, :gitlab_domain, :timeout)
+            )
+          end
+
+          # Populate options with default gitlab domain if missing
+          #
+          # @return [Hash]
+          def symbolized_options
+            @symbolized_options ||= super.tap do |opts|
+              next unless opts[:gitlab_domain].nil?
+
+              # merge default option lazily to not fetch ip_address_list every time class is loaded
+              opts.merge!({ gitlab_domain: "#{Socket.ip_address_list.detect(&:ipv4_private?).ip_address}.nip.io" })
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/_base.rb b/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/_base.rb
index dc89fb30f8263f1b55c63405d5f6f2b7eea73c23..458afa8faf9e6652c045acc3c355d0955578ffe3 100644
--- a/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/_base.rb
+++ b/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/_base.rb
@@ -20,9 +20,8 @@ module Configurations
         class Base
           include Helpers::Output
 
-          def initialize(namespace, kubeclient, ci, gitlab_domain)
+          def initialize(namespace:, ci:, gitlab_domain:)
             @namespace = namespace
-            @kubeclient = kubeclient
             @ci = ci
             @gitlab_domain = gitlab_domain
           end
@@ -81,7 +80,14 @@ def gitlab_url
 
           private
 
-          attr_reader :namespace, :kubeclient, :ci, :gitlab_domain
+          attr_reader :namespace, :ci, :gitlab_domain
+
+          # Instance of {Kubectl::Client}
+          #
+          # @return [Kubectl::Client]
+          def kubeclient
+            @kubeclient ||= Kubectl::Client.new(namespace)
+          end
         end
       end
     end
diff --git a/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/kind.rb b/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/kind.rb
index 2a00e06dcf7c4a2f9efc70a94038e1180c712e42..23f6625a73d68ac4044b1bdeecf2ad5f0365ddd0 100644
--- a/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/kind.rb
+++ b/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/configurations/kind.rb
@@ -21,6 +21,23 @@ class Kind < Base
             fi
           SH
 
+          def initialize(
+            namespace:,
+            ci:,
+            gitlab_domain:,
+            admin_password:,
+            admin_token:,
+            host_http_port:,
+            host_ssh_port:
+          )
+            super(namespace: namespace, ci: ci, gitlab_domain: gitlab_domain)
+
+            @admin_password = admin_password
+            @admin_token = admin_token
+            @host_http_port = host_http_port
+            @host_ssh_port = host_ssh_port
+          end
+
           # Run pre-deployment setup
           #
           # @return [void]
@@ -42,6 +59,12 @@ def run_post_deployment_setup
           def values
             {
               global: {
+                shell: {
+                  port: host_ssh_port
+                },
+                pages: {
+                  port: host_http_port
+                },
                 initialRootPassword: {
                   secret: ADMIN_PASSWORD_SECRET
                 },
@@ -60,8 +83,8 @@ def values
                   service: {
                     type: "NodePort",
                     nodePorts: {
-                      "gitlab-shell": 32022,
-                      http: 32080
+                      "gitlab-shell": Cng::Kind::Cluster::SSH_PORT,
+                      http: Cng::Kind::Cluster::HTTP_PORT
                     }
                   }
                 }
@@ -73,24 +96,12 @@ def values
           #
           # @return [String]
           def gitlab_url
-            "http://gitlab.#{gitlab_domain}#{ci ? '' : ':32080'}"
+            @gitlab_url ||= URI("http://gitlab.#{gitlab_domain}:#{host_http_port}").to_s
           end
 
           private
 
-          # Gitlab initial admin password, defaults to commonly used password across development environments
-          #
-          # @return [String]
-          def admin_password
-            @admin_password ||= ENV["GITLAB_ADMIN_PASSWORD"] || "5iveL!fe"
-          end
-
-          # Gitlab admin user personal access token, defaults to value used in development seed data
-          #
-          # @return [String]
-          def admin_token
-            @admin_token ||= ENV["GITLAB_ADMIN_ACCESS_TOKEN"] || "ypCa3Dzb23o5nvsixwPA"
-          end
+          attr_reader :admin_password, :admin_token, :host_http_port, :host_ssh_port
 
           # Token seed script for root user
           #
diff --git a/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/default_values.rb b/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/default_values.rb
index 508b8a5291f99ba3602a35b8dec717be6a367a4e..d5368757d4616ec7d210e654476f8ccfe2aad25e 100644
--- a/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/default_values.rb
+++ b/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/default_values.rb
@@ -47,22 +47,22 @@ def common_values(domain)
           # @return [Hash]
           def component_ci_versions
             {
-              "gitaly.image.repository" => "#{IMAGE_REPOSITORY}/gitaly",
-              "gitaly.image.tag" => gitaly_version,
-              "gitlab-shell.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-shell",
-              "gitlab-shell.image.tag" => "v#{gitlab_shell_version}",
-              "migrations.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-toolbox-ee",
-              "migrations.image.tag" => commit_sha,
-              "toolbox.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-toolbox-ee",
-              "toolbox.image.tag" => commit_sha,
-              "sidekiq.annotations.commit" => commit_short_sha,
-              "sidekiq.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-sidekiq-ee",
-              "sidekiq.image.tag" => commit_sha,
-              "webservice.annotations.commit" => commit_short_sha,
-              "webservice.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-webservice-ee",
-              "webservice.image.tag" => commit_sha,
-              "webservice.workhorse.image" => "#{IMAGE_REPOSITORY}/gitlab-workhorse-ee",
-              "webservice.workhorse.tag" => commit_sha
+              "gitlab.gitaly.image.repository" => "#{IMAGE_REPOSITORY}/gitaly",
+              "gitlab.gitaly.image.tag" => gitaly_version,
+              "gitlab.gitlab-shell.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-shell",
+              "gitlab.gitlab-shell.image.tag" => "v#{gitlab_shell_version}",
+              "gitlab.migrations.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-toolbox-ee",
+              "gitlab.migrations.image.tag" => commit_sha,
+              "gitlab.toolbox.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-toolbox-ee",
+              "gitlab.toolbox.image.tag" => commit_sha,
+              "gitlab.sidekiq.annotations.commit" => commit_short_sha,
+              "gitlab.sidekiq.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-sidekiq-ee",
+              "gitlab.sidekiq.image.tag" => commit_sha,
+              "gitlab.webservice.annotations.commit" => commit_short_sha,
+              "gitlab.webservice.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-webservice-ee",
+              "gitlab.webservice.image.tag" => commit_sha,
+              "gitlab.webservice.workhorse.image" => "#{IMAGE_REPOSITORY}/gitlab-workhorse-ee",
+              "gitlab.webservice.workhorse.tag" => commit_sha
             }
           end
         end
diff --git a/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/installation.rb b/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/installation.rb
index bfa0d5b139e56cec4fcaf3b39ed06dd047ecbfa4..6e65ccc59f3fa1aa32f54d6aadb0b9e32aaaddc7 100644
--- a/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/installation.rb
+++ b/gems/gitlab-cng/lib/gitlab/cng/lib/deployment/installation.rb
@@ -1,6 +1,5 @@
 # frozen_string_literal: true
 
-require "socket"
 require "yaml"
 require "active_support/core_ext/hash"
 
@@ -15,12 +14,13 @@ class Installation
 
         LICENSE_SECRET = "gitlab-license"
 
-        def initialize(name, configuration:, namespace:, ci:, gitlab_domain: nil, set: [])
+        def initialize(name, configuration:, namespace:, ci:, gitlab_domain:, timeout:, set: [])
           @name = name
           @configuration = configuration
           @namespace = namespace
           @ci = ci
           @gitlab_domain = gitlab_domain
+          @timeout = timeout
           @set = set
         end
 
@@ -28,7 +28,7 @@ def initialize(name, configuration:, namespace:, ci:, gitlab_domain: nil, set: [
         #
         # @return [void]
         def create
-          log("Creating CNG deployment '#{name}' using '#{configuration}' configuration", :info, bright: true)
+          log("Creating CNG deployment '#{name}'", :info, bright: true)
           run_pre_deploy_setup
           run_deploy
           run_post_deploy_setup
@@ -36,9 +36,16 @@ def create
           exit(1)
         end
 
+        # Specific component version values used in CI
+        #
+        # @return [String]
+        def component_version_values
+          @component_version_values ||= DefaultValues.component_ci_versions.map { |k, v| "#{k}=#{v}" }
+        end
+
         private
 
-        attr_reader :name, :configuration, :namespace, :ci, :set
+        attr_reader :name, :configuration, :namespace, :ci, :set, :gitlab_domain, :timeout
         alias_method :cli_values, :set
 
         # Kubectl client instance
@@ -48,25 +55,6 @@ def kubeclient
           @kubeclient ||= Kubectl::Client.new(namespace)
         end
 
-        # Gitlab app domain
-        #
-        # @return [String]
-        def gitlab_domain
-          @gitlab_domain ||= "#{Socket.ip_address_list.detect(&:ipv4_private?).ip_address}.nip.io"
-        end
-
-        # Configuration class instance
-        #
-        # @return [Configuration::Base]
-        def config_instance
-          @config_instance ||= Configurations.const_get(configuration.capitalize, false).new(
-            namespace,
-            kubeclient,
-            ci,
-            gitlab_domain
-          )
-        end
-
         # Gitlab license
         #
         # @return [String]
@@ -105,7 +93,7 @@ def run_pre_deploy_setup
             create_namespace
             create_license
 
-            config_instance.run_pre_deployment_setup
+            configuration.run_pre_deployment_setup
           end
         end
 
@@ -117,26 +105,26 @@ def run_deploy
             "upgrade",
             "--install", name, "gitlab/gitlab",
             "--namespace", namespace,
-            "--timeout", "5m",
+            "--timeout", timeout,
             "--wait"
           ]
-          cmd.push(*DefaultValues.component_ci_versions.flat_map { |k, v| ["--set", "gitlab.#{k}=#{v}"] }) if ci
-          cmd.push(*cli_values.flat_map { |v| ["--set", v] })
+          cmd.push(*component_version_values.flat_map { |v| ["--set", v] }) if ci
+          cmd.push("--set", cli_values.join(",")) unless cli_values.empty?
           cmd.push("--values", "-")
           values = DefaultValues.common_values(gitlab_domain)
             .deep_merge(license_values)
-            .deep_merge(config_instance.values)
+            .deep_merge(configuration.values)
             .deep_stringify_keys
 
           Helpers::Spinner.spin("running helm deployment") { puts run_helm_cmd(cmd, values.to_yaml) }
-          log("Deployment successfull and app is available via: #{config_instance.gitlab_url}", :success, bright: true)
+          log("Deployment successful and app is available via: #{configuration.gitlab_url}", :success, bright: true)
         end
 
         # Execute post-deployment setup
         #
         # @return [void]
         def run_post_deploy_setup
-          Helpers::Spinner.spin("running post-deployment setup") { config_instance.run_post_deployment_setup }
+          Helpers::Spinner.spin("running post-deployment setup") { configuration.run_post_deployment_setup }
         end
 
         # Add helm chart repo
diff --git a/gems/gitlab-cng/lib/gitlab/cng/lib/kind/cluster.rb b/gems/gitlab-cng/lib/gitlab/cng/lib/kind/cluster.rb
index 41bc8bb1148a21d9f83b328c45de0549065dbf78..448fa4a11b57456ce3712f8836382f55148c874c 100644
--- a/gems/gitlab-cng/lib/gitlab/cng/lib/kind/cluster.rb
+++ b/gems/gitlab-cng/lib/gitlab/cng/lib/kind/cluster.rb
@@ -1,8 +1,8 @@
 # frozen_string_literal: true
 
 require "uri"
-
-require_relative "configs"
+require "tmpdir"
+require "erb"
 
 module Gitlab
   module Cng
@@ -12,11 +12,15 @@ module Kind
       class Cluster
         include Helpers::Output
         include Helpers::Shell
-        include Configs
 
-        def initialize(ci:, name:, docker_hostname: nil)
+        HTTP_PORT = 32080
+        SSH_PORT = 32022
+
+        def initialize(ci:, name:, host_http_port:, host_ssh_port:, docker_hostname: nil)
           @ci = ci
           @name = name
+          @host_http_port = host_http_port
+          @host_ssh_port = host_ssh_port
           @docker_hostname = ci ? docker_hostname || "docker" : docker_hostname
         end
 
@@ -34,14 +38,7 @@ def create
 
         private
 
-        attr_reader :ci, :name, :docker_hostname
-
-        # Check if cluster exists
-        #
-        # @return [Boolean]
-        def cluster_exists?
-          execute_shell(%w[kind get clusters]).include?(name)
-        end
+        attr_reader :ci, :name, :docker_hostname, :host_http_port, :host_ssh_port
 
         # Create kind cluster
         #
@@ -54,7 +51,7 @@ def create_cluster
               "cluster",
               "--name", name,
               "--wait", "30s",
-              "--config", ci ? ci_config(docker_hostname) : default_config(docker_hostname)
+              "--config", ci ? ci_config : default_config
             ])
           end
         end
@@ -75,6 +72,91 @@ def update_server_url
             execute_shell(%W[kubectl config set-cluster #{cluster_name} --server=#{uri}])
           end
         end
+
+        # Check if cluster exists
+        #
+        # @return [Boolean]
+        def cluster_exists?
+          execute_shell(%w[kind get clusters]).include?(name)
+        end
+
+        # Create temporary kind config file
+        #
+        # @param [String] config_yml
+        # @return [String]
+        def tmp_config_file(config_yml)
+          File.join(Dir.tmpdir, "kind-config.yml").tap do |path|
+            File.write(path, config_yml)
+          end
+        end
+
+        # Temporary ci specific kind configuration file
+        #
+        # @return [String] file path
+        def ci_config
+          config_yml = <<~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:
+                        - "#{docker_hostname}"
+                extraPortMappings:
+                  - containerPort: #{HTTP_PORT}
+                    hostPort: #{host_http_port}
+                    listenAddress: "0.0.0.0"
+                  - containerPort: #{SSH_PORT}
+                    hostPort: #{host_ssh_port}
+                    listenAddress: "0.0.0.0"
+          YML
+
+          tmp_config_file(config_yml)
+        end
+
+        # Temporary kind configuration file
+        #
+        # @return [String] file path
+        def default_config
+          template = ERB.new(<<~YML, trim_mode: "-")
+            kind: Cluster
+            apiVersion: kind.x-k8s.io/v1alpha4
+            nodes:
+            - role: control-plane
+              kubeadmConfigPatches:
+                - |
+                  kind: InitConfiguration
+                  nodeRegistration:
+                    kubeletExtraArgs:
+                      node-labels: "ingress-ready=true"
+            <% if docker_hostname -%>
+                - |
+                  kind: ClusterConfiguration
+                  apiServer:
+                    certSANs:
+                      - "<%= docker_hostname %>"
+            <% end -%>
+              extraPortMappings:
+                - containerPort: #{HTTP_PORT}
+                  hostPort: #{host_http_port}
+                  listenAddress: "0.0.0.0"
+                - containerPort: #{SSH_PORT}
+                  hostPort: #{host_ssh_port}
+                  listenAddress: "0.0.0.0"
+          YML
+
+          tmp_config_file(template.result(binding))
+        end
       end
     end
   end
diff --git a/gems/gitlab-cng/lib/gitlab/cng/lib/kind/configs.rb b/gems/gitlab-cng/lib/gitlab/cng/lib/kind/configs.rb
deleted file mode 100644
index 7406b4bb6141dcb8d671fbbb8f003b69ad351e5b..0000000000000000000000000000000000000000
--- a/gems/gitlab-cng/lib/gitlab/cng/lib/kind/configs.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-# frozen_string_literal: true
-
-require "tmpdir"
-require "erb"
-
-module Gitlab
-  module Cng
-    module Kind
-      # Kind configuration file templates
-      #
-      module Configs
-        # Temporary ci specific kind configuration file
-        #
-        # @param [String] docker_hostname
-        # @return [String] file path
-        def ci_config(docker_hostname)
-          config_yml = <<~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:
-                        - "#{docker_hostname}"
-                extraPortMappings:
-                    # containerPort below must match the values file:
-                    #   nginx-ingress.controller.service.nodePorts.http
-                  - containerPort: 32080
-                    hostPort: 80
-                    listenAddress: "0.0.0.0"
-                    # containerPort below must match the values file:
-                    #   nginx-ingress.controller.service.nodePorts.gitlab-shell
-                  - containerPort: 32022
-                    hostPort: 22
-                    listenAddress: "0.0.0.0"
-          YML
-
-          tmp_config_file(config_yml)
-        end
-
-        # Temporary kind configuration file
-        #
-        # @param [String, nil] docker_hostname
-        # @return [String] file path
-        def default_config(docker_hostname)
-          template = ERB.new(<<~YML, trim_mode: "-")
-            kind: Cluster
-            apiVersion: kind.x-k8s.io/v1alpha4
-            nodes:
-            - role: control-plane
-              kubeadmConfigPatches:
-                - |
-                  kind: InitConfiguration
-                  nodeRegistration:
-                    kubeletExtraArgs:
-                      node-labels: "ingress-ready=true"
-            <% if docker_hostname -%>
-                - |
-                  kind: ClusterConfiguration
-                  apiServer:
-                    certSANs:
-                      - "<%= docker_hostname %>"
-            <% end -%>
-              extraPortMappings:
-                # containerPort below must match the values file:
-                #   nginx-ingress.controller.service.nodePorts.http
-              - containerPort: 32080
-                hostPort: 32080
-                listenAddress: "0.0.0.0"
-                # containerPort below must match the values file:
-                #   nginx-ingress.controller.service.nodePorts.ssh
-              - containerPort: 32022
-                hostPort: 32022
-                listenAddress: "0.0.0.0"
-          YML
-
-          tmp_config_file(template.result(binding))
-        end
-
-        # Create temporary kind config file
-        #
-        # @param [String] config_yml
-        # @return [String]
-        def tmp_config_file(config_yml)
-          File.join(Dir.tmpdir, "kind-config.yml").tap do |path|
-            File.write(path, config_yml)
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/gems/gitlab-cng/spec/integration/gitlab/cng/cli_spec.rb b/gems/gitlab-cng/spec/integration/gitlab/cng/cli_spec.rb
index 8bab0b9186793d12a0efaf6e0d20abe4e75f9292..6ceb84c600914710f744a61e765d95ccae59641a 100644
--- a/gems/gitlab-cng/spec/integration/gitlab/cng/cli_spec.rb
+++ b/gems/gitlab-cng/spec/integration/gitlab/cng/cli_spec.rb
@@ -3,17 +3,17 @@
 RSpec.describe Gitlab::Cng::CLI do
   shared_examples "command with help" do |args, help_output|
     it "shows help" do
-      expect { cli.invoke(*args) }.to output(/#{help_output}/).to_stdout
+      expect { cli.start(args) }.to output(/#{help_output}/).to_stdout
     end
   end
 
-  subject(:cli) { described_class.new }
+  subject(:cli) { described_class }
 
   describe "version command" do
-    it_behaves_like "command with help", [:help, ["version"]], /Print cng orchestrator version/
+    it_behaves_like "command with help", %w[help version], /Print cng orchestrator version/
 
     it "executes version command" do
-      expect { cli.invoke(:version) }.to output(/#{Gitlab::Cng::VERSION}/o).to_stdout
+      expect { cli.start(%w[version]) }.to output(/#{Gitlab::Cng::VERSION}/o).to_stdout
     end
   end
 
@@ -25,10 +25,10 @@
       allow(command_instance).to receive(:doctor)
     end
 
-    it_behaves_like "command with help", [:help, ["doctor"]], /Validate presence of all required system dependencies/
+    it_behaves_like "command with help", %w[help doctor], /Validate presence of all required system dependencies/
 
     it "invokes doctor command" do
-      cli.invoke(:doctor)
+      cli.start(%w[doctor])
 
       expect(command_instance).to have_received(:doctor)
     end
@@ -42,12 +42,13 @@
         allow(Gitlab::Cng::Kind::Cluster).to receive(:new).and_return(cluster_instance)
       end
 
-      it_behaves_like "command with help", [:create, %w[help cluster]], /Create kind cluster for local deployments/
+      it_behaves_like "command with help", %w[create help cluster], /Create kind cluster for local deployments/
 
       it "invokes cluster create command" do
-        cli.invoke(:create, %w[cluster])
+        cli.start(%w[create cluster])
 
-        expect(Gitlab::Cng::Kind::Cluster).to have_received(:new).with(ci: false, name: "gitlab")
+        expect(Gitlab::Cng::Kind::Cluster).to have_received(:new)
+          .with(ci: false, name: "gitlab", host_http_port: 80, host_ssh_port: 22)
         expect(cluster_instance).to have_received(:create)
       end
     end
@@ -55,23 +56,22 @@
     context "with deployment subcommand" do
       let(:installation_instance) { instance_double(Gitlab::Cng::Deployment::Installation, create: nil) }
 
-      before do
-        allow(Gitlab::Cng::Deployment::Installation).to receive(:new).and_return(installation_instance)
-      end
+      context "with kind deployment" do
+        let(:configuration_instance) { instance_double(Gitlab::Cng::Deployment::Configurations::Kind) }
 
-      it_behaves_like "command with help", [:create, %w[help deployment]],
-        /This command installs a GitLab chart archive/
+        before do
+          allow(Gitlab::Cng::Deployment::Installation).to receive(:new).and_return(installation_instance)
+          allow(Gitlab::Cng::Deployment::Configurations::Kind).to receive(:new)
+        end
 
-      it "invokes cluster create command" do
-        cli.invoke(:create, %w[deployment])
-
-        expect(Gitlab::Cng::Deployment::Installation).to have_received(:new).with(
-          "gitlab",
-          configuration: "kind",
-          namespace: "gitlab",
-          ci: false
-        )
-        expect(installation_instance).to have_received(:create)
+        it_behaves_like "command with help", %w[create deployment help kind],
+          /Create CNG deployment against local kind k8s cluster/
+
+        it "invokes kind deployment" do
+          cli.start(%w[create deployment kind --gitlab-domain 127.0.0.1.nip.io --skip-create-cluster])
+
+          expect(installation_instance).to have_received(:create)
+        end
       end
     end
   end
diff --git a/gems/gitlab-cng/spec/unit/gitlab/cng/commands/create_spec.rb b/gems/gitlab-cng/spec/unit/gitlab/cng/commands/create_spec.rb
index e5e6a1267907c47d94474013c05d7f9ace2c77ae..b394e5147385c91620b5c8a2d3283be8ff5f6349 100644
--- a/gems/gitlab-cng/spec/unit/gitlab/cng/commands/create_spec.rb
+++ b/gems/gitlab-cng/spec/unit/gitlab/cng/commands/create_spec.rb
@@ -26,58 +26,10 @@
       expect(kind_cluster).to have_received(:create)
       expect(Gitlab::Cng::Kind::Cluster).to have_received(:new).with({
         ci: true,
-        name: "test-cluster"
+        name: "test-cluster",
+        host_http_port: 80,
+        host_ssh_port: 22
       })
     end
   end
-
-  describe "deployment command" do
-    let(:command_name) { "deployment" }
-    let(:deployment_install) { instance_double(Gitlab::Cng::Deployment::Installation, create: nil) }
-
-    before do
-      allow(Gitlab::Cng::Deployment::Installation).to receive(:new).and_return(deployment_install)
-    end
-
-    it "defines deployment command" do
-      expect_command_to_include_attributes(command_name, {
-        description: "Create CNG deployment from official GitLab Helm chart",
-        name: command_name,
-        usage: "#{command_name} [NAME]"
-      })
-    end
-
-    it "invokes kind cluster creation with correct arguments" do
-      invoke_command(command_name, [], {
-        configuration: "kind",
-        ci: true,
-        namespace: "gitlab",
-        gitlab_domain: "127.0.0.1.nip.io"
-      })
-
-      expect(deployment_install).to have_received(:create)
-      expect(Gitlab::Cng::Deployment::Installation).to have_received(:new).with(
-        "gitlab",
-        configuration: "kind",
-        ci: true,
-        namespace: "gitlab",
-        gitlab_domain: "127.0.0.1.nip.io"
-      )
-    end
-
-    it "invokes kind cluster creation when --with-cluster argument is passed" do
-      invoke_command(command_name, [], {
-        configuration: "kind",
-        ci: true,
-        with_cluster: true
-      })
-
-      expect(kind_cluster).to have_received(:create)
-      expect(Gitlab::Cng::Kind::Cluster).to have_received(:new).with({
-        ci: true,
-        name: "gitlab"
-      })
-      expect(deployment_install).to have_received(:create)
-    end
-  end
 end
diff --git a/gems/gitlab-cng/spec/unit/gitlab/cng/commands/subcommands/deployment_spec.rb b/gems/gitlab-cng/spec/unit/gitlab/cng/commands/subcommands/deployment_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ee38785f279c83bdc3bf11b1b705113a81bdb781
--- /dev/null
+++ b/gems/gitlab-cng/spec/unit/gitlab/cng/commands/subcommands/deployment_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+RSpec.describe Gitlab::Cng::Commands::Subcommands::Deployment do
+  include_context "with command testing helper"
+
+  describe "kind deployment command" do
+    let(:command_name) { "kind" }
+
+    let(:installation_instance) { instance_double(Gitlab::Cng::Deployment::Installation, create: nil) }
+    let(:configuration_instance) { instance_double(Gitlab::Cng::Deployment::Configurations::Kind) }
+    let(:cluster_instance) { instance_double(Gitlab::Cng::Kind::Cluster, create: nil) }
+    let(:ip) { instance_double(Addrinfo, ipv4_private?: true, ip_address: "127.0.0.1") }
+
+    before do
+      allow(Gitlab::Cng::Deployment::Installation).to receive(:new).and_return(installation_instance)
+      allow(Gitlab::Cng::Deployment::Configurations::Kind).to receive(:new).and_return(configuration_instance)
+      allow(Gitlab::Cng::Kind::Cluster).to receive(:new).and_return(cluster_instance)
+      allow(Socket).to receive(:ip_address_list).and_return([ip])
+    end
+
+    it "defines kind deployment" do
+      expect_command_to_include_attributes(command_name, {
+        description: "Create CNG deployment against local kind k8s cluster where NAME is deployment name",
+        name: command_name,
+        usage: "#{command_name} [NAME]"
+      })
+    end
+
+    it "invokes kind cluster creation with correct arguments" do
+      invoke_command(command_name, [], {
+        namespace: "gitlab",
+        ci: false
+      })
+
+      expect(Gitlab::Cng::Deployment::Installation).to have_received(:new).with(
+        "gitlab",
+        configuration: configuration_instance,
+        namespace: "gitlab",
+        ci: false,
+        gitlab_domain: "127.0.0.1.nip.io",
+        timeout: "10m"
+      )
+      expect(Gitlab::Cng::Deployment::Configurations::Kind).to have_received(:new).with(
+        namespace: "gitlab",
+        ci: false,
+        gitlab_domain: "127.0.0.1.nip.io",
+        admin_password: "5iveL!fe",
+        admin_token: "ypCa3Dzb23o5nvsixwPA",
+        host_http_port: 80,
+        host_ssh_port: 22
+      )
+      expect(installation_instance).to have_received(:create)
+    end
+
+    it "create 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(cluster_instance).to have_received(:create)
+    end
+  end
+end
diff --git a/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/base_spec.rb b/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/base_spec.rb
index ae0271e6d0ec2bffc5c6c283c1098abdc639acad..30600bba8c9ac84b39e21cb0505eaff538a2a742 100644
--- a/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/base_spec.rb
+++ b/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/base_spec.rb
@@ -4,7 +4,11 @@
   subject(:configuration) { Class.new(described_class) }
 
   let(:config) do
-    configuration.new("gitlab", Gitlab::Cng::Kubectl::Client.new("gitlab"), false, "domain")
+    configuration.new(
+      namespace: "gitlab",
+      ci: false,
+      gitlab_domain: "domain"
+    )
   end
 
   it "returns empty values by default" do
diff --git a/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/kind_spec.rb b/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/kind_spec.rb
index d9c052488f0a9dd4d8dda80ce498947d3d8affbb..f200bb1f3c335c0dc5c24c6471ffdb7a0b6e777e 100644
--- a/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/kind_spec.rb
+++ b/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/configurations/kind_spec.rb
@@ -1,19 +1,22 @@
 # frozen_string_literal: true
 
 RSpec.describe Gitlab::Cng::Deployment::Configurations::Kind do
-  subject(:configuration) { described_class.new("gitlab", kubeclient, true, "127.0.0.1.nip.io") }
+  subject(:configuration) do
+    described_class.new(
+      namespace: "gitlab",
+      ci: true,
+      gitlab_domain: "127.0.0.1.nip.io",
+      admin_password: "password",
+      admin_token: "token",
+      host_http_port: 80,
+      host_ssh_port: 22
+    )
+  end
 
   let(:kubeclient) { instance_double(Gitlab::Cng::Kubectl::Client, create_resource: "", execute: "") }
 
-  let(:env) do
-    {
-      "GITLAB_ADMIN_PASSWORD" => "password",
-      "GITLAB_ADMIN_ACCESS_TOKEN" => "token"
-    }
-  end
-
-  around do |example|
-    ClimateControl.modify(env) { example.run }
+  before do
+    allow(Gitlab::Cng::Kubectl::Client).to receive(:new).and_return(kubeclient)
   end
 
   it "runs pre-deployment setup", :aggregate_failures do
@@ -69,6 +72,12 @@
   it "returns configuration specific values" do
     expect(configuration.values).to eq({
       global: {
+        shell: {
+          port: 22
+        },
+        pages: {
+          port: 80
+        },
         initialRootPassword: {
           secret: "gitlab-initial-root-password"
         },
diff --git a/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/installation_spec.rb b/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/installation_spec.rb
index 9974af29ae53e9f045366cedbd35ead7c021aee3..1f6e3ae21950dc53412c6366ac94672acbfc654f 100644
--- a/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/installation_spec.rb
+++ b/gems/gitlab-cng/spec/unit/gitlab/cng/deployment/installation_spec.rb
@@ -4,16 +4,17 @@
   subject(:installation) do
     described_class.new(
       "gitlab",
-      configuration: "kind",
+      configuration: configuration,
       namespace: "gitlab",
-      ci: ci
+      ci: ci,
+      gitlab_domain: gitlab_domain,
+      timeout: "10m"
     )
   end
 
-  let(:stdin) { StringIO.new }
   let(:config_values) { { configuration_specific: true } }
-
   let(:ip) { instance_double(Addrinfo, ipv4_private?: true, ip_address: "127.0.0.1") }
+  let(:gitlab_domain) { "#{ip.ip_address}.nip.io" }
 
   let(:kubeclient) do
     instance_double(Gitlab::Cng::Kubectl::Client, create_namespace: "", create_resource: "", execute: "")
@@ -25,7 +26,7 @@
       run_pre_deployment_setup: nil,
       run_post_deployment_setup: nil,
       values: config_values,
-      gitlab_url: "http://gitlab.#{ip.ip_address}.nip.io"
+      gitlab_url: "http://gitlab.#{gitlab_domain}"
     )
   end
 
@@ -42,7 +43,7 @@
     {
       global: {
         hosts: {
-          domain: "#{ip.ip_address}.nip.io",
+          domain: gitlab_domain,
           https: false
         },
         ingress: {
@@ -77,7 +78,6 @@
     allow(Gitlab::Cng::Deployment::Configurations::Kind).to receive(:new).and_return(configuration)
 
     allow(installation).to receive(:execute_shell)
-    allow(Socket).to receive(:ip_address_list).and_return([ip])
   end
 
   around do |example|
@@ -88,14 +88,8 @@
     let(:ci) { false }
 
     it "runs setup and helm deployment" do
-      expect { installation.create }.to output(/Creating CNG deployment 'gitlab' using 'kind' configuration/).to_stdout
+      expect { installation.create }.to output(/Creating CNG deployment 'gitlab'/).to_stdout
 
-      expect(Gitlab::Cng::Deployment::Configurations::Kind).to have_received(:new).with(
-        "gitlab",
-        kubeclient,
-        ci,
-        "#{ip.ip_address}.nip.io"
-      )
       expect(installation).to have_received(:execute_shell).with(
         %w[helm repo add gitlab https://charts.gitlab.io],
         stdin_data: nil
@@ -113,7 +107,7 @@
           helm upgrade
           --install gitlab gitlab/gitlab
           --namespace gitlab
-          --timeout 5m
+          --timeout 10m
           --wait
           --values -
         ],
@@ -133,14 +127,14 @@
     let(:ci) { true }
 
     it "runs helm install with correctly merged values and component versions" do
-      expect { installation.create }.to output(/Creating CNG deployment 'gitlab' using 'kind' configuration/).to_stdout
+      expect { installation.create }.to output(/Creating CNG deployment 'gitlab'/).to_stdout
 
       expect(installation).to have_received(:execute_shell).with(
         %W[
           helm upgrade
           --install gitlab gitlab/gitlab
           --namespace gitlab
-          --timeout 5m
+          --timeout 10m
           --wait
           --set gitlab.gitaly.image.repository=registry.gitlab.com/gitlab-org/build/cng-mirror/gitaly
           --set gitlab.gitaly.image.tag=7aa06a578d76bdc294ee8e9acb4f063e7d9f1d5f
diff --git a/gems/gitlab-cng/spec/unit/gitlab/cng/kind/cluster_spec.rb b/gems/gitlab-cng/spec/unit/gitlab/cng/kind/cluster_spec.rb
index 957c362e5ee1597e303b6684d00179e0d508ceb4..2e102d0f8926ca01a09e5f1d12dfb06bffc562d4 100644
--- a/gems/gitlab-cng/spec/unit/gitlab/cng/kind/cluster_spec.rb
+++ b/gems/gitlab-cng/spec/unit/gitlab/cng/kind/cluster_spec.rb
@@ -1,7 +1,15 @@
 # frozen_string_literal: true
 
 RSpec.describe Gitlab::Cng::Kind::Cluster do
-  subject(:cluster) { described_class.new(ci: ci, name: name, docker_hostname: docker_hostname) }
+  subject(:cluster) do
+    described_class.new(
+      ci: ci,
+      name: name,
+      docker_hostname: docker_hostname,
+      host_http_port: 32080,
+      host_ssh_port: 32022
+    )
+  end
 
   let(:ci) { false }
   let(:name) { "gitlab" }
@@ -51,15 +59,11 @@
                   certSANs:
                     - "#{docker_hostname}"
             extraPortMappings:
-                # containerPort below must match the values file:
-                #   nginx-ingress.controller.service.nodePorts.http
               - containerPort: 32080
-                hostPort: 80
+                hostPort: 32080
                 listenAddress: "0.0.0.0"
-                # containerPort below must match the values file:
-                #   nginx-ingress.controller.service.nodePorts.gitlab-shell
               - containerPort: 32022
-                hostPort: 22
+                hostPort: 32022
                 listenAddress: "0.0.0.0"
       YML
     end
@@ -97,16 +101,12 @@
                 kubeletExtraArgs:
                   node-labels: "ingress-ready=true"
           extraPortMappings:
-            # containerPort below must match the values file:
-            #   nginx-ingress.controller.service.nodePorts.http
-          - containerPort: 32080
-            hostPort: 32080
-            listenAddress: "0.0.0.0"
-            # containerPort below must match the values file:
-            #   nginx-ingress.controller.service.nodePorts.ssh
-          - containerPort: 32022
-            hostPort: 32022
-            listenAddress: "0.0.0.0"
+            - containerPort: 32080
+              hostPort: 32080
+              listenAddress: "0.0.0.0"
+            - containerPort: 32022
+              hostPort: 32022
+              listenAddress: "0.0.0.0"
       YML
     end
 
diff --git a/scripts/qa/cng_deploy/cng-kind.sh b/scripts/qa/cng_deploy/cng-kind.sh
index 9271cd13923dce5fdadf81a6bf55b0e92c1b8559..5de49b2e6de2a5e0a65ea6af2a137eb2c5ca5b5c 100644
--- a/scripts/qa/cng_deploy/cng-kind.sh
+++ b/scripts/qa/cng_deploy/cng-kind.sh
@@ -29,15 +29,15 @@ function save_install_logs() {
   log_with_header "Events of namespace ${NAMESPACE}"
   kubectl get events --output wide --namespace ${NAMESPACE}
 
-  for pod in $(kubectl get pods --no-headers --namespace ${NAMESPACE} --output jsonpath={.items[*].metadata.name}); do
+  for pod in $(kubectl get pods --no-headers --namespace ${NAMESPACE} --output 'jsonpath={.items[*].metadata.name}'); do
     log_with_header "Description of pod ${pod}"
     kubectl describe pod ${pod} --namespace ${NAMESPACE}
 
-    for container in $(kubectl get pods ${pod} --no-headers --namespace ${NAMESPACE} --output jsonpath={.spec.initContainers[*].name}); do
+    for container in $(kubectl get pods ${pod} --no-headers --namespace ${NAMESPACE} --output 'jsonpath={.spec.initContainers[*].name}'); do
       kubectl logs ${pod} --namespace ${NAMESPACE} --container ${container} >"${container}.log"
     done
 
-    for container in $(kubectl get pods ${pod} --no-headers --namespace ${NAMESPACE} --output jsonpath={.spec.containers[*].name}); do
+    for container in $(kubectl get pods ${pod} --no-headers --namespace ${NAMESPACE} --output 'jsonpath={.spec.containers[*].name}'); do
       kubectl logs ${pod} --namespace ${NAMESPACE} --container ${container} >"${container}.log"
     done
   done