<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Hosted Control Plane on TechBlog about OpenShift/Ansible/Satellite and much more</title><link>https://blog.stderr.at/categories/hosted-control-plane/</link><description>TechBlog about OpenShift/Ansible/Satellite and much more</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>Toni Schmidbauer &amp; Thomas Jungbauer</copyright><lastBuildDate>Mon, 15 Dec 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.stderr.at/categories/hosted-control-plane/index.xml" rel="self" type="application/rss+xml"/><item><title>Hosted Control Planes behind a Proxy</title><link>https://blog.stderr.at/openshift-platform/other-topics/2025-12-15-hosted-control-planes-and-proxy/</link><pubDate>Mon, 15 Dec 2025 00:00:00 +0000</pubDate><guid>https://blog.stderr.at/openshift-platform/other-topics/2025-12-15-hosted-control-planes-and-proxy/</guid><description>&lt;div class="paragraph"&gt;
&lt;p&gt;Recently, I encountered a problem deploying a Hosted Control Plane (HCP) at a customer site. The installation started successfully—etcd came up fine—but then it just stopped. The virtual machines were created, but they never joined the cluster. No OVN or Multus pods ever started.
The only meaningful message in the cluster-version-operator pod logs was:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-console hljs" data-lang="console"&gt;I1204 08:22:35.473783 1 status.go:185] Synchronizing status errs=field.ErrorList(nil) status=&amp;amp;cvo.SyncWorkerStatus{Generation:1, Failure:(*payload.UpdateError)(0xc0006313b0), Done:575, Total:623,&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This message did appear over and over again.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_problem_summary"&gt;Problem Summary&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;etcd started successfully, but the installation stalled&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API server was running&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;VMs started but never joined the cluster&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No OVN or Multus pods ever started&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The installation was stuck in a loop&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_troubleshooting"&gt;Troubleshooting&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Troubleshooting was not straightforward. The cluster-version-operator logs provided the only clue.
However, the VMs were already running, so we could log in to them—and there it was, the reason for the stalled installation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_connect_to_a_vm"&gt;Connect to a VM&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;To connect to a VM, use the &lt;code&gt;virtctl&lt;/code&gt; command. This connects you to the machine as the &lt;code&gt;core&lt;/code&gt; user:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="admonitionblock note"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-note" title="Note"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
You can download &lt;code&gt;virtctl&lt;/code&gt; from the OpenShift Downloads page in the OpenShift web console.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="admonitionblock warning"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-warning" title="Warning"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
You need the SSH key for the &lt;code&gt;core&lt;/code&gt; user.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;virtctl ssh -n clusters-my-hosted-cluster core@vmi/my-node-pool-dsj7z-sss8w &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Replace &lt;strong&gt;my-hosted-cluster&lt;/strong&gt; with the name of your hosted cluster and &lt;strong&gt;my-node-pool-dsj7z-sss8w&lt;/strong&gt; with the name of your VM.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect2"&gt;
&lt;h3 id="_verify_the_problem"&gt;Verify the Problem&lt;/h3&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Once logged in, check the &lt;code&gt;journalctl -xf&lt;/code&gt; output. In case of a proxy issue, you’ll see an error like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;&amp;gt; Dec 10 06:23:09 my-node-pool2-gwvjh-rwtx8 sh[2143]: time=&amp;#34;2025-12-10T06:23:09Z&amp;#34; level=warning msg=&amp;#34;Failed, retrying in 1s ... (3/3). Error: initializing source docker://quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:500704de3ef374e61417cc14eda99585450c317d72f454dda0dadd5dda1ba57a: pinging container registry quay.io: Get \&amp;#34;https://quay.io/v2/\&amp;#34;: dial tcp 3.209.93.201:443: i/o timeout&amp;#34;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;So we have a timeout when trying to pull the image from the container registry. This is a classic proxy issue. When you try &lt;code&gt;curl&lt;/code&gt; or manual pulls you will get the same message.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_configuring_the_proxy_for_the_hosted_control_plane"&gt;Configuring the Proxy for the Hosted Control Plane&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The big question is: How do we configure the proxy for the Hosted Control Plane?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This is not well documented yet—in fact, it’s barely documented at all.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The Hosted Control Plane is managed through a custom resource called &lt;code&gt;HostedCluster&lt;/code&gt;, and that’s exactly where we configure the proxy.
The upstream documentation at &lt;a href="https://hypershift.pages.dev/how-to/configure-ocp-components/#overview" target="_blank" rel="noopener"&gt;HyperShift Documentation&lt;/a&gt; explains that you can add a &lt;code&gt;configuration&lt;/code&gt; section to the resource. Let’s do that:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Update the &lt;code&gt;HostedCluster&lt;/code&gt; resource with the following configuration:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-yaml hljs" data-lang="yaml"&gt;spec:
configuration:
proxy:
httpProxy: http://proxy.example.com:8080 &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
httpsProxy: https://proxy.example.com:8080 &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
noProxy: .cluster.local,.svc,10.128.0.0/14,127.0.0.1,localhost &lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
trustedCA:
name: user-ca-bundle &lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;HTTP proxy URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;HTTPS proxy URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="3"&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Comma-separated list of domains, IPs, or CIDRs to exclude from proxy routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="4"&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;OPTIONAL: Name of a ConfigMap containing a custom CA certificate bundle&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="admonitionblock caution"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class="icon"&gt;
&lt;i class="fa icon-caution" title="Caution"&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class="content"&gt;
If you’re using a custom CA, create the ConfigMap beforehand or alongside the &lt;code&gt;HostedCluster&lt;/code&gt; resource. The ConfigMap must contain a key named &lt;code&gt;ca-bundle.crt&lt;/code&gt; with your CA certificate(s).
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_but_wait_there_is_more"&gt;But wait there is more…​&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If you are using such a proxy, which is injecting it’s own certificate, then you probably saw the following: The &lt;strong&gt;Release Image&lt;/strong&gt; is not available when you try to deploy a new Hosted Control Plane.
The drop down in the UI is empty and you can’t select a release image.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This happens because the Pod that is trying to fetch the image is not able to connect to Github.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;You can test this with the following commands:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc rsh cluster-image-set-controller-XXXXX -n multicluster-engine &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
curl -v https://github.com/stolostron/acm-hive-openshift-releases.git/info/refs?service=git-upload-pack &lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Replace &lt;strong&gt;XXXXX&lt;/strong&gt; with the name of the Pod cluster-image-set-controller in the &lt;strong&gt;multicluster-engine&lt;/strong&gt; namespace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="2"&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Try to execute the curl command to see if you can connect to Github&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;If this command fails with a certificate error, then you need to add the certificate to the Pod/Deployment.
A Configmap called &lt;strong&gt;trusted-ca-bundle&lt;/strong&gt; should already exist in the multicluster-engine namespace. If not, it must be created with the certificate chain of your Proxy (key: ca-bundle.crt)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The following command will add the ConfigMap to the deployment.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc -n multicluster-engine set volume deployment/cluster-image-set-controller --add --type configmap --configmap-name trusted-ca-bundle --name trusted-ca-bundle --mount-path /etc/pki/tls/certs/ --overwrite&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Wait a couple of minutes after the Pods has been restarted. It will try to download the release images from Github again.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;You can check the logs of the Pod to see if the download was successful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="listingblock"&gt;
&lt;div class="content"&gt;
&lt;pre class="highlightjs highlight"&gt;&lt;code class="language-bash hljs" data-lang="bash"&gt;oc logs cluster-image-set-controller-XXXXX -n multicluster-engine &lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="colist arabic"&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;i class="conum" data-value="1"&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Replace &lt;strong&gt;XXXXX&lt;/strong&gt; with the name of the Pod cluster-image-set-controller in the &lt;strong&gt;multicluster-engine&lt;/strong&gt; namespace&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;That should do it, you should now be able to select a release image and deploy a new Hosted Control Plane.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="imageblock"&gt;
&lt;div class="content"&gt;
&lt;img src="https://blog.stderr.at/openshift-platform/other-topics/images/HCP-Release-Images.png" alt="Release Images"/&gt;
&lt;/div&gt;
&lt;div class="title"&gt;Figure 1. Drow Down with Release Images&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="sect1"&gt;
&lt;h2 id="_summary"&gt;Summary&lt;/h2&gt;
&lt;div class="sectionbody"&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;That’s actually everything you need for proxy configuration with Hosted Control Planes. Hopefully, the official OpenShift documentation will be updated soon to include this information.
red Hat created two tickets to track the progress of this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="ulist"&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://issues.redhat.com/browse/ACM-10151" target="_blank" rel="noopener"&gt;ACM-10151&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://issues.redhat.com/browse/ACM-23664" target="_blank" rel="noopener"&gt;ACM-23664&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item></channel></rss>